1use std::marker::PhantomData;
2use std::sync::Arc;
3
4use crate::{Resolve, ServiceContainer, Services};
5
6pub trait Construct<S = Self, C = ServiceContainer>: Send + Sync {
7 fn construct(container: &C) -> Option<S>;
8}
9
10pub struct Constructor<S> {
11 _phantom: PhantomData<fn() -> S>,
12}
13
14impl<S> Constructor<S> {
15 pub fn new() -> Self {
16 Self {
17 _phantom: PhantomData,
18 }
19 }
20}
21
22impl<S> Default for Constructor<S> {
23 fn default() -> Self {
24 Self::new()
25 }
26}
27
28impl<S, C> Resolve<S, C> for Constructor<S>
29where
30 S: Construct<S, C>,
31{
32 fn resolve(&self, container: &C) -> Option<Arc<S>> {
33 Some(Arc::new(S::construct(container)?))
34 }
35}
36
37pub trait ConstructServices: Services {
38 fn construct<S>(&mut self)
39 where
40 S: Construct<S, Self> + 'static,
41 {
42 self.put(Constructor::<S>::new());
43 }
44}
45
46impl<C> ConstructServices for C where C: Services {}
47
48#[cfg(test)]
49mod tests {
50 use std::sync::Arc;
51
52 use crate::construct::{Construct, ConstructServices};
53 use crate::singleton::SingletonServices;
54 use crate::{ServiceContainer, Services};
55
56 struct Foo {
57 name: String,
58 }
59
60 struct Bar {
61 foo: Arc<Foo>,
62 }
63
64 impl Bar {
65 fn greet(&self) -> String {
66 format!("Hello, {}!", self.foo.name)
67 }
68 }
69
70 impl<C> Construct<Self, C> for Bar
71 where
72 C: Services,
73 {
74 fn construct(container: &C) -> Option<Self> {
75 Some(Self {
76 foo: container.get()?,
77 })
78 }
79 }
80
81 #[test]
82 fn construct() {
83 let mut container = ServiceContainer::default();
84
85 container.construct::<Bar>();
88
89 container.singleton(Foo {
91 name: "Taro".to_string(),
92 });
93
94 let bar = container.get::<Bar>().unwrap();
95 assert_eq!("Hello, Taro!".to_string(), bar.greet());
96 }
97}