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