ferrunix_core/
dependencies.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
//! All possible dependencies for injected types.
//!
//! The following dependency types are available, as of right now:
//!   * [`Transient`]: Dependencies that are created from scratch when
//!     requested.
//!   * [`Singleton`]: Dependencies that are created once for every registry.
//!
//! All dependency types implement the [`Dep`] trait, and can get access to the
//! inner type via `.get`.
//!
//! # Examples
//! ```
//! # use ferrunix_core::{Registry, Singleton, Transient};
//! struct Template {
//!     template: &'static str,
//! }
//!
//! let registry = Registry::empty();
//! registry.transient(|| 1_u8);
//! registry.singleton(|| Template { template: "u8 is:" });
//!
//! registry
//!     .with_deps::<_, (Transient<u8>, Singleton<Template>)>()
//!     .transient(|(num, template)| {
//!         let num = num.get(); // grab the inner `u8`.
//!         format!("{} {num}", template.template) // you can also use the `Deref` impl.
//!     });
//!
//! let s = registry.get_transient::<String>().unwrap();
//! assert_eq!(s, "u8 is: 1".to_string());
//! ```

use std::any::TypeId;

use crate::types::Registerable;
use crate::{types::Ref, Registry};

/// Required for sealing the `Dep` trait. *Must not be public*.
mod private {
    /// Private trait for sealing [`Dep`].
    pub trait Sealed {}
}

/// Trait to specify a dependency. Every possible dependency type is
/// implementing this trait.
///
/// Current implementors:
///   * [`Transient`]
///   * [`Singleton`]
///
/// This trait is sealed, it cannot be implemented outside of this crate.
pub trait Dep: Registerable + private::Sealed {
    /// Looks up the dependency in `registry`, and constructs a new [`Dep`].
    ///
    /// This function is allowed to panic, if the type isn't registered.
    fn new(registry: &Registry) -> Self;

    /// Returns [`std::any::TypeId`] of the dependency type.
    fn type_id() -> TypeId;
}

/// Transient dependencies.
///
/// This dependency is created from scratch every time it's requested.
#[repr(transparent)]
pub struct Transient<T> {
    /// The resolved type.
    inner: T,
}

impl<T: std::fmt::Debug> std::fmt::Debug for Transient<T> {
    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        fmt.debug_struct("Transient")
            .field("inner", &self.inner)
            .finish()
    }
}

impl<T: Registerable> std::ops::Deref for Transient<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.inner
    }
}

impl<T: Registerable> std::ops::DerefMut for Transient<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.inner
    }
}

impl<T: Registerable> Transient<T> {
    /// Access the inner `T`.
    #[must_use]
    pub fn get(self) -> T {
        self.inner
    }
}

// Required for implementing `Dep`.
impl<T> private::Sealed for Transient<T> {}

impl<T: Registerable> Dep for Transient<T> {
    /// Create a new [`Transient`].
    ///
    /// # Panic
    /// This function panics if the `T` isn't registered.
    fn new(registry: &Registry) -> Self {
        Self {
            inner: registry.get_transient::<T>().expect(
                "transient dependency must only be constructed if it's \
                 fulfillable",
            ),
        }
    }

    /// Returns [`std::any::TypeId`] of the inner type `T`.
    fn type_id() -> TypeId {
        TypeId::of::<T>()
    }
}

/// Singleton dependencies.
///
/// This dependency is created only once for the specified registry. It's
/// created lazily on-demand.
#[repr(transparent)]
pub struct Singleton<T> {
    /// The resolved type.
    inner: Ref<T>,
}

impl<T: std::fmt::Debug> std::fmt::Debug for Singleton<T> {
    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        fmt.debug_struct("Singleton")
            .field("inner", &self.inner)
            .finish()
    }
}

impl<T: Registerable> From<Singleton<T>> for Ref<T> {
    fn from(value: Singleton<T>) -> Self {
        value.inner
    }
}

impl<T: Registerable> std::ops::Deref for Singleton<T> {
    type Target = Ref<T>;

    fn deref(&self) -> &Self::Target {
        &self.inner
    }
}

impl<T: Registerable> std::ops::DerefMut for Singleton<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.inner
    }
}

impl<T: Registerable> Singleton<T> {
    /// Access the inner dependency, returns a ref-counted object.
    #[must_use]
    pub fn get(self) -> Ref<T> {
        self.inner
    }
}

// Required for implementing `Dep`.
impl<T> private::Sealed for Singleton<T> {}

impl<T: Registerable> Dep for Singleton<T> {
    /// Create a new [`Singleton`].
    ///
    /// # Panic
    /// This function panics if the `T` isn't registered.
    fn new(registry: &Registry) -> Self {
        Self {
            inner: registry.get_singleton::<T>().expect(
                "singleton dependency must only be constructed if it's \
                 fulfillable",
            ),
        }
    }

    /// Returns [`std::any::TypeId`] of the inner type `T`.
    fn type_id() -> TypeId {
        TypeId::of::<T>()
    }
}