ferrunix_core/
dependencies.rs

1//! All possible dependencies for injected types.
2//!
3//! The following dependency types are available, as of right now:
4//!   * [`Transient`]: Dependencies that are created from scratch when
5//!     requested.
6//!   * [`Singleton`]: Dependencies that are created once for every registry.
7//!
8//! All dependency types implement the [`Dep`] trait, and can get access to the
9//! inner type via `.get`.
10//!
11//! # Examples
12//! ```ignore,no_run
13//! use ferrunix_core::{Registry, Singleton, Transient};
14//!
15//! struct Template {
16//!     template: &'static str,
17//! }
18//!
19//! let registry = Registry::empty();
20//! registry.transient(|| 1_u8);
21//! registry.singleton(|| Template { template: "u8 is:" });
22//!
23//! registry
24//!     .with_deps::<_, (Transient<u8>, Singleton<Template>)>()
25//!     .transient(|(num, template)| {
26//!         let num = num.get(); // grab the inner `u8`.
27//!         format!("{} {num}", template.template) // you can also use the `Deref` impl.
28//!     });
29//!
30//! let s = registry.get_transient::<String>().unwrap();
31//! assert_eq!(s, "u8 is: 1".to_string());
32//! ```
33
34use std::any::TypeId;
35
36use crate::types::{Registerable, RegisterableSingleton};
37use crate::{types::Ref, Registry};
38
39/// Required for sealing the `Dep` trait. *Must not be public*.
40mod private {
41    /// Private trait for sealing [`Dep`].
42    pub trait Sealed {}
43}
44
45/// Trait to specify a dependency. Every possible dependency type is
46/// implementing this trait.
47///
48/// Current implementors:
49///   * [`Transient`]
50///   * [`Singleton`]
51///
52/// This trait is sealed, it cannot be implemented outside of this crate.
53pub trait Dep: Registerable + private::Sealed {
54    /// Looks up the dependency in `registry`, and constructs a new [`Dep`].
55    ///
56    /// This function is allowed to panic, if the type isn't registered.
57    #[cfg(not(feature = "tokio"))]
58    fn new(registry: &Registry) -> Self;
59
60    /// Looks up the dependency in `registry`, and constructs a new [`Dep`].
61    ///
62    /// This function is allowed to panic, if the type isn't registered.
63    #[cfg(feature = "tokio")]
64    fn new(
65        registry: &Registry,
66    ) -> impl std::future::Future<Output = Self> + Send
67    where
68        Self: Sized;
69
70    /// Returns [`std::any::TypeId`] of the dependency type.
71    fn type_id() -> TypeId;
72}
73
74/// Transient dependencies.
75///
76/// This dependency is created from scratch every time it's requested.
77#[repr(transparent)]
78pub struct Transient<T> {
79    /// The resolved type.
80    inner: T,
81}
82
83impl<T: std::fmt::Debug> std::fmt::Debug for Transient<T> {
84    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
85        fmt.debug_struct("Transient")
86            .field("inner", &self.inner)
87            .finish()
88    }
89}
90
91impl<T: Registerable> std::ops::Deref for Transient<T> {
92    type Target = T;
93
94    fn deref(&self) -> &Self::Target {
95        &self.inner
96    }
97}
98
99impl<T: Registerable> std::ops::DerefMut for Transient<T> {
100    fn deref_mut(&mut self) -> &mut Self::Target {
101        &mut self.inner
102    }
103}
104
105impl<T: Registerable> Transient<T> {
106    /// Access the inner `T`.
107    #[must_use]
108    #[cfg_attr(feature = "tracing", tracing::instrument(skip(self)))]
109    pub fn get(self) -> T {
110        self.inner
111    }
112}
113
114// Required for implementing `Dep`.
115impl<T> private::Sealed for Transient<T> {}
116
117impl<T: Registerable> Dep for Transient<T> {
118    /// Create a new [`Transient`].
119    ///
120    /// # Panic
121    /// This function panics if the `T` isn't registered.
122    #[cfg(not(feature = "tokio"))]
123    fn new(registry: &Registry) -> Self {
124        Self {
125            inner: registry.get_transient::<T>().expect(
126                "transient dependency must only be constructed if it's \
127                 fulfillable",
128            ),
129        }
130    }
131
132    /// Create a new [`Transient`], asynchronously.
133    ///
134    /// # Panic
135    /// This function panics if the `T` isn't registered.
136    #[cfg(feature = "tokio")]
137    async fn new(registry: &Registry) -> Self {
138        Self {
139            inner: registry.get_transient::<T>().await.expect(
140                "transient dependency must only be constructed if it's \
141                 fulfillable",
142            ),
143        }
144    }
145
146    /// Returns [`std::any::TypeId`] of the inner type `T`.
147    fn type_id() -> TypeId {
148        TypeId::of::<T>()
149    }
150}
151
152/// Singleton dependencies.
153///
154/// This dependency is created only once for the specified registry. It's
155/// created lazily on-demand.
156#[repr(transparent)]
157pub struct Singleton<T> {
158    /// The resolved type.
159    inner: Ref<T>,
160}
161
162impl<T: std::fmt::Debug> std::fmt::Debug for Singleton<T> {
163    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
164        fmt.debug_struct("Singleton")
165            .field("inner", &self.inner)
166            .finish()
167    }
168}
169
170impl<T: RegisterableSingleton> From<Singleton<T>> for Ref<T> {
171    fn from(value: Singleton<T>) -> Self {
172        value.inner
173    }
174}
175
176impl<T: RegisterableSingleton> std::ops::Deref for Singleton<T> {
177    type Target = Ref<T>;
178
179    fn deref(&self) -> &Self::Target {
180        &self.inner
181    }
182}
183
184impl<T: RegisterableSingleton> std::ops::DerefMut for Singleton<T> {
185    fn deref_mut(&mut self) -> &mut Self::Target {
186        &mut self.inner
187    }
188}
189
190impl<T: RegisterableSingleton> Singleton<T> {
191    /// Access the inner dependency, returns a ref-counted object.
192    #[must_use]
193    #[cfg_attr(feature = "tracing", tracing::instrument(skip(self)))]
194    pub fn get(self) -> Ref<T> {
195        self.inner
196    }
197}
198
199// Required for implementing `Dep`.
200impl<T> private::Sealed for Singleton<T> {}
201
202impl<T: RegisterableSingleton> Dep for Singleton<T> {
203    /// Create a new [`Singleton`].
204    ///
205    /// # Panic
206    /// This function panics if the `T` isn't registered.
207    #[cfg(not(feature = "tokio"))]
208    fn new(registry: &Registry) -> Self {
209        Self {
210            inner: registry.get_singleton::<T>().expect(
211                "singleton dependency must only be constructed if it's \
212                 fulfillable",
213            ),
214        }
215    }
216
217    /// Create a new [`Singleton`], asynchronously.
218    ///
219    /// # Panic
220    /// This function panics if the `T` isn't registered.
221    #[cfg(feature = "tokio")]
222    async fn new(registry: &Registry) -> Self {
223        Self {
224            inner: registry.get_singleton::<T>().await.expect(
225                "singleton dependency must only be constructed if it's \
226                 fulfillable",
227            ),
228        }
229    }
230
231    /// Returns [`std::any::TypeId`] of the inner type `T`.
232    fn type_id() -> TypeId {
233        TypeId::of::<T>()
234    }
235}