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}