1use std::marker::PhantomData;
2use std::sync::Arc;
3
4use crate::{Catalog, InjectionError};
5
6pub trait DependencySpec {
12 type ReturnType;
13 fn get(cat: &Catalog) -> Result<Self::ReturnType, InjectionError>;
15 fn check(cat: &Catalog) -> Result<(), InjectionError>;
17}
18
19pub struct OneOf<Iface>
27where
28 Iface: 'static + ?Sized + Send + Sync,
29{
30 _dummy: PhantomData<Iface>,
31}
32
33impl<Iface> DependencySpec for OneOf<Iface>
34where
35 Iface: 'static + ?Sized + Send + Sync,
36{
37 type ReturnType = Arc<Iface>;
38
39 default fn get(cat: &Catalog) -> Result<Self::ReturnType, InjectionError> {
40 let mut builders = cat.builders_for::<Iface>();
41 if let Some(first) = builders.next() {
42 if builders.next().is_some() {
43 Err(InjectionError::ambiguous::<Iface>())
44 } else {
45 first.get(cat)
46 }
47 } else {
48 Err(InjectionError::unregistered::<Iface>())
49 }
50 }
51
52 default fn check(cat: &Catalog) -> Result<(), InjectionError> {
53 let mut builders = cat.builders_for::<Iface>();
54 if builders.next().is_some() {
55 if builders.next().is_some() {
56 Err(InjectionError::ambiguous::<Iface>())
57 } else {
58 Ok(())
59 }
60 } else {
61 Err(InjectionError::unregistered::<Iface>())
62 }
63 }
64}
65
66impl DependencySpec for OneOf<Catalog> {
67 fn get(cat: &Catalog) -> Result<Self::ReturnType, InjectionError> {
68 Ok(Arc::new(cat.clone()))
70 }
71
72 fn check(_: &Catalog) -> Result<(), InjectionError> {
73 Ok(())
74 }
75}
76
77pub struct AllOf<Iface>
84where
85 Iface: 'static + ?Sized,
86{
87 _dummy: PhantomData<Iface>,
88}
89
90impl<Iface> DependencySpec for AllOf<Iface>
91where
92 Iface: 'static + ?Sized,
93{
94 type ReturnType = Vec<Arc<Iface>>;
95
96 fn get(cat: &Catalog) -> Result<Self::ReturnType, InjectionError> {
97 cat.builders_for::<Iface>().map(|b| b.get(cat)).collect()
98 }
99
100 fn check(_cat: &Catalog) -> Result<(), InjectionError> {
101 Ok(())
102 }
103}
104
105pub struct Maybe<Inner: DependencySpec> {
111 _dummy: PhantomData<Inner>,
112}
113
114impl<Inner: DependencySpec> DependencySpec for Maybe<Inner> {
115 type ReturnType = Option<Inner::ReturnType>;
116
117 fn get(cat: &Catalog) -> Result<Self::ReturnType, InjectionError> {
118 match Inner::get(cat) {
119 Ok(v) => Ok(Some(v)),
120 Err(InjectionError::Unregistered(_)) => Ok(None),
121 Err(err) => Err(err),
122 }
123 }
124
125 fn check(cat: &Catalog) -> Result<(), InjectionError> {
126 match Inner::check(cat) {
127 Ok(()) => Ok(()),
128 Err(InjectionError::Unregistered(_)) => Ok(()),
129 Err(err) => Err(err),
130 }
131 }
132}
133
134pub struct Lazy<Inner: DependencySpec> {
142 _dummy: PhantomData<Inner>,
143}
144
145impl<Inner: DependencySpec> DependencySpec for Lazy<Inner> {
146 type ReturnType = crate::lazy::Lazy<Inner::ReturnType>;
147
148 #[cfg(not(feature = "tokio"))]
149 fn get(cat: &Catalog) -> Result<Self::ReturnType, InjectionError> {
150 let cat = cat.clone();
151 Ok(crate::lazy::Lazy::new(move || Inner::get(&cat)))
152 }
153
154 #[cfg(feature = "tokio")]
155 fn get(cat: &Catalog) -> Result<Self::ReturnType, InjectionError> {
156 let fallback_cat = cat.clone();
160 Ok(crate::lazy::Lazy::new(move || match crate::CURRENT_CATALOG
161 .try_with(|cat| Inner::get(cat))
162 {
163 Ok(v) => v,
164 Err(_) => Inner::get(&fallback_cat),
165 }))
166 }
167
168 fn check(cat: &Catalog) -> Result<(), InjectionError> {
169 Inner::check(cat)
170 }
171}