Skip to main content

maomi/
node.rs

1//! Helper types for node trees.
2
3use std::{any::Any, collections::HashMap, hash::Hash, marker::PhantomData};
4
5use crate::{
6    backend::{tree, AsElementTag},
7    error::Error,
8};
9use tree::ForestTokenAddr;
10
11/// An unsafe option as a union used to reduce some checking overhead.
12pub union UnionOption<T> {
13    none: (),
14    some: std::mem::ManuallyDrop<T>,
15}
16
17impl<T> UnionOption<T> {
18    /// Create a none value.
19    #[inline(always)]
20    pub fn none() -> Self {
21        Self { none: () }
22    }
23
24    /// Create a none value.
25    #[inline(always)]
26    pub fn some(inner: T) -> Self {
27        Self {
28            some: std::mem::ManuallyDrop::new(inner),
29        }
30    }
31
32    /// Assume it is not none and get the contained value.
33    #[inline(always)]
34    pub unsafe fn unwrap_unchecked(self) -> T {
35        std::mem::ManuallyDrop::into_inner(self.some)
36    }
37
38    /// Assume it is not none and get the reference.
39    #[inline(always)]
40    pub unsafe fn as_ref_unchecked(&self) -> &T {
41        &self.some
42    }
43}
44
45/// A weak ref to the owner.
46///
47/// This is used by the backend implementor.
48/// *In most cases, it should not be used in component implementors.*
49pub trait OwnerWeak {
50    /// Schedule an update on the owner.
51    fn apply_updates(&self) -> Result<(), Error>;
52    /// Clone the owner itself.
53    fn clone_owner_weak(&self) -> Box<dyn OwnerWeak>;
54}
55
56/// A general node type.
57pub struct DynNode {
58    inner: Box<dyn Any>,
59}
60
61impl DynNode {
62    /// Build from a node.
63    #[inline(always)]
64    pub fn new<N: 'static>(n: N) -> Self {
65        Self { inner: Box::new(n) }
66    }
67
68    /// Cast into a node of specified type.
69    #[inline(always)]
70    pub unsafe fn node_unchecked<N: 'static>(&mut self) -> &mut N {
71        &mut *(&mut *self.inner as *mut dyn Any as *mut N)
72    }
73
74    /// Cast into a node of specified type.
75    #[inline(always)]
76    pub fn as_mut<N: 'static>(&mut self) -> &mut N {
77        self.inner.downcast_mut().unwrap()
78    }
79
80    /// Cast into a node of specified type.
81    #[inline(always)]
82    pub fn as_ref<N: 'static>(&self) -> &N {
83        self.inner.downcast_ref().unwrap()
84    }
85}
86
87/// A general node list.
88pub type DynNodeList = Box<[DynNode]>;
89
90/// A helper type for a node with child nodes.
91#[derive(Debug)]
92pub struct Node<N: AsElementTag> {
93    /// The node itself.
94    pub tag: N::Target,
95    /// The child nodes of the node.
96    pub child_nodes: N::SlotChildren,
97}
98
99impl<N: AsElementTag> Node<N> {
100    /// Create a node with specified children.
101    #[inline(always)]
102    pub fn new(tag: N::Target, child_nodes: N::SlotChildren) -> Self {
103        Self { tag, child_nodes }
104    }
105
106    /// Iterator over slots of the node.
107    #[inline]
108    pub fn iter_slots(
109        &self,
110    ) -> <N::SlotChildren as SlotKindTrait<ForestTokenAddr, DynNodeList>>::Iter<'_> {
111        self.child_nodes.iter()
112    }
113
114    /// If the node has only one slot, returns it.
115    #[inline]
116    pub fn single_slot(&self) -> Option<&DynNodeList> {
117        self.child_nodes.single_slot()
118    }
119}
120
121/// A helper type for control flow node such as "if" node and "for" node.
122#[derive(Debug)]
123pub struct ControlNode<C> {
124    /// The backend node token
125    ///
126    /// It is auto-managed by the `#[component]` .
127    /// Do not touch unless you know how it works exactly.
128    pub forest_token: tree::ForestToken,
129    /// The content nodes of the control node.
130    pub content: C,
131}
132
133impl<C> ControlNode<C> {
134    /// Create a control node.
135    #[inline(always)]
136    pub fn new(forest_token: tree::ForestToken, content: C) -> Self {
137        Self {
138            forest_token,
139            content,
140        }
141    }
142}
143
144/// A helper type for "if" and "match" node.
145pub struct Branch {
146    /// The current branch index.
147    pub cur: usize,
148    /// Child node list in "if...else" or "match" node.
149    pub children: DynNodeList,
150}
151
152/// A helper trait for managing slot list and slot content.
153///
154/// It is auto-managed by the `#[component]` .
155/// Do not touch unless you know how it works exactly.
156pub trait SlotKindTrait<K, C>: Default {
157    /// The updater type.
158    type Update<'a>: SlotKindUpdateTrait<'a, K, C>
159    where
160        Self: 'a,
161        K: 'a,
162        C: 'a;
163
164    /// The iterator type.
165    type Iter<'a>: Iterator<Item = &'a C>
166    where
167        Self: 'a,
168        C: 'a;
169
170    /// Whether the slot may update after created
171    fn may_update(&self) -> bool;
172
173    /// Add a slot with the slot content.
174    #[doc(hidden)]
175    fn add(&mut self, k: K, c: C) -> Result<(), Error>;
176
177    /// Remove a slot and return the slot content.
178    #[doc(hidden)]
179    fn remove(&mut self, k: K) -> Result<C, Error>;
180
181    /// Get a reference of the slot content.
182    #[doc(hidden)]
183    fn get(&self, k: K) -> Result<&C, Error>;
184
185    /// Get a mutable reference of the slot content.
186    #[doc(hidden)]
187    fn get_mut(&mut self, k: K) -> Result<&mut C, Error>;
188
189    /// Start an update for all slots.
190    #[doc(hidden)]
191    fn update<'a>(&'a mut self) -> Self::Update<'a>;
192
193    /// Iterator over all slots.
194    fn iter<'a>(&'a self) -> Self::Iter<'a>;
195
196    /// If there is only one slot, returns it.
197    fn single_slot(&self) -> Option<&C>;
198}
199
200/// A helper trait for a group of slot list updates.
201pub trait SlotKindUpdateTrait<'a, K: 'a, C: 'a> {
202    /// Add a slot with the slot content.
203    #[doc(hidden)]
204    fn add(&mut self, k: K, c: C) -> Result<(), Error>;
205
206    /// Reuse a slot, returning it.
207    #[doc(hidden)]
208    fn reuse(&mut self, k: K) -> Result<&mut C, Error>;
209
210    /// Finish update, handling unused items
211    #[doc(hidden)]
212    fn finish(self, remove_item_fn: impl FnMut(C) -> Result<(), Error>) -> Result<(), Error>;
213}
214
215/// A slot list that is always empty.
216#[derive(Debug)]
217pub struct NoneSlot<K, C> {
218    phantom: PhantomData<(K, C)>,
219}
220
221impl<K, C> Default for NoneSlot<K, C> {
222    #[inline]
223    fn default() -> Self {
224        Self {
225            phantom: PhantomData,
226        }
227    }
228}
229
230impl<K, C> SlotKindTrait<K, C> for NoneSlot<K, C> {
231    type Update<'a> = NoneSlotUpdate<'a, K, C> where K: 'a, C: 'a;
232    type Iter<'a> = std::iter::Empty<&'a C> where K: 'a, C: 'a;
233
234    #[inline(always)]
235    fn may_update(&self) -> bool {
236        false
237    }
238
239    #[inline]
240    fn add(&mut self, _: K, _: C) -> Result<(), Error> {
241        Err(Error::ListChangeWrong)
242    }
243
244    #[inline]
245    fn remove(&mut self, _: K) -> Result<C, Error> {
246        Err(Error::ListChangeWrong)
247    }
248
249    #[inline]
250    fn get(&self, _: K) -> Result<&C, Error> {
251        Err(Error::ListChangeWrong)
252    }
253
254    #[inline]
255    fn get_mut(&mut self, _: K) -> Result<&mut C, Error> {
256        Err(Error::ListChangeWrong)
257    }
258
259    #[inline]
260    fn update<'a>(&'a mut self) -> Self::Update<'a> {
261        NoneSlotUpdate {
262            phantom: PhantomData,
263        }
264    }
265
266    #[inline]
267    fn iter(&self) -> Self::Iter<'_> {
268        std::iter::empty()
269    }
270
271    #[inline]
272    fn single_slot(&self) -> Option<&C> {
273        None
274    }
275}
276
277#[doc(hidden)]
278pub struct NoneSlotUpdate<'a, K, C> {
279    phantom: PhantomData<&'a (K, C)>,
280}
281
282impl<'a, K: 'a, C: 'a> SlotKindUpdateTrait<'a, K, C> for NoneSlotUpdate<'a, K, C> {
283    #[inline]
284    fn add(&mut self, _: K, _: C) -> Result<(), Error> {
285        Err(Error::ListChangeWrong)
286    }
287
288    #[inline]
289    fn reuse(&mut self, _: K) -> Result<&mut C, Error> {
290        Err(Error::ListChangeWrong)
291    }
292
293    #[inline]
294    fn finish(self, _: impl FnMut(C) -> Result<(), Error>) -> Result<(), Error> {
295        Ok(())
296    }
297}
298
299/// A slot list that always contains a single slot.
300///
301/// It is auto-managed by the `#[component]` .
302/// Do not touch unless you know how it works exactly.
303#[derive(Debug)]
304pub struct StaticSingleSlot<K, C> {
305    kc: Option<C>,
306    phantom: PhantomData<K>,
307}
308
309impl<K, C> Default for StaticSingleSlot<K, C> {
310    #[inline]
311    fn default() -> Self
312    where
313        Self: Sized,
314    {
315        Self {
316            kc: None,
317            phantom: PhantomData,
318        }
319    }
320}
321
322impl<K, C> SlotKindTrait<K, C> for StaticSingleSlot<K, C> {
323    type Update<'a> = StaticSingleSlotUpdate<'a, K, C> where K: 'a, C: 'a;
324    type Iter<'a> = std::option::IntoIter<&'a C> where K: 'a, C: 'a;
325
326    #[inline(always)]
327    fn may_update(&self) -> bool {
328        false
329    }
330
331    #[inline(always)]
332    fn add(&mut self, _: K, c: C) -> Result<(), Error> {
333        if self.kc.is_some() {
334            return Err(Error::ListChangeWrong);
335        }
336        self.kc = Some(c);
337        Ok(())
338    }
339
340    #[inline(always)]
341    fn remove(&mut self, _: K) -> Result<C, Error> {
342        if self.kc.is_none() {
343            return Err(Error::ListChangeWrong);
344        }
345        match self.kc.take() {
346            Some(c) => Ok(c),
347            None => Err(Error::ListChangeWrong),
348        }
349    }
350
351    #[inline]
352    fn get(&self, _: K) -> Result<&C, Error> {
353        self.kc.as_ref().ok_or(Error::ListChangeWrong)
354    }
355
356    #[inline]
357    fn get_mut(&mut self, _: K) -> Result<&mut C, Error> {
358        self.kc.as_mut().ok_or(Error::ListChangeWrong)
359    }
360
361    #[inline]
362    fn update<'a>(&'a mut self) -> Self::Update<'a> {
363        StaticSingleSlotUpdate {
364            s: self,
365            visited: false,
366        }
367    }
368
369    #[inline]
370    fn iter<'a>(&'a self) -> Self::Iter<'a> {
371        self.kc.as_ref().into_iter()
372    }
373
374    #[inline]
375    fn single_slot(&self) -> Option<&C> {
376        self.kc.as_ref()
377    }
378}
379
380#[doc(hidden)]
381pub struct StaticSingleSlotUpdate<'a, K, C> {
382    s: &'a mut StaticSingleSlot<K, C>,
383    visited: bool,
384}
385
386impl<'a, K, C> SlotKindUpdateTrait<'a, K, C> for StaticSingleSlotUpdate<'a, K, C> {
387    #[inline]
388    fn add(&mut self, k: K, c: C) -> Result<(), Error> {
389        let ret = self.s.add(k, c);
390        if ret.is_ok() {
391            self.visited = true;
392        }
393        ret
394    }
395
396    #[inline]
397    fn reuse(&mut self, k: K) -> Result<&mut C, Error> {
398        let ret = self.s.get_mut(k);
399        if ret.is_ok() {
400            self.visited = true;
401        }
402        ret
403    }
404
405    #[inline]
406    fn finish(self, mut remove_item_fn: impl FnMut(C) -> Result<(), Error>) -> Result<(), Error> {
407        if !self.visited {
408            if let Some(c) = self.s.kc.take() {
409                return remove_item_fn(c);
410            }
411        }
412        Ok(())
413    }
414}
415
416/// A slot list that can contain any number of slots.
417///
418/// It is auto-managed by the `#[component]` .
419/// Do not touch unless you know how it works exactly.
420#[derive(Debug)]
421pub struct DynamicSlot<K, C> {
422    slots: HashMap<K, C>,
423}
424
425impl<K, C> Default for DynamicSlot<K, C> {
426    #[inline]
427    fn default() -> Self
428    where
429        Self: Sized,
430    {
431        Self {
432            slots: HashMap::new(),
433        }
434    }
435}
436
437impl<K: Hash + Eq, C> SlotKindTrait<K, C> for DynamicSlot<K, C> {
438    type Update<'a> = DynamicSlotUpdate<'a, K, C> where K: 'a, C: 'a;
439    type Iter<'a> = std::collections::hash_map::Values<'a, K, C> where K: 'a, C: 'a;
440
441    #[inline(always)]
442    fn may_update(&self) -> bool {
443        true
444    }
445
446    #[inline]
447    fn add(&mut self, k: K, v: C) -> Result<(), Error> {
448        self.slots.insert(k, v);
449        Ok(())
450    }
451
452    #[inline]
453    fn remove(&mut self, k: K) -> Result<C, Error> {
454        self.slots.remove(&k).ok_or(Error::ListChangeWrong)
455    }
456
457    #[inline]
458    fn get(&self, k: K) -> Result<&C, Error> {
459        self.slots.get(&k).ok_or(Error::ListChangeWrong)
460    }
461
462    #[inline]
463    fn get_mut(&mut self, k: K) -> Result<&mut C, Error> {
464        self.slots.get_mut(&k).ok_or(Error::ListChangeWrong)
465    }
466
467    #[inline]
468    fn update(&mut self) -> Self::Update<'_> {
469        DynamicSlotUpdate {
470            cur_map: HashMap::with_capacity(self.slots.len()),
471            old: self,
472        }
473    }
474
475    #[inline]
476    fn iter(&self) -> Self::Iter<'_> {
477        self.slots.values()
478    }
479
480    #[inline]
481    fn single_slot(&self) -> Option<&C> {
482        match self.slots.len() {
483            1 => self.slots.values().next(),
484            _ => None,
485        }
486    }
487}
488
489#[doc(hidden)]
490pub struct DynamicSlotUpdate<'a, K, C> {
491    cur_map: HashMap<K, C>,
492    old: &'a mut DynamicSlot<K, C>,
493}
494
495impl<'a, K: Hash + Eq, C> SlotKindUpdateTrait<'a, K, C> for DynamicSlotUpdate<'a, K, C> {
496    #[inline]
497    fn add(&mut self, k: K, v: C) -> Result<(), Error> {
498        self.cur_map.insert(k, v);
499        Ok(())
500    }
501
502    #[inline]
503    fn reuse(&mut self, k: K) -> Result<&mut C, Error> {
504        let c = self.old.slots.remove(&k).ok_or(Error::ListChangeWrong)?;
505        let ret = self.cur_map.entry(k).or_insert(c);
506        Ok(ret)
507    }
508
509    #[inline]
510    fn finish(self, mut item_fn: impl FnMut(C) -> Result<(), Error>) -> Result<(), Error> {
511        let r = std::mem::replace(&mut self.old.slots, self.cur_map);
512        for (_, c) in r {
513            item_fn(c)?;
514        }
515        Ok(())
516    }
517}
518
519/// A helper type for slot changes
520///
521/// It is auto-managed by the `#[component]` .
522/// Do not touch unless you know how it works exactly.
523#[derive(Debug, Clone, PartialEq)]
524pub enum SlotChange<N, M, T> {
525    /// The slot is not changed.
526    Unchanged(N, M, T),
527    /// The data of the slot may have changed.
528    DataChanged(N, M, T),
529    /// The slot is added.
530    Added(N, M, T),
531    /// The slot is removed.
532    Removed(M),
533}