dill/
builder.rs

1use std::any::{Any, TypeId};
2use std::sync::{Arc, Mutex};
3
4use crate::*;
5
6/////////////////////////////////////////////////////////////////////////////////////////
7
8/// Builders are responsible for resolving dependencies and creating new
9/// instances of a certain type. Builders typically create new instances for
10/// every call, delegating the lifetime management to [Scope]s,
11pub trait Builder: Send + Sync {
12    /// [`TypeId`] of the type that this builder supplies
13    fn instance_type_id(&self) -> TypeId;
14
15    /// Name of the type that this builder supplies in the `mod1::mod2::Typ`
16    /// format
17    fn instance_type_name(&self) -> &'static str;
18
19    /// Lists interfaces that the supplied type supports. Avoid using this
20    /// low-level method directly - use [`BuilderExt`] convenience methods
21    /// instead.
22    fn interfaces(&self, clb: &mut dyn FnMut(&InterfaceDesc) -> bool);
23
24    /// Provider interface for accessing associated metadata. Avoid using this
25    /// low-level method directly - use [`BuilderExt`] convenience methods
26    /// instead.
27    fn metadata<'a>(&'a self, clb: &mut dyn FnMut(&'a dyn std::any::Any) -> bool);
28
29    /// Get an instance of the supplied type
30    fn get_any(&self, cat: &Catalog) -> Result<Arc<dyn Any + Send + Sync>, InjectionError>;
31
32    /// Validate the dependency tree
33    fn check(&self, cat: &Catalog) -> Result<(), ValidationError>;
34}
35
36/////////////////////////////////////////////////////////////////////////////////////////
37
38pub trait BuilderExt {
39    fn interfaces_get_all(&self) -> Vec<InterfaceDesc>;
40    fn interfaces_contain<Iface: 'static>(&self) -> bool;
41    fn interfaces_contain_type_id(&self, type_id: &TypeId) -> bool;
42
43    fn metadata_get_first<Meta: 'static>(&self) -> Option<&Meta>;
44    fn metadata_find_first<Meta: 'static>(&self, pred: impl Fn(&Meta) -> bool) -> Option<&Meta>;
45    fn metadata_get_all<Meta: 'static>(&self) -> Vec<&Meta>;
46    fn metadata_find_all<Meta: 'static>(&self, pred: impl Fn(&Meta) -> bool) -> Vec<&Meta>;
47    fn metadata_contains<Meta: 'static>(&self, pred: impl Fn(&Meta) -> bool) -> bool;
48}
49
50impl<T: Builder + ?Sized> BuilderExt for T {
51    fn interfaces_get_all(&self) -> Vec<InterfaceDesc> {
52        let mut ret = Vec::new();
53        self.interfaces(&mut |i| {
54            ret.push(*i);
55            true
56        });
57        ret
58    }
59
60    fn interfaces_contain<Iface: 'static>(&self) -> bool {
61        let type_id = TypeId::of::<Iface>();
62        self.interfaces_contain_type_id(&type_id)
63    }
64
65    fn interfaces_contain_type_id(&self, type_id: &TypeId) -> bool {
66        let mut ret = false;
67        self.interfaces(&mut |i| {
68            if i.type_id == *type_id {
69                ret = true;
70                return false;
71            }
72            true
73        });
74        ret
75    }
76
77    fn metadata_get_first<Meta: 'static>(&self) -> Option<&Meta> {
78        let mut ret: Option<&Meta> = None;
79        self.metadata(&mut |m| {
80            if let Some(v) = m.downcast_ref::<Meta>() {
81                ret = Some(v);
82                return false;
83            }
84            true
85        });
86        ret
87    }
88
89    fn metadata_find_first<Meta: 'static>(&self, pred: impl Fn(&Meta) -> bool) -> Option<&Meta> {
90        let mut ret: Option<&Meta> = None;
91        self.metadata(&mut |m| {
92            if let Some(v) = m.downcast_ref::<Meta>() {
93                if pred(v) {
94                    ret = Some(v);
95                    return false;
96                }
97            }
98            true
99        });
100        ret
101    }
102
103    fn metadata_get_all<Meta: 'static>(&self) -> Vec<&Meta> {
104        let mut ret: Vec<&Meta> = Vec::new();
105        self.metadata(&mut |m| {
106            if let Some(v) = m.downcast_ref::<Meta>() {
107                ret.push(v);
108            }
109            true
110        });
111        ret
112    }
113
114    fn metadata_find_all<Meta: 'static>(&self, pred: impl Fn(&Meta) -> bool) -> Vec<&Meta> {
115        let mut ret: Vec<&Meta> = Vec::new();
116        self.metadata(&mut |m| {
117            if let Some(v) = m.downcast_ref::<Meta>() {
118                if pred(v) {
119                    ret.push(v);
120                }
121            }
122            true
123        });
124        ret
125    }
126
127    fn metadata_contains<Meta: 'static>(&self, pred: impl Fn(&Meta) -> bool) -> bool {
128        let mut ret = false;
129        self.metadata(&mut |m| {
130            if let Some(v) = m.downcast_ref::<Meta>() {
131                if pred(v) {
132                    ret = true;
133                    return false;
134                }
135            }
136            true
137        });
138        ret
139    }
140}
141
142/////////////////////////////////////////////////////////////////////////////////////////
143
144pub trait TypedBuilder<T: Send + Sync + ?Sized>: Builder {
145    /// Called to get an instance of the component, respecting the lifetime
146    /// defined by the scope
147    fn get(&self, cat: &Catalog) -> Result<Arc<T>, InjectionError>;
148
149    /// Called during registration to automatically bind this builder to all
150    /// interfaces this component implements
151    fn bind_interfaces(&self, cat: &mut CatalogBuilder);
152}
153
154pub trait TypedBuilderExt<T: Send + Sync + ?Sized>: TypedBuilder<T> {
155    /// Stops builder from auto-registering the default interfaces, allowing a
156    /// fine-grain control over the binding
157    fn without_default_interfaces(self) -> impl TypedBuilder<T>;
158}
159
160pub trait TypedBuilderCast<I: Send + Sync + ?Sized> {
161    fn cast(self) -> impl TypedBuilder<I>;
162}
163
164/// Allows [CatalogBuilder::add()] to accept types with associated builder
165pub trait Component {
166    type Impl: Send + Sync;
167    type Builder: TypedBuilder<Self::Impl>;
168
169    fn builder() -> Self::Builder;
170}
171
172#[derive(Debug, Copy, Clone)]
173pub struct InterfaceDesc {
174    pub type_id: TypeId,
175    pub type_name: &'static str,
176}
177
178/////////////////////////////////////////////////////////////////////////////////////////
179
180impl<Bld, Impl> TypedBuilderExt<Impl> for Bld
181where
182    Impl: Send + Sync,
183    Bld: TypedBuilder<Impl>,
184{
185    fn without_default_interfaces(self) -> impl TypedBuilder<Impl> {
186        TypedBuilderWithoudDefaultInterfaces(self)
187    }
188}
189
190/// A wrapper builder that stops it from auto-registering default interfaces
191pub struct TypedBuilderWithoudDefaultInterfaces<Bld>(Bld);
192
193impl<Bld> Builder for TypedBuilderWithoudDefaultInterfaces<Bld>
194where
195    Bld: Builder,
196{
197    fn instance_type_id(&self) -> TypeId {
198        self.0.instance_type_id()
199    }
200
201    fn instance_type_name(&self) -> &'static str {
202        self.0.instance_type_name()
203    }
204
205    fn interfaces(&self, clb: &mut dyn FnMut(&InterfaceDesc) -> bool) {
206        self.0.interfaces(clb);
207    }
208
209    fn metadata<'a>(&'a self, clb: &mut dyn FnMut(&'a dyn std::any::Any) -> bool) {
210        self.0.metadata(clb);
211    }
212
213    fn get_any(&self, cat: &Catalog) -> Result<Arc<dyn Any + Send + Sync>, InjectionError> {
214        self.0.get_any(cat)
215    }
216
217    fn check(&self, cat: &Catalog) -> Result<(), ValidationError> {
218        self.0.check(cat)
219    }
220}
221
222impl<Bld, Impl> TypedBuilder<Impl> for TypedBuilderWithoudDefaultInterfaces<Bld>
223where
224    Impl: Send + Sync,
225    Bld: TypedBuilder<Impl>,
226{
227    fn get(&self, cat: &Catalog) -> Result<Arc<Impl>, InjectionError> {
228        self.0.get(cat)
229    }
230
231    fn bind_interfaces(&self, _cat: &mut CatalogBuilder) {}
232}
233
234/////////////////////////////////////////////////////////////////////////////////////////
235
236/// Arc<T> can infinitely produce clones of itself and therefore is a builder
237impl<Impl> Builder for Arc<Impl>
238where
239    Impl: Send + Sync + 'static,
240{
241    fn instance_type_id(&self) -> TypeId {
242        TypeId::of::<Impl>()
243    }
244
245    fn instance_type_name(&self) -> &'static str {
246        std::any::type_name::<Impl>()
247    }
248
249    fn interfaces(&self, _clb: &mut dyn FnMut(&InterfaceDesc) -> bool) {}
250
251    fn metadata<'a>(&'a self, _clb: &mut dyn FnMut(&'a dyn Any) -> bool) {}
252
253    fn get_any(&self, _cat: &Catalog) -> Result<Arc<dyn Any + Send + Sync>, InjectionError> {
254        Ok(self.clone())
255    }
256
257    fn check(&self, _cat: &Catalog) -> Result<(), ValidationError> {
258        Ok(())
259    }
260}
261
262impl<Impl> TypedBuilder<Impl> for Arc<Impl>
263where
264    Impl: Send + Sync + 'static,
265{
266    fn get(&self, _cat: &Catalog) -> Result<Arc<Impl>, InjectionError> {
267        Ok(self.clone())
268    }
269
270    fn bind_interfaces(&self, _cat: &mut CatalogBuilder) {}
271}
272
273/////////////////////////////////////////////////////////////////////////////////////////
274
275/// Fn() -> Arc<T> acts as a builder
276impl<Fct, Impl> Builder for Fct
277where
278    Fct: Fn() -> Arc<Impl> + Send + Sync,
279    Impl: Send + Sync + 'static,
280{
281    fn instance_type_id(&self) -> TypeId {
282        TypeId::of::<Impl>()
283    }
284
285    fn instance_type_name(&self) -> &'static str {
286        std::any::type_name::<Impl>()
287    }
288
289    fn interfaces(&self, _clb: &mut dyn FnMut(&InterfaceDesc) -> bool) {}
290
291    fn metadata<'a>(&'a self, _clb: &mut dyn FnMut(&'a dyn Any) -> bool) {}
292
293    fn get_any(&self, _cat: &Catalog) -> Result<Arc<dyn Any + Send + Sync>, InjectionError> {
294        Ok(self())
295    }
296
297    fn check(&self, _cat: &Catalog) -> Result<(), ValidationError> {
298        Ok(())
299    }
300}
301
302impl<Fct, Impl> TypedBuilder<Impl> for Fct
303where
304    Fct: Fn() -> Arc<Impl> + Send + Sync,
305    Impl: Send + Sync + 'static,
306{
307    fn get(&self, _cat: &Catalog) -> Result<Arc<Impl>, InjectionError> {
308        Ok(self())
309    }
310
311    fn bind_interfaces(&self, _cat: &mut CatalogBuilder) {}
312}
313
314/////////////////////////////////////////////////////////////////////////////////////////
315
316pub(crate) struct LazyBuilder<Fct, Impl>
317where
318    Fct: FnOnce() -> Impl,
319    Impl: 'static + Send + Sync,
320{
321    state: Mutex<LazyBuilderState<Fct, Impl>>,
322}
323
324struct LazyBuilderState<Fct, Impl> {
325    factory: Option<Fct>,
326    instance: Option<Arc<Impl>>,
327}
328
329impl<Fct, Impl> LazyBuilder<Fct, Impl>
330where
331    Fct: FnOnce() -> Impl,
332    Impl: 'static + Send + Sync,
333{
334    pub fn new(factory: Fct) -> Self {
335        Self {
336            state: Mutex::new(LazyBuilderState {
337                factory: Some(factory),
338                instance: None,
339            }),
340        }
341    }
342}
343
344impl<Fct, Impl> Builder for LazyBuilder<Fct, Impl>
345where
346    Fct: FnOnce() -> Impl + Send + Sync,
347    Impl: 'static + Send + Sync,
348{
349    fn instance_type_id(&self) -> TypeId {
350        TypeId::of::<Impl>()
351    }
352
353    fn instance_type_name(&self) -> &'static str {
354        std::any::type_name::<Impl>()
355    }
356
357    fn interfaces(&self, _clb: &mut dyn FnMut(&InterfaceDesc) -> bool) {}
358
359    fn metadata<'a>(&'a self, _clb: &mut dyn FnMut(&'a dyn Any) -> bool) {}
360
361    fn get_any(&self, cat: &Catalog) -> Result<Arc<dyn Any + Send + Sync>, InjectionError> {
362        Ok(TypedBuilder::get(self, cat)?)
363    }
364
365    fn check(&self, _cat: &Catalog) -> Result<(), ValidationError> {
366        Ok(())
367    }
368}
369
370impl<Fct, Impl> TypedBuilder<Impl> for LazyBuilder<Fct, Impl>
371where
372    Fct: FnOnce() -> Impl + Send + Sync,
373    Impl: 'static + Send + Sync,
374{
375    fn get(&self, _cat: &Catalog) -> Result<Arc<Impl>, InjectionError> {
376        let mut s = self.state.lock().unwrap();
377        if let Some(inst) = s.instance.as_ref() {
378            Ok(inst.clone())
379        } else {
380            let factory = s.factory.take().unwrap();
381            let inst = Arc::new(factory());
382            s.instance = Some(inst.clone());
383            Ok(inst)
384        }
385    }
386
387    fn bind_interfaces(&self, _cat: &mut CatalogBuilder) {}
388}