easy_di/
lib.rs

1//! Easy DI is dependency injection container for Rust.
2//!
3//! Setup:
4//! ```
5//! use std::sync::Arc;
6//! use easy_di::{Container, ServiceProvider};
7//!
8//! pub trait Animal {
9//!     fn make_sound(&self);
10//! }
11//!
12//! #[derive(Clone)]
13//! struct Dog;
14//! impl Animal for Dog {
15//!     fn make_sound(&self) {
16//!         println!("woof woof!")
17//!     }
18//! }
19//!
20//! let mut container = Container::new();
21//! let animal: Arc<dyn Animal + Sync + Send> = Arc::new(Dog);
22//! container.inject(animal);
23//!
24//! let animal2 = container.find::<Arc<dyn Animal + Sync + Send>>();
25//! animal2.unwrap().make_sound();
26//!
27//! ```
28//!
29use std::borrow::Borrow;
30use std::sync::{Mutex, MutexGuard};
31
32pub use service_provider::ServiceProvider;
33
34use crate::service_provider_extensions::ServiceProviderExtensions;
35
36pub mod service_provider;
37pub mod service_provider_extensions;
38
39#[derive(Debug, thiserror::Error, PartialEq)]
40pub enum Error {
41    #[error("InjectLookupError({0})")]
42    InjectLookupError(String),
43}
44
45#[derive(Default)]
46pub struct Container {
47    extensions: Mutex<ServiceProviderExtensions>,
48}
49
50impl Container {
51    pub fn new() -> Self {
52        Self::default()
53    }
54}
55
56impl ServiceProvider for Container {
57    fn extensions(&self) -> MutexGuard<'_, ServiceProviderExtensions> {
58        self.extensions.borrow().lock().unwrap()
59    }
60}
61
62#[cfg(test)]
63mod tests {
64    use std::borrow::Borrow;
65    use std::sync::{Arc, Mutex, MutexGuard};
66
67    use totems::assert_err;
68
69    use crate::{Container, ServiceProvider, ServiceProviderExtensions};
70
71    pub trait Animal {
72        fn make_sound(&self);
73    }
74
75    #[derive(Clone)]
76    struct Dog;
77
78    impl Animal for Dog {
79        fn make_sound(&self) {
80            println!("woof woof!")
81        }
82    }
83
84    #[test]
85    fn test_dependency_is_injected() {
86        let mut container = Container::new();
87        let animal: Arc<dyn Animal + Sync + Send> = Arc::new(Dog);
88        container.inject(animal.clone());
89
90        let animal2 = container.find::<Arc<dyn Animal + Sync + Send>>();
91
92        assert!(animal2.is_ok())
93    }
94
95    #[derive(Default)]
96    struct ServiceProviderStub {
97        extensions: Mutex<ServiceProviderExtensions>,
98    }
99
100    impl ServiceProvider for ServiceProviderStub {
101        fn extensions(&self) -> MutexGuard<'_, ServiceProviderExtensions> {
102            self.extensions.borrow().lock().unwrap()
103        }
104    }
105
106    #[test]
107    fn empty_service_provider() {
108        let sp = ServiceProviderStub::default();
109
110        assert_err!(sp.find::<String>());
111        assert_err!(sp.find::<Arc<String>>());
112    }
113
114    #[test]
115    fn value_is_injected_by_type_not_by_value() {
116        let mut sp = ServiceProviderStub::default();
117        sp.inject("String".to_string());
118        sp.inject("Ae".to_string());
119
120        assert_eq!(sp.count(), 1);
121        assert_ne!(*sp.find::<String>().unwrap(), "String".to_string());
122        assert_eq!(*sp.find::<String>().unwrap(), "Ae".to_string());
123    }
124
125    #[test]
126    fn inject_arc() {
127        struct MyStub {}
128        let mut sp = ServiceProviderStub::default();
129        sp.inject(Arc::new(MyStub {}));
130
131        assert!(sp.find::<Arc<MyStub>>().is_ok());
132    }
133}