changeset 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 04105e9a7de8
files Cargo.lock Cargo.toml build.rs libpam-sys/README.md libpam-sys/libpam-sys-impls/Cargo.toml libpam-sys/libpam-sys-impls/build.rs libpam-sys/libpam-sys-impls/src/lib.rs libpam-sys/libpam-sys-test/Cargo.toml libpam-sys/libpam-sys-test/build.rs libpam-sys/libpam-sys-test/tests/test_constants.rs libpam-sys/src/constants.rs libpam-sys/src/helpers.rs libpam-sys/src/lib.rs
diffstat 13 files changed, 292 insertions(+), 103 deletions(-) [+]
line wrap: on
line diff
--- a/Cargo.lock	Sat Jun 28 02:49:35 2025 -0400
+++ b/Cargo.lock	Sun Jun 29 02:15:46 2025 -0400
@@ -177,6 +177,17 @@
 ]
 
 [[package]]
+name = "libpam-sys-test"
+version = "0.0.0"
+dependencies = [
+ "bindgen",
+ "libpam-sys",
+ "libpam-sys-impls",
+ "quote",
+ "syn",
+]
+
+[[package]]
 name = "log"
 version = "0.4.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
--- a/Cargo.toml	Sat Jun 28 02:49:35 2025 -0400
+++ b/Cargo.toml	Sun Jun 29 02:15:46 2025 -0400
@@ -1,5 +1,5 @@
 [workspace]
-members = ["libpam-sys", "libpam-sys/libpam-sys-impls", "testharness"]
+members = ["libpam-sys", "libpam-sys/libpam-sys-impls", "libpam-sys/libpam-sys-test", "testharness"]
 resolver = "2"
 
 [workspace.package]
--- a/build.rs	Sat Jun 28 02:49:35 2025 -0400
+++ b/build.rs	Sun Jun 29 02:15:46 2025 -0400
@@ -32,7 +32,6 @@
             .header_contents(
                 "linux-pam.h",
                 r#"
-                #include <syslog.h> // for log levels
                 #include <security/_pam_types.h>
                 #include <security/pam_appl.h>
                 #include <security/pam_ext.h>
--- a/libpam-sys/README.md	Sat Jun 28 02:49:35 2025 -0400
+++ b/libpam-sys/README.md	Sun Jun 29 02:15:46 2025 -0400
@@ -8,11 +8,11 @@
 
 - Linux: `LinuxPam`
 - BSDs, including Mac OS: `OpenPam`
-- Illumos/Solaris: `Illumos`
+- Illumos/Solaris: `Sun`
 - Unknown: `OpenPamMinimal`
 
 Each implementation exports all the functionality available in its respective PAM library.
-`OpenPamMinimal` is a subset that includes only the functions available in the spec, and the constants shared in common between OpenPAM and Illumos' implementation. 
+`OpenPamMinimal` is a subset that includes only the functions available in the spec, and the constants shared in common between OpenPAM and Sun's implementation. 
 
 ## References
 
@@ -22,7 +22,7 @@
   - [Linux-PAM guides][linux-guides]: Documentation for developers using PAM and sysadmins.
 - [OpenPAM repository][openpam]: The OpenPAM implementation, used by many BSD varieties. This hews very close to the spec.
   - [OpenPAM man page][manbsd]: NetBSD's root man page for OpenPAM.
-- [Illumos PAM repository][illumos-pam]: Illumos's implementation of PAM. Even more basic than OpenPAM.
+- [Illumos PAM repository][illumos-pam]: Illumos's implementation of PAM, based on Sun's Solaris. Even more basic than OpenPAM.
   - [Illumos PAM man page][manillumos]: Illumos's root man page for its PAM implementation.
 
 [xsso]: https://pubs.opengroup.org/onlinepubs/8329799/toc.htm
--- a/libpam-sys/libpam-sys-impls/Cargo.toml	Sat Jun 28 02:49:35 2025 -0400
+++ b/libpam-sys/libpam-sys-impls/Cargo.toml	Sun Jun 29 02:15:46 2025 -0400
@@ -2,15 +2,17 @@
 name = "libpam-sys-impls"
 description = "Macros for use in libpam-sys."
 version = "0.0.1"
-edition = "2021"
+rust-version.workspace = true
+edition.workspace = true
 
 [lib]
 proc-macro = true
 
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [build-dependencies]
 bindgen = "0.72.0"
+proc-macro2 = "1.0.95"
+quote = "1.0.40"
 strum = { version = "0.27.1", features = ["derive"] }
 
 
--- a/libpam-sys/libpam-sys-impls/build.rs	Sat Jun 28 02:49:35 2025 -0400
+++ b/libpam-sys/libpam-sys-impls/build.rs	Sun Jun 29 02:15:46 2025 -0400
@@ -1,10 +1,20 @@
+//! This absurd build script basically sets up everything for libpam-sys-impl.
+//!
+//!  1. It's the definition site for the [`PamImpl`] enum, which then gets
+//!     output to the `OUT_DIR/pam_impl_enum.rs` file for parsing/inclusion
+//!     into the `__pam_impl_enum__` macro.
+//!  2. It detects the current PAM implementation and sets an env var for
+//!     the macros in `libpam-sys-impl`.
+
+use std::{env, fs};
 use strum::EnumString;
+use proc_macro2::TokenStream;
+use quote::quote;
 
 fn main() {
     let pam_impl = match option_env!("LIBPAMSYS_IMPL") {
         // The default option: Guess what PAM impl we're using based on OS.
         None => {
-            // Otherwise, guess what PAM impl we're using based on the OS.
             if cfg!(target_os = "linux") {
                 PamImpl::LinuxPam
             } else if cfg!(any(
@@ -15,8 +25,11 @@
                 target_os = "openbsd"
             )) {
                 PamImpl::OpenPam
-            } else if cfg!(any()) {
-                PamImpl::Illumos
+            } else if cfg!(any(
+                target_os = "illumos",
+                target_os = "solaris",
+            )) {
+                PamImpl::Sun
             } else {
                 PamImpl::MinimalOpenPam
             }
@@ -28,8 +41,8 @@
             } else if header_exists("security/openpam.h") {
                 PamImpl::OpenPam
             } else if header_exists("security/pam_appl.h") {
-                // We figure we're *probably* on Illumos or something like that.
-                PamImpl::Illumos
+                // We figure we're *probably* on a Sun derivative.
+                PamImpl::Sun
             } else {
                 // If all else fails, assume the bare minimum.
                 PamImpl::MinimalOpenPam
@@ -40,17 +53,63 @@
             Err(_) => panic!("unknown PAM implementation {other:?}"),
         },
     };
+    fs::write(format!("{}/pam_impl_enum.rs", env::var("OUT_DIR").unwrap()), PamImpl::enum_tokens().to_string()).unwrap();
     println!("cargo:rustc-env=LIBPAMSYS_IMPL={pam_impl:?}");
 }
 
-#[derive(Debug, EnumString)]
-enum PamImpl {
-    Illumos,
-    LinuxPam,
-    OpenPam,
-    MinimalOpenPam,
+/// This defines a local enum with an `enum_tokens()` method that can spit out
+/// its own contents.
+macro_rules! self_aware_enum {
+    (
+        $(#here[$here:meta])*
+        $(#[$attr:meta])*
+        $name:ident {
+            $($tt:tt)*
+        }
+    ) => {
+        $(#[$here])*
+        $(#[$attr])*
+        pub enum $name {
+            $($tt)*
+        }
+
+        impl $name {
+            fn enum_tokens() -> TokenStream {
+                quote!(
+                    $(#[$attr])*
+                    pub enum $name {
+                        $($tt)*
+                    }
+                )
+            }
+        }
+    }
 }
 
+self_aware_enum!(
+    #here[derive(EnumString, strum::Display)]
+    /// The PAM implementations supported by `libpam-sys`.
+    #[derive(Clone, Copy, Debug, PartialEq)]
+    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 in [the PAM spec], with OpenPAM/Sun consts.
+        ///
+        /// [the PAM spec]: https://pubs.opengroup.org/onlinepubs/8329799/toc.htm
+        MinimalOpenPam,
+    }
+);
+
 fn header_exists(header: &str) -> bool {
     bindgen::Builder::default()
         .blocklist_item(".*")
--- 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);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpam-sys/libpam-sys-test/Cargo.toml	Sun Jun 29 02:15:46 2025 -0400
@@ -0,0 +1,15 @@
+[package]
+name = "libpam-sys-test"
+version = "0.0.0"
+edition.workspace = true
+rust-version.workspace = true
+publish = false
+
+[dependencies]
+libpam-sys = { path = ".." }
+
+[build-dependencies]
+bindgen = "0.72.0"
+libpam-sys-impls = { path = "../libpam-sys-impls" }
+quote = "1.0.40"
+syn = { version = "2.0.104", default-features = false }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpam-sys/libpam-sys-test/build.rs	Sun Jun 29 02:15:46 2025 -0400
@@ -0,0 +1,103 @@
+use bindgen::MacroTypeVariation;
+use libpam_sys_impls::cfg_pam_impl;
+use quote::ToTokens;
+use std::path::PathBuf;
+use std::{env, fs};
+use syn::{Item, ItemConst};
+
+fn main() {
+    generate_const_test();
+}
+
+#[cfg_pam_impl("LinuxPam")]
+fn test_config() -> TestConfig {
+    TestConfig {
+        headers: vec![
+            "security/_pam_types.h".into(),
+            "security/pam_appl.h".into(),
+            "security/pam_ext.h".into(),
+            "security/pam_modules.h".into(),
+        ],
+        ignore_consts: vec!["__LINUX_PAM__".into(), "__LINUX_PAM_MINOR__".into()],
+    }
+}
+
+#[cfg_pam_impl("OpenPam")]
+fn test_config() -> TestConfig {
+    TestConfig {
+        headers: vec![
+            "security/pam_types.h",
+            "security/openpam.h",
+            "security/pam_appl.h",
+            "security/pam_constants.h",
+        ],
+        ignore_consts: vec![],
+    }
+}
+
+#[cfg_pam_impl(not(any("LinuxPam", "OpenPam")))]
+fn test_config() -> TestConfig {
+    panic!("This PAM implementation is not yet tested.")
+}
+
+fn generate_const_test() {
+    let config = test_config();
+    let builder = bindgen::Builder::default()
+        .header_contents("_.h", &config.header_contents())
+        .merge_extern_blocks(true)
+        .parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
+        .blocklist_type(".*")
+        .blocklist_function(".*")
+        .allowlist_var(".*")
+        .default_macro_constant_type(MacroTypeVariation::Unsigned);
+
+    let generated = builder.generate().unwrap().to_string();
+    let file = syn::parse_file(&generated).unwrap();
+    let mut tests = vec![];
+    tests.push("{".into());
+    tests.extend(
+        file.items
+            .iter()
+            .filter_map(|item| {
+                if let Item::Const(item) = item {
+                    Some(item)
+                } else {
+                    None
+                }
+            })
+            .filter(|item| config.should_check_const(item))
+            .map(|item| {
+                let tokens = item.expr.to_token_stream();
+                format!(
+                    "assert_eq!({tokens}, libpam_sys::{name});",
+                    name = item.ident
+                )
+            }),
+    );
+    tests.push("}".into());
+    fs::write(
+        PathBuf::from(env::var("OUT_DIR").unwrap()).join("constant_test.rs"),
+        tests.join("\n"),
+    )
+    .unwrap();
+}
+
+struct TestConfig {
+    headers: Vec<String>,
+    ignore_consts: Vec<String>,
+}
+
+impl TestConfig {
+    fn header_contents(&self) -> String {
+        let vec: Vec<_> = self
+            .headers
+            .iter()
+            .map(|h| format!("#include <{h}>\n"))
+            .collect();
+        vec.join("")
+    }
+
+    fn should_check_const(&self, item: &ItemConst) -> bool {
+        !self.ignore_consts.contains(&item.ident.to_string())
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpam-sys/libpam-sys-test/tests/test_constants.rs	Sun Jun 29 02:15:46 2025 -0400
@@ -0,0 +1,5 @@
+
+#[test]
+fn check_constants() {
+    include!(concat!(env!("OUT_DIR"), "/constant_test.rs"))
+}
--- a/libpam-sys/src/constants.rs	Sat Jun 28 02:49:35 2025 -0400
+++ b/libpam-sys/src/constants.rs	Sun Jun 29 02:15:46 2025 -0400
@@ -1,4 +1,7 @@
 //! All the constants.
+//!
+//! These constants are tested on a per-platform basis by `libpam-sys-test`'s
+//! `test_constants.rs`.
 
 use libpam_sys_impls::cfg_pam_impl;
 
@@ -71,6 +74,7 @@
         PAM_NO_MODULE_DATA = 18;
         PAM_CONV_ERR = 19;
         PAM_AUTHTOK_ERR = 20;
+        PAM_AUTHTOK_RECOVER_ERR = 21;
         PAM_AUTHTOK_RECOVERY_ERR = 21;
         PAM_AUTHTOK_LOCK_BUSY = 22;
         PAM_AUTHTOK_DISABLE_AGING = 23;
@@ -106,7 +110,7 @@
         PAM_FAIL_DELAY = 10;
         PAM_XDISPLAY = 11;
         PAM_XAUTHDATA = 12;
-        PAM_AUTHTOKTYPE = 13;
+        PAM_AUTHTOK_TYPE = 13;
     );
 
     /// To suppress messages in the item cleanup function.
@@ -184,10 +188,10 @@
 }
 
 /// Constants exclusive to Illumos.
-#[cfg_pam_impl("Illumos")]
-pub use illumos::*;
-#[cfg_pam_impl("Illumos")]
-mod illumos {
+#[cfg_pam_impl("Sun")]
+pub use sun::*;
+#[cfg_pam_impl("Sun")]
+mod sun {
     /// The total number of PAM error codes.
     pub const PAM_TOTAL_ERRNUM: u32 = 28;
 
@@ -227,5 +231,3 @@
     pub const PAM_NUM_ITEMS: u32 = 14;
 }
 
-#[cfg(test)]
-mod test {}
--- a/libpam-sys/src/helpers.rs	Sat Jun 28 02:49:35 2025 -0400
+++ b/libpam-sys/src/helpers.rs	Sun Jun 29 02:15:46 2025 -0400
@@ -1,10 +1,10 @@
 //! This module contains a few non-required helpers to deal with some of the
 //! more annoying memory management in the PAM API.
 use crate::structs::BinaryPayload;
+use std::error::Error;
 use std::fmt;
+use std::mem::ManuallyDrop;
 use std::ptr::NonNull;
-use std::error::Error;
-use std::mem::ManuallyDrop;
 
 /// Error returned when attempting to allocate a buffer that is too big.
 ///
--- a/libpam-sys/src/lib.rs	Sat Jun 28 02:49:35 2025 -0400
+++ b/libpam-sys/src/lib.rs	Sun Jun 29 02:15:46 2025 -0400
@@ -2,17 +2,54 @@
 //!
 //! ## PAM implementation
 //!
-#![doc = concat!("This documentation was built for the **", pam_impl_name!(), "** implementation.")]
+#![doc = concat!("This documentation was built for the **", __pam_impl_name__!(), "** implementation.")]
 
-#[doc(inline)]
-pub use libpam_sys_impls::cfg_pam_impl;
-use libpam_sys_impls::{pam_impl_enum, pam_impl_name};
+use libpam_sys_impls::{__pam_impl_enum__, __pam_impl_name__};
+
 mod constants;
-
-pam_impl_enum!();
-
 pub mod helpers;
 mod structs;
 
+/// 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]).
+///
+/// This macro will let you figure out which PAM you're compiling
+/// (and eventually running) against so you can make those critical changes.
+///
+/// The implementation names are the same as those in the [`PamImpl`] enum.
+///
+/// ```
+/// use libpam_sys::cfg_pam_impl;
+///
+/// #[cfg_pam_impl("Sun")]
+/// fn do_something() { /* Illumos/Solaris-only code */ }
+///
+/// #[cfg_pam_impl(not("Sun"))]
+/// 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("Sun", "OpenPam")))]
+/// fn do_a_third_thing() { /* Neither Sun 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() { /* I, sure, whatever, you do you. */ }
+/// ```
+///
+/// [man7]: https://man7.org/linux/man-pages/man3/pam_conv.3.html
+#[doc(inline)]
+pub use libpam_sys_impls::cfg_pam_impl;
+
+// Looking for the actual code defining this enum?
+// It's in the build.rs file for libpam_sys_impls.
+__pam_impl_enum__!(#[non_exhaustive]);
+
 #[doc(inline)]
 pub use crate::{constants::*, structs::*};