ferrunix_core/
registration.rs

1//! Utilities for auto-registration of types into the global registry.
2//!
3//! The global registry is available via [`Registry::global`].
4
5use crate::{types::OnceCell, types::Ref, Registry};
6
7/// The global, `'static` default [`Registry`]. It's constructed and accessible
8/// via [`Registry::global`].
9#[cfg(all(feature = "multithread", not(feature = "tokio")))]
10pub(crate) static DEFAULT_REGISTRY: OnceCell<Ref<Registry>> = OnceCell::new();
11
12#[cfg(all(not(feature = "multithread"), not(feature = "tokio")))]
13thread_local! {
14    /// The global, `'static` default [`Registry`]. It's constructed and accessible via
15    /// [`Registry::global`] from the current thread only.
16    ///
17    /// Since this is a thread local, every thread will have it's own registry.
18    ///
19    /// To enable multithreaded registries, the `multithread` feature must be enabled.
20    pub(crate) static DEFAULT_REGISTRY: OnceCell<Ref<Registry>> = const { OnceCell::new() };
21}
22
23/// The global, `'static` default [`Registry`]. It's constructed and accessible
24/// via [`Registry::global`].
25#[cfg(feature = "tokio")]
26pub(crate) static DEFAULT_REGISTRY: OnceCell<Ref<Registry>> = OnceCell::const_new();
27
28/// Synchronous registration.
29#[cfg(not(feature = "tokio"))]
30mod unsync {
31    use crate::Registry;
32
33    /// Signature of the function for the registration; usually created via the `derive` macro.
34    pub(crate) type RegisterFn = fn(&Registry) -> ();
35
36    /// All auto-registration functions need to use this type for registration.
37    ///
38    /// This is, usually, used by the derive macro, and not manually.
39    #[non_exhaustive]
40    pub struct RegistrationFunc(pub(crate) RegisterFn);
41
42    impl RegistrationFunc {
43        /// Create a new [`RegistrationFunc`] from a `register` function.
44        ///
45        /// The `register` function gets passed a [`Registry`], which it must use to
46        /// register one or more types.
47        ///
48        /// The function must not have any side-effects. It may be called
49        /// concurrently, in parallel, and from any thread (not only the main
50        /// thread).
51        ///
52        /// # Example
53        /// ```no_run
54        /// # use ferrunix_core::*;
55        /// # use ferrunix_core::registration::*;
56        /// #[derive(Debug)]
57        /// struct StringTemplate {
58        ///     template: &'static str,
59        /// }
60        ///
61        /// // Usually, this `impl` is generated by the `Inject` proc-macro.
62        /// impl StringTemplate {
63        ///     pub(crate) fn register(registry: &Registry) {
64        ///         registry
65        ///             .register_transient::<StringTemplate, _>(|| StringTemplate { template: "" });
66        ///     }
67        /// }
68        ///
69        /// // The construction must be `const`.
70        /// autoregister!(RegistrationFunc::new(
71        ///     StringTemplate::register
72        /// ));
73        /// ```
74        pub const fn new(register: RegisterFn) -> Self {
75            Self(register)
76        }
77    }
78
79    impl std::fmt::Debug for RegistrationFunc {
80        fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
81            fmt.debug_tuple("RegistrationFunc").finish()
82        }
83    }
84
85    // Create a new inventory for the auto-registration.
86    inventory::collect!(RegistrationFunc);
87}
88
89/// Asynchronous registration.
90#[cfg(feature = "tokio")]
91mod sync {
92    use crate::Registry;
93
94    /// Signature of the function for the registration; usually created via the `derive` macro.
95    pub(crate) type RegisterFn = for<'reg> fn(
96        &'reg Registry,
97    ) -> std::pin::Pin<
98        Box<dyn std::future::Future<Output = ()> + Send + 'reg>,
99    >;
100
101    /// All auto-registration functions need to use this type for registration.
102    ///
103    /// This is, usually, used by the derive macro, and not manually.
104    #[non_exhaustive]
105    pub struct RegistrationFunc(pub(crate) RegisterFn);
106
107    impl RegistrationFunc {
108        /// Create a new [`RegistrationFunc`] from a `register` function.
109        ///
110        /// The `register` function gets passed a [`Registry`], which it must use to
111        /// register one or more types.
112        ///
113        /// The function must not have any side-effects. It may be called
114        /// concurrently, in parallel, and from any thread (not only the main
115        /// thread).
116        ///
117        /// # Example
118        /// ```ignore,no_run
119        /// # use ferrunix_core::*;
120        /// # use ferrunix_core::registration::*;
121        /// #[derive(Debug)]
122        /// struct StringTemplate {
123        ///     template: &'static str,
124        /// }
125        ///
126        /// // Usually, this `impl` is generated by the `Inject` proc-macro.
127        /// impl StringTemplate {
128        ///     pub(crate) fn register(registry: &Registry) {
129        ///         registry
130        ///             .register_transient::<StringTemplate, _>(|| StringTemplate { template: "" });
131        ///     }
132        /// }
133        ///
134        /// // The construction must be `const`.
135        /// autoregister!(RegistrationFunc::new(
136        ///     StringTemplate::register
137        /// ));
138        /// ```
139        pub const fn new(register: RegisterFn) -> Self {
140            Self(register)
141        }
142    }
143
144    impl std::fmt::Debug for RegistrationFunc {
145        fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
146            fmt.debug_tuple("RegistrationFunc").finish()
147        }
148    }
149
150    // Create a new inventory for the auto-registration.
151    inventory::collect!(RegistrationFunc);
152}
153
154#[cfg(feature = "tokio")]
155pub use sync::*;
156
157#[cfg(not(feature = "tokio"))]
158pub use unsync::*;
159
160/// Use `autoregister` to register a new [`RegistrationFunc`].
161pub use inventory::submit as autoregister;