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
14pub 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
83pub struct Scope {
85 type_id: TypeId,
86 index: usize,
87}