tawasuyu

tawasuyu/taffy

A high performance rust-powered UI layout library

HTML 231Rust 9TOML 3CSS 1345 Definiciones

Return iterator for children for `LayoutTree` (#260)

* Return iterator for children for `LayoutTree`

* Implement review changes

* Fix clippy warnings

* Add entry to RELEASES.md for LayoutTree changes

* 0.3 should be called out as unreleased

* Line break after heading

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>

af3bc5340e223b969155ffbd350d56084973b20e · por George Atkinson · (hace 3 años) · padre 2f7843698 · ver el árbol en este commit

Delta semántico · 14

src/compute/flexbox.rs

src/compute/mod.rs

src/node.rs

src/tree.rs

5 archivos · +51 −25

diff --git a/RELEASES.md b/RELEASES.md
index df4e77468..739c9cd4b 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,5 +1,16 @@
 # Release Notes
 
+## 0.3.0 (Unreleased)
+
+### Breaking API changes
+
+#### Changes to `LayoutTree`
+
+- Added generic associated type to `LayoutTree` for a `ChildIter`, an iterator on the children of a given node.
+- Changed the `children` method of `LayoutTree` to return the `ChildIter` generic associated type to allow for custom tree storage implementations which do not store the children of a node contiguously.
+- Added `child_count`  method to `LayoutTree` for querying the number of children of a node. Required because the `children` method now returns an iterator instead of an array.
+- Added `is_childless` method to `LayoutTree` for querying whether a node has no children.
+
 ## 0.2.0
 
 ### New features
diff --git a/src/compute/flexbox.rs b/src/compute/flexbox.rs
index f4bcdde79..a418fb444 100644
--- a/src/compute/flexbox.rs
+++ b/src/compute/flexbox.rs
@@ -332,7 +332,7 @@ fn compute_preliminary(
 
     #[cfg(feature = "debug")]
     NODE_LOGGER.log("hidden_layout");
-    let len = tree.children(node).len();
+    let len = tree.child_count(node);
     for order in 0..len {
         let child = tree.child(node, order);
         if tree.style(child).display == Display::None {
@@ -395,7 +395,6 @@ fn compute_constants(style: &Style, node_size: Size<Option<f32>>, parent_size: S
 #[inline]
 fn generate_anonymous_flex_items(tree: &impl LayoutTree, node: Node, constants: &AlgoConstants) -> Vec<FlexItem> {
     tree.children(node)
-        .iter()
         .map(|child| (child, tree.style(*child)))
         .filter(|(_, style)| style.position_type != PositionType::Absolute)
         .filter(|(_, style)| style.display != Display::None)
@@ -974,20 +973,12 @@ fn calculate_children_base_lines(
 ) {
     /// Recursively calculates the baseline for children
     fn calc_baseline(db: &impl LayoutTree, node: Node, layout: &Layout) -> f32 {
-        let children = db.children(node);
-        if children.is_empty() {
-            layout.size.height
+        if let Some(first_child) = db.children(node).next() {
+            let layout = db.layout(*first_child);
+            calc_baseline(db, *first_child, layout)
         } else {
-            let child = children[0];
-            let layout = db.layout(child);
-            calc_baseline(db, child, layout)
+            layout.size.height
         }
-        // if db.children[node].is_empty() {
-        //     layout.size.height
-        // } else {
-        //     let child = db.children[node][0];
-        //     calc_baseline(db, child, &db.nodes[child].layout)
-        // }
     }
 
     for line in flex_lines {
@@ -1027,7 +1018,7 @@ fn calculate_children_base_lines(
                 tree,
                 child.node,
                 &Layout {
-                    order: tree.children(node).iter().position(|n| *n == child.node).unwrap() as u32,
+                    order: tree.children(node).position(|n| *n == child.node).unwrap() as u32,
                     size: preliminary_size,
                     location: Point::ZERO,
                 },
@@ -1579,8 +1570,10 @@ fn calculate_flex_item(
         + item.margin.cross_start(direction)
         + (item.position.cross_start(direction).unwrap_or(0.0) - item.position.cross_end(direction).unwrap_or(0.0));
 
+    let order = tree.children(node).position(|n| *n == item.node).unwrap() as u32;
+
     *tree.layout_mut(item.node) = Layout {
-        order: tree.children(node).iter().position(|n| *n == item.node).unwrap() as u32,
+        order,
         size: preliminary_size,
         location: Point {
             x: if direction.is_row() { offset_main } else { offset_cross },
@@ -1673,7 +1666,6 @@ fn perform_absolute_layout_on_absolute_children(tree: &mut impl LayoutTree, node
     // TODO: remove number of Vec<_> generated
     let candidates = tree
         .children(node)
-        .iter()
         .cloned()
         .enumerate()
         .filter(|(_, child)| tree.style(*child).position_type == PositionType::Absolute)
@@ -1829,7 +1821,7 @@ fn perform_absolute_layout_on_absolute_children(tree: &mut impl LayoutTree, node
 fn hidden_layout(tree: &mut impl LayoutTree, node: Node, order: u32) {
     *tree.layout_mut(node) = Layout::with_order(order);
 
-    let len = tree.children(node).len();
+    let len = tree.child_count(node);
     for order in 0..len {
         hidden_layout(tree, tree.child(node, order), order as _);
     }
diff --git a/src/compute/mod.rs b/src/compute/mod.rs
index dc1a0d9e7..bc6bbc39b 100644
--- a/src/compute/mod.rs
+++ b/src/compute/mod.rs
@@ -48,7 +48,7 @@ fn compute_node_layout(
     println!();
 
     // First we check if we have a cached result for the given input
-    let cache_run_mode = if tree.children(node).is_empty() { RunMode::PeformLayout } else { run_mode };
+    let cache_run_mode = if tree.is_childless(node) { RunMode::PeformLayout } else { run_mode };
     if let Some(cached_size) =
         compute_from_cache(tree, node, known_dimensions, available_space, cache_run_mode, sizing_mode)
     {
@@ -103,7 +103,7 @@ fn compute_node_layout(
     // }
 
     // If this is a leaf node we can skip a lot of this function in some cases
-    let computed_size = if tree.children(node).is_empty() {
+    let computed_size = if tree.is_childless(node) {
         #[cfg(feature = "debug")]
         NODE_LOGGER.log("Algo: leaf");
         self::leaf::compute(tree, node, known_dimensions, available_space, run_mode, sizing_mode)
@@ -196,7 +196,7 @@ fn round_layout(tree: &mut impl LayoutTree, root: Node, abs_x: f32, abs_y: f32)
     layout.size.height = round(layout.size.height);
 
     // Satisfy the borrow checker here by re-indexing to shorten the lifetime to the loop scope
-    for x in 0..tree.children(root).len() {
+    for x in 0..tree.child_count(root) {
         let child = tree.child(root, x);
         round_layout(tree, child, abs_x, abs_y);
     }
diff --git a/src/node.rs b/src/node.rs
index 9ad53f588..a280b366f 100644
--- a/src/node.rs
+++ b/src/node.rs
@@ -1,7 +1,7 @@
 //! UI [`Node`] types and related data structures.
 //!
 //! Layouts are composed of multiple nodes, which live in a tree-like data structure.
-use slotmap::{SlotMap, SparseSecondaryMap};
+use slotmap::{DefaultKey, SlotMap, SparseSecondaryMap};
 
 /// A node in a layout.
 pub type Node = slotmap::DefaultKey;
@@ -58,8 +58,18 @@ impl Default for Taffy {
 }
 
 impl LayoutTree for Taffy {
-    fn children(&self, node: Node) -> &[Node] {
-        &self.children[node]
+    type ChildIter<'a> = std::slice::Iter<'a, DefaultKey>;
+
+    fn children(&self, node: Node) -> Self::ChildIter<'_> {
+        self.children[node].iter()
+    }
+
+    fn child_count(&self, node: Node) -> usize {
+        self.children[node].len()
+    }
+
+    fn is_childless(&self, node: Node) -> bool {
+        self.children[node].is_empty()
     }
 
     fn parent(&self, node: Node) -> Option<Node> {
diff --git a/src/tree.rs b/src/tree.rs
index ddd05b965..ca6248048 100644
--- a/src/tree.rs
+++ b/src/tree.rs
@@ -1,5 +1,7 @@
 //! The baseline requirements of any UI Tree so Taffy can efficiently calculate the layout
 
+use slotmap::DefaultKey;
+
 use crate::{
     error::TaffyResult,
     layout::{AvailableSpace, Cache, Layout},
@@ -11,8 +13,19 @@ use crate::{
 /// Generally, Taffy expects your Node tree to be indexable by stable indices. A "stable" index means that the Node's ID
 /// remains the same between re-layouts.
 pub trait LayoutTree {
+    /// Type representing an iterator of the children of a node
+    type ChildIter<'a>: Iterator<Item = &'a DefaultKey>
+    where
+        Self: 'a;
+
     /// Get the list of children IDs for the given node
-    fn children(&self, node: Node) -> &[Node];
+    fn children(&self, node: Node) -> Self::ChildIter<'_>;
+
+    /// Get the number of children for the given node
+    fn child_count(&self, node: Node) -> usize;
+
+    /// Returns true if the node has no children
+    fn is_childless(&self, node: Node) -> bool;
 
     /// Get a specific child of a node, where the index represents the nth child
     fn child(&self, node: Node, index: usize) -> Node;