diff libpam-sys/libpam-sys-impls/src/lib.rs @ 110:2346fd501b7a

Add tests for constants and do other macro niceties. - Adds tests for all the constants. Pretty sweet. - Moves documentation for cfg-pam-impl macro to `libpam-sys`. - Renames `Illumos` to `Sun`. - other stuff
author Paul Fisher <paul@pfish.zone>
date Sun, 29 Jun 2025 02:15:46 -0400
parents bb465393621f
children 178310336596
line wrap: on
line diff
--- a/libpam-sys/libpam-sys-impls/src/lib.rs	Sat Jun 28 02:49:35 2025 -0400
+++ b/libpam-sys/libpam-sys-impls/src/lib.rs	Sun Jun 29 02:15:46 2025 -0400
@@ -2,36 +2,10 @@
 use proc_macro2::{Delimiter, Group, Literal, Span, TokenStream, TokenTree};
 use quote::{format_ident, quote};
 use std::fmt::Display;
+use std::str::FromStr;
 use syn::Lit;
 
-/// A `cfg`-like attribute macro for code specific to one PAM implementation.
-///
-/// Different versions of PAM export different functions and have some
-/// meaningful internal implementation differences, like the way `pam_conv`
-/// is handled (see [the Linux-PAM man page for details][man7]).
-///
-/// ```
-/// # use libpam_sys_impls::cfg_pam_impl;
-/// #[cfg_pam_impl("Illumos")]
-/// fn do_something() { /* illumos-only code */ }
-///
-/// #[cfg_pam_impl(not("Illumos"))]
-/// fn do_something() { /* non-illumos code */ }
-///
-/// #[cfg_pam_impl(any("LinuxPam", "MinimalOpenPam"))]
-/// fn do_something_else() { /* Linux-PAM or minimal OpenPAM */ }
-///
-/// #[cfg_pam_impl(not(any("Illumos", "OpenPam")))]
-/// fn do_a_third_thing() { /* Neither Illumos nor OpenPAM */ }
-///
-/// #[cfg_pam_impl(any())]
-/// fn this_will_never_build() { /* why would you do this? */ }
-///
-/// #[cfg_pam_impl(not(any()))]
-/// fn this_will_always_build() { /* this is technically legal */ }
-/// ```
-///
-/// [man7]: https://man7.org/linux/man-pages/man3/pam_conv.3.html
+// For documentation on this, see the `libpam-sys` crate.
 #[proc_macro_attribute]
 pub fn cfg_pam_impl(attr: pm::TokenStream, item: pm::TokenStream) -> pm::TokenStream {
     Predicate::parse(attr.into(), None)
@@ -45,48 +19,28 @@
         .unwrap_or_else(|e| syn::Error::from(e).into_compile_error().into())
 }
 
-/// Outputs the `PamImpl` enum and `LIBPAMSYS_IMPL` constant. Private.
+/// Outputs the `PamImpl` enum and `LIBPAMSYS_IMPL` constant.
+/// For use only in `libpam-sys`.
+///
+/// The tokens passed into the macro are pasted immediately before the enum.
 #[proc_macro]
-pub fn pam_impl_enum(data: pm::TokenStream) -> pm::TokenStream {
-    if !data.is_empty() {
-        panic!("unexpected stuff in pam_impl_enum!()")
-    }
-
+pub fn __pam_impl_enum__(data: pm::TokenStream) -> pm::TokenStream {
     let variant = format_ident!("{}", pam_impl_str());
-
-    quote!(
-        /// The PAM implementations supported by `libpam-sys`.
-        #[non_exhaustive]
-        #[derive(Clone, Copy, Debug, PartialEq)]
-        pub enum PamImpl {
-            /// [Linux-PAM] is provided by most Linux implementations.
-            ///
-            /// [Linux-PAM]: https://github.com/linux-pam/linux-pam
-            LinuxPam,
-            /// [OpenPAM] is used by most BSD distributions, including Mac OS X.
-            ///
-            /// [OpenPAM]: https://git.des.dev/OpenPAM/OpenPAM
-            OpenPam,
-            /// [Illumos PAM] is used on Illumos and Solaris systems.
-            ///
-            /// [Illumos PAM]: https://code.illumos.org/plugins/gitiles/illumos-gate/+/refs/heads/master/usr/src/lib/libpam
-            Illumos,
-            /// Only the functionality in [the PAM spec],
-            /// with OpenPAM/Illumos constants.
-            ///
-            /// [the PAM spec]: https://pubs.opengroup.org/onlinepubs/8329799/toc.htm
-            MinimalOpenPam,
-        }
-
-        #[doc = concat!("This version of libpam-sys was built for **", stringify!(#variant), "**.")]
-        pub const LIBPAMSYS_IMPL: PamImpl = PamImpl::#variant;
-    )
-    .into()
+    TokenStream::from_iter([
+        data.into(),
+        TokenStream::from_str(include_str!(concat!(env!("OUT_DIR"), "/pam_impl_enum.rs"))).unwrap(),
+        quote!(
+            impl PamImpl {
+                #[doc = concat!("The PAM implementation this was built for (currently `", stringify!(#variant), ")`.")]
+                pub const CURRENT: Self = Self::#variant;
+            }
+        ),
+    ]).into()
 }
 
-/// The name of the PAM implementation. Used only in `libpam-sys`. Private.
+/// The name of the PAM implementation. For use only in `libpam-sys`.
 #[proc_macro]
-pub fn pam_impl_name(data: pm::TokenStream) -> pm::TokenStream {
+pub fn __pam_impl_name__(data: pm::TokenStream) -> pm::TokenStream {
     if !data.is_empty() {
         panic!("pam_impl_name! does not take any input")
     }
@@ -296,8 +250,8 @@
             }
         }
         let matching = cases![
-            ("Illumos", (any("Illumos", "OpenPam"))),
-            ("OpenPam", (any("Illumos", "OpenPam"))),
+            ("Sun", (any("Sun", "OpenPam"))),
+            ("OpenPam", (any("Sun", "OpenPam"))),
             ("LinuxPam", (not("OpenPam"))),
             ("MinimalOpenPam", (not("OpenPam"))),
             ("Other", (not(any("This", "That")))),
@@ -311,10 +265,12 @@
 
         let nonmatching = cases![
             ("LinuxPam", (not("LinuxPam"))),
-            ("Illumos", ("LinuxPam")),
-            ("OpenPam", (any("LinuxPam", "Illumos"))),
+            ("Sun", ("LinuxPam")),
+            ("OpenPam", (any("LinuxPam", "Sun"))),
             ("One", (not(any("One", "Another")))),
             ("Negatory", (not(not("Affirmative")))),
+            ("MinimalOpenPam", ("OpenPam")),
+            ("OpenPam", (("MinimalOpenPam"))),
         ];
         for (bad, tree) in nonmatching {
             let pred = parse(tree);