gioser

tawasuyu/taffy

A high performance rust-powered UI layout library

Rust 1111HTML 1039Markdown 12TOML 94524 Sutichaykuna

⎇ 23ff477566b0239f04d3b89a2b3a4da2495e9577 src/tree/taffy_tree/tree.rs Rust · 927 siq'ikuna · 33.1 KB Ñawpa willay Pi imata llamkarqan ch'uya

Remove `LayoutAlgorithm` trait (#562) daa07e0f4 · Nico Burns ·

1//! UI node types and related data structures.
2//!
3//! Layouts are composed of multiple nodes, which live in a tree-like data structure.
4use slotmap::{DefaultKey, SlotMap, SparseSecondaryMap};
5
6use crate::compute::taffy_tree::{compute_layout, compute_node_layout};
7use crate::geometry::{Line, Size};
8use crate::prelude::LayoutTree;
9use crate::style::{AvailableSpace, Style};
10use crate::tree::{Layout, LayoutInput, LayoutOutput, NodeData, NodeId, RunMode, SizingMode};
11use crate::util::sys::{new_vec_with_capacity, ChildrenVec, Vec};
12
13use super::{TaffyError, TaffyResult};
14
15/// Global configuration values for a Taffy instance
16pub(crate) struct TaffyConfig {
17    /// Whether to round layout values
18    pub(crate) use_rounding: bool,
19}
20
21impl Default for TaffyConfig {
22    fn default() -> Self {
23        Self { use_rounding: true }
24    }
25}
26
27/// A tree of UI nodes suitable for UI layout
28pub struct Taffy<NodeContext = ()> {
29    /// The [`NodeData`] for each node stored in this tree
30    pub(crate) nodes: SlotMap<DefaultKey, NodeData>,
31
32    /// Functions/closures that compute the intrinsic size of leaf nodes
33    pub(crate) node_context_data: SparseSecondaryMap<DefaultKey, NodeContext>,
34
35    /// The children of each node
36    ///
37    /// The indexes in the outer vector correspond to the position of the parent [`NodeData`]
38    pub(crate) children: SlotMap<DefaultKey, ChildrenVec<NodeId>>,
39
40    /// The parents of each node
41    ///
42    /// The indexes in the outer vector correspond to the position of the child [`NodeData`]
43    pub(crate) parents: SlotMap<DefaultKey, Option<NodeId>>,
44
45    /// Layout mode configuration
46    pub(crate) config: TaffyConfig,
47}
48
49impl Default for Taffy {
50    fn default() -> Taffy<()> {
51        Taffy::new()
52    }
53}
54
55/// Iterator that wraps a slice of nodes, lazily converting them to u64
56pub struct TaffyChildIter<'a>(core::slice::Iter<'a, NodeId>);
57impl<'a> Iterator for TaffyChildIter<'a> {
58    type Item = NodeId;
59
60    fn next(&mut self) -> Option<Self::Item> {
61        self.0.next().copied()
62    }
63}
64
65/// View over the Taffy tree that holds the tree itself along with a reference to the context
66/// and implements LayoutTree. This allows the context to be stored outside of the Taffy struct
67/// which makes the lifetimes of the context much more flexible.
68pub struct TaffyView<'t, NodeContext, MeasureFunction>
69where
70    MeasureFunction: FnMut(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&mut NodeContext>) -> Size<f32>,
71{
72    /// A reference to the Taffy tree
73    pub(crate) taffy: &'t mut Taffy<NodeContext>,
74    /// The context provided for passing to measure functions if layout is run over this struct
75    pub(crate) measure_function: MeasureFunction,
76}
77
78impl<'t, NodeContext, MeasureFunction> LayoutTree for TaffyView<'t, NodeContext, MeasureFunction>
79where
80    MeasureFunction: FnMut(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&mut NodeContext>) -> Size<f32>,
81{
82    type ChildIter<'a> = TaffyChildIter<'a> where Self: 'a;
83
84    #[inline(always)]
85    fn children(&self, node: NodeId) -> Self::ChildIter<'_> {
86        TaffyChildIter(self.taffy.children[node.into()].iter())
87    }
88
89    #[inline(always)]
90    fn child_count(&self, node: NodeId) -> usize {
91        self.taffy.children[node.into()].len()
92    }
93
94    #[inline(always)]
95    fn style(&self, node: NodeId) -> &Style {
96        &self.taffy.nodes[node.into()].style
97    }
98
99    #[inline(always)]
100    fn layout(&self, node: NodeId) -> &Layout {
101        if self.taffy.config.use_rounding {
102            &self.taffy.nodes[node.into()].unrounded_layout
103        } else {
104            &self.taffy.nodes[node.into()].final_layout
105        }
106    }
107
108    #[inline(always)]
109    fn layout_mut(&mut self, node: NodeId) -> &mut Layout {
110        if self.taffy.config.use_rounding {
111            &mut self.taffy.nodes[node.into()].unrounded_layout
112        } else {
113            &mut self.taffy.nodes[node.into()].final_layout
114        }
115    }
116
117    #[inline(always)]
118    fn child(&self, node: NodeId, id: usize) -> NodeId {
119        self.taffy.children[node.into()][id]
120    }
121
122    #[inline(always)]
123    fn measure_child_size(
124        &mut self,
125        node: NodeId,
126        known_dimensions: Size<Option<f32>>,
127        parent_size: Size<Option<f32>>,
128        available_space: Size<AvailableSpace>,
129        sizing_mode: SizingMode,
130        vertical_margins_are_collapsible: Line<bool>,
131    ) -> Size<f32> {
132        compute_node_layout(
133            self,
134            node,
135            LayoutInput {
136                known_dimensions,
137                parent_size,
138                available_space,
139                sizing_mode,
140                run_mode: RunMode::ComputeSize,
141                vertical_margins_are_collapsible,
142            },
143        )
144        .size
145    }
146
147    #[inline(always)]
148    fn perform_child_layout(
149        &mut self,
150        node: NodeId,
151        known_dimensions: Size<Option<f32>>,
152        parent_size: Size<Option<f32>>,
153        available_space: Size<AvailableSpace>,
154        sizing_mode: SizingMode,
155        vertical_margins_are_collapsible: Line<bool>,
156    ) -> LayoutOutput {
157        compute_node_layout(
158            self,
159            node,
160            LayoutInput {
161                known_dimensions,
162                parent_size,
163                available_space,
164                sizing_mode,
165                run_mode: RunMode::PerformLayout,
166                vertical_margins_are_collapsible,
167            },
168        )
169    }
170}
171
172#[allow(clippy::iter_cloned_collect)] // due to no-std support, we need to use `iter_cloned` instead of `collect`
173impl<NodeContext> Taffy<NodeContext> {
174    /// Creates a new [`Taffy`]
175    ///
176    /// The default capacity of a [`Taffy`] is 16 nodes.
177    #[must_use]
178    pub fn new() -> Self {
179        Self::with_capacity(16)
180    }
181
182    /// Creates a new [`Taffy`] that can store `capacity` nodes before reallocation
183    #[must_use]
184    pub fn with_capacity(capacity: usize) -> Self {
185        Taffy {
186            // TODO: make this method const upstream,
187            // so constructors here can be const
188            nodes: SlotMap::with_capacity(capacity),
189            children: SlotMap::with_capacity(capacity),
190            parents: SlotMap::with_capacity(capacity),
191            node_context_data: SparseSecondaryMap::with_capacity(capacity),
192            config: TaffyConfig::default(),
193        }
194    }
195
196    /// Enable rounding of layout values. Rounding is enabled by default.
197    pub fn enable_rounding(&mut self) {
198        self.config.use_rounding = true;
199    }
200
201    /// Disable rounding of layout values. Rounding is enabled by default.
202    pub fn disable_rounding(&mut self) {
203        self.config.use_rounding = false;
204    }
205
206    /// Creates and adds a new unattached leaf node to the tree, and returns the node of the new node
207    pub fn new_leaf(&mut self, layout: Style) -> TaffyResult<NodeId> {
208        let id = self.nodes.insert(NodeData::new(layout));
209        let _ = self.children.insert(new_vec_with_capacity(0));
210        let _ = self.parents.insert(None);
211
212        Ok(id.into())
213    }
214
215    /// Creates and adds a new unattached leaf node to the tree, and returns the [`NodeId`] of the new node
216    ///
217    /// Creates and adds a new leaf node with a supplied context
218    pub fn new_leaf_with_context(&mut self, layout: Style, context: NodeContext) -> TaffyResult<NodeId> {
219        let mut data = NodeData::new(layout);
220        data.needs_measure = true;
221
222        let id = self.nodes.insert(data);
223        self.node_context_data.insert(id, context);
224
225        let _ = self.children.insert(new_vec_with_capacity(0));
226        let _ = self.parents.insert(None);
227
228        Ok(id.into())
229    }
230
231    /// Creates and adds a new node, which may have any number of `children`
232    pub fn new_with_children(&mut self, layout: Style, children: &[NodeId]) -> TaffyResult<NodeId> {
233        let id = NodeId::from(self.nodes.insert(NodeData::new(layout)));
234
235        for child in children {
236            self.parents[(*child).into()] = Some(id);
237        }
238
239        let _ = self.children.insert(children.iter().copied().collect::<_>());
240        let _ = self.parents.insert(None);
241
242        Ok(id)
243    }
244
245    /// Drops all nodes in the tree
246    pub fn clear(&mut self) {
247        self.nodes.clear();
248        self.children.clear();
249        self.parents.clear();
250    }
251
252    /// Remove a specific node from the tree and drop it
253    ///
254    /// Returns the id of the node removed.
255    pub fn remove(&mut self, node: NodeId) -> TaffyResult<NodeId> {
256        let key = node.into();
257        if let Some(parent) = self.parents[key] {
258            if let Some(children) = self.children.get_mut(parent.into()) {
259                children.retain(|f| *f != node);
260            }
261        }
262
263        // Remove "parent" references to a node when removing that node
264        if let Some(children) = self.children.get(key) {
265            for child in children.iter().copied() {
266                self.parents[child.into()] = None;
267            }
268        }
269
270        let _ = self.children.remove(key);
271        let _ = self.parents.remove(key);
272        let _ = self.nodes.remove(key);
273
274        Ok(node)
275    }
276
277    /// Sets the context data associated with the node
278    pub fn set_node_context(&mut self, node: NodeId, measure: Option<NodeContext>) -> TaffyResult<()> {
279        let key = node.into();
280        if let Some(measure) = measure {
281            self.nodes[key].needs_measure = true;
282            self.node_context_data.insert(key, measure);
283        } else {
284            self.nodes[key].needs_measure = false;
285            self.node_context_data.remove(key);
286        }
287
288        self.mark_dirty(node)?;
289
290        Ok(())
291    }
292
293    /// Get's a mutable reference to the the context data associated with the node
294    pub fn get_node_context_mut(&mut self, node: NodeId) -> Option<&mut NodeContext> {
295        self.node_context_data.get_mut(node.into())
296    }
297
298    /// Adds a `child` node under the supplied `parent`
299    pub fn add_child(&mut self, parent: NodeId, child: NodeId) -> TaffyResult<()> {
300        let parent_key = parent.into();
301        let child_key = child.into();
302        self.parents[child_key] = Some(parent);
303        self.children[parent_key].push(child);
304        self.mark_dirty(parent)?;
305
306        Ok(())
307    }
308
309    /// Inserts a `child` node at the given `child_index` under the supplied `parent`, shifting all children after it to the right.
310    pub fn insert_child_at_index(&mut self, parent: NodeId, child_index: usize, child: NodeId) -> TaffyResult<()> {
311        let parent_key = parent.into();
312
313        let child_count = self.children[parent_key].len();
314        if child_index > child_count {
315            return Err(TaffyError::ChildIndexOutOfBounds { parent, child_index, child_count });
316        }
317
318        self.parents[child.into()] = Some(parent);
319        self.children[parent_key].insert(child_index, child);
320        self.mark_dirty(parent)?;
321
322        Ok(())
323    }
324
325    /// Directly sets the `children` of the supplied `parent`
326    pub fn set_children(&mut self, parent: NodeId, children: &[NodeId]) -> TaffyResult<()> {
327        let parent_key = parent.into();
328
329        // Remove node as parent from all its current children.
330        for child in &self.children[parent_key] {
331            self.parents[(*child).into()] = None;
332        }
333
334        // Build up relation node <-> child
335        for child in children {
336            self.parents[(*child).into()] = Some(parent);
337        }
338
339        let parent_children = &mut self.children[parent_key];
340        parent_children.clear();
341        children.iter().for_each(|child| parent_children.push(*child));
342
343        self.mark_dirty(parent)?;
344
345        Ok(())
346    }
347
348    /// Removes the `child` of the parent `node`
349    ///
350    /// The child is not removed from the tree entirely, it is simply no longer attached to its previous parent.
351    pub fn remove_child(&mut self, parent: NodeId, child: NodeId) -> TaffyResult<NodeId> {
352        let index = self.children[parent.into()].iter().position(|n| *n == child).unwrap();
353        self.remove_child_at_index(parent, index)
354    }
355
356    /// Removes the child at the given `index` from the `parent`
357    ///
358    /// The child is not removed from the tree entirely, it is simply no longer attached to its previous parent.
359    pub fn remove_child_at_index(&mut self, parent: NodeId, child_index: usize) -> TaffyResult<NodeId> {
360        let parent_key = parent.into();
361        let child_count = self.children[parent_key].len();
362        if child_index >= child_count {
363            return Err(TaffyError::ChildIndexOutOfBounds { parent, child_index, child_count });
364        }
365
366        let child = self.children[parent_key].remove(child_index);
367        self.parents[child.into()] = None;
368
369        self.mark_dirty(parent)?;
370
371        Ok(child)
372    }
373
374    /// Replaces the child at the given `child_index` from the `parent` node with the new `child` node
375    ///
376    /// The child is not removed from the tree entirely, it is simply no longer attached to its previous parent.
377    pub fn replace_child_at_index(
378        &mut self,
379        parent: NodeId,
380        child_index: usize,
381        new_child: NodeId,
382    ) -> TaffyResult<NodeId> {
383        let parent_key = parent.into();
384
385        let child_count = self.children[parent_key].len();
386        if child_index >= child_count {
387            return Err(TaffyError::ChildIndexOutOfBounds { parent, child_index, child_count });
388        }
389
390        self.parents[new_child.into()] = Some(parent);
391        let old_child = core::mem::replace(&mut self.children[parent_key][child_index], new_child);
392        self.parents[old_child.into()] = None;
393
394        self.mark_dirty(parent)?;
395
396        Ok(old_child)
397    }
398
399    /// Returns the child node of the parent `node` at the provided `child_index`
400    pub fn child_at_index(&self, parent: NodeId, child_index: usize) -> TaffyResult<NodeId> {
401        let parent_key = parent.into();
402        let child_count = self.children[parent_key].len();
403        if child_index >= child_count {
404            return Err(TaffyError::ChildIndexOutOfBounds { parent, child_index, child_count });
405        }
406
407        Ok(self.children[parent_key][child_index])
408    }
409
410    /// Returns the total number of nodes in the tree
411    pub fn total_node_count(&self) -> usize {
412        self.nodes.len()
413    }
414
415    /// Returns the number of children of the `parent` node
416    pub fn child_count(&self, parent: NodeId) -> TaffyResult<usize> {
417        Ok(self.children[parent.into()].len())
418    }
419
420    /// Returns a list of children that belong to the parent node
421    pub fn children(&self, parent: NodeId) -> TaffyResult<Vec<NodeId>> {
422        Ok(self.children[parent.into()].iter().copied().collect::<_>())
423    }
424
425    /// Sets the [`Style`] of the provided `node`
426    pub fn set_style(&mut self, node: NodeId, style: Style) -> TaffyResult<()> {
427        self.nodes[node.into()].style = style;
428        self.mark_dirty(node)?;
429        Ok(())
430    }
431
432    /// Gets the [`Style`] of the provided `node`
433    pub fn style(&self, node: NodeId) -> TaffyResult<&Style> {
434        Ok(&self.nodes[node.into()].style)
435    }
436
437    /// Return this node layout relative to its parent
438    pub fn layout(&self, node: NodeId) -> TaffyResult<&Layout> {
439        Ok(&self.nodes[node.into()].final_layout)
440    }
441
442    /// Marks the layout computation of this node and its children as outdated
443    ///
444    /// Performs a recursive depth-first search up the tree until the root node is reached
445    ///
446    /// WARNING: this will stack-overflow if the tree contains a cycle
447    pub fn mark_dirty(&mut self, node: NodeId) -> TaffyResult<()> {
448        /// WARNING: this will stack-overflow if the tree contains a cycle
449        fn mark_dirty_recursive(
450            nodes: &mut SlotMap<DefaultKey, NodeData>,
451            parents: &SlotMap<DefaultKey, Option<NodeId>>,
452            node_key: DefaultKey,
453        ) {
454            nodes[node_key].mark_dirty();
455
456            if let Some(Some(node)) = parents.get(node_key) {
457                mark_dirty_recursive(nodes, parents, (*node).into());
458            }
459        }
460
461        mark_dirty_recursive(&mut self.nodes, &self.parents, node.into());
462
463        Ok(())
464    }
465
466    /// Indicates whether the layout of this node (and its children) need to be recomputed
467    pub fn dirty(&self, node: NodeId) -> TaffyResult<bool> {
468        Ok(self.nodes[node.into()].cache.is_empty())
469    }
470
471    /// Updates the stored layout of the provided `node` and its children
472    pub fn compute_layout_with_measure<MeasureFunction>(
473        &mut self,
474        node: NodeId,
475        available_space: Size<AvailableSpace>,
476        measure_function: MeasureFunction,
477    ) -> Result<(), TaffyError>
478    where
479        MeasureFunction: FnMut(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&mut NodeContext>) -> Size<f32>,
480    {
481        let mut taffy_view = TaffyView { taffy: self, measure_function };
482        compute_layout(&mut taffy_view, node, available_space)
483    }
484
485    /// Updates the stored layout of the provided `node` and its children
486    pub fn compute_layout(&mut self, node: NodeId, available_space: Size<AvailableSpace>) -> Result<(), TaffyError> {
487        self.compute_layout_with_measure(node, available_space, |_, _, _, _| Size::ZERO)
488    }
489
490    /// Prints a debug representation of the tree's layout
491    #[cfg(feature = "std")]
492    pub fn print_tree(&mut self, root: NodeId) {
493        let taffy_view = TaffyView { taffy: self, measure_function: |_, _, _, _| Size::ZERO };
494        crate::util::print_tree(&taffy_view, root)
495    }
496}
497
498#[cfg(test)]
499mod tests {
500    #![allow(clippy::bool_assert_comparison)]
501
502    use super::*;
503    use crate::style::{Dimension, Display, FlexDirection};
504    use crate::style_helpers::*;
505    use crate::util::sys;
506
507    fn size_measure_function(
508        known_dimensions: Size<Option<f32>>,
509        _available_space: Size<AvailableSpace>,
510        _node_id: NodeId,
511        node_context: Option<&mut Size<f32>>,
512    ) -> Size<f32> {
513        known_dimensions.unwrap_or(node_context.cloned().unwrap_or(Size::ZERO))
514    }
515
516    #[test]
517    fn new_should_allocate_default_capacity() {
518        const DEFAULT_CAPACITY: usize = 16; // This is the capacity defined in the `impl Default`
519        let taffy: Taffy<()> = Taffy::new();
520
521        assert!(taffy.children.capacity() >= DEFAULT_CAPACITY);
522        assert!(taffy.parents.capacity() >= DEFAULT_CAPACITY);
523        assert!(taffy.nodes.capacity() >= DEFAULT_CAPACITY);
524    }
525
526    #[test]
527    fn test_with_capacity() {
528        const CAPACITY: usize = 8;
529        let taffy: Taffy<()> = Taffy::with_capacity(CAPACITY);
530
531        assert!(taffy.children.capacity() >= CAPACITY);
532        assert!(taffy.parents.capacity() >= CAPACITY);
533        assert!(taffy.nodes.capacity() >= CAPACITY);
534    }
535
536    #[test]
537    fn test_new_leaf() {
538        let mut taffy: Taffy<()> = Taffy::new();
539
540        let res = taffy.new_leaf(Style::default());
541        assert!(res.is_ok());
542        let node = res.unwrap();
543
544        // node should be in the taffy tree and have no children
545        assert!(taffy.child_count(node).unwrap() == 0);
546    }
547
548    #[test]
549    fn new_leaf_with_context() {
550        let mut taffy: Taffy<Size<f32>> = Taffy::new();
551
552        let res = taffy.new_leaf_with_context(Style::default(), Size::ZERO);
553        assert!(res.is_ok());
554        let node = res.unwrap();
555
556        // node should be in the taffy tree and have no children
557        assert!(taffy.child_count(node).unwrap() == 0);
558    }
559
560    /// Test that new_with_children works as expected
561    #[test]
562    fn test_new_with_children() {
563        let mut taffy: Taffy<()> = Taffy::new();
564        let child0 = taffy.new_leaf(Style::default()).unwrap();
565        let child1 = taffy.new_leaf(Style::default()).unwrap();
566        let node = taffy.new_with_children(Style::default(), &[child0, child1]).unwrap();
567
568        // node should have two children
569        assert_eq!(taffy.child_count(node).unwrap(), 2);
570        assert_eq!(taffy.children(node).unwrap()[0], child0);
571        assert_eq!(taffy.children(node).unwrap()[1], child1);
572    }
573
574    #[test]
575    fn remove_node_should_remove() {
576        let mut taffy: Taffy<()> = Taffy::new();
577
578        let node = taffy.new_leaf(Style::default()).unwrap();
579
580        let _ = taffy.remove(node).unwrap();
581    }
582
583    #[test]
584    fn remove_node_should_detach_herarchy() {
585        let mut taffy: Taffy<()> = Taffy::new();
586
587        // Build a linear tree layout: <0> <- <1> <- <2>
588        let node2 = taffy.new_leaf(Style::default()).unwrap();
589        let node1 = taffy.new_with_children(Style::default(), &[node2]).unwrap();
590        let node0 = taffy.new_with_children(Style::default(), &[node1]).unwrap();
591
592        // Both node0 and node1 should have 1 child nodes
593        assert_eq!(taffy.children(node0).unwrap().as_slice(), &[node1]);
594        assert_eq!(taffy.children(node1).unwrap().as_slice(), &[node2]);
595
596        // Disconnect the tree: <0> <2>
597        let _ = taffy.remove(node1).unwrap();
598
599        // Both remaining nodes should have no child nodes
600        assert!(taffy.children(node0).unwrap().is_empty());
601        assert!(taffy.children(node2).unwrap().is_empty());
602    }
603
604    #[test]
605    fn remove_last_node() {
606        let mut taffy: Taffy<()> = Taffy::new();
607
608        let parent = taffy.new_leaf(Style::default()).unwrap();
609        let child = taffy.new_leaf(Style::default()).unwrap();
610        taffy.add_child(parent, child).unwrap();
611
612        taffy.remove(child).unwrap();
613        taffy.remove(parent).unwrap();
614    }
615
616    #[test]
617    fn set_measure() {
618        let mut taffy: Taffy<Size<f32>> = Taffy::new();
619        let node = taffy.new_leaf_with_context(Style::default(), Size { width: 200.0, height: 200.0 }).unwrap();
620        taffy.compute_layout_with_measure(node, Size::MAX_CONTENT, size_measure_function).unwrap();
621        assert_eq!(taffy.layout(node).unwrap().size.width, 200.0);
622
623        taffy.set_node_context(node, Some(Size { width: 100.0, height: 100.0 })).unwrap();
624        taffy.compute_layout_with_measure(node, Size::MAX_CONTENT, size_measure_function).unwrap();
625        assert_eq!(taffy.layout(node).unwrap().size.width, 100.0);
626    }
627
628    #[test]
629    fn set_measure_of_previously_unmeasured_node() {
630        let mut taffy: Taffy<Size<f32>> = Taffy::new();
631        let node = taffy.new_leaf(Style::default()).unwrap();
632        taffy.compute_layout_with_measure(node, Size::MAX_CONTENT, size_measure_function).unwrap();
633        assert_eq!(taffy.layout(node).unwrap().size.width, 0.0);
634
635        taffy.set_node_context(node, Some(Size { width: 100.0, height: 100.0 })).unwrap();
636        taffy.compute_layout_with_measure(node, Size::MAX_CONTENT, size_measure_function).unwrap();
637        assert_eq!(taffy.layout(node).unwrap().size.width, 100.0);
638    }
639
640    /// Test that adding `add_child()` works
641    #[test]
642    fn add_child() {
643        let mut taffy: Taffy<()> = Taffy::new();
644        let node = taffy.new_leaf(Style::default()).unwrap();
645        assert_eq!(taffy.child_count(node).unwrap(), 0);
646
647        let child0 = taffy.new_leaf(Style::default()).unwrap();
648        taffy.add_child(node, child0).unwrap();
649        assert_eq!(taffy.child_count(node).unwrap(), 1);
650
651        let child1 = taffy.new_leaf(Style::default()).unwrap();
652        taffy.add_child(node, child1).unwrap();
653        assert_eq!(taffy.child_count(node).unwrap(), 2);
654    }
655
656    #[test]
657    fn insert_child_at_index() {
658        let mut taffy: Taffy<()> = Taffy::new();
659
660        let child0 = taffy.new_leaf(Style::default()).unwrap();
661        let child1 = taffy.new_leaf(Style::default()).unwrap();
662        let child2 = taffy.new_leaf(Style::default()).unwrap();
663
664        let node = taffy.new_leaf(Style::default()).unwrap();
665        assert_eq!(taffy.child_count(node).unwrap(), 0);
666
667        taffy.insert_child_at_index(node, 0, child0).unwrap();
668        assert_eq!(taffy.child_count(node).unwrap(), 1);
669        assert_eq!(taffy.children(node).unwrap()[0], child0);
670
671        taffy.insert_child_at_index(node, 0, child1).unwrap();
672        assert_eq!(taffy.child_count(node).unwrap(), 2);
673        assert_eq!(taffy.children(node).unwrap()[0], child1);
674        assert_eq!(taffy.children(node).unwrap()[1], child0);
675
676        taffy.insert_child_at_index(node, 1, child2).unwrap();
677        assert_eq!(taffy.child_count(node).unwrap(), 3);
678        assert_eq!(taffy.children(node).unwrap()[0], child1);
679        assert_eq!(taffy.children(node).unwrap()[1], child2);
680        assert_eq!(taffy.children(node).unwrap()[2], child0);
681    }
682
683    #[test]
684    fn set_children() {
685        let mut taffy: Taffy<()> = Taffy::new();
686
687        let child0 = taffy.new_leaf(Style::default()).unwrap();
688        let child1 = taffy.new_leaf(Style::default()).unwrap();
689        let node = taffy.new_with_children(Style::default(), &[child0, child1]).unwrap();
690
691        assert_eq!(taffy.child_count(node).unwrap(), 2);
692        assert_eq!(taffy.children(node).unwrap()[0], child0);
693        assert_eq!(taffy.children(node).unwrap()[1], child1);
694
695        let child2 = taffy.new_leaf(Style::default()).unwrap();
696        let child3 = taffy.new_leaf(Style::default()).unwrap();
697        taffy.set_children(node, &[child2, child3]).unwrap();
698
699        assert_eq!(taffy.child_count(node).unwrap(), 2);
700        assert_eq!(taffy.children(node).unwrap()[0], child2);
701        assert_eq!(taffy.children(node).unwrap()[1], child3);
702    }
703
704    /// Test that removing a child works
705    #[test]
706    fn remove_child() {
707        let mut taffy: Taffy<()> = Taffy::new();
708        let child0 = taffy.new_leaf(Style::default()).unwrap();
709        let child1 = taffy.new_leaf(Style::default()).unwrap();
710        let node = taffy.new_with_children(Style::default(), &[child0, child1]).unwrap();
711
712        assert_eq!(taffy.child_count(node).unwrap(), 2);
713
714        taffy.remove_child(node, child0).unwrap();
715        assert_eq!(taffy.child_count(node).unwrap(), 1);
716        assert_eq!(taffy.children(node).unwrap()[0], child1);
717
718        taffy.remove_child(node, child1).unwrap();
719        assert_eq!(taffy.child_count(node).unwrap(), 0);
720    }
721
722    #[test]
723    fn remove_child_at_index() {
724        let mut taffy: Taffy<()> = Taffy::new();
725        let child0 = taffy.new_leaf(Style::default()).unwrap();
726        let child1 = taffy.new_leaf(Style::default()).unwrap();
727        let node = taffy.new_with_children(Style::default(), &[child0, child1]).unwrap();
728
729        assert_eq!(taffy.child_count(node).unwrap(), 2);
730
731        taffy.remove_child_at_index(node, 0).unwrap();
732        assert_eq!(taffy.child_count(node).unwrap(), 1);
733        assert_eq!(taffy.children(node).unwrap()[0], child1);
734
735        taffy.remove_child_at_index(node, 0).unwrap();
736        assert_eq!(taffy.child_count(node).unwrap(), 0);
737    }
738
739    // Related to: https://github.com/DioxusLabs/taffy/issues/510
740    #[test]
741    fn remove_child_updates_parents() {
742        let mut taffy: Taffy<()> = Taffy::new();
743
744        let parent = taffy.new_leaf(Style::default()).unwrap();
745        let child = taffy.new_leaf(Style::default()).unwrap();
746
747        taffy.add_child(parent, child).unwrap();
748
749        taffy.remove(parent).unwrap();
750
751        // Once the parent is removed this shouldn't panic.
752        assert!(taffy.set_children(child, &[]).is_ok());
753    }
754
755    #[test]
756    fn replace_child_at_index() {
757        let mut taffy: Taffy<()> = Taffy::new();
758
759        let child0 = taffy.new_leaf(Style::default()).unwrap();
760        let child1 = taffy.new_leaf(Style::default()).unwrap();
761
762        let node = taffy.new_with_children(Style::default(), &[child0]).unwrap();
763        assert_eq!(taffy.child_count(node).unwrap(), 1);
764        assert_eq!(taffy.children(node).unwrap()[0], child0);
765
766        taffy.replace_child_at_index(node, 0, child1).unwrap();
767        assert_eq!(taffy.child_count(node).unwrap(), 1);
768        assert_eq!(taffy.children(node).unwrap()[0], child1);
769    }
770    #[test]
771    fn test_child_at_index() {
772        let mut taffy: Taffy<()> = Taffy::new();
773        let child0 = taffy.new_leaf(Style::default()).unwrap();
774        let child1 = taffy.new_leaf(Style::default()).unwrap();
775        let child2 = taffy.new_leaf(Style::default()).unwrap();
776        let node = taffy.new_with_children(Style::default(), &[child0, child1, child2]).unwrap();
777
778        assert!(if let Ok(result) = taffy.child_at_index(node, 0) { result == child0 } else { false });
779        assert!(if let Ok(result) = taffy.child_at_index(node, 1) { result == child1 } else { false });
780        assert!(if let Ok(result) = taffy.child_at_index(node, 2) { result == child2 } else { false });
781    }
782    #[test]
783    fn test_child_count() {
784        let mut taffy: Taffy<()> = Taffy::new();
785        let child0 = taffy.new_leaf(Style::default()).unwrap();
786        let child1 = taffy.new_leaf(Style::default()).unwrap();
787        let node = taffy.new_with_children(Style::default(), &[child0, child1]).unwrap();
788
789        assert!(if let Ok(count) = taffy.child_count(node) { count == 2 } else { false });
790        assert!(if let Ok(count) = taffy.child_count(child0) { count == 0 } else { false });
791        assert!(if let Ok(count) = taffy.child_count(child1) { count == 0 } else { false });
792    }
793
794    #[allow(clippy::vec_init_then_push)]
795    #[test]
796    fn test_children() {
797        let mut taffy: Taffy<()> = Taffy::new();
798        let child0 = taffy.new_leaf(Style::default()).unwrap();
799        let child1 = taffy.new_leaf(Style::default()).unwrap();
800        let node = taffy.new_with_children(Style::default(), &[child0, child1]).unwrap();
801
802        let mut children = sys::Vec::new();
803        children.push(child0);
804        children.push(child1);
805
806        let children_result = taffy.children(node).unwrap();
807        assert_eq!(children_result, children);
808
809        assert!(taffy.children(child0).unwrap().is_empty());
810    }
811    #[test]
812    fn test_set_style() {
813        let mut taffy: Taffy<()> = Taffy::new();
814
815        let node = taffy.new_leaf(Style::default()).unwrap();
816        assert_eq!(taffy.style(node).unwrap().display, Display::Flex);
817
818        taffy.set_style(node, Style { display: Display::None, ..Style::default() }).unwrap();
819        assert_eq!(taffy.style(node).unwrap().display, Display::None);
820    }
821    #[test]
822    fn test_style() {
823        let mut taffy: Taffy<()> = Taffy::new();
824
825        let style = Style { display: Display::None, flex_direction: FlexDirection::RowReverse, ..Default::default() };
826
827        let node = taffy.new_leaf(style.clone()).unwrap();
828
829        let res = taffy.style(node);
830        assert!(res.is_ok());
831        assert!(res.unwrap() == &style);
832    }
833    #[test]
834    fn test_layout() {
835        let mut taffy: Taffy<()> = Taffy::new();
836        let node = taffy.new_leaf(Style::default()).unwrap();
837
838        // TODO: Improve this test?
839        let res = taffy.layout(node);
840        assert!(res.is_ok());
841    }
842
843    #[test]
844    fn test_mark_dirty() {
845        let mut taffy: Taffy<()> = Taffy::new();
846        let child0 = taffy.new_leaf(Style::default()).unwrap();
847        let child1 = taffy.new_leaf(Style::default()).unwrap();
848        let node = taffy.new_with_children(Style::default(), &[child0, child1]).unwrap();
849
850        taffy.compute_layout(node, Size::MAX_CONTENT).unwrap();
851
852        assert_eq!(taffy.dirty(child0).unwrap(), false);
853        assert_eq!(taffy.dirty(child1).unwrap(), false);
854        assert_eq!(taffy.dirty(node).unwrap(), false);
855
856        taffy.mark_dirty(node).unwrap();
857        assert_eq!(taffy.dirty(child0).unwrap(), false);
858        assert_eq!(taffy.dirty(child1).unwrap(), false);
859        assert_eq!(taffy.dirty(node).unwrap(), true);
860
861        taffy.compute_layout(node, Size::MAX_CONTENT).unwrap();
862        taffy.mark_dirty(child0).unwrap();
863        assert_eq!(taffy.dirty(child0).unwrap(), true);
864        assert_eq!(taffy.dirty(child1).unwrap(), false);
865        assert_eq!(taffy.dirty(node).unwrap(), true);
866    }
867
868    #[test]
869    fn compute_layout_should_produce_valid_result() {
870        let mut taffy: Taffy<()> = Taffy::new();
871        let node_result = taffy.new_leaf(Style {
872            size: Size { width: Dimension::Length(10f32), height: Dimension::Length(10f32) },
873            ..Default::default()
874        });
875        assert!(node_result.is_ok());
876        let node = node_result.unwrap();
877        let layout_result = taffy.compute_layout(
878            node,
879            Size { width: AvailableSpace::Definite(100.), height: AvailableSpace::Definite(100.) },
880        );
881        assert!(layout_result.is_ok());
882    }
883
884    #[test]
885    fn make_sure_layout_location_is_top_left() {
886        use crate::prelude::Rect;
887
888        let mut taffy: Taffy<()> = Taffy::new();
889
890        let node = taffy
891            .new_leaf(Style {
892                size: Size { width: Dimension::Percent(1f32), height: Dimension::Percent(1f32) },
893                ..Default::default()
894            })
895            .unwrap();
896
897        let root = taffy
898            .new_with_children(
899                Style {
900                    size: Size { width: Dimension::Length(100f32), height: Dimension::Length(100f32) },
901                    padding: Rect {
902                        left: length(10f32),
903                        right: length(20f32),
904                        top: length(30f32),
905                        bottom: length(40f32),
906                    },
907                    ..Default::default()
908                },
909                &[node],
910            )
911            .unwrap();
912
913        taffy.compute_layout(root, Size::MAX_CONTENT).unwrap();
914
915        // If Layout::location represents top-left coord, 'node' location
916        // must be (due applied 'root' padding): {x: 10, y: 30}.
917        //
918        // It's important, since result will be different for each other
919        // coordinate space:
920        // - bottom-left:  {x: 10, y: 40}
921        // - top-right:    {x: 20, y: 30}
922        // - bottom-right: {x: 20, y: 40}
923        let layout = taffy.layout(node).unwrap();
924        assert_eq!(layout.location.x, 10f32);
925        assert_eq!(layout.location.y, 30f32);
926    }
927}