1
//! Node tree data structures and hierarchy management.
2
//!
3
//! This module provides the core data structures for managing DOM-like tree hierarchies:
4
//!
5
//! - `NodeId`: Type-safe node identifiers with Option<NodeId> optimization
6
//! - `NodeHierarchy`: Parent-child relationships between nodes
7
//! - `NodeDataContainer`: Generic storage for node data with efficient indexing
8
//!
9
//! # Memory Layout
10
//!
11
//! `NodeId` stores a plain `usize` index internally. For FFI structs that need
12
//! `Option<NodeId>`, a manual 1-based encoding is used (0 = None, n > 0 = Some(n-1)).
13
//!
14
//! # Performance
15
//!
16
//! - Node lookups are O(1) via direct array indexing
17
//! - Parent/child traversal is O(1) via pre-computed indices
18
//! - No heap allocations after initial tree construction
19

            
20
use alloc::vec::Vec;
21
use core::{
22
    ops::{Index, IndexMut},
23
    slice::Iter,
24
};
25

            
26
pub use self::node_id::NodeId;
27
use crate::styled_dom::NodeHierarchyItem;
28

            
29
/// Type alias for depth-first traversal results: (depth, node_id) pairs
30
pub type NodeDepths = Vec<(usize, NodeId)>;
31

            
32
// Simple FFI-safe NodeId - just a wrapper around usize
33
pub mod node_id {
34

            
35
    use alloc::vec::Vec;
36
    use core::{
37
        fmt,
38
        ops::{Add, AddAssign},
39
    };
40

            
41
    /// A type-safe identifier for a node within a DOM tree.
42
    ///
43
    /// `NodeId` is FFI-safe (`#[repr(C)]`) and stores a **zero-based** index internally.
44
    /// Use `NodeId::index()` to get the array index for direct node access.
45
    ///
46
    /// # Zero-based indexing
47
    ///
48
    /// - `NodeId::new(0)` → first node (index 0)
49
    /// - `NodeId::new(5)` → sixth node (index 5)
50
    /// - Use `node_id.index()` to get the array index
51
    ///
52
    /// # FFI Encoding (for `Option<NodeId>`)
53
    ///
54
    /// When storing `Option<NodeId>` in FFI structs (like `NodeHierarchyItem`),
55
    /// we use a **1-based encoding** to represent None:
56
    ///
57
    /// - `0` means `None` (no node)
58
    /// - `n > 0` means `Some(NodeId(n - 1))`
59
    ///
60
    /// Use [`NodeId::from_usize`] to decode and [`NodeId::into_raw`] to encode.
61
    /// See also: [`crate::styled_dom::NodeHierarchyItemId`] for the FFI wrapper type.
62
    ///
63
    /// # Warning
64
    ///
65
    /// **Never manually construct raw usize values for node hierarchy fields!**
66
    /// Always use the provided `from_usize`/`into_raw` functions to avoid
67
    /// off-by-one errors that can cause index-out-of-bounds panics.
68
    ///
69
    #[repr(C)]
70
    #[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
71
    pub struct NodeId {
72
        // Private field to prevent direct manipulation.
73
        // Use NodeId::new() to create, NodeId::index() to read.
74
        inner: usize,
75
    }
76

            
77
    impl NodeId {
78
        /// The zero/first node ID (index 0).
79
        pub const ZERO: NodeId = NodeId { inner: 0 };
80

            
81
        /// Creates a new `NodeId` from a zero-based index.
82
        #[inline(always)]
83
1794231
        pub const fn new(value: usize) -> Self {
84
1794231
            NodeId { inner: value }
85
1794231
        }
86

            
87
        /// Decodes a raw `usize` to `Option<NodeId>` using 1-based encoding.
88
        ///
89
        /// This is the inverse of [`NodeId::into_usize`].
90
        ///
91
        /// - `0` → `None` (no node)
92
        /// - `n > 0` → `Some(NodeId(n - 1))`
93
        ///
94
        /// # Warning
95
        ///
96
        /// This function is for decoding values stored in FFI structs like
97
        /// `NodeHierarchyItem`. Do not use raw usize values directly - always
98
        /// decode them first!
99
        #[inline]
100
1600684
        pub const fn from_usize(value: usize) -> Option<Self> {
101
1600684
            match value {
102
727648
                0 => None,
103
873036
                i => Some(NodeId { inner: i - 1 }),
104
            }
105
1600684
        }
106

            
107
        /// Encodes `Option<NodeId>` to a raw `usize` for storage in FFI structs.
108
        ///
109
        /// - `None` → `0`
110
        /// - `Some(NodeId(n))` → `n + 1`
111
        ///
112
        /// The returned value uses **1-based encoding**! A value of `0` means "no node",
113
        /// NOT "node at index 0". Use [`NodeId::from_usize`] to decode.
114
        ///
115
        #[inline]
116
237432
        pub const fn into_raw(val: &Option<Self>) -> usize {
117
237432
            match val {
118
61208
                None => 0,
119
176224
                Some(s) => s.inner + 1,
120
            }
121
237432
        }
122

            
123
        /// Returns the **zero-based** index of this node.
124
        ///
125
        /// This is the actual array index where the node data is stored.
126
        #[inline(always)]
127
15272934
        pub const fn index(&self) -> usize {
128
15272934
            self.inner
129
15272934
        }
130
    }
131

            
132
    impl From<usize> for NodeId {
133
        fn from(val: usize) -> Self {
134
            NodeId::new(val)
135
        }
136
    }
137

            
138
    impl From<NodeId> for usize {
139
        fn from(val: NodeId) -> Self {
140
            val.inner
141
        }
142
    }
143

            
144
    impl Add<usize> for NodeId {
145
        type Output = NodeId;
146
        #[inline(always)]
147
259166
        fn add(self, other: usize) -> NodeId {
148
259166
            NodeId::new(self.inner + other)
149
259166
        }
150
    }
151

            
152
    impl AddAssign<usize> for NodeId {
153
        #[inline(always)]
154
        fn add_assign(&mut self, other: usize) {
155
            *self = *self + other;
156
        }
157
    }
158

            
159
    impl fmt::Display for NodeId {
160
84
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
161
84
            write!(f, "{}", self.inner)
162
84
        }
163
    }
164

            
165
    impl fmt::Debug for NodeId {
166
164011
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
167
164011
            write!(f, "NodeId({})", self.inner)
168
164011
        }
169
    }
170
}
171

            
172
/// Hierarchical information about a node (stores the indices of the parent / child nodes).
173
#[derive(Debug, Default, Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
174
pub struct Node {
175
    pub parent: Option<NodeId>,
176
    pub previous_sibling: Option<NodeId>,
177
    pub next_sibling: Option<NodeId>,
178
    pub last_child: Option<NodeId>,
179
    // NOTE: first_child can be calculated on the fly:
180
    //
181
    //   - if last_child is None, first_child is None
182
    //   - if last_child is Some, first_child is parent_index + 1
183
    //
184
    // This makes the "Node" struct take up 4 registers instead of 5
185
    //
186
    // pub first_child: Option<NodeId>,
187
}
188

            
189
impl Node {
190
    pub const ROOT: Node = Node {
191
        parent: None,
192
        previous_sibling: None,
193
        next_sibling: None,
194
        last_child: None,
195
    };
196

            
197
    #[inline]
198
    pub const fn has_parent(&self) -> bool {
199
        self.parent.is_some()
200
    }
201
    #[inline]
202
    pub const fn has_previous_sibling(&self) -> bool {
203
        self.previous_sibling.is_some()
204
    }
205
    #[inline]
206
    pub const fn has_next_sibling(&self) -> bool {
207
        self.next_sibling.is_some()
208
    }
209
    #[inline]
210
37052
    pub const fn has_first_child(&self) -> bool {
211
37052
        self.last_child.is_some() /* last_child and first_child are always set together */
212
37052
    }
213
    #[inline]
214
    pub const fn has_last_child(&self) -> bool {
215
        self.last_child.is_some()
216
    }
217

            
218
    #[inline]
219
55304
    pub fn get_first_child(&self, current_node_id: NodeId) -> Option<NodeId> {
220
        // last_child and first_child are always set together
221
55304
        self.last_child.map(|_| current_node_id + 1)
222
55304
    }
223
}
224

            
225
/// The hierarchy of nodes is stored separately from the actual node content in order
226
/// to save on memory, since the hierarchy can be re-used across several DOM trees even
227
/// if the content changes.
228
#[derive(Debug, Default, Clone, PartialEq, Hash, Eq, PartialOrd, Ord)]
229
pub struct NodeHierarchy {
230
    pub internal: Vec<Node>,
231
}
232

            
233
impl NodeHierarchy {
234
    #[inline(always)]
235
7
    pub const fn new(data: Vec<Node>) -> Self {
236
7
        Self { internal: data }
237
7
    }
238

            
239
    #[inline(always)]
240
32577
    pub fn as_ref(&self) -> NodeHierarchyRef<'_> {
241
32577
        NodeHierarchyRef {
242
32577
            internal: &self.internal[..],
243
32577
        }
244
32577
    }
245

            
246
}
247

            
248
/// The hierarchy of nodes is stored separately from the actual node content in order
249
/// to save on memory, since the hierarchy can be re-used across several DOM trees even
250
/// if the content changes.
251
#[derive(Debug, PartialEq, Hash, Eq)]
252
pub struct NodeHierarchyRef<'a> {
253
    pub internal: &'a [Node],
254
}
255

            
256
impl<'a> NodeHierarchyRef<'a> {
257
    #[inline(always)]
258
    pub fn from_slice(data: &'a [Node]) -> NodeHierarchyRef<'a> {
259
        NodeHierarchyRef { internal: data }
260
    }
261

            
262
    #[inline(always)]
263
17719
    pub fn len(&self) -> usize {
264
17719
        self.internal.len()
265
17719
    }
266

            
267
    #[inline(always)]
268
153
    pub fn get(&self, id: NodeId) -> Option<&Node> {
269
153
        self.internal.get(id.index())
270
153
    }
271

            
272
    #[inline(always)]
273
68
    pub fn linear_iter(&self) -> LinearIterator {
274
68
        LinearIterator {
275
68
            arena_len: self.len(),
276
68
            position: 0,
277
68
        }
278
68
    }
279

            
280
    /// Returns the `(depth, NodeId)` of all parent nodes (i.e. nodes that have a
281
    /// `first_child`), in depth sorted order, (i.e. `NodeId(0)` with a depth of 0) is
282
    /// the first element.
283
    ///
284
    /// Runtime: O(n) max
285
8970
    pub fn get_parents_sorted_by_depth(&self) -> NodeDepths {
286
8970
        let mut non_leaf_nodes = Vec::new();
287
8970
        let mut current_children = vec![(0, NodeId::new(0))];
288
8970
        let mut next_children = Vec::new();
289
8970
        let mut depth = 1_usize;
290

            
291
        loop {
292
50154
            for id in &current_children {
293
37052
                for child_id in id.1.children(self).filter(|id| self[*id].has_first_child()) {
294
18682
                    next_children.push((depth, child_id));
295
18682
                }
296
            }
297

            
298
22502
            non_leaf_nodes.extend(&mut current_children.drain(..));
299

            
300
22502
            if next_children.is_empty() {
301
8970
                break;
302
13532
            } else {
303
13532
                current_children.extend(&mut next_children.drain(..));
304
13532
                depth += 1;
305
13532
            }
306
        }
307

            
308
8970
        non_leaf_nodes
309
8970
    }
310

            
311
}
312

            
313
#[derive(Debug, Clone, PartialEq, Hash, Eq, PartialOrd, Ord)]
314
pub struct NodeDataContainer<T> {
315
    pub internal: Vec<T>,
316
}
317

            
318
impl<T> From<Vec<T>> for NodeDataContainer<T> {
319
    fn from(v: Vec<T>) -> NodeDataContainer<T> {
320
        NodeDataContainer { internal: v }
321
    }
322
}
323

            
324
#[derive(Debug, PartialEq, Hash, Eq, PartialOrd, Ord)]
325
pub struct NodeDataContainerRef<'a, T> {
326
    pub internal: &'a [T],
327
}
328

            
329
#[derive(Debug, PartialEq, Hash, Eq, PartialOrd, Ord)]
330
pub struct NodeDataContainerRefMut<'a, T> {
331
    pub internal: &'a mut [T],
332
}
333

            
334
impl<T> Default for NodeDataContainer<T> {
335
    fn default() -> Self {
336
        Self {
337
            internal: Vec::new(),
338
        }
339
    }
340
}
341

            
342
impl<'a> Index<NodeId> for NodeHierarchyRef<'a> {
343
    type Output = Node;
344

            
345
    #[inline(always)]
346
256480
    fn index(&self, node_id: NodeId) -> &Node {
347
256480
        &self.internal[node_id.index()]
348
256480
    }
349
}
350

            
351
impl<T> NodeDataContainer<T> {
352
    #[inline(always)]
353
    pub const fn new(data: Vec<T>) -> Self {
354
        Self { internal: data }
355
    }
356

            
357
    #[inline(always)]
358
    pub fn is_empty(&self) -> bool {
359
        self.internal.is_empty()
360
    }
361

            
362
    #[inline(always)]
363
69499
    pub fn as_ref(&self) -> NodeDataContainerRef<'_, T> {
364
69499
        NodeDataContainerRef {
365
69499
            internal: &self.internal[..],
366
69499
        }
367
69499
    }
368

            
369
    #[inline(always)]
370
    pub fn as_ref_mut(&mut self) -> NodeDataContainerRefMut<'_, T> {
371
        NodeDataContainerRefMut {
372
            internal: &mut self.internal[..],
373
        }
374
    }
375

            
376
    #[inline(always)]
377
8681
    pub fn len(&self) -> usize {
378
8681
        self.internal.len()
379
8681
    }
380
}
381

            
382
impl<'a, T: 'a> NodeDataContainerRefMut<'a, T> {
383
    #[inline(always)]
384
    pub fn from_slice(data: &'a mut [T]) -> NodeDataContainerRefMut<'a, T> {
385
        NodeDataContainerRefMut { internal: data }
386
    }
387
}
388

            
389
impl<'a, T: 'a> NodeDataContainerRefMut<'a, T> {
390
    #[inline(always)]
391
    pub fn get_mut(&mut self, id: NodeId) -> Option<&mut T> {
392
        self.internal.get_mut(id.index())
393
    }
394
}
395

            
396
impl<'a, T: Send + 'a> NodeDataContainerRef<'a, T> {
397
5400
    pub fn transform_nodeid_optional<U: Send, F: Send + Sync>(
398
5400
        &self,
399
5400
        closure: F,
400
5400
    ) -> NodeDataContainer<U>
401
5400
    where
402
5400
        F: Fn(NodeId) -> Option<U>,
403
    {
404
5400
        let len = self.len();
405
        NodeDataContainer {
406
5400
            internal: (0..len)
407
25635
                .filter_map(|node_id| closure(NodeId::new(node_id)))
408
5400
                .collect::<Vec<U>>(),
409
        }
410
5400
    }
411
}
412

            
413
impl<'a, T: 'a> NodeDataContainerRef<'a, T> {
414
    #[inline(always)]
415
    pub fn from_slice(data: &'a [T]) -> NodeDataContainerRef<'a, T> {
416
        NodeDataContainerRef { internal: data }
417
    }
418

            
419
    #[inline(always)]
420
5432
    pub fn len(&self) -> usize {
421
5432
        self.internal.len()
422
5432
    }
423

            
424
    #[inline(always)]
425
1190527
    pub fn get(&self, id: NodeId) -> Option<&T> {
426
1190527
        self.internal.get(id.index())
427
1190527
    }
428

            
429
    #[inline(always)]
430
    pub fn iter(&self) -> Iter<T> {
431
        self.internal.iter()
432
    }
433

            
434
    #[inline(always)]
435
    pub fn linear_iter(&self) -> LinearIterator {
436
        LinearIterator {
437
            arena_len: self.len(),
438
            position: 0,
439
        }
440
    }
441
}
442

            
443
impl<'a, T> Index<NodeId> for NodeDataContainerRef<'a, T> {
444
    type Output = T;
445

            
446
    #[inline(always)]
447
3342441
    fn index(&self, node_id: NodeId) -> &T {
448
3342441
        &self.internal[node_id.index()]
449
3342441
    }
450
}
451

            
452
impl<'a, T> Index<NodeId> for NodeDataContainerRefMut<'a, T> {
453
    type Output = T;
454

            
455
    #[inline(always)]
456
136
    fn index(&self, node_id: NodeId) -> &T {
457
136
        &self.internal[node_id.index()]
458
136
    }
459
}
460

            
461
impl<'a, T> IndexMut<NodeId> for NodeDataContainerRefMut<'a, T> {
462
    #[inline(always)]
463
1173
    fn index_mut(&mut self, node_id: NodeId) -> &mut T {
464
1173
        &mut self.internal[node_id.index()]
465
1173
    }
466
}
467

            
468
impl NodeId {
469
    /// Return an iterator of references to this node and the siblings before it.
470
    ///
471
    /// Call `.next().unwrap()` once on the iterator to skip the node itself.
472
    #[inline]
473
27652
    pub const fn preceding_siblings<'a>(
474
27652
        self,
475
27652
        node_hierarchy: &'a NodeHierarchyRef<'a>,
476
27652
    ) -> PrecedingSiblings<'a> {
477
27652
        PrecedingSiblings {
478
27652
            node_hierarchy,
479
27652
            node: Some(self),
480
27652
        }
481
27652
    }
482

            
483
    /// Return an iterator of references to this node's children.
484
    #[inline]
485
55304
    pub fn children<'a>(self, node_hierarchy: &'a NodeHierarchyRef<'a>) -> Children<'a> {
486
55304
        Children {
487
55304
            node_hierarchy,
488
55304
            node: node_hierarchy[self].get_first_child(self),
489
55304
        }
490
55304
    }
491
}
492

            
493
macro_rules! impl_node_iterator {
494
    ($name:ident, $next:expr) => {
495
        impl<'a> Iterator for $name<'a> {
496
            type Item = NodeId;
497

            
498
190165
            fn next(&mut self) -> Option<NodeId> {
499
190165
                match self.node.take() {
500
107209
                    Some(node) => {
501
107209
                        self.node = $next(&self.node_hierarchy[node]);
502
107209
                        Some(node)
503
                    }
504
82956
                    None => None,
505
                }
506
190165
            }
507
        }
508
    };
509
}
510

            
511
/// An linear iterator, does not respect the DOM in any way,
512
/// it just iterates over the nodes like a Vec
513
#[derive(Debug, Copy, Clone)]
514
pub struct LinearIterator {
515
    arena_len: usize,
516
    position: usize,
517
}
518

            
519
impl Iterator for LinearIterator {
520
    type Item = NodeId;
521

            
522
272
    fn next(&mut self) -> Option<NodeId> {
523
272
        if self.arena_len < 1 || self.position > (self.arena_len - 1) {
524
68
            None
525
        } else {
526
204
            let new_id = Some(NodeId::new(self.position));
527
204
            self.position += 1;
528
204
            new_id
529
        }
530
272
    }
531
}
532

            
533
/// An iterator of references to the siblings before a given node.
534
pub struct PrecedingSiblings<'a> {
535
    node_hierarchy: &'a NodeHierarchyRef<'a>,
536
    node: Option<NodeId>,
537
}
538

            
539
impl_node_iterator!(PrecedingSiblings, |node: &Node| node.previous_sibling);
540

            
541
/// Special iterator for using NodeDataContainerRef<AzNode> instead of NodeHierarchy
542
pub struct AzChildren<'a> {
543
    node_hierarchy: &'a NodeDataContainerRef<'a, NodeHierarchyItem>,
544
    node: Option<NodeId>,
545
}
546

            
547
impl<'a> Iterator for AzChildren<'a> {
548
    type Item = NodeId;
549

            
550
161688
    fn next(&mut self) -> Option<NodeId> {
551
161688
        match self.node.take() {
552
76430
            Some(node) => {
553
76430
                self.node = self.node_hierarchy[node].next_sibling_id();
554
76430
                Some(node)
555
            }
556
85258
            None => None,
557
        }
558
161688
    }
559
}
560

            
561
/// Special iterator for using NodeDataContainerRef<AzNode> instead of NodeHierarchy
562
pub struct AzReverseChildren<'a> {
563
    node_hierarchy: &'a NodeDataContainerRef<'a, NodeHierarchyItem>,
564
    node: Option<NodeId>,
565
}
566

            
567
impl<'a> Iterator for AzReverseChildren<'a> {
568
    type Item = NodeId;
569

            
570
    fn next(&mut self) -> Option<NodeId> {
571
        match self.node.take() {
572
            Some(node) => {
573
                self.node = self.node_hierarchy[node].previous_sibling_id();
574
                Some(node)
575
            }
576
            None => None,
577
        }
578
    }
579
}
580

            
581
impl NodeId {
582
    /// Traverse up through the hierarchy until a node matching the predicate is found.
583
    ///
584
    /// Necessary to resolve the last positioned (= relative)
585
    /// element of an absolute node.
586
    pub fn get_nearest_matching_parent<'a, F>(
587
        self,
588
        node_hierarchy: &'a NodeDataContainerRef<'a, NodeHierarchyItem>,
589
        predicate: F,
590
    ) -> Option<NodeId>
591
    where
592
        F: Fn(NodeId) -> bool,
593
    {
594
        let mut current_node = node_hierarchy[self].parent_id()?;
595
        loop {
596
            match predicate(current_node) {
597
                true => {
598
                    return Some(current_node);
599
                }
600
                false => {
601
                    current_node = node_hierarchy[current_node].parent_id()?;
602
                }
603
            }
604
        }
605
    }
606

            
607
    /// Return the children of this node (necessary for parallel iteration over children)
608
    #[inline]
609
    pub fn az_children_collect<'a>(
610
        self,
611
        node_hierarchy: &'a NodeDataContainerRef<'a, NodeHierarchyItem>,
612
    ) -> Vec<NodeId> {
613
        self.az_children(node_hierarchy).collect()
614
    }
615

            
616
    /// Return an iterator of references to this node's children.
617
    #[inline]
618
93994
    pub fn az_children<'a>(
619
93994
        self,
620
93994
        node_hierarchy: &'a NodeDataContainerRef<'a, NodeHierarchyItem>,
621
93994
    ) -> AzChildren<'a> {
622
93994
        AzChildren {
623
93994
            node_hierarchy,
624
93994
            node: node_hierarchy[self].first_child_id(self),
625
93994
        }
626
93994
    }
627

            
628
    /// Return an iterator of references to this node's children.
629
    #[inline]
630
    pub fn az_reverse_children<'a>(
631
        self,
632
        node_hierarchy: &'a NodeDataContainerRef<'a, NodeHierarchyItem>,
633
    ) -> AzReverseChildren<'a> {
634
        AzReverseChildren {
635
            node_hierarchy,
636
            node: node_hierarchy[self].last_child_id(),
637
        }
638
    }
639
}
640

            
641
/// An iterator of references to the children of a given node.
642
pub struct Children<'a> {
643
    node_hierarchy: &'a NodeHierarchyRef<'a>,
644
    node: Option<NodeId>,
645
}
646

            
647
impl_node_iterator!(Children, |node: &Node| node.next_sibling);