tawasuyu

tawasuyu/taffy

A high performance rust-powered UI layout library

HTML 5544Rust 88Markdown 11TOML 91926 Definitions

⎇ e8253b1ae8ad9e95777144ce91aa6fb1ec8d4e32 src/node.rs Rust · 734 lines · 25.6 KB History Who touched what raw

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