xylem/
typemap_context.rs

1use std::any::TypeId;
2use std::marker::PhantomData;
3
4use typemap::TypeMap;
5
6use super::Context;
7
8struct TypeMapKey<T: 'static>(PhantomData<T>);
9
10impl<T> typemap::Key for TypeMapKey<T> {
11    type Value = T;
12}
13
14/// A [`Context`] implementation based on [`typemap::TypeMap`].
15pub struct DefaultContext {
16    layers: Vec<Layer>,
17}
18
19impl Default for DefaultContext {
20    fn default() -> Self {
21        DefaultContext {
22            layers: vec![Layer { type_id: TypeId::of::<()>(), map: TypeMap::custom() }],
23        }
24    }
25}
26
27impl Context for DefaultContext {
28    type Scope = Scope;
29
30    fn start_scope<T: 'static>(&mut self) -> Scope {
31        let type_id = TypeId::of::<T>();
32        let index = self.layers.len();
33
34        self.layers.push(Layer { type_id, map: TypeMap::custom() });
35
36        Scope { type_id, index }
37    }
38
39    fn end_scope(&mut self, scope: Scope) {
40        let layer = self.layers.pop().expect("Ending scope of empty layout");
41        debug_assert_eq!(scope.type_id, layer.type_id, "Scope mismatch");
42        debug_assert_eq!(scope.index, self.layers.len(), "Scope mismatch");
43    }
44
45    fn nth_last_scope(&self, n: usize) -> Option<TypeId> {
46        self.layers.get(self.layers.len() - n - 1).map(|layer| layer.type_id)
47    }
48
49    fn get<T>(&self, scope: TypeId) -> Option<&T>
50    where
51        T: 'static,
52    {
53        let layer = self.layers.iter().rev().find(|layer| layer.type_id == scope)?;
54        layer.map.get::<TypeMapKey<T>>()
55    }
56
57    #[inline]
58    fn get_each<T>(&self) -> Box<dyn Iterator<Item = &T> + '_>
59    where
60        T: 'static,
61    {
62        Box::new(self.layers.iter().rev().filter_map(|layer| layer.map.get::<TypeMapKey<T>>()))
63    }
64
65    fn get_mut<T, F>(&mut self, scope: TypeId, default: F) -> &mut T
66    where
67        F: FnOnce() -> T,
68        T: 'static,
69    {
70        let layer = match self.layers.iter_mut().rev().find(|layer| layer.type_id == scope) {
71            Some(layer) => layer,
72            None => panic!("Attempt to fetch from scope {:?} which is not in the stack", scope,),
73        };
74        layer.map.entry::<TypeMapKey<T>>().or_insert_with(default)
75    }
76}
77
78struct Layer {
79    type_id: TypeId,
80    map:     TypeMap,
81}
82
83/// Return value for [`DefaultContext::start_scope`].
84pub struct Scope {
85    type_id: TypeId,
86    index:   usize,
87}