sauron_core/dom/program/
app_context.rs1#[cfg(feature = "with-measure")]
2use crate::dom::Measurements;
3use crate::dom::{Application, Dispatch};
4use crate::vdom;
5use std::{
6 cell::{Ref, RefCell},
7 collections::VecDeque,
8 rc::Rc,
9 rc::Weak,
10};
11
12pub(crate) struct AppContext<APP>
15where
16 APP: Application,
17{
18 pub(crate) app: Rc<RefCell<APP>>,
20
21 pub(crate) current_vdom: Rc<RefCell<vdom::Node<APP::MSG>>>,
24
25 pub(crate) pending_msgs: Rc<RefCell<VecDeque<APP::MSG>>>,
30
31 pub(crate) pending_dispatches: Rc<RefCell<VecDeque<Dispatch<APP>>>>,
33}
34
35pub(crate) struct WeakContext<APP>
36where
37 APP: Application,
38{
39 pub(crate) app: Weak<RefCell<APP>>,
40 pub(crate) current_vdom: Weak<RefCell<vdom::Node<APP::MSG>>>,
41 pub(crate) pending_msgs: Weak<RefCell<VecDeque<APP::MSG>>>,
42 pub(crate) pending_dispatches: Weak<RefCell<VecDeque<Dispatch<APP>>>>,
43}
44
45impl<APP> WeakContext<APP>
46where
47 APP: Application,
48{
49 pub(crate) fn upgrade(&self) -> Option<AppContext<APP>> {
50 let app = self.app.upgrade()?;
51 let current_vdom = self.current_vdom.upgrade()?;
52 let pending_msgs = self.pending_msgs.upgrade()?;
53 let pending_dispatches = self.pending_dispatches.upgrade()?;
54 Some(AppContext {
55 app,
56 current_vdom,
57 pending_msgs,
58 pending_dispatches,
59 })
60 }
61}
62
63impl<APP> Clone for WeakContext<APP>
64where
65 APP: Application,
66{
67 fn clone(&self) -> Self {
68 Self {
69 app: Weak::clone(&self.app),
70 current_vdom: Weak::clone(&self.current_vdom),
71 pending_msgs: Weak::clone(&self.pending_msgs),
72 pending_dispatches: Weak::clone(&self.pending_dispatches),
73 }
74 }
75}
76
77impl<APP> AppContext<APP>
78where
79 APP: Application,
80{
81 pub(crate) fn downgrade(this: &Self) -> WeakContext<APP> {
82 WeakContext {
83 app: Rc::downgrade(&this.app),
84 current_vdom: Rc::downgrade(&this.current_vdom),
85 pending_msgs: Rc::downgrade(&this.pending_msgs),
86 pending_dispatches: Rc::downgrade(&this.pending_dispatches),
87 }
88 }
89 pub fn strong_count(&self) -> usize {
90 Rc::strong_count(&self.app)
91 }
92 pub fn weak_count(&self) -> usize {
93 Rc::weak_count(&self.app)
94 }
95}
96
97impl<APP> Clone for AppContext<APP>
98where
99 APP: Application,
100{
101 fn clone(&self) -> Self {
102 Self {
103 app: Rc::clone(&self.app),
104 current_vdom: Rc::clone(&self.current_vdom),
105 pending_msgs: Rc::clone(&self.pending_msgs),
106 pending_dispatches: Rc::clone(&self.pending_dispatches),
107 }
108 }
109}
110
111impl<APP> AppContext<APP>
112where
113 APP: Application,
114{
115 pub fn init_app(&self) -> Dispatch<APP> {
116 Dispatch::from(self.app.borrow_mut().init())
117 }
118
119 pub fn view(&self) -> vdom::Node<APP::MSG> {
120 self.app.borrow().view()
121 }
122 pub fn dynamic_style(&self) -> String {
123 self.app.borrow().style().join("")
124 }
125
126 pub fn static_style(&self) -> String {
127 APP::stylesheet().join("")
128 }
129
130 pub fn set_current_dom(&mut self, new_vdom: vdom::Node<APP::MSG>) {
131 *self.current_vdom.borrow_mut() = new_vdom;
132 }
133
134 pub fn current_vdom(&self) -> Ref<'_, vdom::Node<APP::MSG>> {
135 self.current_vdom.borrow()
136 }
137
138 #[cfg(feature = "with-measure")]
139 pub fn measurements(&mut self, measurements: Measurements) {
140 self.app.borrow_mut().measurements(measurements)
141 }
142
143 pub fn push_msgs(&mut self, msgs: impl IntoIterator<Item = APP::MSG>) {
144 self.pending_msgs.borrow_mut().extend(msgs);
145 }
146
147 pub fn update_app(&mut self, msg: APP::MSG) -> Dispatch<APP> {
148 Dispatch::from(self.app.borrow_mut().update(msg))
149 }
150
151 pub fn has_pending_msgs(&self) -> bool {
153 !self.pending_msgs.borrow().is_empty()
154 }
155
156 #[cfg(feature = "ensure-check")]
158 pub fn pending_msgs_count(&self) -> usize {
159 self.pending_msgs.borrow().len()
160 }
161
162 pub fn dispatch_pending_msg(&mut self) -> bool {
165 let pending_msg = self.pending_msgs.borrow_mut().pop_front();
166 let cmd = if let Some(pending_msg) = pending_msg {
167 let cmd = self.update_app(pending_msg);
170 Some(cmd)
171 } else {
172 None
173 };
174
175 if let Some(cmd) = cmd {
176 self.pending_dispatches.borrow_mut().push_back(cmd);
178 true
179 } else {
180 false
181 }
182 }
183
184 pub fn batch_pending_cmds(&mut self) -> Dispatch<APP> {
185 Dispatch::batch(self.pending_dispatches.borrow_mut().drain(..))
186 }
187}