tawasuyu

tawasuyu/taffy

A high performance rust-powered UI layout library

Rust 709HTML 662Markdown 12TOML 62348 Sutichaykuna

⎇ 3bda6444237f92c60a8a9ba24495554b9faa72c3 src/node.rs Rust · 762 siq'ikuna · 26.8 KB Ñawpa willay Pi imata llamkarqan ch'uya

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