tawasuyu

tawasuyu/taffy

A high performance rust-powered UI layout library

Rust 1061HTML 997Markdown 12TOML 83120 Definitions

⎇ c9e45e50db2fdae4c838d091f1a5dc9d3be60216 src/tree/taffy_tree/tree.rs Rust · 841 lines · 29.3 KB History Who touched what raw

update parents list on remove (#511) c9e45e50d · Max Stoumen ·

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