Skip to main content

di/inject/
injectable.rs

1use crate::{InjectBuilder, ServiceLifetime};
2
3/// Defines the behavior of an injectable type.
4pub trait Injectable: Sized {
5    /// Creates and returns a [builder](InjectBuilder) for an injected type.
6    ///
7    /// # Arguments
8    ///
9    /// * `lifetime` - The [lifetime](ServiceLifetime) of the injected type
10    fn inject(lifetime: ServiceLifetime) -> InjectBuilder;
11
12    /// Creates and returns a [builder](InjectBuilder) for a singleton injected type.
13    fn singleton() -> InjectBuilder {
14        Self::inject(ServiceLifetime::Singleton)
15    }
16
17    /// Creates and returns a [builder](crate::InjectBuilder) for a scoped injected type.
18    fn scoped() -> InjectBuilder {
19        Self::inject(ServiceLifetime::Scoped)
20    }
21
22    /// Creates and returns a [builder](crate::InjectBuilder) for a transient injected type.
23    fn transient() -> InjectBuilder {
24        Self::inject(ServiceLifetime::Transient)
25    }
26}
27
28#[cfg(test)]
29mod tests {
30    use super::*;
31    use crate::{Activator, Mut, Ref, ServiceCollection};
32
33    #[cfg_attr(feature = "async", maybe_impl::traits(Send, Sync))]
34    trait TestService {}
35
36    #[cfg_attr(feature = "async", maybe_impl::traits(Send, Sync))]
37    trait OtherTestService {}
38
39    #[derive(Default)]
40    struct TestServiceImpl {}
41
42    struct OtherTestServiceImpl {
43        _service: Ref<dyn TestService>,
44    }
45
46    impl TestService for TestServiceImpl {}
47
48    impl Injectable for TestServiceImpl {
49        fn inject(lifetime: ServiceLifetime) -> InjectBuilder {
50            InjectBuilder::new(
51                Activator::new::<dyn TestService, Self>(
52                    |_| Ref::new(Self::default()),
53                    |_| Ref::new(Mut::new(Self::default())),
54                ),
55                lifetime,
56            )
57        }
58    }
59
60    impl OtherTestServiceImpl {
61        fn new(service: Ref<dyn TestService>) -> Self {
62            Self { _service: service }
63        }
64    }
65
66    impl Injectable for OtherTestServiceImpl {
67        fn inject(lifetime: ServiceLifetime) -> InjectBuilder {
68            InjectBuilder::new(
69                Activator::new::<dyn OtherTestService, Self>(
70                    |sp| Ref::new(Self::new(sp.get_required::<dyn TestService>())),
71                    |sp| Ref::new(Mut::new(Self::new(sp.get_required::<dyn TestService>()))),
72                ),
73                lifetime,
74            )
75        }
76    }
77
78    impl OtherTestService for OtherTestServiceImpl {}
79
80    #[test]
81    fn inject_should_invoke_constructor_injection() {
82        // arrange
83        let services = ServiceCollection::new()
84            .add(TestServiceImpl::singleton())
85            .add(OtherTestServiceImpl::transient())
86            .build_provider()
87            .unwrap();
88
89        // act
90        let service = services.get::<dyn OtherTestService>();
91
92        // assert
93        assert!(service.is_some());
94    }
95}