Mercurial > crates > nonstick
diff libpam-sys/src/pam_impl.rs @ 134:6c1e1bdb4164
Use standard #[cfg] directives rather than custom proc macros.
Instead of having to do a bunch of custom parsing and other logic
that tools often choke on, this change introduces an easy way
to depend upon custom #[cfg]s provided by the libpam-sys crate.
author | Paul Fisher <paul@pfish.zone> |
---|---|
date | Thu, 03 Jul 2025 11:03:36 -0400 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpam-sys/src/pam_impl.rs Thu Jul 03 11:03:36 2025 -0400 @@ -0,0 +1,121 @@ +/// An enum that knows its own values. +macro_rules! self_aware_enum { + ( + $(#[$enumeta:meta])* + $viz:vis enum $name:ident { + $( + $(#[$itemeta:meta])* + $item:ident, + )* + } + ) => { + $(#[$enumeta])* + $viz enum $name { + $( + $(#[$itemeta])* + $item, + )* + } + + // The implementations in this block are private for now + // to avoid putting a contract into the public API. + #[allow(dead_code)] + impl $name { + /// Iterator over the items in the enum. For internal use. + fn items() -> Vec<Self> { + vec![$(Self::$item),*] + } + + /// Attempts to parse the enum from the string. For internal use. + fn try_from(value: &str) -> Result<Self, String> { + match value { + $(stringify!($item) => Ok(Self::$item),)* + _ => Err(value.into()), + } + } + } + }; + } + +self_aware_enum! { + /// The PAM implementations supported by `libpam-sys`. + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + #[cfg_attr(pam_impl, non_exhaustive)] + pub enum PamImpl { + /// [Linux-PAM] is provided by most Linux distributions. + /// + /// [Linux-PAM]: https://github.com/linux-pam/linux-pam + LinuxPam, + /// [OpenPAM] is used by most BSDs, including Mac OS X. + /// + /// [OpenPAM]: https://git.des.dev/OpenPAM/OpenPAM + OpenPam, + /// Illumos and Solaris use a derivative of [Sun's implementation][sun]. + /// + /// [sun]: https://code.illumos.org/plugins/gitiles/illumos-gate/+/refs/heads/master/usr/src/lib/libpam + Sun, + /// Only the functionality and constants in [the PAM spec]. + /// + /// [the PAM spec]: https://pubs.opengroup.org/onlinepubs/8329799/toc.htm + XSso, + } +} + +#[cfg(pam_impl)] +include!(concat!(env!("OUT_DIR"), "/pam_impl_const.rs")); + +/// Generates `cargo` directives for build scripts to enable `cfg(pam_impl)`. +/// +/// Print this in your `build.rs` script to be able to use the custom `pam_impl` +/// configuration directive. +/// +/// ``` +/// // build.rs +/// use libpam_sys::pam_impl; +/// fn main() { +/// println!("{}", pam_impl::enable_pam_impl_cfg()) +/// +/// // Whatever other stuff you do in your build.rs. +/// } +/// ``` +/// +/// This will set the current `pam_impl` as well as registering all known +/// PAM implementations with `rustc-check-cfg` so you can easily use them: +/// +/// ``` +/// #[cfg(pam_impl = "OpenPam")] +/// fn openpam_specific_func(handle: *const libpam_sys::pam_handle) { +/// let environ = libpam_sys::pam_getenvlist(handle); +/// // ... +/// libpam_sys::openpam_free_envlist() +/// } +/// +/// // This will give you a warning since "UnknownImpl" is not in the cfg. +/// #[cfg(not(pam_impl = "UnknownImpl"))] +/// fn do_something() { +/// // ... +/// } +/// ``` +#[cfg(pam_impl)] +pub fn enable_pam_impl_cfg() -> String { + format!("{}\n{}", checkcfg(), implcfg(PamImpl::CURRENT_STR)) +} + +/// Generates the `cargo:rustc-check-cfg` directive to print in build scripts. +fn checkcfg() -> String { + let impls: Vec<_> = PamImpl::items() + .into_iter() + .map(|i| format!(r#""{i:?}""#)) + .collect(); + format!( + "\ + cargo:rustc-check-cfg=cfg(pam_impl)\n\ + cargo:rustc-check-cfg=cfg(pam_impl, values({impls}))\ + ", + impls = impls.join(",") + ) +} + +fn implcfg(name: &str) -> String { + format!("cargo:rustc-cfg=pam_impl\ncargo:rustc-cfg=pam_impl={name:?}") +}