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 {