je_di/
lib.rs

1#![doc = include_str!("../README.md")]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3
4#[cfg(feature = "axum")]
5#[cfg_attr(docsrs, doc(cfg(feature = "axum")))]
6pub mod axum;
7
8#[cfg(feature = "async")]
9#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
10pub mod async_dependency;
11
12#[cfg(feature = "async")]
13#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
14pub use async_dependency::*;
15
16#[cfg(feature = "async")]
17#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
18pub use async_trait::async_trait;
19
20/// # Entry point to je-di
21///
22/// Describes a struct that can be constructed from a given World
23///
24/// you can associate a type to a single World
25///
26/// # Usage
27/// ```ignore
28/// use je-di::FromWorld;
29///
30/// struct MyWorld(String);
31///
32/// struct MyDependency(String);
33///
34/// impl je_di::FromWorld for MyDependency {
35///     type World<'a> = MyWorld;
36///     type Error = MyError;
37///
38///     fn from_world<'a>(world: &'a Self::World<'a>) -> Result<Self, Self::Error> {
39///         Ok(Self(world.0.clone()))
40///     }
41/// }
42/// ```
43pub trait FromWorld {
44    type World<'a>;
45    type Error;
46
47    fn from_world(world: &Self::World<'_>) -> Result<Self, Self::Error>
48    where
49        Self: std::marker::Sized;
50}
51
52/// # Defines a dependency
53///
54/// Describes a struct that can be constructed from a world and a dependency that implements
55/// FromWorld for the same World
56///
57/// # Usage
58/// ```ignore
59/// use je_di::FromDependency;
60///
61/// pub struct MyNestedDependency(OtherDependency);
62///
63/// impl FromDependency for MyNestedDependency {
64///     type World<'a> = MyWorld;
65///     type Error = MyError;
66///     type Dependency = OtherDependency;
67///
68///     fn from_dependency(
69///         _world: &Self::World,
70///         dependency: &Self::Dependency
71///     ) -> Result<Self, Self::Error> {
72///         Ok(Self(dependency.clone()))
73///     }
74/// }
75///
76/// ```
77pub trait FromDependency {
78    type Error;
79    type World<'a>;
80    type Dependency: for<'a> FromWorld<World<'a> = Self::World<'a>, Error = Self::Error>;
81
82    fn from_dependency(
83        world: &Self::World<'_>,
84        dependency: &Self::Dependency,
85    ) -> Result<Self, Self::Error>
86    where
87        Self: std::marker::Sized;
88}
89
90impl<T> FromWorld for T
91where
92    T: FromDependency,
93    T::Dependency: FromWorld,
94{
95    type Error = T::Error;
96    type World<'a> = T::World<'a>;
97
98    fn from_world(world: &Self::World<'_>) -> Result<Self, T::Error> {
99        let dependency = <T::Dependency as FromWorld>::from_world(world)?;
100
101        Self::from_dependency(world, &dependency)
102    }
103}
104
105macro_rules! impl_tuple {
106    ($first_n:tt:$first_name:ident, $($n:tt:$name:ident),+) => {
107        impl<$first_name, $($name),*> FromWorld for ($first_name, $($name),+)
108        where
109            $first_name: FromWorld,
110            $($name: for<'a> FromWorld<World<'a> = $first_name::World<'a>, Error = $first_name::Error>),*
111        {
112            type Error = $first_name::Error;
113            type World<'a> = $first_name::World<'a>;
114
115            fn from_world(world: &Self::World<'_>) -> Result<Self, Self::Error> {
116                Ok((
117                    $first_name::from_world(world)?,
118                    $($name::from_world(world)?),+
119                ))
120            }
121        }
122    };
123}
124
125impl_tuple!(0:Dep0, 1:Dep1, 2:Dep2, 3:Dep3, 4:Dep4, 5:Dep5, 6:Dep6, 7:Dep7, 8:Dep8);
126impl_tuple!(0:Dep0, 1:Dep1, 2:Dep2, 3:Dep3, 4:Dep4, 5:Dep5, 6:Dep6, 7:Dep7);
127impl_tuple!(0:Dep0, 1:Dep1, 2:Dep2, 3:Dep3, 4:Dep4, 5:Dep5, 6:Dep6);
128impl_tuple!(0:Dep0, 1:Dep1, 2:Dep2, 3:Dep3, 4:Dep4, 5:Dep5);
129impl_tuple!(0:Dep0, 1:Dep1, 2:Dep2, 3:Dep3, 4:Dep4);
130impl_tuple!(0:Dep0, 1:Dep1, 2:Dep2, 3:Dep3);
131impl_tuple!(0:Dep0, 1:Dep1, 2:Dep2);
132impl_tuple!(0:Dep0, 1:Dep1);
133
134pub struct DIContainer<World> {
135    world: World,
136}
137
138impl<World> DIContainer<World> {
139    pub fn new(world: World) -> Self {
140        Self { world }
141    }
142
143    pub fn extract<T: for<'a> FromWorld<World<'a> = World>>(
144        &self,
145    ) -> Result<T, <T as FromWorld>::Error> {
146        T::from_world(&self.world)
147    }
148}
149
150#[cfg(feature = "async")]
151#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
152impl<World> DIContainer<World> {
153    pub async fn extract_async<
154        T: for<'a> crate::async_dependency::FromAsyncWorld<World<'a> = World>,
155    >(
156        &self,
157    ) -> Result<T, <T as crate::async_dependency::FromAsyncWorld>::Error> {
158        T::from_world(&self.world).await
159    }
160}