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}