polyhorn_core/
context.rs

1use super::{Component, Element, Key, Manager, Platform};
2use std::any::{Any, TypeId};
3use std::cell::RefCell;
4use std::collections::HashMap;
5use std::rc::{Rc, Weak};
6
7pub struct ContextTree {
8    parent: Option<Rc<ContextTree>>,
9    values: RefCell<HashMap<TypeId, Rc<dyn Any>>>,
10}
11
12impl ContextTree {
13    /// This function creates a new context tree root.
14    pub fn new() -> ContextTree {
15        ContextTree {
16            parent: None,
17            values: RefCell::new(HashMap::new()),
18        }
19    }
20
21    /// This function enters a new branch of a given context tree.
22    pub fn enter(self: &Rc<Self>) -> ContextTree {
23        ContextTree {
24            parent: Some(self.clone()),
25            values: RefCell::new(HashMap::new()),
26        }
27    }
28
29    pub fn insert<T>(&self, value: Rc<T>)
30    where
31        T: 'static,
32    {
33        self.insert_raw(value);
34    }
35
36    pub fn insert_raw(&self, value: Rc<dyn Any>) {
37        self.values
38            .borrow_mut()
39            .insert(value.as_ref().type_id(), value);
40    }
41
42    pub fn get_flat<T>(&self) -> Option<Rc<T>>
43    where
44        T: 'static,
45    {
46        let id = TypeId::of::<T>();
47        let values = self.values.borrow();
48        let value = values.get(&id)?;
49        value.clone().downcast::<T>().ok()
50    }
51
52    pub fn get<T>(&self) -> Option<Rc<T>>
53    where
54        T: 'static,
55    {
56        self.get_flat()
57            .or_else(|| self.parent.as_ref().and_then(|parent| parent.get()))
58    }
59}
60
61impl Default for ContextTree {
62    fn default() -> Self {
63        ContextTree::new()
64    }
65}
66
67pub struct Context<T> {
68    current: Weak<T>,
69}
70
71impl<T> Context<T> {
72    pub fn new(value: &Rc<T>) -> Context<T> {
73        Context {
74            current: Rc::downgrade(value),
75        }
76    }
77
78    pub fn is_none(&self) -> bool {
79        !self.is_some()
80    }
81
82    pub fn is_some(&self) -> bool {
83        self.current.upgrade().is_some()
84    }
85
86    pub fn upgrade(&self) -> Option<Rc<T>> {
87        self.current.upgrade()
88    }
89
90    pub fn to_owned(&self) -> Option<T>
91    where
92        T: Clone,
93    {
94        Some(self.upgrade()?.as_ref().to_owned())
95    }
96}
97
98impl<T> Clone for Context<T> {
99    fn clone(&self) -> Self {
100        Context {
101            current: self.current.clone(),
102        }
103    }
104}
105
106pub struct ContextProvider<T>
107where
108    T: 'static,
109{
110    pub value: Rc<T>,
111}
112
113impl<T> Clone for ContextProvider<T>
114where
115    T: 'static,
116{
117    fn clone(&self) -> ContextProvider<T> {
118        ContextProvider {
119            value: self.value.clone(),
120        }
121    }
122}
123
124impl<T, P> Component<P> for ContextProvider<T>
125where
126    T: 'static,
127    P: Platform + ?Sized,
128{
129    fn render(&self, manager: &mut Manager<P>) -> Element<P> {
130        Element::context(Key::new(()), self.value.clone(), manager.children())
131    }
132}