freya_native_core/
tree.rs

1//! A tree of nodes intigated with shipyard
2
3use std::fmt::Debug;
4
5use shipyard::{
6    Component,
7    EntitiesViewMut,
8    Get,
9    View,
10    ViewMut,
11};
12
13use crate::NodeId;
14
15/// A shadow tree reference inside of a tree. This tree is isolated from the main tree.
16#[derive(PartialEq, Eq, Clone, Debug, Component)]
17pub struct ShadowTree {
18    /// The root of the shadow tree
19    pub shadow_roots: Vec<NodeId>,
20    /// The node that children of the super tree should be inserted under.
21    pub slot: Option<NodeId>,
22}
23
24/// A node in a tree.
25#[derive(PartialEq, Eq, Clone, Debug, Component)]
26pub struct Node {
27    parent: Option<NodeId>,
28    children: Vec<NodeId>,
29    child_subtree: Option<ShadowTree>,
30    /// If this node is a slot in a shadow_tree, this is node whose child_subtree is that shadow_tree.
31    slot_for_light_tree: Option<NodeId>,
32    /// If this node is a root of a shadow_tree, this is the node whose child_subtree is that shadow_tree.
33    root_for_light_tree: Option<NodeId>,
34    height: u16,
35}
36
37/// A view of a tree.
38pub type TreeRefView<'a> = View<'a, Node>;
39/// A mutable view of a tree.
40pub type TreeMutView<'a> = (EntitiesViewMut<'a>, ViewMut<'a, Node>);
41
42/// A immutable view of a tree.
43pub trait TreeRef {
44    /// Get the id of the parent of the current node, if enter_shadow_dom is true and the current node is a shadow root, the node the shadow root is attached to will be returned
45    #[inline]
46    fn parent_id_advanced(&self, id: NodeId, enter_shadow_dom: bool) -> Option<NodeId> {
47        // If this node is the root of a shadow_tree, return the node the shadow_tree is attached
48        let root_for_light_tree = self.root_for_light_tree(id);
49        match (root_for_light_tree, enter_shadow_dom) {
50            (Some(id), true) => Some(id),
51            _ => {
52                let parent_id = self.parent_id(id);
53                if enter_shadow_dom {
54                    // If this node is attached via a slot, return the slot as the parent instead of the light tree parent
55                    parent_id.map(|id| {
56                        self.shadow_tree(id)
57                            .and_then(|tree| tree.slot)
58                            .unwrap_or(id)
59                    })
60                } else {
61                    parent_id
62                }
63            }
64        }
65    }
66    /// The parent id of the node.
67    fn parent_id(&self, id: NodeId) -> Option<NodeId>;
68    /// 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
69    #[inline]
70    fn children_ids_advanced(&self, id: NodeId, enter_shadow_dom: bool) -> Vec<NodeId> {
71        let shadow_tree = self.shadow_tree(id);
72        let slot_of_light_tree = self.slot_for_light_tree(id);
73        match (shadow_tree, slot_of_light_tree, enter_shadow_dom) {
74            // If this node is a shadow root, return the shadow roots
75            (Some(tree), _, true) => tree.shadow_roots.clone(),
76            // If this node is a slot, return the children of the node the slot is attached to
77            (None, Some(id), true) => self.children_ids(id),
78            _ => self.children_ids(id),
79        }
80    }
81    /// The children ids of the node.
82    fn children_ids(&self, id: NodeId) -> Vec<NodeId>;
83    /// The shadow tree tree under the node.
84    fn shadow_tree(&self, id: NodeId) -> Option<&ShadowTree>;
85    /// The node that contains the shadow tree this node is a slot for
86    fn slot_for_light_tree(&self, id: NodeId) -> Option<NodeId>;
87    /// The node that contains the shadow tree this node is a root of
88    fn root_for_light_tree(&self, id: NodeId) -> Option<NodeId>;
89    /// The height of the node.
90    fn height(&self, id: NodeId) -> Option<u16>;
91    /// Returns true if the node exists.
92    fn contains(&self, id: NodeId) -> bool;
93}
94
95/// A mutable view of a tree.
96pub trait TreeMut: TreeRef {
97    /// Removes the node and its children from the tree but do not delete the entities.
98    fn remove(&mut self, id: NodeId);
99    /// Adds a new node to the tree.
100    fn create_node(&mut self, id: NodeId);
101    /// Adds a child to the node.
102    fn add_child(&mut self, parent: NodeId, new: NodeId);
103    /// Replaces the node with a new node.
104    fn replace(&mut self, old_id: NodeId, new_id: NodeId);
105    /// Inserts a node before another node.
106    fn insert_before(&mut self, old_id: NodeId, new_id: NodeId);
107    /// Inserts a node after another node.
108    fn insert_after(&mut self, old_id: NodeId, new_id: NodeId);
109    /// Creates a new shadow tree.
110    fn create_subtree(&mut self, id: NodeId, shadow_roots: Vec<NodeId>, slot: Option<NodeId>);
111    /// Remove any shadow tree.
112    fn remove_subtree(&mut self, id: NodeId);
113}
114
115impl TreeRef for TreeRefView<'_> {
116    fn parent_id(&self, id: NodeId) -> Option<NodeId> {
117        self.get(id).ok()?.parent
118    }
119
120    fn children_ids(&self, id: NodeId) -> Vec<NodeId> {
121        self.get(id)
122            .map(|node| node.children.clone())
123            .unwrap_or_default()
124    }
125
126    fn height(&self, id: NodeId) -> Option<u16> {
127        Some(self.get(id).ok()?.height)
128    }
129
130    fn contains(&self, id: NodeId) -> bool {
131        self.get(id).is_ok()
132    }
133
134    fn shadow_tree(&self, id: NodeId) -> Option<&ShadowTree> {
135        self.get(id).ok()?.child_subtree.as_ref()
136    }
137
138    fn slot_for_light_tree(&self, id: NodeId) -> Option<NodeId> {
139        self.get(id).ok()?.slot_for_light_tree
140    }
141
142    fn root_for_light_tree(&self, id: NodeId) -> Option<NodeId> {
143        self.get(id).ok()?.root_for_light_tree
144    }
145}
146
147impl TreeMut for TreeMutView<'_> {
148    fn remove(&mut self, id: NodeId) {
149        fn recurse(tree: &mut TreeMutView<'_>, id: NodeId) {
150            let (light_tree, children) = {
151                let node = (&mut tree.1).get(id).unwrap();
152                (node.slot_for_light_tree, std::mem::take(&mut node.children))
153            };
154
155            for child in children {
156                recurse(tree, child);
157            }
158
159            // If this node is a slot in a shadow_tree, remove it from the shadow_tree.
160            if let Some(light_tree) = light_tree {
161                let root_for_light_tree = (&mut tree.1).get(light_tree).unwrap();
162
163                if let Some(shadow_tree) = &mut root_for_light_tree.child_subtree {
164                    shadow_tree.slot = None;
165                }
166
167                debug_assert!(
168                    root_for_light_tree.children.is_empty(),
169                    "ShadowTree root should have no children when slot is removed."
170                );
171            }
172        }
173
174        {
175            let mut node_data_mut = &mut self.1;
176            if let Some(parent) = node_data_mut.get(id).unwrap().parent {
177                let parent = (&mut node_data_mut).get(parent).unwrap();
178                parent.children.retain(|&child| child != id);
179            }
180        }
181
182        recurse(self, id);
183    }
184
185    fn create_node(&mut self, id: NodeId) {
186        let (entities, node_data_mut) = self;
187        entities.add_component(
188            id,
189            node_data_mut,
190            Node {
191                parent: None,
192                children: Vec::new(),
193                height: 0,
194                child_subtree: None,
195                slot_for_light_tree: None,
196                root_for_light_tree: None,
197            },
198        );
199    }
200
201    fn add_child(&mut self, parent: NodeId, new: NodeId) {
202        {
203            let mut node_state = &mut self.1;
204            (&mut node_state).get(new).unwrap().parent = Some(parent);
205            let parent = (&mut node_state).get(parent).unwrap();
206            parent.children.push(new);
207        }
208        let height = child_height((&self.1).get(parent).unwrap(), self);
209        set_height(self, new, height);
210    }
211
212    fn replace(&mut self, old_id: NodeId, new_id: NodeId) {
213        {
214            let mut node_state = &mut self.1;
215            // update the parent's link to the child
216            if let Some(parent_id) = node_state.get(old_id).unwrap().parent {
217                let parent = (&mut node_state).get(parent_id).unwrap();
218                for id in &mut parent.children {
219                    if *id == old_id {
220                        *id = new_id;
221                        break;
222                    }
223                }
224                let height = child_height((&self.1).get(parent_id).unwrap(), self);
225                set_height(self, new_id, height);
226            }
227        }
228        self.remove(old_id);
229    }
230
231    fn insert_before(&mut self, old_id: NodeId, new_id: NodeId) {
232        let new_parent_id = {
233            let new_id = self.1.get(new_id).unwrap();
234            new_id.parent
235        };
236        if let Some(new_parent_id) = new_parent_id {
237            (&mut self.1)
238                .get(new_parent_id)
239                .unwrap()
240                .children
241                .retain(|id| *id != new_id);
242        }
243
244        let parent_id = {
245            let old_node = self.1.get(old_id).unwrap();
246            old_node.parent.expect("tried to insert before root")
247        };
248        (&mut self.1).get(new_id).unwrap().parent = Some(parent_id);
249
250        let parent = (&mut self.1).get(parent_id).unwrap();
251        let index = parent
252            .children
253            .iter()
254            .position(|child| *child == old_id)
255            .unwrap();
256        parent.children.insert(index, new_id);
257        let height = child_height((&self.1).get(parent_id).unwrap(), self);
258        set_height(self, new_id, height);
259    }
260
261    fn insert_after(&mut self, old_id: NodeId, new_id: NodeId) {
262        let new_parent_id = {
263            let new_id = self.1.get(new_id).unwrap();
264            new_id.parent
265        };
266        if let Some(new_parent_id) = new_parent_id {
267            (&mut self.1)
268                .get(new_parent_id)
269                .unwrap()
270                .children
271                .retain(|id| *id != new_id);
272        }
273
274        let mut node_state = &mut self.1;
275        let old_node = node_state.get(old_id).unwrap();
276        let parent_id = old_node.parent.expect("tried to insert after root");
277        (&mut node_state).get(new_id).unwrap().parent = Some(parent_id);
278        let parent = (&mut node_state).get(parent_id).unwrap();
279        let index = parent
280            .children
281            .iter()
282            .position(|child| *child == old_id)
283            .unwrap();
284        parent.children.insert(index + 1, new_id);
285        let height = child_height((&self.1).get(parent_id).unwrap(), self);
286        set_height(self, new_id, height);
287    }
288
289    fn create_subtree(&mut self, id: NodeId, shadow_roots: Vec<NodeId>, slot: Option<NodeId>) {
290        let (_, node_data_mut) = self;
291
292        let light_root_height;
293        {
294            let shadow_tree = ShadowTree {
295                shadow_roots: shadow_roots.clone(),
296                slot,
297            };
298
299            let light_root = node_data_mut
300                .get(id)
301                .expect("tried to create shadow_tree with non-existent id");
302
303            light_root.child_subtree = Some(shadow_tree);
304            light_root_height = light_root.height;
305
306            if let Some(slot) = slot {
307                let slot = node_data_mut
308                    .get(slot)
309                    .expect("tried to create shadow_tree with non-existent slot");
310                slot.slot_for_light_tree = Some(id);
311            }
312        }
313
314        // Now that we have created the shadow_tree, we need to update the height of the shadow_tree roots
315        for root in shadow_roots {
316            (&mut self.1).get(root).unwrap().root_for_light_tree = Some(id);
317            set_height(self, root, light_root_height + 1);
318        }
319    }
320
321    fn remove_subtree(&mut self, id: NodeId) {
322        let (_, node_data_mut) = self;
323
324        if let Ok(node) = node_data_mut.get(id) {
325            if let Some(shadow_tree) = node.child_subtree.take() {
326                // Remove the slot's link to the shadow_tree
327                if let Some(slot) = shadow_tree.slot {
328                    let slot = node_data_mut
329                        .get(slot)
330                        .expect("tried to remove shadow_tree with non-existent slot");
331                    slot.slot_for_light_tree = None;
332                }
333
334                let node = node_data_mut.get(id).unwrap();
335
336                // Reset the height of the light root's children
337                let height = node.height;
338                for child in node.children.clone() {
339                    set_height(self, child, height + 1);
340                }
341
342                // Reset the height of the shadow roots
343                for root in &shadow_tree.shadow_roots {
344                    set_height(self, *root, 0);
345                }
346            }
347        }
348    }
349}
350
351fn child_height(parent: &Node, tree: &impl TreeRef) -> u16 {
352    match &parent.child_subtree {
353        Some(shadow_tree) => {
354            if let Some(slot) = shadow_tree.slot {
355                tree.height(slot)
356                    .expect("Attempted to read a slot that does not exist")
357                    + 1
358            } else {
359                panic!("Attempted to read the height of a child of a node with a shadow tree, but the shadow tree does not have a slot. Every shadow tree attached to a node with children must have a slot.")
360            }
361        }
362        None => parent.height + 1,
363    }
364}
365
366/// Sets the height of a node and updates the height of all its children
367fn set_height(tree: &mut TreeMutView<'_>, node: NodeId, height: u16) {
368    let (shadow_tree, light_tree, children) = {
369        let mut node_data_mut = &mut tree.1;
370        let node = (&mut node_data_mut).get(node).unwrap();
371        node.height = height;
372
373        (
374            node.child_subtree.clone(),
375            node.slot_for_light_tree,
376            node.children.clone(),
377        )
378    };
379
380    // If the children are actually part of a shadow_tree, there height is determined by the height of the shadow_tree
381    if let Some(shadow_tree) = shadow_tree {
382        // Set the height of the shadow_tree roots
383        for &shadow_root in &shadow_tree.shadow_roots {
384            set_height(tree, shadow_root, height + 1);
385        }
386    } else {
387        // Otherwise, we just set the height of the children to be one more than the height of the parent
388        for child in children {
389            set_height(tree, child, height + 1);
390        }
391    }
392
393    // If this nodes is a slot for a shadow_tree, we need to go to the super tree and update the height of its children
394    if let Some(light_tree) = light_tree {
395        let children = (&tree.1).get(light_tree).unwrap().children.clone();
396        for child in children {
397            set_height(tree, child, height + 1);
398        }
399    }
400}
401
402impl TreeRef for TreeMutView<'_> {
403    fn parent_id(&self, id: NodeId) -> Option<NodeId> {
404        let node_data = &self.1;
405        node_data.get(id).unwrap().parent
406    }
407
408    fn children_ids(&self, id: NodeId) -> Vec<NodeId> {
409        let node_data = &self.1;
410        node_data
411            .get(id)
412            .map(|node| node.children.clone())
413            .unwrap_or_default()
414    }
415
416    fn height(&self, id: NodeId) -> Option<u16> {
417        let node_data = &self.1;
418        node_data.get(id).map(|node| node.height).ok()
419    }
420
421    fn contains(&self, id: NodeId) -> bool {
422        self.1.get(id).is_ok()
423    }
424
425    fn shadow_tree(&self, id: NodeId) -> Option<&ShadowTree> {
426        let node_data = &self.1;
427        node_data.get(id).ok()?.child_subtree.as_ref()
428    }
429
430    fn slot_for_light_tree(&self, id: NodeId) -> Option<NodeId> {
431        let node_data = &self.1;
432        node_data.get(id).ok()?.slot_for_light_tree
433    }
434
435    fn root_for_light_tree(&self, id: NodeId) -> Option<NodeId> {
436        let node_data = &self.1;
437        node_data.get(id).ok()?.root_for_light_tree
438    }
439}
440
441#[test]
442fn creation() {
443    use shipyard::World;
444    #[allow(dead_code)]
445    #[derive(Component)]
446    struct Num(i32);
447
448    let mut world = World::new();
449    let parent_id = world.add_entity(Num(1i32));
450    let child_id = world.add_entity(Num(0i32));
451
452    let mut tree = world.borrow::<TreeMutView>().unwrap();
453
454    tree.create_node(parent_id);
455    tree.create_node(child_id);
456
457    tree.add_child(parent_id, child_id);
458
459    assert_eq!(tree.height(parent_id), Some(0));
460    assert_eq!(tree.height(child_id), Some(1));
461    assert_eq!(tree.parent_id(parent_id), None);
462    assert_eq!(tree.parent_id(child_id).unwrap(), parent_id);
463    assert_eq!(tree.children_ids(parent_id), &[child_id]);
464}
465
466#[test]
467fn shadow_tree() {
468    use shipyard::World;
469    #[allow(dead_code)]
470    #[derive(Component)]
471    struct Num(i32);
472
473    let mut world = World::new();
474    // Create main tree
475    let parent_id = world.add_entity(Num(1i32));
476    let child_id = world.add_entity(Num(0i32));
477
478    // Create shadow tree
479    let shadow_parent_id = world.add_entity(Num(2i32));
480    let shadow_child_id = world.add_entity(Num(3i32));
481
482    let mut tree = world.borrow::<TreeMutView>().unwrap();
483
484    tree.create_node(parent_id);
485    tree.create_node(child_id);
486
487    tree.add_child(parent_id, child_id);
488
489    tree.create_node(shadow_parent_id);
490    tree.create_node(shadow_child_id);
491
492    tree.add_child(shadow_parent_id, shadow_child_id);
493
494    // Check that both trees are correct individually
495    assert_eq!(tree.height(parent_id), Some(0));
496    assert_eq!(tree.height(child_id), Some(1));
497    assert_eq!(tree.parent_id(parent_id), None);
498    assert_eq!(tree.parent_id(child_id).unwrap(), parent_id);
499    assert_eq!(tree.children_ids(parent_id), &[child_id]);
500
501    assert_eq!(tree.height(shadow_parent_id), Some(0));
502    assert_eq!(tree.height(shadow_child_id), Some(1));
503    assert_eq!(tree.parent_id(shadow_parent_id), None);
504    assert_eq!(tree.parent_id(shadow_child_id).unwrap(), shadow_parent_id);
505    assert_eq!(tree.children_ids(shadow_parent_id), &[shadow_child_id]);
506
507    // Add shadow tree to main tree
508    tree.create_subtree(parent_id, vec![shadow_parent_id], Some(shadow_child_id));
509
510    assert_eq!(tree.height(parent_id), Some(0));
511    assert_eq!(tree.height(shadow_parent_id), Some(1));
512    assert_eq!(tree.height(shadow_child_id), Some(2));
513    assert_eq!(tree.height(child_id), Some(3));
514    assert_eq!(
515        tree.1
516            .get(parent_id)
517            .unwrap()
518            .child_subtree
519            .as_ref()
520            .unwrap()
521            .shadow_roots,
522        &[shadow_parent_id]
523    );
524    assert_eq!(
525        tree.1.get(shadow_child_id).unwrap().slot_for_light_tree,
526        Some(parent_id)
527    );
528
529    // Remove shadow tree from main tree
530    tree.remove_subtree(parent_id);
531
532    // Check that both trees are correct individually
533    assert_eq!(tree.height(parent_id), Some(0));
534    assert_eq!(tree.height(child_id), Some(1));
535    assert_eq!(tree.parent_id(parent_id), None);
536    assert_eq!(tree.parent_id(child_id).unwrap(), parent_id);
537    assert_eq!(tree.children_ids(parent_id), &[child_id]);
538
539    assert_eq!(tree.height(shadow_parent_id), Some(0));
540    assert_eq!(tree.height(shadow_child_id), Some(1));
541    assert_eq!(tree.parent_id(shadow_parent_id), None);
542    assert_eq!(tree.parent_id(shadow_child_id).unwrap(), shadow_parent_id);
543    assert_eq!(tree.children_ids(shadow_parent_id), &[shadow_child_id]);
544}
545
546#[test]
547fn insertion() {
548    use shipyard::World;
549    #[allow(dead_code)]
550    #[derive(Component)]
551    struct Num(i32);
552
553    let mut world = World::new();
554    let parent = world.add_entity(Num(0));
555    let child = world.add_entity(Num(2));
556    let before = world.add_entity(Num(1));
557    let after = world.add_entity(Num(3));
558
559    let mut tree = world.borrow::<TreeMutView>().unwrap();
560
561    tree.create_node(parent);
562    tree.create_node(child);
563    tree.create_node(before);
564    tree.create_node(after);
565
566    tree.add_child(parent, child);
567    tree.insert_before(child, before);
568    tree.insert_after(child, after);
569
570    assert_eq!(tree.height(parent), Some(0));
571    assert_eq!(tree.height(child), Some(1));
572    assert_eq!(tree.height(before), Some(1));
573    assert_eq!(tree.height(after), Some(1));
574    assert_eq!(tree.parent_id(before).unwrap(), parent);
575    assert_eq!(tree.parent_id(child).unwrap(), parent);
576    assert_eq!(tree.parent_id(after).unwrap(), parent);
577    assert_eq!(tree.children_ids(parent), &[before, child, after]);
578}
579
580#[test]
581fn deletion() {
582    use shipyard::World;
583    #[allow(dead_code)]
584    #[derive(Component)]
585    struct Num(i32);
586
587    let mut world = World::new();
588    let parent = world.add_entity(Num(0));
589    let child = world.add_entity(Num(2));
590    let before = world.add_entity(Num(1));
591    let after = world.add_entity(Num(3));
592
593    let mut tree = world.borrow::<TreeMutView>().unwrap();
594
595    tree.create_node(parent);
596    tree.create_node(child);
597    tree.create_node(before);
598    tree.create_node(after);
599
600    tree.add_child(parent, child);
601    tree.insert_before(child, before);
602    tree.insert_after(child, after);
603
604    assert_eq!(tree.height(parent), Some(0));
605    assert_eq!(tree.height(child), Some(1));
606    assert_eq!(tree.height(before), Some(1));
607    assert_eq!(tree.height(after), Some(1));
608    assert_eq!(tree.parent_id(before).unwrap(), parent);
609    assert_eq!(tree.parent_id(child).unwrap(), parent);
610    assert_eq!(tree.parent_id(after).unwrap(), parent);
611    assert_eq!(tree.children_ids(parent), &[before, child, after]);
612
613    tree.remove(child);
614
615    assert_eq!(tree.height(parent), Some(0));
616    assert_eq!(tree.height(before), Some(1));
617    assert_eq!(tree.height(after), Some(1));
618    assert_eq!(tree.parent_id(before).unwrap(), parent);
619    assert_eq!(tree.parent_id(after).unwrap(), parent);
620    assert_eq!(tree.children_ids(parent), &[before, after]);
621
622    tree.remove(before);
623
624    assert_eq!(tree.height(parent), Some(0));
625    assert_eq!(tree.height(after), Some(1));
626    assert_eq!(tree.parent_id(after).unwrap(), parent);
627    assert_eq!(tree.children_ids(parent), &[after]);
628
629    tree.remove(after);
630
631    assert_eq!(tree.height(parent), Some(0));
632    assert_eq!(tree.children_ids(parent), &[]);
633}