pixel_widgets/node/
component_node.rs

1use std::cell::{Cell, RefCell, RefMut};
2use std::collections::hash_map::DefaultHasher;
3use std::future::Future;
4use std::hash::{Hash, Hasher};
5use std::ops::{Deref, DerefMut};
6use std::ptr::null_mut;
7use std::task::Poll;
8
9use futures::{FutureExt, Stream, StreamExt};
10
11use crate::bitset::BitSet;
12use crate::component::{Component, Context};
13use crate::draw::Primitive;
14use crate::event::Event;
15use crate::layout::{Rectangle, Size};
16use crate::node::{GenericNode, Node};
17use crate::style::tree::Query;
18use crate::tracker::{ManagedState, ManagedStateTracker};
19use crate::widget::Context as WidgetContext;
20
21pub struct ComponentNode<'a, C: 'a + Component> {
22    props: Box<C>,
23    state: RefCell<Option<&'a mut ManagedState>>,
24    view: RefCell<Option<Node<'a, C::Message>>>,
25    component_state: Cell<*mut (C::State, Runtime<C::Message>)>,
26    style_query: Option<Query>,
27    style_position: (usize, usize),
28    style_matches: BitSet,
29    key: u64,
30}
31
32pub struct Runtime<Message> {
33    futures: Vec<Box<dyn Future<Output = Message> + Send + Sync + Unpin>>,
34    streams: Vec<Box<dyn Stream<Item = Message> + Send + Sync + Unpin>>,
35    modified: bool,
36}
37
38/// Mutable state accessor.
39/// By wrapping the mutable reference, the runtime knows if the state was mutated at all.
40pub struct State<'a, T> {
41    inner: &'a mut T,
42    dirty: &'a mut bool,
43}
44
45impl<'a, C: 'a + Component> ComponentNode<'a, C> {
46    pub fn new(props: C) -> Self {
47        let mut hasher = DefaultHasher::new();
48        std::any::type_name::<C>().hash(&mut hasher);
49        Self {
50            props: Box::new(props),
51            state: RefCell::new(None),
52            view: RefCell::new(None),
53            component_state: Cell::new(null_mut()),
54            style_query: None,
55            style_position: (0, 1),
56            style_matches: BitSet::new(),
57            key: hasher.finish(),
58        }
59    }
60
61    pub fn dirty(&self) -> bool {
62        self.view.borrow().is_none()
63    }
64
65    pub fn set_dirty(&self) {
66        self.view.replace(None);
67    }
68
69    pub fn props(&self) -> &C {
70        self.props.as_ref()
71    }
72
73    pub fn props_mut(&mut self) -> &mut C {
74        self.set_dirty();
75        self.props.as_mut()
76    }
77
78    pub fn update(&mut self, message: C::Message, context: &mut WidgetContext<C::Output>) {
79        let mut dirty = false;
80
81        let (state, runtime) = unsafe { self.component_state.get().as_mut().unwrap() };
82
83        self.props.update(
84            message,
85            State {
86                inner: state,
87                dirty: &mut dirty,
88            },
89            Context::new(context, runtime),
90        );
91
92        if dirty {
93            self.set_dirty();
94        }
95    }
96
97    pub fn view(&self) -> RefMut<Node<'a, C::Message>> {
98        if self.dirty() {
99            let mut tracker = unsafe {
100                self.state
101                    .borrow_mut()
102                    .as_mut()
103                    .map(|s| (*s) as *mut ManagedState)
104                    .unwrap_or(null_mut())
105                    .as_mut()
106                    .unwrap()
107                    .tracker()
108            };
109
110            let state = tracker.begin(0, || (self.props.mount(), Runtime::default()));
111            self.component_state.set(state as *mut _);
112
113            let mut root = unsafe { (self.props.as_ref() as *const C).as_ref().unwrap() }.view(&state.0);
114            let mut query = self.style_query.clone().unwrap();
115            root.acquire_state(&mut tracker);
116            root.style(&mut query, self.style_position);
117
118            self.view.replace(Some(root));
119        }
120        RefMut::map(self.view.borrow_mut(), |b| b.as_mut().unwrap())
121    }
122
123    pub(crate) fn needs_poll(&self) -> bool {
124        let (_, runtime) = unsafe { self.component_state.get().as_mut().unwrap() };
125        runtime.modified
126    }
127}
128
129impl<'a, C: 'a + Component> GenericNode<'a, C::Output> for ComponentNode<'a, C> {
130    fn get_key(&self) -> u64 {
131        self.key
132    }
133
134    fn set_key(&mut self, key: u64) {
135        self.key = key;
136    }
137
138    fn set_class(&mut self, _: &'a str) {}
139
140    fn acquire_state(&mut self, tracker: &mut ManagedStateTracker<'a>) {
141        self.state
142            .replace(Some(tracker.begin::<ManagedState, _>(self.key, ManagedState::default)));
143        tracker.end();
144    }
145
146    fn size(&self) -> (Size, Size) {
147        self.view().size()
148    }
149
150    fn hit(&self, layout: Rectangle, clip: Rectangle, x: f32, y: f32) -> bool {
151        self.view().hit(layout, clip, x, y)
152    }
153
154    fn focused(&self) -> bool {
155        self.view().focused()
156    }
157
158    fn draw(&mut self, layout: Rectangle, clip: Rectangle) -> Vec<Primitive<'a>> {
159        self.view().draw(layout, clip)
160    }
161
162    fn style(&mut self, query: &mut Query, position: (usize, usize)) {
163        self.style_matches = query.match_widget::<String>(
164            std::any::type_name::<C>(),
165            "",
166            &[],
167            self.style_position.0,
168            self.style_position.1,
169        );
170        self.style_query = Some(Query {
171            style: query.style.clone(),
172            ancestors: {
173                let mut a = query.ancestors.clone();
174                a.push(self.style_matches.clone());
175                a
176            },
177            siblings: Vec::new(),
178        });
179        self.style_position = position;
180
181        self.set_dirty();
182
183        query.siblings.push(self.style_matches.clone());
184    }
185
186    fn add_matches(&mut self, query: &mut Query) {
187        let additions = query.match_widget::<String>(
188            std::any::type_name::<C>(),
189            "",
190            &[],
191            self.style_position.0,
192            self.style_position.1,
193        );
194
195        let new_style = self.style_matches.union(&additions);
196        if new_style != self.style_matches {
197            self.style_matches = new_style;
198        }
199
200        query.ancestors.push(additions);
201        let own_siblings = std::mem::take(&mut query.siblings);
202        self.view().add_matches(query);
203        query.siblings = own_siblings;
204        query.siblings.push(query.ancestors.pop().unwrap());
205    }
206
207    fn remove_matches(&mut self, query: &mut Query) {
208        let removals = query.match_widget::<String>(
209            std::any::type_name::<C>(),
210            "",
211            &[],
212            self.style_position.0,
213            self.style_position.1,
214        );
215
216        let new_style = self.style_matches.difference(&removals);
217        if new_style != self.style_matches {
218            self.style_matches = new_style;
219        }
220
221        query.ancestors.push(removals);
222        let own_siblings = std::mem::take(&mut query.siblings);
223        self.view().remove_matches(query);
224        query.siblings = own_siblings;
225        query.siblings.push(query.ancestors.pop().unwrap());
226    }
227
228    fn event(
229        &mut self,
230        layout: Rectangle,
231        clip: Rectangle,
232        event: Event,
233        context: &mut WidgetContext<<C as Component>::Output>,
234    ) {
235        let mut sub_context = context.sub_context();
236        self.view().event(layout, clip, event, &mut sub_context);
237
238        if sub_context.redraw_requested() {
239            context.redraw();
240        }
241
242        for message in sub_context {
243            self.update(message, context);
244        }
245
246        let (_, runtime) = unsafe { self.component_state.get().as_mut().unwrap() };
247        while runtime.modified {
248            for message in runtime.poll(&mut context.task_context()) {
249                self.update(message, context);
250            }
251        }
252    }
253
254    fn poll(&mut self, context: &mut WidgetContext<<C as Component>::Output>) {
255        let mut sub_context = context.sub_context();
256        self.view().poll(&mut sub_context);
257
258        if sub_context.redraw_requested() {
259            context.redraw();
260        }
261
262        for message in sub_context {
263            self.update(message, context);
264        }
265
266        let (_, runtime) = unsafe { self.component_state.get().as_mut().unwrap() };
267        loop {
268            for message in runtime.poll(&mut context.task_context()) {
269                self.update(message, context);
270            }
271            if !runtime.modified {
272                break;
273            }
274        }
275    }
276}
277
278unsafe impl<'a, C: 'a + Component> Send for ComponentNode<'a, C> {}
279
280impl<'a, C: 'a + Component> Drop for ComponentNode<'a, C> {
281    fn drop(&mut self) {
282        self.view.replace(None);
283    }
284}
285
286impl<Message> Default for Runtime<Message> {
287    fn default() -> Self {
288        Self {
289            futures: Vec::new(),
290            streams: Vec::new(),
291            modified: false,
292        }
293    }
294}
295
296impl<Message> Runtime<Message> {
297    pub fn wait<F: 'static + Future<Output = Message> + Send + Sync + Unpin>(&mut self, fut: F) {
298        self.futures.push(Box::new(fut));
299        self.modified = true;
300    }
301
302    pub fn stream<S: 'static + Stream<Item = Message> + Send + Sync + Unpin>(&mut self, stream: S) {
303        self.streams.push(Box::new(stream));
304        self.modified = true;
305    }
306
307    pub(crate) fn poll(&mut self, cx: &mut std::task::Context) -> Vec<Message> {
308        self.modified = false;
309
310        let mut result = Vec::new();
311
312        let mut i = 0;
313        while i < self.futures.len() {
314            match self.futures[i].poll_unpin(&mut *cx) {
315                Poll::Ready(message) => {
316                    result.push(message);
317                    drop(self.futures.remove(i));
318                }
319                Poll::Pending => {
320                    i += 1;
321                }
322            }
323        }
324
325        let mut i = 0;
326        while i < self.streams.len() {
327            match self.streams[i].poll_next_unpin(&mut *cx) {
328                Poll::Ready(Some(message)) => {
329                    result.push(message);
330                }
331                Poll::Ready(None) => {
332                    drop(self.streams.remove(i));
333                }
334                Poll::Pending => {
335                    i += 1;
336                }
337            }
338        }
339
340        result
341    }
342}
343
344impl<'a, T> Deref for State<'a, T> {
345    type Target = T;
346
347    fn deref(&self) -> &T {
348        self.inner
349    }
350}
351
352impl<'a, T> DerefMut for State<'a, T> {
353    fn deref_mut(&mut self) -> &mut T {
354        *self.dirty = true;
355        self.inner
356    }
357}