reinhardt_di/scope.rs
1//! Dependency scopes
2
3use std::any::{Any, TypeId};
4use std::collections::HashMap;
5use std::sync::{Arc, PoisonError, RwLock};
6
7/// Defines the lifetime scope of a dependency.
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum Scope {
10 /// A new instance is created for each request.
11 Request,
12 /// A single instance is shared across the entire application lifetime.
13 Singleton,
14}
15
16/// Per-request dependency cache that stores resolved instances for the duration of a request.
17#[derive(Clone)]
18pub struct RequestScope {
19 cache: Arc<RwLock<HashMap<TypeId, Arc<dyn Any + Send + Sync>>>>,
20}
21
22impl RequestScope {
23 /// Creates a new RequestScope with an empty cache.
24 ///
25 /// # Examples
26 ///
27 /// ```
28 /// use reinhardt_di::RequestScope;
29 ///
30 /// let scope = RequestScope::new();
31 /// ```
32 pub fn new() -> Self {
33 Self {
34 cache: Arc::new(RwLock::new(HashMap::new())),
35 }
36 }
37 /// Retrieves a value from the request scope cache by type.
38 ///
39 /// Returns `None` if no value of type `T` exists in the cache.
40 ///
41 /// # Examples
42 ///
43 /// ```
44 /// use reinhardt_di::RequestScope;
45 ///
46 /// let scope = RequestScope::new();
47 /// scope.set(42i32);
48 ///
49 /// let value = scope.get::<i32>().unwrap();
50 /// assert_eq!(*value, 42);
51 /// ```
52 pub fn get<T: Any + Send + Sync>(&self) -> Option<Arc<T>> {
53 let cache = self.cache.read().unwrap_or_else(PoisonError::into_inner);
54 let type_id = TypeId::of::<T>();
55 cache
56 .get(&type_id)
57 .and_then(|arc| arc.clone().downcast::<T>().ok())
58 }
59 /// Stores a value in the request scope cache.
60 ///
61 /// The value is stored by its type and can be retrieved later using `get`.
62 ///
63 /// # Examples
64 ///
65 /// ```
66 /// use reinhardt_di::RequestScope;
67 ///
68 /// let scope = RequestScope::new();
69 /// scope.set(42i32);
70 /// scope.set("hello".to_string());
71 ///
72 /// assert_eq!(*scope.get::<i32>().unwrap(), 42);
73 /// assert_eq!(*scope.get::<String>().unwrap(), "hello");
74 /// ```
75 pub fn set<T: Any + Send + Sync>(&self, value: T) {
76 let mut cache = self.cache.write().unwrap_or_else(PoisonError::into_inner);
77 let type_id = TypeId::of::<T>();
78 cache.insert(type_id, Arc::new(value));
79 }
80
81 /// Stores a pre-wrapped `Arc<T>` in the request scope cache.
82 ///
83 /// Unlike `set`, this method accepts an already-wrapped Arc value,
84 /// avoiding the need to unwrap and re-wrap. This is useful when
85 /// the value is produced by a factory that returns `Arc<T>`.
86 ///
87 /// # Examples
88 ///
89 /// ```
90 /// use reinhardt_di::RequestScope;
91 /// use std::sync::Arc;
92 ///
93 /// let scope = RequestScope::new();
94 /// let value = Arc::new(42i32);
95 /// scope.set_arc(value);
96 ///
97 /// assert_eq!(*scope.get::<i32>().unwrap(), 42);
98 /// ```
99 pub fn set_arc<T: Any + Send + Sync>(&self, value: Arc<T>) {
100 let mut cache = self.cache.write().unwrap_or_else(PoisonError::into_inner);
101 let type_id = TypeId::of::<T>();
102 cache.insert(type_id, value);
103 }
104}
105
106impl RequestScope {
107 /// Creates a deep clone of this scope with an independent cache.
108 ///
109 /// The cloned scope contains the same cached entries as the original,
110 /// but modifications to either scope will not affect the other.
111 pub fn deep_clone(&self) -> Self {
112 let cache = self.cache.read().unwrap_or_else(PoisonError::into_inner);
113 Self {
114 cache: Arc::new(RwLock::new(cache.clone())),
115 }
116 }
117}
118
119impl Default for RequestScope {
120 fn default() -> Self {
121 Self::new()
122 }
123}
124
125/// Application-wide dependency cache that persists across all requests.
126pub struct SingletonScope {
127 cache: Arc<RwLock<HashMap<TypeId, Arc<dyn Any + Send + Sync>>>>,
128}
129
130impl SingletonScope {
131 /// Creates a new SingletonScope with an empty cache.
132 ///
133 /// # Examples
134 ///
135 /// ```
136 /// use reinhardt_di::SingletonScope;
137 ///
138 /// let scope = SingletonScope::new();
139 /// ```
140 pub fn new() -> Self {
141 Self {
142 cache: Arc::new(RwLock::new(HashMap::new())),
143 }
144 }
145 /// Retrieves a singleton value from the cache by type.
146 ///
147 /// Returns `None` if no value of type `T` exists in the singleton cache.
148 ///
149 /// # Examples
150 ///
151 /// ```
152 /// use reinhardt_di::SingletonScope;
153 ///
154 /// let scope = SingletonScope::new();
155 /// scope.set(100u64);
156 ///
157 /// let value = scope.get::<u64>().unwrap();
158 /// assert_eq!(*value, 100);
159 /// ```
160 pub fn get<T: Any + Send + Sync>(&self) -> Option<Arc<T>> {
161 let cache = self.cache.read().unwrap_or_else(PoisonError::into_inner);
162 let type_id = TypeId::of::<T>();
163 cache
164 .get(&type_id)
165 .and_then(|arc| arc.clone().downcast::<T>().ok())
166 }
167 /// Stores a singleton value in the cache.
168 ///
169 /// The value persists across multiple requests and is shared application-wide.
170 ///
171 /// # Examples
172 ///
173 /// ```
174 /// use reinhardt_di::SingletonScope;
175 ///
176 /// let scope = SingletonScope::new();
177 /// scope.set(42i32);
178 ///
179 /// // Same value retrieved across multiple calls
180 /// let val1 = scope.get::<i32>().unwrap();
181 /// let val2 = scope.get::<i32>().unwrap();
182 /// assert_eq!(*val1, *val2);
183 /// ```
184 pub fn set<T: Any + Send + Sync>(&self, value: T) {
185 let mut cache = self.cache.write().unwrap_or_else(PoisonError::into_inner);
186 let type_id = TypeId::of::<T>();
187 cache.insert(type_id, Arc::new(value));
188 }
189
190 /// Stores a pre-wrapped `Arc<T>` in the singleton scope cache.
191 ///
192 /// Unlike `set`, this method accepts an already-wrapped Arc value,
193 /// avoiding the need to unwrap and re-wrap. This is useful when
194 /// the value is produced by a factory that returns `Arc<T>`.
195 ///
196 /// # Examples
197 ///
198 /// ```
199 /// use reinhardt_di::SingletonScope;
200 /// use std::sync::Arc;
201 ///
202 /// let scope = SingletonScope::new();
203 /// let value = Arc::new(42i32);
204 /// scope.set_arc(value);
205 ///
206 /// assert_eq!(*scope.get::<i32>().unwrap(), 42);
207 /// ```
208 pub fn set_arc<T: Any + Send + Sync>(&self, value: Arc<T>) {
209 let mut cache = self.cache.write().unwrap_or_else(PoisonError::into_inner);
210 let type_id = TypeId::of::<T>();
211 cache.insert(type_id, value);
212 }
213
214 /// Inserts a pre-erased `Arc<dyn Any + Send + Sync>` keyed by an explicit
215 /// `TypeId`.
216 ///
217 /// This is the type-erased counterpart of [`set_arc`](Self::set_arc) and
218 /// is intended for callers (such as the `Middleware::di_registrations`
219 /// bridge in `reinhardt-urls`) that have already type-erased the value to
220 /// avoid a circular crate dependency on `reinhardt-di`.
221 pub fn set_arc_any(&self, type_id: TypeId, value: Arc<dyn Any + Send + Sync>) {
222 let mut cache = self.cache.write().unwrap_or_else(PoisonError::into_inner);
223 cache.insert(type_id, value);
224 }
225}
226
227impl Default for SingletonScope {
228 fn default() -> Self {
229 Self::new()
230 }
231}