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;