Skip to main content

reinhardt_di/
injected.rs

1//! Injected wrapper for dependency injection
2//!
3//! FastAPI-inspired dependency injection wrapper that provides:
4//! - Automatic dependency resolution
5//! - Caching control via scope and cache flag
6//! - Type-safe dependency injection with metadata
7//!
8//! # Examples
9//!
10//! ```
11//! use reinhardt_di::{Injected, OptionalInjected, Injectable, InjectionContext};
12//!
13//! # #[derive(Clone, Default)]
14//! # struct Database;
15//! # #[derive(Clone, Default)]
16//! # struct Cache;
17//! #
18//! # #[async_trait::async_trait]
19//! # impl Injectable for Database {
20//! #     async fn inject(ctx: &InjectionContext) -> reinhardt_di::DiResult<Self> {
21//! #         Ok(Database::default())
22//! #     }
23//! # }
24//! #
25//! # #[async_trait::async_trait]
26//! # impl Injectable for Cache {
27//! #     async fn inject(ctx: &InjectionContext) -> reinhardt_di::DiResult<Self> {
28//! #         Ok(Cache::default())
29//! #     }
30//! # }
31//! #
32//! async fn handler(
33//!     db: Injected<Database>,
34//!     optional_cache: OptionalInjected<Cache>,
35//! ) -> String {
36//!     // db is always available
37//!     // optional_cache can be treated as Option<Injected<Cache>>
38//!     "OK".to_string()
39//! }
40//! ```
41
42use crate::{
43	DiError, DiResult, Injectable, InjectionContext, begin_resolution, with_cycle_detection_scope,
44};
45use std::any::TypeId;
46use std::ops::Deref;
47use std::sync::Arc;
48
49/// Injection metadata
50///
51/// Tracks the scope and caching status of an injected dependency.
52#[derive(Debug, Clone, Copy)]
53pub struct InjectionMetadata {
54	/// Dependency scope (Request or Singleton)
55	pub scope: DependencyScope,
56	/// Whether caching was enabled during resolution
57	pub cached: bool,
58}
59
60/// Dependency scope
61#[derive(Debug, Clone, Copy, PartialEq, Eq)]
62pub enum DependencyScope {
63	/// Request-scoped dependency (lifetime tied to request)
64	Request,
65	/// Singleton-scoped dependency (shared across requests)
66	Singleton,
67}
68
69/// Injected dependency wrapper
70///
71/// Wraps an `Arc<T>` with injection metadata, providing:
72/// - Shared ownership via `Arc`
73/// - Metadata tracking (scope, cache status)
74/// - Transparent access via `Deref`
75///
76/// # Examples
77///
78/// ```
79/// use reinhardt_di::{Injected, InjectionContext, Injectable, SingletonScope};
80/// use std::sync::Arc;
81///
82/// # #[derive(Clone, Default)]
83/// # struct Config;
84/// #
85/// # #[async_trait::async_trait]
86/// # impl Injectable for Config {
87/// #     async fn inject(ctx: &InjectionContext) -> reinhardt_di::DiResult<Self> {
88/// #         Ok(Config::default())
89/// #     }
90/// # }
91/// #
92/// # async fn example() -> reinhardt_di::DiResult<()> {
93/// let singleton_scope = Arc::new(SingletonScope::new());
94/// let ctx = InjectionContext::builder(singleton_scope).build();
95///
96/// // Resolve with cache enabled (default)
97/// let config1 = Injected::<Config>::resolve(&ctx).await?;
98/// let config2 = Injected::<Config>::resolve(&ctx).await?;
99///
100/// // Resolve without cache
101/// let config3 = Injected::<Config>::resolve_uncached(&ctx).await?;
102/// # Ok(())
103/// # }
104/// ```
105#[deprecated(
106	since = "0.1.0-rc.16",
107	note = "use `Depends<T>` instead. `Injected<T>` will be removed in a future version."
108)]
109#[derive(Debug)]
110pub struct Injected<T: Injectable> {
111	inner: Arc<T>,
112	metadata: InjectionMetadata,
113}
114
115#[allow(deprecated)]
116impl<T: Injectable> Injected<T> {
117	/// Resolve dependency with cache enabled (default)
118	///
119	/// # Examples
120	///
121	/// ```
122	/// use reinhardt_di::{Injected, InjectionContext, Injectable, SingletonScope};
123	/// use std::sync::Arc;
124	///
125	/// # #[derive(Clone, Default)]
126	/// # struct Config;
127	/// #
128	/// # #[async_trait::async_trait]
129	/// # impl Injectable for Config {
130	/// #     async fn inject(ctx: &InjectionContext) -> reinhardt_di::DiResult<Self> {
131	/// #         Ok(Config::default())
132	/// #     }
133	/// # }
134	/// #
135	/// # async fn example() -> reinhardt_di::DiResult<()> {
136	/// let singleton_scope = Arc::new(SingletonScope::new());
137	/// let ctx = InjectionContext::builder(singleton_scope).build();
138	/// let config = Injected::<Config>::resolve(&ctx).await?;
139	/// # Ok(())
140	/// # }
141	/// ```
142	pub async fn resolve(ctx: &InjectionContext) -> DiResult<Self> {
143		Self::resolve_with_cache(ctx, true).await
144	}
145
146	/// Resolve dependency without cache
147	///
148	/// # Examples
149	///
150	/// ```
151	/// use reinhardt_di::{Injected, InjectionContext, Injectable, SingletonScope};
152	/// use std::sync::Arc;
153	///
154	/// # #[derive(Clone, Default)]
155	/// # struct Config;
156	/// #
157	/// # #[async_trait::async_trait]
158	/// # impl Injectable for Config {
159	/// #     async fn inject(ctx: &InjectionContext) -> reinhardt_di::DiResult<Self> {
160	/// #         Ok(Config::default())
161	/// #     }
162	/// # }
163	/// #
164	/// # async fn example() -> reinhardt_di::DiResult<()> {
165	/// let singleton_scope = Arc::new(SingletonScope::new());
166	/// let ctx = InjectionContext::builder(singleton_scope).build();
167	/// let config = Injected::<Config>::resolve_uncached(&ctx).await?;
168	/// # Ok(())
169	/// # }
170	/// ```
171	pub async fn resolve_uncached(ctx: &InjectionContext) -> DiResult<Self> {
172		Self::resolve_with_cache(ctx, false).await
173	}
174
175	/// Resolve dependency with cache control (internal use)
176	///
177	/// # Arguments
178	///
179	/// * `ctx` - Injection context
180	/// * `use_cache` - Whether to use request-scoped cache
181	async fn resolve_with_cache(ctx: &InjectionContext, use_cache: bool) -> DiResult<Self> {
182		with_cycle_detection_scope(async {
183			let inner = if use_cache {
184				// Check request cache first
185				if let Some(cached) = ctx.get_request::<T>() {
186					cached
187				} else {
188					// Begin circular dependency detection
189					let type_id = TypeId::of::<T>();
190					let type_name = std::any::type_name::<T>();
191					let _guard = begin_resolution(type_id, type_name)
192						.map_err(|e| DiError::CircularDependency(e.to_string()))?;
193
194					let v = T::inject(ctx).await?;
195					let arc = Arc::new(v);
196					ctx.set_request_arc(Arc::clone(&arc));
197					arc
198				}
199			} else {
200				// Begin circular dependency detection (even for uncached)
201				let type_id = TypeId::of::<T>();
202				let type_name = std::any::type_name::<T>();
203				let _guard = begin_resolution(type_id, type_name)
204					.map_err(|e| DiError::CircularDependency(e.to_string()))?;
205
206				// Skip cache
207				Arc::new(T::inject_uncached(ctx).await?)
208			};
209
210			Ok(Self {
211				inner,
212				metadata: InjectionMetadata {
213					scope: DependencyScope::Request,
214					cached: use_cache,
215				},
216			})
217		})
218		.await
219	}
220
221	/// Create from value for testing
222	///
223	/// # Examples
224	///
225	/// ```
226	/// use reinhardt_di::{Injected, Injectable};
227	///
228	/// # #[derive(Clone, Default)]
229	/// # struct Database {
230	/// #     connection_count: usize,
231	/// # }
232	/// #
233	/// # #[async_trait::async_trait]
234	/// # impl Injectable for Database {
235	/// #     async fn inject(ctx: &reinhardt_di::InjectionContext) -> reinhardt_di::DiResult<Self> {
236	/// #         Ok(Database::default())
237	/// #     }
238	/// # }
239	/// #
240	/// let db = Database { connection_count: 10 };
241	/// let injected = Injected::from_value(db);
242	/// assert_eq!(injected.connection_count, 10);
243	/// ```
244	pub fn from_value(value: T) -> Self {
245		Self {
246			inner: Arc::new(value),
247			metadata: InjectionMetadata {
248				scope: DependencyScope::Request,
249				cached: false,
250			},
251		}
252	}
253
254	/// Get Arc reference
255	///
256	/// # Examples
257	///
258	/// ```
259	/// use reinhardt_di::{Injected, Injectable};
260	/// use std::sync::Arc;
261	///
262	/// # #[derive(Clone, Default)]
263	/// # struct Config;
264	/// #
265	/// # #[async_trait::async_trait]
266	/// # impl Injectable for Config {
267	/// #     async fn inject(ctx: &reinhardt_di::InjectionContext) -> reinhardt_di::DiResult<Self> {
268	/// #         Ok(Config::default())
269	/// #     }
270	/// # }
271	/// #
272	/// let injected = Injected::from_value(Config::default());
273	/// let arc: &Arc<Config> = injected.as_arc();
274	/// ```
275	pub fn as_arc(&self) -> &Arc<T> {
276		&self.inner
277	}
278
279	/// Get injection metadata
280	///
281	/// # Examples
282	///
283	/// ```
284	/// use reinhardt_di::{Injected, Injectable};
285	///
286	/// # #[derive(Clone, Default)]
287	/// # struct Config;
288	/// #
289	/// # #[async_trait::async_trait]
290	/// # impl Injectable for Config {
291	/// #     async fn inject(ctx: &reinhardt_di::InjectionContext) -> reinhardt_di::DiResult<Self> {
292	/// #         Ok(Config::default())
293	/// #     }
294	/// # }
295	/// #
296	/// let injected = Injected::from_value(Config::default());
297	/// let metadata = injected.metadata();
298	/// assert!(!metadata.cached);
299	/// ```
300	pub fn metadata(&self) -> &InjectionMetadata {
301		&self.metadata
302	}
303
304	/// Attempt to unwrap the inner `Arc`, returning `T` if this is the only
305	/// strong reference. Returns `Err(Self)` if other references exist.
306	///
307	/// This mirrors [`Arc::try_unwrap`] semantics. Unlike
308	/// [`into_inner`](Injected::into_inner), this method does **not** require
309	/// `T: Clone`.
310	///
311	/// # Examples
312	///
313	/// ```
314	/// use reinhardt_di::{Injected, Injectable};
315	///
316	/// # #[derive(Clone, Debug, Default)]
317	/// # struct Config;
318	/// #
319	/// # #[async_trait::async_trait]
320	/// # impl Injectable for Config {
321	/// #     async fn inject(ctx: &reinhardt_di::InjectionContext) -> reinhardt_di::DiResult<Self> {
322	/// #         Ok(Config::default())
323	/// #     }
324	/// # }
325	/// #
326	/// let injected = Injected::from_value(Config::default());
327	/// let config = injected.try_unwrap().unwrap();
328	/// ```
329	pub fn try_unwrap(self) -> Result<T, Self> {
330		match Arc::try_unwrap(self.inner) {
331			Ok(val) => Ok(val),
332			Err(arc) => Err(Self {
333				inner: arc,
334				metadata: self.metadata,
335			}),
336		}
337	}
338}
339
340#[allow(deprecated)]
341impl<T: Injectable + Clone> Injected<T> {
342	/// Extract inner value
343	///
344	/// This method tries to unwrap the Arc. If the Arc has multiple strong references,
345	/// it clones the inner value instead. Requires `T: Clone`.
346	///
347	/// # Examples
348	///
349	/// ```
350	/// use reinhardt_di::{Injected, Injectable};
351	///
352	/// # #[derive(Clone, Default)]
353	/// # struct Config;
354	/// #
355	/// # #[async_trait::async_trait]
356	/// # impl Injectable for Config {
357	/// #     async fn inject(ctx: &reinhardt_di::InjectionContext) -> reinhardt_di::DiResult<Self> {
358	/// #         Ok(Config::default())
359	/// #     }
360	/// # }
361	/// #
362	/// let injected = Injected::from_value(Config::default());
363	/// let config = injected.into_inner();
364	/// ```
365	pub fn into_inner(self) -> T {
366		Arc::try_unwrap(self.inner).unwrap_or_else(|arc| (*arc).clone())
367	}
368}
369
370#[allow(deprecated)]
371impl<T: Injectable> Deref for Injected<T> {
372	type Target = T;
373
374	fn deref(&self) -> &Self::Target {
375		&self.inner
376	}
377}
378
379#[allow(deprecated)]
380impl<T: Injectable> Clone for Injected<T> {
381	fn clone(&self) -> Self {
382		Self {
383			inner: Arc::clone(&self.inner),
384			metadata: self.metadata,
385		}
386	}
387}
388
389#[allow(deprecated)]
390impl<T: Injectable> AsRef<T> for Injected<T> {
391	fn as_ref(&self) -> &T {
392		&self.inner
393	}
394}
395
396/// Optional injected dependency
397///
398/// Type alias for `Option<Injected<T>>`, used for optional dependencies.
399///
400/// # Critical Constraint
401///
402/// When using `#[inject]` attribute:
403/// - `#[inject(optional = true)]` → **MUST** use `OptionalInjected<T>` type
404/// - `#[inject(optional = false)]` or `#[inject]` → **MUST** use `Injected<T>` type
405/// - Type/attribute mismatches will cause compile errors
406///
407/// # Examples
408///
409/// ```
410/// use reinhardt_di::{Injected, OptionalInjected};
411///
412/// // ✅ Correct: optional = true with OptionalInjected<T>
413/// // #[get("/data", use_inject = true)]
414/// // async fn handler(
415/// //     #[inject(optional = true)] cache: OptionalInjected<RedisCache>,
416/// // ) -> Result<String> {
417/// //     if let Some(cache) = cache {
418/// //         Ok(cache.get("data").await?)
419/// //     } else {
420/// //         Ok("No cache available".to_string())
421/// //     }
422/// // }
423///
424/// // ✅ Correct: no optional (default false) with Injected<T>
425/// // #[get("/users", use_inject = true)]
426/// // async fn list_users(
427/// //     #[inject] db: Injected<Database>,
428/// // ) -> Result<String> {
429/// //     Ok(db.query("SELECT * FROM users").await?)
430/// // }
431///
432/// // ❌ Error: optional = true but type is Injected<T>
433/// // #[get("/bad", use_inject = true)]
434/// // async fn bad_handler(
435/// //     #[inject(optional = true)] cache: Injected<RedisCache>,
436/// //     //                                  ^^^^^^^^^^^^^^^^^ Error!
437/// // ) -> Result<String> { ... }
438///
439/// // ❌ Error: optional = false but type is OptionalInjected<T>
440/// // #[get("/bad2", use_inject = true)]
441/// // async fn bad_handler2(
442/// //     #[inject(optional = false)] db: OptionalInjected<Database>,
443/// //     //                               ^^^^^^^^^^^^^^^^^^^^^^^^^ Error!
444/// // ) -> Result<String> { ... }
445/// ```
446#[deprecated(
447	since = "0.1.0-rc.16",
448	note = "use `Option<Depends<T>>` instead. `OptionalInjected<T>` will be removed in a future version."
449)]
450#[allow(deprecated)]
451pub type OptionalInjected<T> = Option<Injected<T>>;
452
453#[cfg(test)]
454#[allow(deprecated)]
455mod tests {
456	use super::*;
457	use crate::SingletonScope;
458
459	#[derive(Clone, Default, Debug)]
460	struct TestConfig {
461		value: String,
462	}
463
464	#[async_trait::async_trait]
465	impl Injectable for TestConfig {
466		async fn inject(_ctx: &InjectionContext) -> DiResult<Self> {
467			Ok(TestConfig {
468				value: "test".to_string(),
469			})
470		}
471	}
472
473	#[tokio::test]
474	async fn test_injected_from_value() {
475		let config = TestConfig {
476			value: "custom".to_string(),
477		};
478		let injected = Injected::from_value(config);
479		assert_eq!(injected.value, "custom");
480	}
481
482	#[tokio::test]
483	async fn test_injected_into_inner() {
484		let config = TestConfig {
485			value: "test".to_string(),
486		};
487		let injected = Injected::from_value(config);
488		let extracted = injected.into_inner();
489		assert_eq!(extracted.value, "test");
490	}
491
492	#[tokio::test]
493	async fn test_injected_clone() {
494		let config = TestConfig {
495			value: "test".to_string(),
496		};
497		let injected1 = Injected::from_value(config);
498		let injected2 = injected1.clone();
499
500		assert_eq!(injected1.value, "test");
501		assert_eq!(injected2.value, "test");
502	}
503
504	#[tokio::test]
505	async fn test_injected_deref() {
506		let config = TestConfig {
507			value: "test".to_string(),
508		};
509		let injected = Injected::from_value(config);
510
511		// Can be accessed directly via Deref
512		assert_eq!(injected.value, "test");
513	}
514
515	#[tokio::test]
516	async fn test_injected_metadata() {
517		let config = TestConfig {
518			value: "test".to_string(),
519		};
520		let injected = Injected::from_value(config);
521
522		let metadata = injected.metadata();
523		assert_eq!(metadata.scope, DependencyScope::Request);
524		assert!(!metadata.cached);
525	}
526
527	#[tokio::test]
528	async fn test_optional_injected_some() {
529		let config = TestConfig {
530			value: "test".to_string(),
531		};
532		let optional: OptionalInjected<TestConfig> = Some(Injected::from_value(config));
533
534		assert!(optional.is_some());
535		if let Some(injected) = optional {
536			assert_eq!(injected.value, "test");
537		}
538	}
539
540	#[tokio::test]
541	async fn test_optional_injected_none() {
542		let optional: OptionalInjected<TestConfig> = None;
543		assert!(optional.is_none());
544	}
545
546	// Additional dependency scope tests
547
548	#[test]
549	fn test_dependency_scope_equality() {
550		assert_eq!(DependencyScope::Request, DependencyScope::Request);
551		assert_eq!(DependencyScope::Singleton, DependencyScope::Singleton);
552		assert_ne!(DependencyScope::Request, DependencyScope::Singleton);
553	}
554
555	#[test]
556	fn test_dependency_scope_debug() {
557		let request = DependencyScope::Request;
558		let singleton = DependencyScope::Singleton;
559
560		let request_debug = format!("{:?}", request);
561		let singleton_debug = format!("{:?}", singleton);
562
563		assert!(request_debug.contains("Request"));
564		assert!(singleton_debug.contains("Singleton"));
565	}
566
567	#[test]
568	fn test_dependency_scope_clone() {
569		let request = DependencyScope::Request;
570		let cloned = request;
571
572		assert_eq!(request, cloned);
573	}
574
575	#[test]
576	fn test_injection_metadata_debug() {
577		let metadata = InjectionMetadata {
578			scope: DependencyScope::Request,
579			cached: true,
580		};
581
582		let debug_str = format!("{:?}", metadata);
583
584		assert!(debug_str.contains("InjectionMetadata"));
585		assert!(debug_str.contains("Request"));
586		assert!(debug_str.contains("true"));
587	}
588
589	#[test]
590	fn test_injection_metadata_clone() {
591		let metadata = InjectionMetadata {
592			scope: DependencyScope::Singleton,
593			cached: false,
594		};
595
596		let cloned = metadata;
597
598		assert_eq!(cloned.scope, DependencyScope::Singleton);
599		assert!(!cloned.cached);
600	}
601
602	#[test]
603	fn test_injection_metadata_copy() {
604		let metadata = InjectionMetadata {
605			scope: DependencyScope::Request,
606			cached: true,
607		};
608
609		// InjectionMetadata derives Copy
610		fn takes_copy<T: Copy>(_: T) {}
611		takes_copy(metadata);
612
613		// Original is still valid after copy
614		assert_eq!(metadata.scope, DependencyScope::Request);
615		assert!(metadata.cached);
616	}
617
618	#[tokio::test]
619	async fn test_injected_as_arc() {
620		let config = TestConfig {
621			value: "arc_test".to_string(),
622		};
623		let injected = Injected::from_value(config);
624
625		let arc = injected.as_arc();
626
627		// Arc reference provides access to inner value
628		assert_eq!(arc.value, "arc_test");
629
630		// Arc strong count should be 1 (only one reference)
631		assert_eq!(Arc::strong_count(arc), 1);
632	}
633
634	#[tokio::test]
635	async fn test_injected_as_ref() {
636		let config = TestConfig {
637			value: "ref_test".to_string(),
638		};
639		let injected = Injected::from_value(config);
640
641		// AsRef trait implementation
642		let reference: &TestConfig = injected.as_ref();
643		assert_eq!(reference.value, "ref_test");
644	}
645
646	#[tokio::test]
647	async fn test_injected_debug() {
648		let config = TestConfig {
649			value: "debug_test".to_string(),
650		};
651		let injected = Injected::from_value(config);
652
653		let debug_str = format!("{:?}", injected);
654
655		assert!(debug_str.contains("Injected"));
656	}
657
658	#[tokio::test]
659	async fn test_injected_resolve_with_context() {
660		let singleton_scope = Arc::new(SingletonScope::new());
661		let ctx = InjectionContext::builder(singleton_scope).build();
662
663		let config = Injected::<TestConfig>::resolve(&ctx).await.unwrap();
664
665		assert_eq!(config.value, "test");
666		assert!(config.metadata().cached);
667		assert_eq!(config.metadata().scope, DependencyScope::Request);
668	}
669
670	#[tokio::test]
671	async fn test_injected_resolve_uncached_with_context() {
672		let singleton_scope = Arc::new(SingletonScope::new());
673		let ctx = InjectionContext::builder(singleton_scope).build();
674
675		let config = Injected::<TestConfig>::resolve_uncached(&ctx)
676			.await
677			.unwrap();
678
679		assert_eq!(config.value, "test");
680		assert!(!config.metadata().cached);
681	}
682
683	#[tokio::test]
684	async fn test_injected_clone_shares_arc() {
685		let config = TestConfig {
686			value: "shared".to_string(),
687		};
688		let injected1 = Injected::from_value(config);
689		let injected2 = injected1.clone();
690
691		// Both should share the same Arc
692		assert_eq!(Arc::strong_count(injected1.as_arc()), 2);
693		assert_eq!(Arc::strong_count(injected2.as_arc()), 2);
694
695		// Both point to the same data
696		assert!(Arc::ptr_eq(injected1.as_arc(), injected2.as_arc()));
697	}
698
699	#[tokio::test]
700	async fn test_injected_metadata_preserved_on_clone() {
701		let config = TestConfig {
702			value: "metadata".to_string(),
703		};
704		let injected1 = Injected::from_value(config);
705		let injected2 = injected1.clone();
706
707		// Metadata should be identical
708		assert_eq!(injected1.metadata().scope, injected2.metadata().scope);
709		assert_eq!(injected1.metadata().cached, injected2.metadata().cached);
710	}
711
712	#[tokio::test]
713	async fn test_injected_into_inner_with_single_reference() {
714		let config = TestConfig {
715			value: "single".to_string(),
716		};
717		let injected = Injected::from_value(config);
718
719		// With single reference, Arc::try_unwrap succeeds
720		let inner = injected.into_inner();
721		assert_eq!(inner.value, "single");
722	}
723
724	#[tokio::test]
725	async fn test_injected_into_inner_with_multiple_references() {
726		let config = TestConfig {
727			value: "multiple".to_string(),
728		};
729		let injected1 = Injected::from_value(config);
730		let _injected2 = injected1.clone(); // Create second reference
731
732		// With multiple references, Arc::try_unwrap fails, falls back to clone
733		let inner = injected1.into_inner();
734		assert_eq!(inner.value, "multiple");
735	}
736
737	/// `try_unwrap()` succeeds when there is only one strong reference.
738	#[tokio::test]
739	async fn test_injected_try_unwrap_success() {
740		// Arrange
741		let config = TestConfig {
742			value: "owned".to_string(),
743		};
744		let injected = Injected::from_value(config);
745
746		// Act
747		let result = injected.try_unwrap();
748
749		// Assert
750		assert!(result.is_ok());
751		assert_eq!(result.unwrap().value, "owned");
752	}
753
754	/// `try_unwrap()` returns `Err(Self)` when multiple references exist.
755	#[tokio::test]
756	async fn test_injected_try_unwrap_err_multiple_refs() {
757		// Arrange
758		let config = TestConfig {
759			value: "shared".to_string(),
760		};
761		let injected = Injected::from_value(config);
762		let _clone = injected.clone();
763
764		// Act
765		let result = injected.try_unwrap();
766
767		// Assert
768		let returned = result.unwrap_err();
769		assert_eq!(returned.value, "shared");
770		assert_eq!(returned.metadata().scope, DependencyScope::Request);
771	}
772}