tawasuyu

tawasuyu/taffy

A high performance rust-powered UI layout library

Rust 583HTML 275Markdown 8TOML 41586 Sutichaykuna

⎇ 0.3.x src/node.rs Rust · 761 siq'ikuna · 26.7 KB Ñawpa willay Pi imata llamkarqan ch'uya

Add total_node_count method to Taffy struct c2db86dfc · 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
6/// A node in a layout.
7pub type Node = slotmap::DefaultKey;
8
9use crate::error::{TaffyError, TaffyResult};
10use crate::geometry::Size;
11use crate::layout::{Cache, Layout};
12use crate::prelude::LayoutTree;
13use crate::style::{AvailableSpace, Style};
14#[cfg(any(feature = "std", feature = "alloc"))]
15use crate::sys::Box;
16use crate::sys::{new_vec_with_capacity, ChildrenVec, Vec};
17use crate::{data::NodeData, error};
18
19/// A function type that can be used in a [`MeasureFunc`]
20///
21/// This trait is automatically implemented for all types (including closures) that define a function with the appropriate type signature.
22pub trait Measurable: Send + Sync + Fn(Size<Option<f32>>, Size<AvailableSpace>) -> Size<f32> {}
23impl<F: Send + Sync + Fn(Size<Option<f32>>, Size<AvailableSpace>) -> Size<f32>> Measurable for F {}
24
25/// A function that can be used to compute the intrinsic size of a node
26pub enum MeasureFunc {
27    /// Stores an unboxed function
28    Raw(fn(Size<Option<f32>>, Size<AvailableSpace>) -> Size<f32>),
29
30    /// Stores a boxed function
31    #[cfg(any(feature = "std", feature = "alloc"))]
32    Boxed(Box<dyn Measurable>),
33}
34
35/// Global configuration values for a Taffy instance
36pub(crate) struct TaffyConfig {
37    /// Whether to round layout values
38    pub(crate) use_rounding: bool,
39}
40
41impl Default for TaffyConfig {
42    fn default() -> Self {
43        Self { use_rounding: true }
44    }
45}
46
47/// A tree of UI [`Nodes`](`Node`), suitable for UI layout
48pub struct Taffy {
49    /// The [`NodeData`] for each node stored in this tree
50    pub(crate) nodes: SlotMap<Node, NodeData>,
51
52    /// Functions/closures that compute the intrinsic size of leaf nodes
53    pub(crate) measure_funcs: SparseSecondaryMap<Node, MeasureFunc>,
54
55    /// The children of each node
56    ///
57    /// The indexes in the outer vector correspond to the position of the parent [`NodeData`]
58    pub(crate) children: SlotMap<Node, ChildrenVec<Node>>,
59
60    /// The parents of each node
61    ///
62    /// The indexes in the outer vector correspond to the position of the child [`NodeData`]
63    pub(crate) parents: SlotMap<Node, Option<Node>>,
64
65    /// Layout mode configuration
66    pub(crate) config: TaffyConfig,
67
68    /// Hack to allow the `LayoutTree::layout_mut` function to expose the `NodeData.unrounded_layout` of a node to
69    /// the layout algorithms during layout, while exposing the `NodeData.final_layout` when called by external users.
70    /// This allows us to fix <https://github.com/DioxusLabs/taffy/issues/501> without breaking backwards compatibility
71    pub(crate) is_layouting: bool,
72}
73
74impl Default for Taffy {
75    fn default() -> Self {
76        Taffy::new()
77    }
78}
79
80impl LayoutTree for Taffy {
81    type ChildIter<'a> = core::slice::Iter<'a, DefaultKey>;
82
83    fn children(&self, node: Node) -> Self::ChildIter<'_> {
84        self.children[node].iter()
85    }
86
87    fn child_count(&self, node: Node) -> usize {
88        self.children[node].len()
89    }
90
91    fn is_childless(&self, node: Node) -> bool {
92        self.children[node].is_empty()
93    }
94
95    fn parent(&self, node: Node) -> Option<Node> {
96        self.parents.get(node).copied().flatten()
97    }
98
99    fn style(&self, node: Node) -> &Style {
100        &self.nodes[node].style
101    }
102
103    #[inline(always)]
104    fn layout(&self, node: Node) -> &Layout {
105        if self.is_layouting && self.config.use_rounding {
106            &self.nodes[node].unrounded_layout
107        } else {
108            &self.nodes[node].final_layout
109        }
110    }
111
112    #[inline(always)]
113    fn layout_mut(&mut self, node: Node) -> &mut Layout {
114        if self.is_layouting && self.config.use_rounding {
115            &mut self.nodes[node].unrounded_layout
116        } else {
117            &mut self.nodes[node].final_layout
118        }
119    }
120
121    #[inline(always)]
122    fn mark_dirty(&mut self, node: Node) -> TaffyResult<()> {
123        self.mark_dirty_internal(node)
124    }
125
126    fn measure_node(
127        &self,
128        node: Node,
129        known_dimensions: Size<Option<f32>>,
130        available_space: Size<AvailableSpace>,
131    ) -> Size<f32> {
132        match &self.measure_funcs[node] {
133            MeasureFunc::Raw(measure) => measure(known_dimensions, available_space),
134
135            #[cfg(any(feature = "std", feature = "alloc"))]
136            MeasureFunc::Boxed(measure) => (measure as &dyn Fn(_, _) -> _)(known_dimensions, available_space),
137        }
138    }
139
140    fn needs_measure(&self, node: Node) -> bool {
141        self.nodes[node].needs_measure && self.measure_funcs.get(node).is_some()
142    }
143
144    fn cache_mut(&mut self, node: Node, index: usize) -> &mut Option<Cache> {
145        &mut self.nodes[node].size_cache[index]
146    }
147
148    fn child(&self, node: Node, id: usize) -> Node {
149        self.children[node][id]
150    }
151}
152
153#[allow(clippy::iter_cloned_collect)] // due to no-std support, we need to use `iter_cloned` instead of `collect`
154impl Taffy {
155    /// Creates a new [`Taffy`]
156    ///
157    /// The default capacity of a [`Taffy`] is 16 nodes.
158    #[must_use]
159    pub fn new() -> Self {
160        Self::with_capacity(16)
161    }
162
163    /// Creates a new [`Taffy`] that can store `capacity` nodes before reallocation
164    #[must_use]
165    pub fn with_capacity(capacity: usize) -> Self {
166        Self {
167            // TODO: make this method const upstream,
168            // so constructors here can be const
169            nodes: SlotMap::with_capacity(capacity),
170            children: SlotMap::with_capacity(capacity),
171            parents: SlotMap::with_capacity(capacity),
172            measure_funcs: SparseSecondaryMap::with_capacity(capacity),
173            config: TaffyConfig::default(),
174            is_layouting: false,
175        }
176    }
177
178    /// Enable rounding of layout values. Rounding is enabled by default.
179    pub fn enable_rounding(&mut self) {
180        self.config.use_rounding = true;
181    }
182
183    /// Disable rounding of layout values. Rounding is enabled by default.
184    pub fn disable_rounding(&mut self) {
185        self.config.use_rounding = false;
186    }
187
188    /// Creates and adds a new unattached leaf node to the tree, and returns the [`Node`] of the new node
189    pub fn new_leaf(&mut self, layout: Style) -> TaffyResult<Node> {
190        let id = self.nodes.insert(NodeData::new(layout));
191        let _ = self.children.insert(new_vec_with_capacity(0));
192        let _ = self.parents.insert(None);
193
194        Ok(id)
195    }
196
197    /// Creates and adds a new unattached leaf node to the tree, and returns the [`Node`] of the new node
198    ///
199    /// Creates and adds a new leaf node with a supplied [`MeasureFunc`]
200    pub fn new_leaf_with_measure(&mut self, layout: Style, measure: MeasureFunc) -> TaffyResult<Node> {
201        let mut data = NodeData::new(layout);
202        data.needs_measure = true;
203
204        let id = self.nodes.insert(data);
205        self.measure_funcs.insert(id, measure);
206
207        let _ = self.children.insert(new_vec_with_capacity(0));
208        let _ = self.parents.insert(None);
209
210        Ok(id)
211    }
212
213    /// Creates and adds a new node, which may have any number of `children`
214    pub fn new_with_children(&mut self, layout: Style, children: &[Node]) -> TaffyResult<Node> {
215        let id = self.nodes.insert(NodeData::new(layout));
216
217        for child in children {
218            self.parents[*child] = Some(id);
219        }
220
221        let _ = self.children.insert(children.iter().copied().collect::<_>());
222        let _ = self.parents.insert(None);
223
224        Ok(id)
225    }
226
227    /// Drops all nodes in the tree
228    pub fn clear(&mut self) {
229        self.nodes.clear();
230        self.children.clear();
231        self.parents.clear();
232    }
233
234    /// Remove a specific [`Node`] from the tree and drops it
235    ///
236    /// Returns the id of the node removed.
237    pub fn remove(&mut self, node: Node) -> TaffyResult<Node> {
238        if let Some(parent) = self.parents[node] {
239            if let Some(children) = self.children.get_mut(parent) {
240                children.retain(|f| *f != node);
241            }
242        }
243
244        if let Some(children) = self.children.get(node) {
245            for child in children.iter().copied() {
246                self.parents[child] = None;
247            }
248        }
249
250        let _ = self.children.remove(node);
251        let _ = self.parents.remove(node);
252        let _ = self.nodes.remove(node);
253
254        Ok(node)
255    }
256
257    /// Sets the [`MeasureFunc`] of the associated node
258    pub fn set_measure(&mut self, node: Node, measure: Option<MeasureFunc>) -> TaffyResult<()> {
259        if let Some(measure) = measure {
260            self.nodes[node].needs_measure = true;
261            self.measure_funcs.insert(node, measure);
262        } else {
263            self.nodes[node].needs_measure = false;
264            self.measure_funcs.remove(node);
265        }
266
267        self.mark_dirty_internal(node)?;
268
269        Ok(())
270    }
271
272    /// Adds a `child` [`Node`] under the supplied `parent`
273    pub fn add_child(&mut self, parent: Node, child: Node) -> TaffyResult<()> {
274        self.parents[child] = Some(parent);
275        self.children[parent].push(child);
276        self.mark_dirty_internal(parent)?;
277
278        Ok(())
279    }
280
281    /// Directly sets the `children` of the supplied `parent`
282    pub fn set_children(&mut self, parent: Node, children: &[Node]) -> TaffyResult<()> {
283        // Remove node as parent from all its current children.
284        for child in &self.children[parent] {
285            self.parents[*child] = None;
286        }
287
288        // Build up relation node <-> child
289        for child in children {
290            self.parents[*child] = Some(parent);
291        }
292
293        self.children[parent] = children.iter().copied().collect::<_>();
294
295        self.mark_dirty_internal(parent)?;
296
297        Ok(())
298    }
299
300    /// Removes the `child` of the parent `node`
301    ///
302    /// The child is not removed from the tree entirely, it is simply no longer attached to its previous parent.
303    pub fn remove_child(&mut self, parent: Node, child: Node) -> TaffyResult<Node> {
304        let index = self.children[parent].iter().position(|n| *n == child).unwrap();
305        self.remove_child_at_index(parent, index)
306    }
307
308    /// Removes the child at the given `index` from the `parent`
309    ///
310    /// The child is not removed from the tree entirely, it is simply no longer attached to its previous parent.
311    pub fn remove_child_at_index(&mut self, parent: Node, child_index: usize) -> TaffyResult<Node> {
312        let child_count = self.children[parent].len();
313        if child_index >= child_count {
314            return Err(error::TaffyError::ChildIndexOutOfBounds { parent, child_index, child_count });
315        }
316
317        let child = self.children[parent].remove(child_index);
318        self.parents[child] = None;
319
320        self.mark_dirty_internal(parent)?;
321
322        Ok(child)
323    }
324
325    /// Replaces the child at the given `child_index` from the `parent` node with the new `child` node
326    ///
327    /// The child is not removed from the tree entirely, it is simply no longer attached to its previous parent.
328    pub fn replace_child_at_index(&mut self, parent: Node, child_index: usize, new_child: Node) -> TaffyResult<Node> {
329        let child_count = self.children[parent].len();
330        if child_index >= child_count {
331            return Err(error::TaffyError::ChildIndexOutOfBounds { parent, child_index, child_count });
332        }
333
334        self.parents[new_child] = Some(parent);
335        let old_child = core::mem::replace(&mut self.children[parent][child_index], new_child);
336        self.parents[old_child] = None;
337
338        self.mark_dirty_internal(parent)?;
339
340        Ok(old_child)
341    }
342
343    /// Returns the child [`Node`] of the parent `node` at the provided `child_index`
344    pub fn child_at_index(&self, parent: Node, child_index: usize) -> TaffyResult<Node> {
345        let child_count = self.children[parent].len();
346        if child_index >= child_count {
347            return Err(error::TaffyError::ChildIndexOutOfBounds { parent, child_index, child_count });
348        }
349
350        Ok(self.children[parent][child_index])
351    }
352
353    /// Returns the total number of nodes in the tree
354    pub fn total_node_count(&self) -> usize {
355        self.nodes.len()
356    }
357
358    /// Returns the number of children of the `parent` [`Node`]
359    pub fn child_count(&self, parent: Node) -> TaffyResult<usize> {
360        Ok(self.children[parent].len())
361    }
362
363    /// Returns a list of children that belong to the parent [`Node`]
364    pub fn children(&self, parent: Node) -> TaffyResult<Vec<Node>> {
365        Ok(self.children[parent].iter().copied().collect::<_>())
366    }
367
368    /// Sets the [`Style`] of the provided `node`
369    pub fn set_style(&mut self, node: Node, style: Style) -> TaffyResult<()> {
370        self.nodes[node].style = style;
371        self.mark_dirty_internal(node)?;
372        Ok(())
373    }
374
375    /// Gets the [`Style`] of the provided `node`
376    pub fn style(&self, node: Node) -> TaffyResult<&Style> {
377        Ok(&self.nodes[node].style)
378    }
379
380    /// Return this node layout relative to its parent
381    pub fn layout(&self, node: Node) -> TaffyResult<&Layout> {
382        Ok(&self.nodes[node].final_layout)
383    }
384
385    /// Marks the layout computation of this node and its children as outdated
386    ///
387    /// Performs a recursive depth-first search up the tree until the root node is reached
388    ///
389    /// WARNING: this will stack-overflow if the tree contains a cycle
390    fn mark_dirty_internal(&mut self, node: Node) -> TaffyResult<()> {
391        /// WARNING: this will stack-overflow if the tree contains a cycle
392        fn mark_dirty_recursive(
393            nodes: &mut SlotMap<Node, NodeData>,
394            parents: &SlotMap<Node, Option<Node>>,
395            node_id: Node,
396        ) {
397            nodes[node_id].mark_dirty();
398
399            if let Some(Some(node)) = parents.get(node_id) {
400                mark_dirty_recursive(nodes, parents, *node);
401            }
402        }
403
404        mark_dirty_recursive(&mut self.nodes, &self.parents, node);
405
406        Ok(())
407    }
408
409    /// Indicates whether the layout of this node (and its children) need to be recomputed
410    pub fn dirty(&self, node: Node) -> TaffyResult<bool> {
411        Ok(self.nodes[node].size_cache.iter().all(|entry| entry.is_none()))
412    }
413
414    /// Updates the stored layout of the provided `node` and its children
415    pub fn compute_layout(&mut self, node: Node, available_space: Size<AvailableSpace>) -> Result<(), TaffyError> {
416        crate::compute::compute_layout(self, node, available_space)
417    }
418}
419
420#[cfg(test)]
421mod tests {
422    #![allow(clippy::bool_assert_comparison)]
423
424    use super::*;
425    use crate::style::{Dimension, Display, FlexDirection};
426    use crate::style_helpers::*;
427    use crate::sys;
428
429    #[test]
430    fn new_should_allocate_default_capacity() {
431        const DEFAULT_CAPACITY: usize = 16; // This is the capacity defined in the `impl Default`
432        let taffy = Taffy::new();
433
434        assert!(taffy.children.capacity() >= DEFAULT_CAPACITY);
435        assert!(taffy.parents.capacity() >= DEFAULT_CAPACITY);
436        assert!(taffy.nodes.capacity() >= DEFAULT_CAPACITY);
437    }
438
439    #[test]
440    fn test_with_capacity() {
441        const CAPACITY: usize = 8;
442        let taffy = Taffy::with_capacity(CAPACITY);
443
444        assert!(taffy.children.capacity() >= CAPACITY);
445        assert!(taffy.parents.capacity() >= CAPACITY);
446        assert!(taffy.nodes.capacity() >= CAPACITY);
447    }
448
449    #[test]
450    fn test_new_leaf() {
451        let mut taffy = Taffy::new();
452
453        let res = taffy.new_leaf(Style::default());
454        assert!(res.is_ok());
455        let node = res.unwrap();
456
457        // node should be in the taffy tree and have no children
458        assert!(taffy.child_count(node).unwrap() == 0);
459    }
460
461    #[test]
462    fn new_leaf_with_measure() {
463        let mut taffy = Taffy::new();
464
465        let res = taffy.new_leaf_with_measure(Style::default(), MeasureFunc::Raw(|_, _| Size::ZERO));
466        assert!(res.is_ok());
467        let node = res.unwrap();
468
469        // node should be in the taffy tree and have no children
470        assert!(taffy.child_count(node).unwrap() == 0);
471    }
472
473    /// Test that new_with_children works as expected
474    #[test]
475    fn test_new_with_children() {
476        let mut taffy = Taffy::new();
477        let child0 = taffy.new_leaf(Style::default()).unwrap();
478        let child1 = taffy.new_leaf(Style::default()).unwrap();
479        let node = taffy.new_with_children(Style::default(), &[child0, child1]).unwrap();
480
481        // node should have two children
482        assert_eq!(taffy.child_count(node).unwrap(), 2);
483        assert_eq!(taffy.children(node).unwrap()[0], child0);
484        assert_eq!(taffy.children(node).unwrap()[1], child1);
485    }
486
487    #[test]
488    fn remove_node_should_remove() {
489        let mut taffy = Taffy::new();
490
491        let node = taffy.new_leaf(Style::default()).unwrap();
492
493        let _ = taffy.remove(node).unwrap();
494    }
495
496    #[test]
497    fn remove_node_should_detach_herarchy() {
498        let mut taffy = Taffy::new();
499
500        // Build a linear tree layout: <0> <- <1> <- <2>
501        let node2 = taffy.new_leaf(Style::default()).unwrap();
502        let node1 = taffy.new_with_children(Style::default(), &[node2]).unwrap();
503        let node0 = taffy.new_with_children(Style::default(), &[node1]).unwrap();
504
505        // Both node0 and node1 should have 1 child nodes
506        assert_eq!(taffy.children(node0).unwrap().as_slice(), &[node1]);
507        assert_eq!(taffy.children(node1).unwrap().as_slice(), &[node2]);
508
509        // Disconnect the tree: <0> <2>
510        let _ = taffy.remove(node1).unwrap();
511
512        // Both remaining nodes should have no child nodes
513        assert!(taffy.children(node0).unwrap().is_empty());
514        assert!(taffy.children(node2).unwrap().is_empty());
515    }
516
517    #[test]
518    fn remove_last_node() {
519        let mut taffy = Taffy::new();
520
521        let parent = taffy.new_leaf(Style::default()).unwrap();
522        let child = taffy.new_leaf(Style::default()).unwrap();
523        taffy.add_child(parent, child).unwrap();
524
525        taffy.remove(child).unwrap();
526        taffy.remove(parent).unwrap();
527    }
528
529    #[test]
530    fn set_measure() {
531        let mut taffy = Taffy::new();
532        let node = taffy
533            .new_leaf_with_measure(Style::default(), MeasureFunc::Raw(|_, _| Size { width: 200.0, height: 200.0 }))
534            .unwrap();
535        taffy.compute_layout(node, Size::MAX_CONTENT).unwrap();
536        assert_eq!(taffy.layout(node).unwrap().size.width, 200.0);
537
538        taffy.set_measure(node, Some(MeasureFunc::Raw(|_, _| Size { width: 100.0, height: 100.0 }))).unwrap();
539        taffy.compute_layout(node, Size::MAX_CONTENT).unwrap();
540        assert_eq!(taffy.layout(node).unwrap().size.width, 100.0);
541    }
542
543    #[test]
544    fn set_measure_of_previously_unmeasured_node() {
545        let mut taffy = Taffy::new();
546        let node = taffy.new_leaf(Style::default()).unwrap();
547        taffy.compute_layout(node, Size::MAX_CONTENT).unwrap();
548        assert_eq!(taffy.layout(node).unwrap().size.width, 0.0);
549
550        taffy.set_measure(node, Some(MeasureFunc::Raw(|_, _| Size { width: 100.0, height: 100.0 }))).unwrap();
551        taffy.compute_layout(node, Size::MAX_CONTENT).unwrap();
552        assert_eq!(taffy.layout(node).unwrap().size.width, 100.0);
553    }
554
555    /// Test that adding `add_child()` works
556    #[test]
557    fn add_child() {
558        let mut taffy = Taffy::new();
559        let node = taffy.new_leaf(Style::default()).unwrap();
560        assert_eq!(taffy.child_count(node).unwrap(), 0);
561
562        let child0 = taffy.new_leaf(Style::default()).unwrap();
563        taffy.add_child(node, child0).unwrap();
564        assert_eq!(taffy.child_count(node).unwrap(), 1);
565
566        let child1 = taffy.new_leaf(Style::default()).unwrap();
567        taffy.add_child(node, child1).unwrap();
568        assert_eq!(taffy.child_count(node).unwrap(), 2);
569    }
570
571    #[test]
572    fn set_children() {
573        let mut taffy = Taffy::new();
574
575        let child0 = taffy.new_leaf(Style::default()).unwrap();
576        let child1 = taffy.new_leaf(Style::default()).unwrap();
577        let node = taffy.new_with_children(Style::default(), &[child0, child1]).unwrap();
578
579        assert_eq!(taffy.child_count(node).unwrap(), 2);
580        assert_eq!(taffy.children(node).unwrap()[0], child0);
581        assert_eq!(taffy.children(node).unwrap()[1], child1);
582
583        let child2 = taffy.new_leaf(Style::default()).unwrap();
584        let child3 = taffy.new_leaf(Style::default()).unwrap();
585        taffy.set_children(node, &[child2, child3]).unwrap();
586
587        assert_eq!(taffy.child_count(node).unwrap(), 2);
588        assert_eq!(taffy.children(node).unwrap()[0], child2);
589        assert_eq!(taffy.children(node).unwrap()[1], child3);
590    }
591
592    /// Test that removing a child works
593    #[test]
594    fn remove_child() {
595        let mut taffy = Taffy::new();
596        let child0 = taffy.new_leaf(Style::default()).unwrap();
597        let child1 = taffy.new_leaf(Style::default()).unwrap();
598        let node = taffy.new_with_children(Style::default(), &[child0, child1]).unwrap();
599
600        assert_eq!(taffy.child_count(node).unwrap(), 2);
601
602        taffy.remove_child(node, child0).unwrap();
603        assert_eq!(taffy.child_count(node).unwrap(), 1);
604        assert_eq!(taffy.children(node).unwrap()[0], child1);
605
606        taffy.remove_child(node, child1).unwrap();
607        assert_eq!(taffy.child_count(node).unwrap(), 0);
608    }
609
610    #[test]
611    fn remove_child_at_index() {
612        let mut taffy = Taffy::new();
613        let child0 = taffy.new_leaf(Style::default()).unwrap();
614        let child1 = taffy.new_leaf(Style::default()).unwrap();
615        let node = taffy.new_with_children(Style::default(), &[child0, child1]).unwrap();
616
617        assert_eq!(taffy.child_count(node).unwrap(), 2);
618
619        taffy.remove_child_at_index(node, 0).unwrap();
620        assert_eq!(taffy.child_count(node).unwrap(), 1);
621        assert_eq!(taffy.children(node).unwrap()[0], child1);
622
623        taffy.remove_child_at_index(node, 0).unwrap();
624        assert_eq!(taffy.child_count(node).unwrap(), 0);
625    }
626
627    #[test]
628    fn replace_child_at_index() {
629        let mut taffy = Taffy::new();
630
631        let child0 = taffy.new_leaf(Style::default()).unwrap();
632        let child1 = taffy.new_leaf(Style::default()).unwrap();
633
634        let node = taffy.new_with_children(Style::default(), &[child0]).unwrap();
635        assert_eq!(taffy.child_count(node).unwrap(), 1);
636        assert_eq!(taffy.children(node).unwrap()[0], child0);
637
638        taffy.replace_child_at_index(node, 0, child1).unwrap();
639        assert_eq!(taffy.child_count(node).unwrap(), 1);
640        assert_eq!(taffy.children(node).unwrap()[0], child1);
641    }
642    #[test]
643    fn test_child_at_index() {
644        let mut taffy = Taffy::new();
645        let child0 = taffy.new_leaf(Style::default()).unwrap();
646        let child1 = taffy.new_leaf(Style::default()).unwrap();
647        let child2 = taffy.new_leaf(Style::default()).unwrap();
648        let node = taffy.new_with_children(Style::default(), &[child0, child1, child2]).unwrap();
649
650        assert!(if let Ok(result) = taffy.child_at_index(node, 0) { result == child0 } else { false });
651        assert!(if let Ok(result) = taffy.child_at_index(node, 1) { result == child1 } else { false });
652        assert!(if let Ok(result) = taffy.child_at_index(node, 2) { result == child2 } else { false });
653    }
654    #[test]
655    fn test_child_count() {
656        let mut taffy = Taffy::new();
657        let child0 = taffy.new_leaf(Style::default()).unwrap();
658        let child1 = taffy.new_leaf(Style::default()).unwrap();
659        let node = taffy.new_with_children(Style::default(), &[child0, child1]).unwrap();
660
661        assert!(if let Ok(count) = taffy.child_count(node) { count == 2 } else { false });
662        assert!(if let Ok(count) = taffy.child_count(child0) { count == 0 } else { false });
663        assert!(if let Ok(count) = taffy.child_count(child1) { count == 0 } else { false });
664    }
665
666    #[allow(clippy::vec_init_then_push)]
667    #[test]
668    fn test_children() {
669        let mut taffy = Taffy::new();
670        let child0 = taffy.new_leaf(Style::default()).unwrap();
671        let child1 = taffy.new_leaf(Style::default()).unwrap();
672        let node = taffy.new_with_children(Style::default(), &[child0, child1]).unwrap();
673
674        let mut children: sys::Vec<Node> = sys::Vec::new();
675        children.push(child0);
676        children.push(child1);
677
678        let children_result = taffy.children(node).unwrap();
679        assert_eq!(children_result, children);
680
681        assert!(taffy.children(child0).unwrap().is_empty());
682    }
683    #[test]
684    fn test_set_style() {
685        let mut taffy = Taffy::new();
686
687        let node = taffy.new_leaf(Style::default()).unwrap();
688        assert_eq!(taffy.style(node).unwrap().display, Display::Flex);
689
690        taffy.set_style(node, Style { display: Display::None, ..Style::default() }).unwrap();
691        assert_eq!(taffy.style(node).unwrap().display, Display::None);
692    }
693    #[test]
694    fn test_style() {
695        let mut taffy = Taffy::new();
696
697        let style = Style { display: Display::None, flex_direction: FlexDirection::RowReverse, ..Default::default() };
698
699        let node = taffy.new_leaf(style.clone()).unwrap();
700
701        let res = taffy.style(node);
702        assert!(res.is_ok());
703        assert!(res.unwrap() == &style);
704    }
705    #[test]
706    fn test_layout() {
707        let mut taffy = Taffy::new();
708        let node = taffy.new_leaf(Style::default()).unwrap();
709
710        // TODO: Improve this test?
711        let res = taffy.layout(node);
712        assert!(res.is_ok());
713    }
714
715    #[test]
716    fn test_mark_dirty() {
717        let mut taffy = Taffy::new();
718        let child0 = taffy.new_leaf(Style::default()).unwrap();
719        let child1 = taffy.new_leaf(Style::default()).unwrap();
720        let node = taffy.new_with_children(Style::default(), &[child0, child1]).unwrap();
721
722        taffy.compute_layout(node, Size::MAX_CONTENT).unwrap();
723
724        assert_eq!(taffy.dirty(child0).unwrap(), false);
725        assert_eq!(taffy.dirty(child1).unwrap(), false);
726        assert_eq!(taffy.dirty(node).unwrap(), false);
727
728        taffy.mark_dirty(node).unwrap();
729        assert_eq!(taffy.dirty(child0).unwrap(), false);
730        assert_eq!(taffy.dirty(child1).unwrap(), false);
731        assert_eq!(taffy.dirty(node).unwrap(), true);
732
733        taffy.compute_layout(node, Size::MAX_CONTENT).unwrap();
734        taffy.mark_dirty(child0).unwrap();
735        assert_eq!(taffy.dirty(child0).unwrap(), true);
736        assert_eq!(taffy.dirty(child1).unwrap(), false);
737        assert_eq!(taffy.dirty(node).unwrap(), true);
738    }
739
740    #[test]
741    fn compute_layout_should_produce_valid_result() {
742        let mut taffy = Taffy::new();
743        let node_result = taffy.new_leaf(Style {
744            size: Size { width: Dimension::Points(10f32), height: Dimension::Points(10f32) },
745            ..Default::default()
746        });
747        assert!(node_result.is_ok());
748        let node = node_result.unwrap();
749        let layout_result = taffy.compute_layout(
750            node,
751            Size { width: AvailableSpace::Definite(100.), height: AvailableSpace::Definite(100.) },
752        );
753        assert!(layout_result.is_ok());
754    }
755
756    #[test]
757    fn measure_func_is_send_and_sync() {
758        fn is_send_and_sync<T: Send + Sync>() {}
759        is_send_and_sync::<MeasureFunc>();
760    }
761}