1use std::future::Future;
2use std::pin::Pin;
3use std::sync::Arc;
4
5use async_trait::async_trait;
6
7use crate::{AsyncResolve, AsyncResolver, AsyncServices, Resolve, ServiceContainer, Services};
8
9pub struct Bound<Interface>
10where
11 Interface: ?Sized,
12{
13 service: Arc<Interface>,
14}
15
16impl<Interface> From<Arc<Interface>> for Bound<Interface>
17where
18 Interface: ?Sized,
19{
20 fn from(value: Arc<Interface>) -> Self {
21 Self { service: value }
22 }
23}
24
25impl<Interface, C> Resolve<Interface, C> for Bound<Interface>
26where
27 Interface: ?Sized + Send + Sync,
28{
29 fn resolve(&self, _container: &C) -> Option<Arc<Interface>> {
30 Some(Arc::clone(&self.service))
31 }
32}
33
34pub struct BindBy<Interface, C = ServiceContainer>
35where
36 Interface: ?Sized + Send + Sync,
37{
38 #[allow(clippy::type_complexity)]
39 f: Arc<dyn Fn(&C) -> Option<Arc<Interface>> + Send + Sync>,
40}
41
42impl<Interface, C, F> From<F> for BindBy<Interface, C>
43where
44 Interface: ?Sized + Send + Sync,
45 F: (Fn(&C) -> Option<Arc<Interface>>) + Send + Sync + 'static,
46{
47 fn from(value: F) -> Self {
48 Self { f: Arc::new(value) }
49 }
50}
51
52impl<Interface, C> Resolve<Interface, C> for BindBy<Interface, C>
53where
54 Interface: ?Sized + Send + Sync,
55{
56 fn resolve(&self, container: &C) -> Option<Arc<Interface>> {
57 (self.f)(container)
58 }
59}
60
61pub struct AsyncBindBy<Interface, C = ServiceContainer>
62where
63 Interface: ?Sized + Send + Sync,
64{
65 #[allow(clippy::type_complexity)]
66 f: Arc<
67 dyn Fn(&C) -> Pin<Box<dyn Future<Output = Option<Arc<Interface>>> + Send>> + Send + Sync,
68 >,
69}
70
71impl<Interface, C, F, Fut> From<F> for AsyncBindBy<Interface, C>
72where
73 Interface: ?Sized + Send + Sync,
74 F: (Fn(&C) -> Fut) + Send + Sync + 'static,
75 Fut: Future<Output = Option<Arc<Interface>>> + Send + 'static,
76 C: Send + Sync,
77{
78 fn from(value: F) -> Self {
79 Self {
80 f: Arc::new(move |c| Box::pin(value(c))),
81 }
82 }
83}
84
85#[async_trait]
86impl<Interface, C> AsyncResolve<Interface, C> for AsyncBindBy<Interface, C>
87where
88 Interface: ?Sized + Send + Sync,
89 C: Send + Sync,
90{
91 async fn async_resolve(&self, container: &C) -> Option<Arc<Interface>> {
92 (self.f)(container).await
93 }
94}
95
96pub trait BindServices: Services {
97 fn bind<Interface>(&mut self, service: Arc<Interface>)
98 where
99 Interface: ?Sized + Send + Sync + 'static,
100 {
101 self.put(Bound::from(service));
102 }
103
104 fn bind_by<Interface, F>(&mut self, f: F)
105 where
106 Interface: ?Sized + Send + Sync + 'static,
107 F: (Fn(&Self) -> Option<Arc<Interface>>) + Send + Sync + 'static,
108 Self: 'static,
109 {
110 self.put(BindBy::from(f))
111 }
112}
113
114impl<C> BindServices for C where C: Services {}
115
116pub trait AsyncBindServices: AsyncServices {
117 fn bind_by_async<Interface, F, Fut>(&mut self, f: F)
118 where
119 Interface: ?Sized + Send + Sync + 'static,
120 F: (Fn(&Self) -> Fut) + Send + Sync + 'static,
121 Fut: Future<Output = Option<Arc<Interface>>> + Send + 'static,
122 Self: Send + Sync + 'static,
123 {
124 self.put_async(AsyncResolver::new(AsyncBindBy::from(f)))
125 }
126}
127
128impl<C> AsyncBindServices for C where C: AsyncServices {}
129
130#[cfg(test)]
131mod tests {
132 use super::*;
133 use crate::ServiceContainer;
134
135 trait Greet: Send + Sync {
136 fn greet(&self) -> String;
137 }
138
139 struct Greeter {
140 name: String,
141 }
142
143 impl Greet for Greeter {
144 fn greet(&self) -> String {
145 format!("Hello, {}!", self.name)
146 }
147 }
148
149 #[test]
150 fn bind() {
151 let mut container = ServiceContainer::default();
152
153 container.bind::<dyn Greet>(Arc::new(Greeter {
155 name: "Taro".to_string(),
156 }));
157
158 let name_getter = container.get::<dyn Greet>().unwrap();
160 assert_eq!("Hello, Taro!".to_string(), name_getter.greet());
161 }
162
163 #[test]
164 fn bind_by() {
165 let mut container = ServiceContainer::default();
166
167 container.bind_by(|_| -> Option<Arc<dyn Greet>> {
169 Some(Arc::new(Greeter {
170 name: "Taro".to_string(),
171 }))
172 });
173
174 let name_getter = container.get::<dyn Greet>().unwrap();
176 assert_eq!("Hello, Taro!".to_string(), name_getter.greet());
177 }
178
179 #[tokio::test]
180 async fn bind_by_async() {
181 let mut container = ServiceContainer::default();
182
183 container.bind_by_async(|_| async {
185 Some(Arc::new(Greeter {
186 name: "Taro".to_string(),
187 }) as Arc<dyn Greet>)
188 });
189
190 assert!(container.get::<dyn Greet>().is_none());
192
193 let name_getter = container.get_async::<dyn Greet>().await.unwrap();
195 assert_eq!("Hello, Taro!".to_string(), name_getter.greet());
196 }
197}