freya_native_core/
real_dom.rs

1//! A Dom that can sync with the VirtualDom mutations intended for use in lazy renderers.
2
3use std::{
4    any::TypeId,
5    ops::{
6        Deref,
7        DerefMut,
8    },
9    sync::Arc,
10};
11
12use rustc_hash::{
13    FxHashMap,
14    FxHashSet,
15};
16use shipyard::{
17    error::GetStorage,
18    track::Untracked,
19    Component,
20    Get,
21    IntoBorrow,
22    ScheduledWorkload,
23    SystemModificator,
24    Unique,
25    View,
26    ViewMut,
27    Workload,
28    World,
29};
30
31use crate::{
32    events::EventName,
33    node::{
34        ElementNode,
35        FromAnyValue,
36        NodeType,
37        OwnedAttributeValue,
38    },
39    node_ref::{
40        NodeMask,
41        NodeMaskBuilder,
42    },
43    passes::{
44        Dependant,
45        DirtyNodeStates,
46        PassDirection,
47        TypeErasedState,
48    },
49    prelude::{
50        AttributeMaskBuilder,
51        AttributeName,
52    },
53    tags::TagName,
54    tree::{
55        TreeMut,
56        TreeMutView,
57        TreeRef,
58        TreeRefView,
59    },
60    NodeId,
61    SendAnyMap,
62};
63
64/// The context passes can receive when they are executed
65#[derive(Unique)]
66pub(crate) struct SendAnyMapWrapper(SendAnyMap);
67
68impl Deref for SendAnyMapWrapper {
69    type Target = SendAnyMap;
70
71    fn deref(&self) -> &Self::Target {
72        &self.0
73    }
74}
75
76/// The nodes that have been marked as dirty in the RealDom
77pub(crate) struct NodesDirty<V: FromAnyValue + Send + Sync> {
78    passes_updated: FxHashMap<NodeId, FxHashSet<TypeId>>,
79    nodes_updated: FxHashMap<NodeId, NodeMask>,
80    nodes_created: FxHashSet<NodeId>,
81    pub(crate) passes: Box<[TypeErasedState<V>]>,
82}
83
84impl<V: FromAnyValue + Send + Sync> NodesDirty<V> {
85    /// Mark a node as dirty
86    fn mark_dirty(&mut self, node_id: NodeId, mask: NodeMask) {
87        self.passes_updated.entry(node_id).or_default().extend(
88            self.passes
89                .iter()
90                .filter_map(|x| x.mask.overlaps(&mask).then_some(x.this_type_id)),
91        );
92        let nodes_updated = &mut self.nodes_updated;
93        if let Some(node) = nodes_updated.get_mut(&node_id) {
94            *node = node.union(&mask);
95        } else {
96            nodes_updated.insert(node_id, mask);
97        }
98    }
99
100    /// Mark a node that has had a parent changed
101    fn mark_parent_added_or_removed(&mut self, node_id: NodeId) {
102        let hm = self.passes_updated.entry(node_id).or_default();
103        for pass in &*self.passes {
104            // If any of the states in this node depend on the parent then mark them as dirty
105            for &pass in &pass.parent_dependancies_ids {
106                hm.insert(pass);
107            }
108        }
109    }
110
111    /// Mark a node as having a child added or removed
112    fn mark_child_changed(&mut self, node_id: NodeId) {
113        let hm = self.passes_updated.entry(node_id).or_default();
114        for pass in &*self.passes {
115            // If any of the states in this node depend on the children then mark them as dirty
116            for &pass in &pass.child_dependancies_ids {
117                hm.insert(pass);
118            }
119        }
120    }
121}
122
123/// A Dom that can sync with the VirtualDom mutations intended for use in lazy renderers.
124/// The render state passes from parent to children and or accumulates state from children to parents.
125/// To get started:
126/// 1) Implement [crate::passes::State] for each part of your state that you want to compute incrementally
127/// 2) Create a RealDom [RealDom::new], passing in each state you created
128/// 3) Update the state of the RealDom by adding and modifying nodes
129/// 4) Call [RealDom::update_state] to update the state of incrementally computed values on each node
130///
131/// # Custom attribute values
132/// To allow custom values to be passed into attributes implement FromAnyValue on a type that can represent your custom value and specify the V generic to be that type. If you have many different custom values, it can be useful to use a enum type to represent the variants.
133pub struct RealDom<V: FromAnyValue + Send + Sync = ()> {
134    pub(crate) world: World,
135    nodes_listening: FxHashMap<EventName, FxHashSet<NodeId>>,
136    pub(crate) dirty_nodes: NodesDirty<V>,
137    workload: ScheduledWorkload,
138    root_id: NodeId,
139    phantom: std::marker::PhantomData<V>,
140}
141
142impl<V: FromAnyValue + Send + Sync> RealDom<V> {
143    /// Create a new RealDom with the given states that will be inserted and updated when needed
144    pub fn new(tracked_states: impl Into<Box<[TypeErasedState<V>]>>) -> RealDom<V> {
145        let mut tracked_states = tracked_states.into();
146        // resolve dependants for each pass
147        for i in 1..=tracked_states.len() {
148            let (before, after) = tracked_states.split_at_mut(i);
149            let (current, before) = before.split_last_mut().unwrap();
150            for state in before.iter_mut().chain(after.iter_mut()) {
151                let dependants = Arc::get_mut(&mut state.dependants).unwrap();
152
153                let current_dependant = Dependant {
154                    type_id: current.this_type_id,
155                    enter_shadow_dom: current.enter_shadow_dom,
156                };
157
158                // If this node depends on the other state as a parent, then the other state should update its children of the current type when it is invalidated
159                if current
160                    .parent_dependancies_ids
161                    .contains(&state.this_type_id)
162                    && !dependants.child.contains(&current_dependant)
163                {
164                    dependants.child.push(current_dependant);
165                }
166                // If this node depends on the other state as a child, then the other state should update its parent of the current type when it is invalidated
167                if current.child_dependancies_ids.contains(&state.this_type_id)
168                    && !dependants.parent.contains(&current_dependant)
169                {
170                    dependants.parent.push(current_dependant);
171                }
172                // If this node depends on the other state as a sibling, then the other state should update its siblings of the current type when it is invalidated
173                if current.node_dependancies_ids.contains(&state.this_type_id)
174                    && !dependants.node.contains(&current.this_type_id)
175                {
176                    dependants.node.push(current.this_type_id);
177                }
178            }
179            // If the current state depends on itself, then it should update itself when it is invalidated
180            let dependants = Arc::get_mut(&mut current.dependants).unwrap();
181            let current_dependant = Dependant {
182                type_id: current.this_type_id,
183                enter_shadow_dom: current.enter_shadow_dom,
184            };
185            match current.pass_direction {
186                PassDirection::ChildToParent => {
187                    if !dependants.parent.contains(&current_dependant) {
188                        dependants.parent.push(current_dependant);
189                    }
190                }
191                PassDirection::ParentToChild => {
192                    if !dependants.child.contains(&current_dependant) {
193                        dependants.child.push(current_dependant);
194                    }
195                }
196                _ => {}
197            }
198        }
199        let workload = construct_workload(&mut tracked_states);
200        let (workload, _) = workload.build().unwrap();
201        let mut world = World::new();
202        let root_node: NodeType<V> = NodeType::Element(ElementNode {
203            tag: TagName::Root,
204            attributes: FxHashMap::default(),
205            listeners: FxHashSet::default(),
206        });
207        let root_id = world.add_entity(root_node);
208        {
209            let mut tree: TreeMutView = world.borrow().unwrap();
210            tree.create_node(root_id);
211        }
212
213        let mut passes_updated = FxHashMap::default();
214        let mut nodes_updated = FxHashMap::default();
215
216        passes_updated.insert(
217            root_id,
218            tracked_states.iter().map(|x| x.this_type_id).collect(),
219        );
220        nodes_updated.insert(root_id, NodeMaskBuilder::ALL.build());
221
222        RealDom {
223            world,
224            nodes_listening: FxHashMap::default(),
225            dirty_nodes: NodesDirty {
226                passes_updated,
227                nodes_updated,
228                passes: tracked_states,
229                nodes_created: [root_id].into_iter().collect(),
230            },
231            workload,
232            root_id,
233            phantom: std::marker::PhantomData,
234        }
235    }
236
237    pub fn deep_clone_node(&mut self, node_id: NodeId) -> NodeMut<V> {
238        let clone_id = self.get_mut(node_id).unwrap().clone_node();
239        self.get_mut(clone_id).unwrap()
240    }
241
242    /// Get a reference to the tree.
243    pub fn tree_ref(&self) -> TreeRefView {
244        self.world.borrow().unwrap()
245    }
246
247    /// Get a mutable reference to the tree.
248    pub fn tree_mut(&self) -> TreeMutView {
249        self.world.borrow().unwrap()
250    }
251
252    /// Create a new node of the given type in the dom and return a mutable reference to it.
253    pub fn create_node(&mut self, node: impl Into<NodeType<V>>) -> NodeMut<'_, V> {
254        let node = node.into();
255
256        let id = self.world.add_entity(node);
257        self.tree_mut().create_node(id);
258
259        self.dirty_nodes
260            .passes_updated
261            .entry(id)
262            .or_default()
263            .extend(self.dirty_nodes.passes.iter().map(|x| x.this_type_id));
264        self.dirty_nodes
265            .mark_dirty(id, NodeMaskBuilder::ALL.build());
266        self.dirty_nodes.nodes_created.insert(id);
267
268        NodeMut::new(id, self)
269    }
270
271    pub fn is_node_listening(&self, node_id: &NodeId, event: &EventName) -> bool {
272        self.nodes_listening
273            .get(event)
274            .map(|listeners| listeners.contains(node_id))
275            .unwrap_or_default()
276    }
277
278    pub fn get_listeners(&self, event: &EventName) -> Vec<NodeRef<V>> {
279        if let Some(nodes) = self.nodes_listening.get(event) {
280            nodes
281                .iter()
282                .map(|id| NodeRef { id: *id, dom: self })
283                .collect()
284        } else {
285            Vec::new()
286        }
287    }
288
289    /// Returns the id of the root node.
290    pub fn root_id(&self) -> NodeId {
291        self.root_id
292    }
293
294    /// Check if a node exists in the dom.
295    pub fn contains(&self, id: NodeId) -> bool {
296        self.tree_ref().contains(id)
297    }
298
299    /// Get a reference to a node.
300    pub fn get(&self, id: NodeId) -> Option<NodeRef<'_, V>> {
301        self.contains(id).then_some(NodeRef { id, dom: self })
302    }
303
304    /// Get a mutable reference to a node.
305    pub fn get_mut(&mut self, id: NodeId) -> Option<NodeMut<'_, V>> {
306        let contains = self.contains(id);
307        contains.then(|| NodeMut::new(id, self))
308    }
309
310    /// Borrow a component from the world without updating the dirty nodes.
311    #[inline(always)]
312    fn borrow_raw<'a, B: IntoBorrow>(&'a self) -> Result<B, GetStorage>
313    where
314        B::Borrow: shipyard::Borrow<'a, View = B>,
315    {
316        self.world.borrow()
317    }
318
319    /// Borrow a component from the world without updating the dirty nodes.
320    fn borrow_node_type_mut(&self) -> Result<ViewMut<NodeType<V>>, GetStorage> {
321        self.world.borrow()
322    }
323
324    /// Update the state of the dom, after appling some mutations. This will keep the nodes in the dom up to date with their VNode counterparts.
325    pub fn update_state(&mut self, ctx: SendAnyMap) -> FxHashMap<NodeId, NodeMask> {
326        let passes = std::mem::take(&mut self.dirty_nodes.passes_updated);
327        let nodes_updated = std::mem::take(&mut self.dirty_nodes.nodes_updated);
328
329        let dirty_nodes =
330            DirtyNodeStates::with_passes(self.dirty_nodes.passes.iter().map(|p| p.this_type_id));
331        let tree = self.tree_ref();
332        for (node_id, passes) in passes {
333            // remove any nodes that were created and then removed in the same mutations from the dirty nodes list
334            if let Some(height) = tree.height(node_id) {
335                for pass in passes {
336                    dirty_nodes.insert(pass, node_id, height);
337                }
338            }
339        }
340
341        let _ = self.world.remove_unique::<DirtyNodeStates>();
342        let _ = self.world.remove_unique::<SendAnyMapWrapper>();
343        self.world.add_unique(dirty_nodes);
344        self.world.add_unique(SendAnyMapWrapper(ctx));
345
346        self.workload.run_with_world(&self.world).unwrap();
347
348        nodes_updated
349    }
350
351    /// Traverses the dom in a depth first manner,
352    /// calling the provided function on each node only when the parent function returns `true`.
353    /// This is useful to not traverse through text nodes for instance.
354    pub fn traverse_depth_first_advanced(&self, mut f: impl FnMut(NodeRef<V>) -> bool) {
355        let mut stack = vec![self.root_id()];
356        let tree = self.tree_ref();
357        while let Some(id) = stack.pop() {
358            if let Some(node) = self.get(id) {
359                let traverse_children = f(node);
360                if traverse_children {
361                    let children = tree.children_ids_advanced(id, false);
362                    stack.extend(children.iter().copied().rev());
363                }
364            }
365        }
366    }
367
368    /// Traverses the dom in a depth first manner, calling the provided function on each node.
369    pub fn traverse_depth_first(&self, mut f: impl FnMut(NodeRef<V>)) {
370        self.traverse_depth_first_advanced(move |node| {
371            f(node);
372            true
373        })
374    }
375
376    /// Returns a reference to the underlying world. Any changes made to the world will not update the reactive system.
377    pub fn raw_world(&self) -> &World {
378        &self.world
379    }
380
381    /// Returns a mutable reference to the underlying world. Any changes made to the world will not update the reactive system.
382    pub fn raw_world_mut(&mut self) -> &mut World {
383        &mut self.world
384    }
385}
386
387/// A reference to a tracked component in a node.
388pub struct ViewEntry<'a, V: Component + Send + Sync> {
389    view: View<'a, V>,
390    id: NodeId,
391}
392
393impl<'a, V: Component + Send + Sync> ViewEntry<'a, V> {
394    fn new(view: View<'a, V>, id: NodeId) -> Self {
395        Self { view, id }
396    }
397}
398
399impl<V: Component + Send + Sync> Deref for ViewEntry<'_, V> {
400    type Target = V;
401
402    fn deref(&self) -> &Self::Target {
403        &self.view[self.id]
404    }
405}
406
407/// A mutable reference to a tracked component in a node.
408pub struct ViewEntryMut<'a, V: Component<Tracking = Untracked> + Send + Sync> {
409    view: ViewMut<'a, V, Untracked>,
410    id: NodeId,
411}
412
413impl<'a, V: Component<Tracking = Untracked> + Send + Sync> ViewEntryMut<'a, V> {
414    fn new(view: ViewMut<'a, V, Untracked>, id: NodeId) -> Self {
415        Self { view, id }
416    }
417}
418
419impl<V: Component<Tracking = Untracked> + Send + Sync> Deref for ViewEntryMut<'_, V> {
420    type Target = V;
421
422    fn deref(&self) -> &Self::Target {
423        self.view.get(self.id).unwrap()
424    }
425}
426
427impl<V: Component<Tracking = Untracked> + Send + Sync> DerefMut for ViewEntryMut<'_, V> {
428    fn deref_mut(&mut self) -> &mut Self::Target {
429        (&mut self.view).get(self.id).unwrap()
430    }
431}
432
433/// A immutable view of a node
434pub trait NodeImmutable<V: FromAnyValue + Send + Sync = ()>: Sized {
435    /// Get the real dom this node was created in
436    fn real_dom(&self) -> &RealDom<V>;
437
438    /// Get the id of the current node
439    fn id(&self) -> NodeId;
440
441    /// Get the type of the current node
442    #[inline]
443    fn node_type(&self) -> ViewEntry<NodeType<V>> {
444        self.get().unwrap()
445    }
446
447    /// Get a component from the current node
448    #[inline(always)]
449    fn get<'a, T: Component + Sync + Send>(&'a self) -> Option<ViewEntry<'a, T>> {
450        // self.real_dom().tree.get(self.id())
451        let view: View<'a, T> = self.real_dom().borrow_raw().ok()?;
452        view.contains(self.id())
453            .then(|| ViewEntry::new(view, self.id()))
454    }
455
456    /// Get the ids of the children of the current node, if enter_shadow_dom is true and the current node is a shadow slot, the ids of the nodes under the node the shadow slot is attached to will be returned
457    #[inline]
458    fn children_ids_advanced(&self, id: NodeId, enter_shadow_dom: bool) -> Vec<NodeId> {
459        self.real_dom()
460            .tree_ref()
461            .children_ids_advanced(id, enter_shadow_dom)
462    }
463
464    /// Get the ids of the children of the current node
465    #[inline]
466    fn child_ids(&self) -> Vec<NodeId> {
467        self.real_dom().tree_ref().children_ids(self.id())
468    }
469
470    /// Get the children of the current node
471    #[inline]
472    fn children(&self) -> Vec<NodeRef<V>> {
473        self.child_ids()
474            .iter()
475            .map(|id| NodeRef {
476                id: *id,
477                dom: self.real_dom(),
478            })
479            .collect()
480    }
481
482    /// Get the id of the parent of the current node
483    #[inline]
484    fn parent_id(&self) -> Option<NodeId> {
485        self.real_dom().tree_ref().parent_id(self.id())
486    }
487
488    /// Get the parent of the current node
489    #[inline]
490    fn parent(&self) -> Option<NodeRef<V>> {
491        self.parent_id().map(|id| NodeRef {
492            id,
493            dom: self.real_dom(),
494        })
495    }
496
497    /// Get the height of the current node in the tree (the number of nodes between the current node and the root)
498    #[inline]
499    fn height(&self) -> u16 {
500        self.real_dom().tree_ref().height(self.id()).unwrap()
501    }
502}
503
504/// An immutable reference to a node in a RealDom
505pub struct NodeRef<'a, V: FromAnyValue + Send + Sync = ()> {
506    id: NodeId,
507    dom: &'a RealDom<V>,
508}
509
510impl<V: FromAnyValue + Send + Sync> Clone for NodeRef<'_, V> {
511    fn clone(&self) -> Self {
512        *self
513    }
514}
515
516impl<V: FromAnyValue + Send + Sync> Copy for NodeRef<'_, V> {}
517
518impl<V: FromAnyValue + Send + Sync> NodeImmutable<V> for NodeRef<'_, V> {
519    #[inline(always)]
520    fn real_dom(&self) -> &RealDom<V> {
521        self.dom
522    }
523
524    #[inline(always)]
525    fn id(&self) -> NodeId {
526        self.id
527    }
528}
529
530/// A mutable refrence to a node in the RealDom that tracks what States need to be updated
531pub struct NodeMut<'a, V: FromAnyValue + Send + Sync = ()> {
532    id: NodeId,
533    dom: &'a mut RealDom<V>,
534}
535
536impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> {
537    /// Create a new mutable refrence to a node in a RealDom
538    pub fn new(id: NodeId, dom: &'a mut RealDom<V>) -> Self {
539        Self { id, dom }
540    }
541}
542
543impl<V: FromAnyValue + Send + Sync> NodeImmutable<V> for NodeMut<'_, V> {
544    #[inline(always)]
545    fn real_dom(&self) -> &RealDom<V> {
546        self.dom
547    }
548
549    #[inline(always)]
550    fn id(&self) -> NodeId {
551        self.id
552    }
553}
554
555impl<V: FromAnyValue + Send + Sync> NodeMut<'_, V> {
556    /// Get the real dom this node was created in mutably
557    #[inline(always)]
558    pub fn real_dom_mut(&mut self) -> &mut RealDom<V> {
559        self.dom
560    }
561
562    /// Get a component from the current node mutably
563    #[inline]
564    pub fn get_mut<T: Component<Tracking = Untracked> + Sync + Send>(
565        &mut self,
566    ) -> Option<ViewEntryMut<T>> {
567        // mark the node state as dirty
568        self.dom
569            .dirty_nodes
570            .passes_updated
571            .entry(self.id)
572            .or_default()
573            .insert(TypeId::of::<T>());
574        let view_mut: ViewMut<T> = self.dom.borrow_raw().ok()?;
575        view_mut
576            .contains(self.id)
577            .then_some(ViewEntryMut::new(view_mut, self.id))
578    }
579
580    /// Insert a custom component into this node
581    ///
582    /// Note: Components that implement State and are added when the RealDom is created will automatically be created
583    #[inline]
584    pub fn insert<T: Component + Sync + Send>(&mut self, value: T) {
585        // mark the node state as dirty
586        self.dom
587            .dirty_nodes
588            .passes_updated
589            .entry(self.id)
590            .or_default()
591            .insert(TypeId::of::<T>());
592        self.dom.world.add_component(self.id, value);
593    }
594
595    /// Add the given node to the end of this nodes children
596    #[inline]
597    pub fn add_child(&mut self, child: NodeId) {
598        self.dom.dirty_nodes.mark_child_changed(self.id);
599        self.dom.dirty_nodes.mark_parent_added_or_removed(child);
600        self.dom.tree_mut().add_child(self.id, child);
601    }
602
603    /// Insert this node after the given node
604    #[inline]
605    pub fn insert_after(&mut self, old: NodeId) {
606        let id = self.id();
607        let parent_id = { self.dom.tree_ref().parent_id(old) };
608        if let Some(parent_id) = parent_id {
609            self.dom.dirty_nodes.mark_child_changed(parent_id);
610            self.dom.dirty_nodes.mark_parent_added_or_removed(id);
611        }
612        self.dom.tree_mut().insert_after(old, id);
613    }
614
615    /// Insert this node before the given node
616    #[inline]
617    pub fn insert_before(&mut self, old: NodeId) {
618        let id = self.id();
619        let parent_id = { self.dom.tree_ref().parent_id(old) };
620        if let Some(parent_id) = parent_id {
621            self.dom.dirty_nodes.mark_child_changed(parent_id);
622            self.dom.dirty_nodes.mark_parent_added_or_removed(id);
623        }
624        self.dom.tree_mut().insert_before(old, id);
625    }
626
627    /// Remove this node from the RealDom
628    #[inline]
629    pub fn remove(&mut self) {
630        let id = self.id();
631        {
632            let RealDom {
633                world,
634                nodes_listening,
635                ..
636            } = &mut self.dom;
637            let mut view: ViewMut<NodeType<V>> = world.borrow().unwrap();
638            if let NodeType::Element(ElementNode { listeners, .. }) = (&mut view).get(id).unwrap() {
639                let listeners = std::mem::take(listeners);
640                for event in listeners {
641                    nodes_listening.get_mut(&event).unwrap().remove(&id);
642                }
643            }
644        }
645        let parent_id = { self.dom.tree_ref().parent_id(id) };
646        if let Some(parent_id) = parent_id {
647            self.real_dom_mut()
648                .dirty_nodes
649                .mark_child_changed(parent_id);
650        }
651        let children_ids = self.child_ids();
652        for child in children_ids {
653            self.dom.get_mut(child).unwrap().remove();
654        }
655        self.dom.tree_mut().remove(id);
656        self.real_dom_mut().raw_world_mut().delete_entity(id);
657    }
658
659    /// Add an event listener
660    #[inline]
661    pub fn add_event_listener(&mut self, event: EventName) {
662        let id = self.id();
663        let RealDom {
664            world,
665            dirty_nodes,
666            nodes_listening,
667            ..
668        } = &mut self.dom;
669        let mut view: ViewMut<NodeType<V>> = world.borrow().unwrap();
670        let node_type: &mut NodeType<V> = (&mut view).get(self.id).unwrap();
671        if let NodeType::Element(ElementNode { listeners, .. }) = node_type {
672            dirty_nodes.mark_dirty(self.id, NodeMaskBuilder::new().with_listeners().build());
673            listeners.insert(event);
674            match nodes_listening.get_mut(&event) {
675                Some(hs) => {
676                    hs.insert(id);
677                }
678                None => {
679                    let mut hs = FxHashSet::default();
680                    hs.insert(id);
681                    nodes_listening.insert(event, hs);
682                }
683            }
684        }
685    }
686
687    /// Remove an event listener
688    #[inline]
689    pub fn remove_event_listener(&mut self, event: &EventName) {
690        let id = self.id();
691        let RealDom {
692            world,
693            dirty_nodes,
694            nodes_listening,
695            ..
696        } = &mut self.dom;
697        let mut view: ViewMut<NodeType<V>> = world.borrow().unwrap();
698        let node_type: &mut NodeType<V> = (&mut view).get(self.id).unwrap();
699        if let NodeType::Element(ElementNode { listeners, .. }) = node_type {
700            dirty_nodes.mark_dirty(self.id, NodeMaskBuilder::new().with_listeners().build());
701            listeners.remove(event);
702
703            nodes_listening.get_mut(event).unwrap().remove(&id);
704        }
705    }
706
707    /// Get a mutable reference to the type of the current node
708    pub fn node_type_mut(&mut self) -> NodeTypeMut<'_, V> {
709        let id = self.id();
710        let RealDom {
711            world, dirty_nodes, ..
712        } = &mut self.dom;
713        let view: ViewMut<NodeType<V>> = world.borrow().unwrap();
714        let node_type = ViewEntryMut::new(view, id);
715        match &*node_type {
716            NodeType::Element(_) => NodeTypeMut::Element(ElementNodeMut {
717                id,
718                element: node_type,
719                dirty_nodes,
720            }),
721            NodeType::Text(_) => NodeTypeMut::Text(TextNodeMut {
722                id,
723                text: node_type,
724                dirty_nodes,
725            }),
726            NodeType::Placeholder => NodeTypeMut::Placeholder,
727        }
728    }
729
730    /// Set the type of the current node
731    pub fn set_type(&mut self, new: NodeType<V>) {
732        {
733            let mut view: ViewMut<NodeType<V>> = self.dom.borrow_node_type_mut().unwrap();
734            *(&mut view).get(self.id).unwrap() = new;
735        }
736        self.dom
737            .dirty_nodes
738            .mark_dirty(self.id, NodeMaskBuilder::ALL.build())
739    }
740
741    /// Clone a node and it's children and returns the id of the new node.
742    /// This is more effecient than creating the node from scratch because it can pre-allocate the memory required.
743    #[inline]
744    pub fn clone_node(&mut self) -> NodeId {
745        let new_node = self.node_type().clone();
746        let rdom = self.real_dom_mut();
747        let new_id = rdom.create_node(new_node).id();
748
749        let children = self.child_ids();
750        let children = children.to_vec();
751        let rdom = self.real_dom_mut();
752        for child in children {
753            let child_id = rdom.get_mut(child).unwrap().clone_node();
754            rdom.get_mut(new_id).unwrap().add_child(child_id);
755        }
756        new_id
757    }
758}
759
760/// A mutable refrence to the type of a node in the RealDom
761pub enum NodeTypeMut<'a, V: FromAnyValue + Send + Sync = ()> {
762    /// An element node
763    Element(ElementNodeMut<'a, V>),
764    /// A text node
765    Text(TextNodeMut<'a, V>),
766    /// A placeholder node
767    Placeholder,
768}
769
770/// A mutable refrence to a text node in the RealDom
771pub struct TextNodeMut<'a, V: FromAnyValue + Send + Sync = ()> {
772    id: NodeId,
773    text: ViewEntryMut<'a, NodeType<V>>,
774    dirty_nodes: &'a mut NodesDirty<V>,
775}
776
777impl<V: FromAnyValue + Send + Sync> TextNodeMut<'_, V> {
778    /// Get the underlying test of the node
779    pub fn text(&self) -> &str {
780        match &*self.text {
781            NodeType::Text(text) => text,
782            _ => unreachable!(),
783        }
784    }
785
786    /// Get the underlying text mutably
787    pub fn text_mut(&mut self) -> &mut String {
788        self.dirty_nodes
789            .mark_dirty(self.id, NodeMaskBuilder::new().with_text().build());
790        match &mut *self.text {
791            NodeType::Text(text) => text,
792            _ => unreachable!(),
793        }
794    }
795}
796
797impl<V: FromAnyValue + Send + Sync> Deref for TextNodeMut<'_, V> {
798    type Target = String;
799
800    fn deref(&self) -> &Self::Target {
801        match &*self.text {
802            NodeType::Text(text) => text,
803            _ => unreachable!(),
804        }
805    }
806}
807
808impl<V: FromAnyValue + Send + Sync> DerefMut for TextNodeMut<'_, V> {
809    fn deref_mut(&mut self) -> &mut Self::Target {
810        self.text_mut()
811    }
812}
813
814/// A mutable refrence to a text Element node in the RealDom
815pub struct ElementNodeMut<'a, V: FromAnyValue + Send + Sync = ()> {
816    id: NodeId,
817    element: ViewEntryMut<'a, NodeType<V>>,
818    dirty_nodes: &'a mut NodesDirty<V>,
819}
820
821impl std::fmt::Debug for ElementNodeMut<'_> {
822    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
823        f.debug_struct("ElementNodeMut")
824            .field("id", &self.id)
825            .field("element", &*self.element)
826            .finish()
827    }
828}
829
830impl<V: FromAnyValue + Send + Sync> ElementNodeMut<'_, V> {
831    /// Get the current element mutably (does not mark anything as dirty)
832    fn element_mut(&mut self) -> &mut ElementNode<V> {
833        match &mut *self.element {
834            NodeType::Element(element) => element,
835            _ => unreachable!(),
836        }
837    }
838
839    /// Set an attribute in the element
840    pub fn set_attribute(
841        &mut self,
842        name: impl Into<AttributeName>,
843        value: impl Into<OwnedAttributeValue<V>>,
844    ) -> Option<OwnedAttributeValue<V>> {
845        let name = name.into();
846        let value = value.into();
847        self.dirty_nodes.mark_dirty(
848            self.id,
849            NodeMaskBuilder::new()
850                .with_attrs(AttributeMaskBuilder::Some(&[name]))
851                .build(),
852        );
853        self.element_mut().attributes.insert(name, value)
854    }
855
856    /// Remove an attribute from the element
857    pub fn remove_attribute(&mut self, name: &AttributeName) -> Option<OwnedAttributeValue<V>> {
858        self.dirty_nodes.mark_dirty(
859            self.id,
860            NodeMaskBuilder::new()
861                .with_attrs(AttributeMaskBuilder::Some(&[*name]))
862                .build(),
863        );
864        self.element_mut().attributes.remove(name)
865    }
866
867    /// Get an attribute of the element
868    pub fn get_attribute_mut(
869        &mut self,
870        name: &AttributeName,
871    ) -> Option<&mut OwnedAttributeValue<V>> {
872        self.dirty_nodes.mark_dirty(
873            self.id,
874            NodeMaskBuilder::new()
875                .with_attrs(AttributeMaskBuilder::Some(&[*name]))
876                .build(),
877        );
878        self.element_mut().attributes.get_mut(name)
879    }
880}
881
882// Create a workload from all of the passes. This orders the passes so that each pass will only run at most once.
883fn construct_workload<V: FromAnyValue + Send + Sync>(
884    passes: &mut [TypeErasedState<V>],
885) -> Workload {
886    let mut workload = Workload::new("Main Workload");
887    // Assign a unique index to keep track of each pass
888    let mut unresloved_workloads = passes
889        .iter_mut()
890        .enumerate()
891        .map(|(i, pass)| {
892            let workload = Some(pass.create_workload());
893            (i, pass, workload)
894        })
895        .collect::<Vec<_>>();
896    // set all the labels
897    for (id, _, workload) in &mut unresloved_workloads {
898        *workload = Some(workload.take().unwrap().tag(id.to_string()));
899    }
900    // mark any dependancies
901    for i in 0..unresloved_workloads.len() {
902        let (_, pass, _) = &unresloved_workloads[i];
903        let all_dependancies: Vec<_> = pass.combined_dependancy_type_ids().collect();
904        for ty_id in all_dependancies {
905            let &(dependancy_id, _, _) = unresloved_workloads
906                .iter()
907                .find(|(_, pass, _)| pass.this_type_id == ty_id)
908                .unwrap();
909            let (_, _, workload) = &mut unresloved_workloads[i];
910            *workload = workload
911                .take()
912                .map(|workload| workload.after_all(dependancy_id.to_string()));
913        }
914    }
915    // Add all of the passes
916    for (_, _, mut workload_system) in unresloved_workloads {
917        workload = workload.with_system(workload_system.take().unwrap());
918    }
919    workload
920}