rustyinject/
container.rs

1use crate::{
2    deps_list::{DepsList, DepsListGetMut, DepsListGetRef, DepsListRemove},
3    injector::{
4        containers::{
5            ConstructorFactoryContainer, FactoryContainer, RefConstructorFactoryContainer,
6            RefFactoryContainer, SingletonContainer,
7        },
8        factories::{ConstructorFactory, Factory, RefFactory},
9    },
10};
11use core::{convert::Infallible, marker::PhantomData};
12
13/// Current scope index.
14pub struct CurrentScope(Infallible);
15/// Parent scope index.
16pub struct ParentScope<Scope>(PhantomData<Scope>, Infallible);
17
18/// An Inversion of Control (IoC) container used for declaring and managing dependencies in a Rust application.
19/// It facilitates the creation, storage, and retrieval of dependencies, supporting both singleton and factory-based dependency injection.
20/// # Generics
21/// - `Parent`: a parent container.
22/// - `Scope`: current scope of the container.
23pub struct DependencyContainer<Parent, Scope> {
24    pub(crate) parent: Parent,
25    pub(crate) scope: Scope,
26}
27
28impl Default for DependencyContainer<(), ()> {
29    fn default() -> Self {
30        Self::new(())
31    }
32}
33
34impl<Parent> DependencyContainer<Parent, ()> {
35    /// Create a new container with the specified parent.
36    pub fn new(parent: Parent) -> Self {
37        Self { parent, scope: () }
38    }
39}
40
41impl<Parent, Scope> DependencyContainer<Parent, Scope>
42where
43    Scope: DepsList,
44{
45    /// Add a concrete instance of a dependency (singleton) to the container.
46    pub fn with_singleton<T>(
47        self,
48        singleton: T,
49    ) -> DependencyContainer<Parent, Scope::PrependedWith<SingletonContainer<T>>> {
50        DependencyContainer {
51            parent: self.parent,
52            scope: self.scope.prepend(SingletonContainer(singleton)),
53        }
54    }
55
56    /// Add a factory-based dependency to the container.
57    pub fn with_factory<F>(
58        self,
59        factory: F,
60    ) -> DependencyContainer<Parent, Scope::PrependedWith<FactoryContainer<F, F::Result>>>
61    where
62        F: Factory,
63    {
64        DependencyContainer {
65            parent: self.parent,
66            scope: self.scope.prepend(FactoryContainer(factory, PhantomData)),
67        }
68    }
69
70    /// Add a factory-based dependency to the container.
71    pub fn with_ref_factory<'a, F>(
72        self,
73        factory: F,
74    ) -> DependencyContainer<Parent, Scope::PrependedWith<RefFactoryContainer<F, F::Result<'a>>>>
75    where
76        F: RefFactory,
77    {
78        DependencyContainer {
79            parent: self.parent,
80            scope: self
81                .scope
82                .prepend(RefFactoryContainer(factory, PhantomData)),
83        }
84    }
85
86    /// Add a struct that builds from a constructor(like a `new` method).
87    pub fn with_constructor_factory<T>(
88        self,
89    ) -> DependencyContainer<Parent, Scope::PrependedWith<ConstructorFactoryContainer<T>>>
90    where
91        T: ConstructorFactory,
92    {
93        DependencyContainer {
94            parent: self.parent,
95            scope: self.scope.prepend(ConstructorFactoryContainer(PhantomData)),
96        }
97    }
98
99    /// Add a struct that builds from a constructor(like a `new` method) and consumes all
100    /// references that passed
101    pub fn with_ref_constructor_factory<T>(
102        self,
103    ) -> DependencyContainer<Parent, Scope::PrependedWith<RefConstructorFactoryContainer<T>>> {
104        DependencyContainer {
105            parent: self.parent,
106            scope: self
107                .scope
108                .prepend(RefConstructorFactoryContainer(PhantomData)),
109        }
110    }
111}
112
113impl<Parent, Scope, T, Idx> DepsListRemove<T, (CurrentScope, Idx)>
114    for DependencyContainer<Parent, Scope>
115where
116    Scope: DepsListRemove<T, Idx>,
117{
118    type Remainder = DependencyContainer<Parent, Scope::Remainder>;
119
120    fn remove(self) -> (T, Self::Remainder) {
121        let (removed, scope_remainder) = self.scope.remove();
122        (
123            removed,
124            DependencyContainer {
125                parent: self.parent,
126                scope: scope_remainder,
127            },
128        )
129    }
130}
131
132impl<Parent, Scope, T, Idx, Subscope> DepsListRemove<T, (ParentScope<Subscope>, Idx)>
133    for DependencyContainer<Parent, Scope>
134where
135    Parent: DepsListRemove<T, (Subscope, Idx)>,
136{
137    type Remainder = DependencyContainer<Parent::Remainder, Scope>;
138
139    fn remove(self) -> (T, Self::Remainder) {
140        let (removed, parent_remainder) = self.parent.remove();
141
142        (
143            removed,
144            DependencyContainer {
145                parent: parent_remainder,
146                scope: self.scope,
147            },
148        )
149    }
150}
151
152impl<Parent, Scope, T, Idx> DepsListGetRef<T, (CurrentScope, Idx)>
153    for DependencyContainer<Parent, Scope>
154where
155    Scope: DepsListGetRef<T, Idx>,
156{
157    fn get(&self) -> &T {
158        self.scope.get()
159    }
160}
161
162impl<Parent, Scope, T, Idx, Subscope> DepsListGetRef<T, (ParentScope<Subscope>, Idx)>
163    for DependencyContainer<Parent, Scope>
164where
165    Parent: DepsListGetRef<T, (Subscope, Idx)>,
166{
167    fn get(&self) -> &T {
168        self.parent.get()
169    }
170}
171
172impl<Parent, Scope, T, Idx> DepsListGetMut<T, (CurrentScope, Idx)>
173    for DependencyContainer<Parent, Scope>
174where
175    Scope: DepsListGetMut<T, Idx>,
176{
177    fn get_mut(&mut self) -> &mut T {
178        self.scope.get_mut()
179    }
180}
181
182impl<Parent, Scope, T, Idx, Subscope> DepsListGetMut<T, (ParentScope<Subscope>, Idx)>
183    for DependencyContainer<Parent, Scope>
184where
185    Parent: DepsListGetMut<T, (Subscope, Idx)>,
186{
187    fn get_mut(&mut self) -> &mut T {
188        self.parent.get_mut()
189    }
190}