Mercurial > crates > nonstick
comparison libpam-sys/libpam-sys-impls/src/lib.rs @ 109:bb465393621f
Minor cleanup and reorg.
- Use those nice new macros we just implemented.
- Straighten out the macro file.
- Move the `BinaryPayload` into `structs.rs`, leaving helpers behind.
| author | Paul Fisher <paul@pfish.zone> |
|---|---|
| date | Sat, 28 Jun 2025 02:49:35 -0400 |
| parents | e97534be35e3 |
| children | 2346fd501b7a |
comparison
equal
deleted
inserted
replaced
| 108:e97534be35e3 | 109:bb465393621f |
|---|---|
| 10 /// meaningful internal implementation differences, like the way `pam_conv` | 10 /// meaningful internal implementation differences, like the way `pam_conv` |
| 11 /// is handled (see [the Linux-PAM man page for details][man7]). | 11 /// is handled (see [the Linux-PAM man page for details][man7]). |
| 12 /// | 12 /// |
| 13 /// ``` | 13 /// ``` |
| 14 /// # use libpam_sys_impls::cfg_pam_impl; | 14 /// # use libpam_sys_impls::cfg_pam_impl; |
| 15 /// #[cfg_pam_impl("illumos")] | 15 /// #[cfg_pam_impl("Illumos")] |
| 16 /// fn do_something() { /* illumos-only code */ } | 16 /// fn do_something() { /* illumos-only code */ } |
| 17 /// | 17 /// |
| 18 /// #[cfg_pam_impl(not("illumos"))] | 18 /// #[cfg_pam_impl(not("Illumos"))] |
| 19 /// fn do_something() { /* non-illumos code */ } | 19 /// fn do_something() { /* non-illumos code */ } |
| 20 /// | 20 /// |
| 21 /// #[cfg_pam_impl(any("linux-pam", "openpam"))] | 21 /// #[cfg_pam_impl(any("LinuxPam", "MinimalOpenPam"))] |
| 22 /// fn do_something_else() { /* Linux-PAM or OpenPAM */ } | 22 /// fn do_something_else() { /* Linux-PAM or minimal OpenPAM */ } |
| 23 /// | 23 /// |
| 24 /// #[cfg_pam_impl(not(any("illumos", "openpam")))] | 24 /// #[cfg_pam_impl(not(any("Illumos", "OpenPam")))] |
| 25 /// fn do_a_third_thing() { /* Neither Illumos nor OpenPAM */ } | 25 /// fn do_a_third_thing() { /* Neither Illumos nor OpenPAM */ } |
| 26 /// | 26 /// |
| 27 /// #[cfg_pam_impl(any())] | 27 /// #[cfg_pam_impl(any())] |
| 28 /// fn this_will_never_build() { /* why would you do this? */ } | 28 /// fn this_will_never_build() { /* why would you do this? */ } |
| 29 /// | |
| 30 /// #[cfg_pam_impl(not(any()))] | |
| 31 /// fn this_will_always_build() { /* this is technically legal */ } | |
| 29 /// ``` | 32 /// ``` |
| 30 /// | 33 /// |
| 31 /// [man7]: https://man7.org/linux/man-pages/man3/pam_conv.3.html | 34 /// [man7]: https://man7.org/linux/man-pages/man3/pam_conv.3.html |
| 32 #[proc_macro_attribute] | 35 #[proc_macro_attribute] |
| 33 pub fn cfg_pam_impl(attr: pm::TokenStream, item: pm::TokenStream) -> pm::TokenStream { | 36 pub fn cfg_pam_impl(attr: pm::TokenStream, item: pm::TokenStream) -> pm::TokenStream { |
| 34 eprintln!("Got TokenStream: {:?}", attr); | |
| 35 Predicate::parse(attr.into(), None) | 37 Predicate::parse(attr.into(), None) |
| 36 .map(|p| { | 38 .map(|p| { |
| 37 if p.matches(pam_impl_str()) { | 39 if p.matches(pam_impl_str()) { |
| 38 item | 40 item |
| 39 } else { | 41 } else { |
| 41 } | 43 } |
| 42 }) | 44 }) |
| 43 .unwrap_or_else(|e| syn::Error::from(e).into_compile_error().into()) | 45 .unwrap_or_else(|e| syn::Error::from(e).into_compile_error().into()) |
| 44 } | 46 } |
| 45 | 47 |
| 48 /// Outputs the `PamImpl` enum and `LIBPAMSYS_IMPL` constant. Private. | |
| 49 #[proc_macro] | |
| 50 pub fn pam_impl_enum(data: pm::TokenStream) -> pm::TokenStream { | |
| 51 if !data.is_empty() { | |
| 52 panic!("unexpected stuff in pam_impl_enum!()") | |
| 53 } | |
| 54 | |
| 55 let variant = format_ident!("{}", pam_impl_str()); | |
| 56 | |
| 57 quote!( | |
| 58 /// The PAM implementations supported by `libpam-sys`. | |
| 59 #[non_exhaustive] | |
| 60 #[derive(Clone, Copy, Debug, PartialEq)] | |
| 61 pub enum PamImpl { | |
| 62 /// [Linux-PAM] is provided by most Linux implementations. | |
| 63 /// | |
| 64 /// [Linux-PAM]: https://github.com/linux-pam/linux-pam | |
| 65 LinuxPam, | |
| 66 /// [OpenPAM] is used by most BSD distributions, including Mac OS X. | |
| 67 /// | |
| 68 /// [OpenPAM]: https://git.des.dev/OpenPAM/OpenPAM | |
| 69 OpenPam, | |
| 70 /// [Illumos PAM] is used on Illumos and Solaris systems. | |
| 71 /// | |
| 72 /// [Illumos PAM]: https://code.illumos.org/plugins/gitiles/illumos-gate/+/refs/heads/master/usr/src/lib/libpam | |
| 73 Illumos, | |
| 74 /// Only the functionality in [the PAM spec], | |
| 75 /// with OpenPAM/Illumos constants. | |
| 76 /// | |
| 77 /// [the PAM spec]: https://pubs.opengroup.org/onlinepubs/8329799/toc.htm | |
| 78 MinimalOpenPam, | |
| 79 } | |
| 80 | |
| 81 #[doc = concat!("This version of libpam-sys was built for **", stringify!(#variant), "**.")] | |
| 82 pub const LIBPAMSYS_IMPL: PamImpl = PamImpl::#variant; | |
| 83 ) | |
| 84 .into() | |
| 85 } | |
| 86 | |
| 87 /// The name of the PAM implementation. Used only in `libpam-sys`. Private. | |
| 88 #[proc_macro] | |
| 89 pub fn pam_impl_name(data: pm::TokenStream) -> pm::TokenStream { | |
| 90 if !data.is_empty() { | |
| 91 panic!("pam_impl_name! does not take any input") | |
| 92 } | |
| 93 pm::TokenTree::Literal(pm::Literal::string(pam_impl_str())).into() | |
| 94 } | |
| 95 | |
| 96 fn pam_impl_str() -> &'static str { | |
| 97 env!("LIBPAMSYS_IMPL") | |
| 98 } | |
| 99 | |
| 46 #[derive(Debug)] | 100 #[derive(Debug)] |
| 47 enum Error { | 101 enum Error { |
| 48 WithSpan(syn::Error), | 102 WithSpan(syn::Error), |
| 49 WithoutSpan(String), | 103 WithoutSpan(String), |
| 50 } | 104 } |
| 91 impl Predicate { | 145 impl Predicate { |
| 92 fn matches(&self, value: &str) -> bool { | 146 fn matches(&self, value: &str) -> bool { |
| 93 match self { | 147 match self { |
| 94 Self::Literal(literal) => value == literal, | 148 Self::Literal(literal) => value == literal, |
| 95 Self::Not(pred) => !pred.matches(value), | 149 Self::Not(pred) => !pred.matches(value), |
| 96 Self::Any(options) => { | 150 Self::Any(options) => options.iter().any(|s| s == value), |
| 97 options.iter().any(|s| s == value) | |
| 98 } | |
| 99 } | 151 } |
| 100 } | 152 } |
| 101 | 153 |
| 102 fn parse(stream: TokenStream, span: Option<Span>) -> Result<Self> { | 154 fn parse(stream: TokenStream, span: Option<Span>) -> Result<Self> { |
| 103 let mut iter = stream.into_iter(); | 155 let mut iter = stream.into_iter(); |
| 142 match iter.next() { | 194 match iter.next() { |
| 143 None => break, | 195 None => break, |
| 144 Some(TokenTree::Literal(lit)) => { | 196 Some(TokenTree::Literal(lit)) => { |
| 145 output.push(Self::string_lit(lit)?); | 197 output.push(Self::string_lit(lit)?); |
| 146 if !maybe_comma(iter.next())? { | 198 if !maybe_comma(iter.next())? { |
| 147 break | 199 break; |
| 148 } | 200 } |
| 149 }, | 201 } |
| 150 Some(other) => return unexpected(&other, "string literal"), | 202 Some(other) => return unexpected(&other, "string literal"), |
| 151 } | 203 } |
| 152 } | 204 } |
| 153 Ok(output) | 205 Ok(output) |
| 154 } | 206 } |
| 183 } | 235 } |
| 184 } | 236 } |
| 185 unexpected(&tree, "',' or ')'") | 237 unexpected(&tree, "',' or ')'") |
| 186 } | 238 } |
| 187 } | 239 } |
| 188 } | |
| 189 | |
| 190 /// A proc macro that outputs the PAM implementation macro and const. | |
| 191 #[proc_macro] | |
| 192 pub fn pam_impl_enum(data: pm::TokenStream) -> pm::TokenStream { | |
| 193 if !data.is_empty() { panic!("unexpected stuff in pam_impl_enum!()") } | |
| 194 | |
| 195 let variant = format_ident!("{}", pam_impl_str()); | |
| 196 | |
| 197 quote!( | |
| 198 /// The PAM implementations supported by `libpam-sys`. | |
| 199 #[non_exhaustive] | |
| 200 #[derive(Clone, Copy, Debug, PartialEq)] | |
| 201 pub enum PamImpl { | |
| 202 /// [Linux-PAM] is provided by most Linux implementations. | |
| 203 /// | |
| 204 /// [Linux-PAM]: https://github.com/linux-pam/linux-pam | |
| 205 LinuxPam, | |
| 206 /// [OpenPAM] is used by most BSD distributions, including Mac OS X. | |
| 207 /// | |
| 208 /// [OpenPAM]: https://git.des.dev/OpenPAM/OpenPAM | |
| 209 OpenPam, | |
| 210 /// [Illumos PAM] is used on Illumos and Solaris systems. | |
| 211 /// | |
| 212 /// [Illumos PAM]: https://code.illumos.org/plugins/gitiles/illumos-gate/+/refs/heads/master/usr/src/lib/libpam | |
| 213 Illumos, | |
| 214 /// Only the functionality in [the PAM spec], | |
| 215 /// with OpenPAM/Illumos constants. | |
| 216 /// | |
| 217 /// [the PAM spec]: https://pubs.opengroup.org/onlinepubs/8329799/toc.htm | |
| 218 MinimalOpenPam, | |
| 219 } | |
| 220 | |
| 221 #[doc = concat!("This version of libpam-sys was built for **", stringify!(#variant), "**.")] | |
| 222 pub const LIBPAMSYS_IMPL: PamImpl = PamImpl::#variant; | |
| 223 ).into() | |
| 224 } | |
| 225 | |
| 226 /// String literal of the name of the PAM implementation this was built for. | |
| 227 /// | |
| 228 /// The value is the string value of `libpamsys::PamImpl`. | |
| 229 #[proc_macro] | |
| 230 pub fn pam_impl_name(data: pm::TokenStream) -> pm::TokenStream { | |
| 231 if !data.is_empty() { | |
| 232 panic!("pam_impl_name! does not take any input") | |
| 233 } | |
| 234 pm::TokenTree::Literal(pm::Literal::string(pam_impl_str())).into() | |
| 235 } | |
| 236 | |
| 237 fn pam_impl_str() -> &'static str { | |
| 238 env!("LIBPAMSYS_IMPL") | |
| 239 } | 240 } |
| 240 | 241 |
| 241 #[cfg(test)] | 242 #[cfg(test)] |
| 242 mod tests { | 243 mod tests { |
| 243 use super::*; | 244 use super::*; |
| 294 [$(($e, quote!($($i)*))),*] | 295 [$(($e, quote!($($i)*))),*] |
| 295 } | 296 } |
| 296 } | 297 } |
| 297 let matching = cases![ | 298 let matching = cases![ |
| 298 ("Illumos", (any("Illumos", "OpenPam"))), | 299 ("Illumos", (any("Illumos", "OpenPam"))), |
| 300 ("OpenPam", (any("Illumos", "OpenPam"))), | |
| 299 ("LinuxPam", (not("OpenPam"))), | 301 ("LinuxPam", (not("OpenPam"))), |
| 302 ("MinimalOpenPam", (not("OpenPam"))), | |
| 300 ("Other", (not(any("This", "That")))), | 303 ("Other", (not(any("This", "That")))), |
| 301 ("OpenPam", (not(not("OpenPam")))), | 304 ("OpenPam", (not(not("OpenPam")))), |
| 302 ("Anything", (not(any()))), | 305 ("Anything", (not(any()))), |
| 303 ]; | 306 ]; |
| 304 for (good, tree) in matching { | 307 for (good, tree) in matching { |
