taffy/tree/
taffy_tree.rs

1//! Contains [TaffyTree](crate::tree::TaffyTree): the default implementation of [LayoutTree](crate::tree::LayoutTree), and the error type for Taffy.
2#[cfg(not(feature = "std"))]
3use slotmap::SecondaryMap;
4#[cfg(feature = "std")]
5use slotmap::SparseSecondaryMap as SecondaryMap;
6use slotmap::{DefaultKey, SlotMap};
7
8use crate::geometry::Size;
9use crate::style::{AvailableSpace, Display, Style};
10use crate::sys::DefaultCheapStr;
11use crate::tree::{
12    Cache, ClearState, Layout, LayoutInput, LayoutOutput, LayoutPartialTree, NodeId, PrintTree, RoundTree, RunMode,
13    TraversePartialTree, TraverseTree,
14};
15use crate::util::debug::{debug_log, debug_log_node};
16use crate::util::sys::{new_vec_with_capacity, ChildrenVec, Vec};
17
18use crate::compute::{
19    compute_cached_layout, compute_hidden_layout, compute_leaf_layout, compute_root_layout, round_layout,
20};
21use crate::CacheTree;
22#[cfg(feature = "block_layout")]
23use crate::{compute::compute_block_layout, LayoutBlockContainer};
24#[cfg(feature = "flexbox")]
25use crate::{compute::compute_flexbox_layout, LayoutFlexboxContainer};
26#[cfg(feature = "grid")]
27use crate::{compute::compute_grid_layout, LayoutGridContainer};
28
29#[cfg(all(feature = "detailed_layout_info", feature = "grid"))]
30use crate::compute::grid::DetailedGridInfo;
31#[cfg(feature = "detailed_layout_info")]
32use crate::tree::layout::DetailedLayoutInfo;
33
34/// The error Taffy generates on invalid operations
35pub type TaffyResult<T> = Result<T, TaffyError>;
36
37/// An error that occurs while trying to access or modify a node's children by index.
38#[derive(Debug, Clone, PartialEq, Eq)]
39pub enum TaffyError {
40    /// The parent node does not have a child at `child_index`. It only has `child_count` children
41    ChildIndexOutOfBounds {
42        /// The parent node whose child was being looked up
43        parent: NodeId,
44        /// The index that was looked up
45        child_index: usize,
46        /// The total number of children the parent has
47        child_count: usize,
48    },
49    /// The parent node was not found in the [`TaffyTree`](crate::TaffyTree) instance.
50    InvalidParentNode(NodeId),
51    /// The child node was not found in the [`TaffyTree`](crate::TaffyTree) instance.
52    InvalidChildNode(NodeId),
53    /// The supplied node was not found in the [`TaffyTree`](crate::TaffyTree) instance.
54    InvalidInputNode(NodeId),
55}
56
57impl core::fmt::Display for TaffyError {
58    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
59        match self {
60            TaffyError::ChildIndexOutOfBounds { parent, child_index, child_count } => {
61                write!(f, "Index (is {child_index}) should be < child_count ({child_count}) for parent node {parent:?}")
62            }
63            TaffyError::InvalidParentNode(parent) => {
64                write!(f, "Parent Node {parent:?} is not in the TaffyTree instance")
65            }
66            TaffyError::InvalidChildNode(child) => write!(f, "Child Node {child:?} is not in the TaffyTree instance"),
67            TaffyError::InvalidInputNode(node) => write!(f, "Supplied Node {node:?} is not in the TaffyTree instance"),
68        }
69    }
70}
71
72#[cfg(feature = "std")]
73impl std::error::Error for TaffyError {}
74
75/// Global configuration values for a TaffyTree instance
76#[derive(Debug, Clone, Copy)]
77pub(crate) struct TaffyConfig {
78    /// Whether to round layout values
79    pub(crate) use_rounding: bool,
80}
81
82impl Default for TaffyConfig {
83    fn default() -> Self {
84        Self { use_rounding: true }
85    }
86}
87
88/// Layout information for a given [`Node`](crate::node::Node)
89///
90/// Stored in a [`TaffyTree`].
91#[derive(Debug, Clone, PartialEq)]
92struct NodeData {
93    /// The layout strategy used by this node
94    pub(crate) style: Style,
95
96    /// The always unrounded results of the layout computation. We must store this separately from the rounded
97    /// layout to avoid errors from rounding already-rounded values. See <https://github.com/DioxusLabs/taffy/issues/501>.
98    pub(crate) unrounded_layout: Layout,
99
100    /// The final results of the layout computation.
101    /// These may be rounded or unrounded depending on what the `use_rounding` config setting is set to.
102    pub(crate) final_layout: Layout,
103
104    /// Whether the node has context data associated with it or not
105    pub(crate) has_context: bool,
106
107    /// The cached results of the layout computation
108    pub(crate) cache: Cache,
109
110    /// The computation result from layout algorithm
111    #[cfg(feature = "detailed_layout_info")]
112    pub(crate) detailed_layout_info: DetailedLayoutInfo,
113}
114
115impl NodeData {
116    /// Create the data for a new node
117    #[must_use]
118    pub const fn new(style: Style) -> Self {
119        Self {
120            style,
121            cache: Cache::new(),
122            unrounded_layout: Layout::new(),
123            final_layout: Layout::new(),
124            has_context: false,
125            #[cfg(feature = "detailed_layout_info")]
126            detailed_layout_info: DetailedLayoutInfo::None,
127        }
128    }
129
130    /// Marks a node and all of its ancestors as requiring relayout
131    ///
132    /// This clears any cached data and signals that the data must be recomputed.
133    /// If the node was already marked as dirty, returns true
134    #[inline]
135    pub fn mark_dirty(&mut self) -> ClearState {
136        self.cache.clear()
137    }
138}
139
140/// An entire tree of UI nodes. The entry point to Taffy's high-level API.
141///
142/// Allows you to build a tree of UI nodes, run Taffy's layout algorithms over that tree, and then access the resultant layout.]
143#[derive(Debug, Clone)]
144pub struct TaffyTree<NodeContext = ()> {
145    /// The [`NodeData`] for each node stored in this tree
146    nodes: SlotMap<DefaultKey, NodeData>,
147
148    /// Functions/closures that compute the intrinsic size of leaf nodes
149    node_context_data: SecondaryMap<DefaultKey, NodeContext>,
150
151    /// The children of each node
152    ///
153    /// The indexes in the outer vector correspond to the position of the parent [`NodeData`]
154    children: SlotMap<DefaultKey, ChildrenVec<NodeId>>,
155
156    /// The parents of each node
157    ///
158    /// The indexes in the outer vector correspond to the position of the child [`NodeData`]
159    parents: SlotMap<DefaultKey, Option<NodeId>>,
160
161    /// Layout mode configuration
162    config: TaffyConfig,
163}
164
165impl Default for TaffyTree {
166    fn default() -> TaffyTree<()> {
167        TaffyTree::new()
168    }
169}
170
171/// Iterator that wraps a slice of nodes, lazily converting them to u64
172pub struct TaffyTreeChildIter<'a>(core::slice::Iter<'a, NodeId>);
173impl Iterator for TaffyTreeChildIter<'_> {
174    type Item = NodeId;
175
176    #[inline]
177    fn next(&mut self) -> Option<Self::Item> {
178        self.0.next().copied()
179    }
180}
181
182// TraversePartialTree impl for TaffyTree
183impl<NodeContext> TraversePartialTree for TaffyTree<NodeContext> {
184    type ChildIter<'a>
185        = TaffyTreeChildIter<'a>
186    where
187        Self: 'a;
188
189    #[inline(always)]
190    fn child_ids(&self, parent_node_id: NodeId) -> Self::ChildIter<'_> {
191        TaffyTreeChildIter(self.children[parent_node_id.into()].iter())
192    }
193
194    #[inline(always)]
195    fn child_count(&self, parent_node_id: NodeId) -> usize {
196        self.children[parent_node_id.into()].len()
197    }
198
199    #[inline(always)]
200    fn get_child_id(&self, parent_node_id: NodeId, id: usize) -> NodeId {
201        self.children[parent_node_id.into()][id]
202    }
203}
204
205// TraverseTree impl for TaffyTree
206impl<NodeContext> TraverseTree for TaffyTree<NodeContext> {}
207
208// CacheTree impl for TaffyTree
209impl<NodeContext> CacheTree for TaffyTree<NodeContext> {
210    fn cache_get(
211        &self,
212        node_id: NodeId,
213        known_dimensions: Size<Option<f32>>,
214        available_space: Size<AvailableSpace>,
215        run_mode: RunMode,
216    ) -> Option<LayoutOutput> {
217        self.nodes[node_id.into()].cache.get(known_dimensions, available_space, run_mode)
218    }
219
220    fn cache_store(
221        &mut self,
222        node_id: NodeId,
223        known_dimensions: Size<Option<f32>>,
224        available_space: Size<AvailableSpace>,
225        run_mode: RunMode,
226        layout_output: LayoutOutput,
227    ) {
228        self.nodes[node_id.into()].cache.store(known_dimensions, available_space, run_mode, layout_output)
229    }
230
231    fn cache_clear(&mut self, node_id: NodeId) {
232        self.nodes[node_id.into()].cache.clear();
233    }
234}
235
236// PrintTree impl for TaffyTree
237impl<NodeContext> PrintTree for TaffyTree<NodeContext> {
238    #[inline(always)]
239    fn get_debug_label(&self, node_id: NodeId) -> &'static str {
240        let node = &self.nodes[node_id.into()];
241        let display = node.style.display;
242        let num_children = self.child_count(node_id);
243
244        match (num_children, display) {
245            (_, Display::None) => "NONE",
246            (0, _) => "LEAF",
247            #[cfg(feature = "block_layout")]
248            (_, Display::Block) => "BLOCK",
249            #[cfg(feature = "flexbox")]
250            (_, Display::Flex) => {
251                use crate::FlexDirection;
252                match node.style.flex_direction {
253                    FlexDirection::Row | FlexDirection::RowReverse => "FLEX ROW",
254                    FlexDirection::Column | FlexDirection::ColumnReverse => "FLEX COL",
255                }
256            }
257            #[cfg(feature = "grid")]
258            (_, Display::Grid) => "GRID",
259        }
260    }
261
262    #[inline(always)]
263    fn get_final_layout(&self, node_id: NodeId) -> Layout {
264        if self.config.use_rounding {
265            self.nodes[node_id.into()].final_layout
266        } else {
267            self.nodes[node_id.into()].unrounded_layout
268        }
269    }
270}
271
272/// View over the Taffy tree that holds the tree itself along with a reference to the context
273/// and implements LayoutTree. This allows the context to be stored outside of the TaffyTree struct
274/// which makes the lifetimes of the context much more flexible.
275pub(crate) struct TaffyView<'t, NodeContext, MeasureFunction>
276where
277    MeasureFunction:
278        FnMut(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&mut NodeContext>, &Style) -> Size<f32>,
279{
280    /// A reference to the TaffyTree
281    pub(crate) taffy: &'t mut TaffyTree<NodeContext>,
282    /// The context provided for passing to measure functions if layout is run over this struct
283    pub(crate) measure_function: MeasureFunction,
284}
285
286// TraversePartialTree impl for TaffyView
287impl<NodeContext, MeasureFunction> TraversePartialTree for TaffyView<'_, NodeContext, MeasureFunction>
288where
289    MeasureFunction:
290        FnMut(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&mut NodeContext>, &Style) -> Size<f32>,
291{
292    type ChildIter<'a>
293        = TaffyTreeChildIter<'a>
294    where
295        Self: 'a;
296
297    #[inline(always)]
298    fn child_ids(&self, parent_node_id: NodeId) -> Self::ChildIter<'_> {
299        self.taffy.child_ids(parent_node_id)
300    }
301
302    #[inline(always)]
303    fn child_count(&self, parent_node_id: NodeId) -> usize {
304        self.taffy.child_count(parent_node_id)
305    }
306
307    #[inline(always)]
308    fn get_child_id(&self, parent_node_id: NodeId, child_index: usize) -> NodeId {
309        self.taffy.get_child_id(parent_node_id, child_index)
310    }
311}
312
313// TraverseTree impl for TaffyView
314impl<NodeContext, MeasureFunction> TraverseTree for TaffyView<'_, NodeContext, MeasureFunction> where
315    MeasureFunction:
316        FnMut(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&mut NodeContext>, &Style) -> Size<f32>
317{
318}
319
320// LayoutPartialTree impl for TaffyView
321impl<NodeContext, MeasureFunction> LayoutPartialTree for TaffyView<'_, NodeContext, MeasureFunction>
322where
323    MeasureFunction:
324        FnMut(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&mut NodeContext>, &Style) -> Size<f32>,
325{
326    type CoreContainerStyle<'a>
327        = &'a Style
328    where
329        Self: 'a;
330
331    type CustomIdent = DefaultCheapStr;
332
333    #[inline(always)]
334    fn get_core_container_style(&self, node_id: NodeId) -> Self::CoreContainerStyle<'_> {
335        &self.taffy.nodes[node_id.into()].style
336    }
337
338    #[inline(always)]
339    fn set_unrounded_layout(&mut self, node_id: NodeId, layout: &Layout) {
340        self.taffy.nodes[node_id.into()].unrounded_layout = *layout;
341    }
342
343    #[inline(always)]
344    fn resolve_calc_value(&self, _val: *const (), _basis: f32) -> f32 {
345        0.0
346    }
347
348    #[inline(always)]
349    fn compute_child_layout(&mut self, node: NodeId, inputs: LayoutInput) -> LayoutOutput {
350        // If RunMode is PerformHiddenLayout then this indicates that an ancestor node is `Display::None`
351        // and thus that we should lay out this node using hidden layout regardless of it's own display style.
352        if inputs.run_mode == RunMode::PerformHiddenLayout {
353            debug_log!("HIDDEN");
354            return compute_hidden_layout(self, node);
355        }
356
357        // We run the following wrapped in "compute_cached_layout", which will check the cache for an entry matching the node and inputs and:
358        //   - Return that entry if exists
359        //   - Else call the passed closure (below) to compute the result
360        //
361        // If there was no cache match and a new result needs to be computed then that result will be added to the cache
362        compute_cached_layout(self, node, inputs, |tree, node, inputs| {
363            let display_mode = tree.taffy.nodes[node.into()].style.display;
364            let has_children = tree.child_count(node) > 0;
365
366            debug_log!(display_mode);
367            debug_log_node!(
368                inputs.known_dimensions,
369                inputs.parent_size,
370                inputs.available_space,
371                inputs.run_mode,
372                inputs.sizing_mode
373            );
374
375            // Dispatch to a layout algorithm based on the node's display style and whether the node has children or not.
376            match (display_mode, has_children) {
377                (Display::None, _) => compute_hidden_layout(tree, node),
378                #[cfg(feature = "block_layout")]
379                (Display::Block, true) => compute_block_layout(tree, node, inputs),
380                #[cfg(feature = "flexbox")]
381                (Display::Flex, true) => compute_flexbox_layout(tree, node, inputs),
382                #[cfg(feature = "grid")]
383                (Display::Grid, true) => compute_grid_layout(tree, node, inputs),
384                (_, false) => {
385                    let node_key = node.into();
386                    let style = &tree.taffy.nodes[node_key].style;
387                    let has_context = tree.taffy.nodes[node_key].has_context;
388                    let node_context = has_context.then(|| tree.taffy.node_context_data.get_mut(node_key)).flatten();
389                    let measure_function = |known_dimensions, available_space| {
390                        (tree.measure_function)(known_dimensions, available_space, node, node_context, style)
391                    };
392                    // TODO: implement calc() in high-level API
393                    compute_leaf_layout(inputs, style, |_, _| 0.0, measure_function)
394                }
395            }
396        })
397    }
398}
399
400impl<NodeContext, MeasureFunction> CacheTree for TaffyView<'_, NodeContext, MeasureFunction>
401where
402    MeasureFunction:
403        FnMut(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&mut NodeContext>, &Style) -> Size<f32>,
404{
405    fn cache_get(
406        &self,
407        node_id: NodeId,
408        known_dimensions: Size<Option<f32>>,
409        available_space: Size<AvailableSpace>,
410        run_mode: RunMode,
411    ) -> Option<LayoutOutput> {
412        self.taffy.nodes[node_id.into()].cache.get(known_dimensions, available_space, run_mode)
413    }
414
415    fn cache_store(
416        &mut self,
417        node_id: NodeId,
418        known_dimensions: Size<Option<f32>>,
419        available_space: Size<AvailableSpace>,
420        run_mode: RunMode,
421        layout_output: LayoutOutput,
422    ) {
423        self.taffy.nodes[node_id.into()].cache.store(known_dimensions, available_space, run_mode, layout_output)
424    }
425
426    fn cache_clear(&mut self, node_id: NodeId) {
427        self.taffy.nodes[node_id.into()].cache.clear();
428    }
429}
430
431#[cfg(feature = "block_layout")]
432impl<NodeContext, MeasureFunction> LayoutBlockContainer for TaffyView<'_, NodeContext, MeasureFunction>
433where
434    MeasureFunction:
435        FnMut(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&mut NodeContext>, &Style) -> Size<f32>,
436{
437    type BlockContainerStyle<'a>
438        = &'a Style
439    where
440        Self: 'a;
441    type BlockItemStyle<'a>
442        = &'a Style
443    where
444        Self: 'a;
445
446    #[inline(always)]
447    fn get_block_container_style(&self, node_id: NodeId) -> Self::BlockContainerStyle<'_> {
448        self.get_core_container_style(node_id)
449    }
450
451    #[inline(always)]
452    fn get_block_child_style(&self, child_node_id: NodeId) -> Self::BlockItemStyle<'_> {
453        self.get_core_container_style(child_node_id)
454    }
455}
456
457#[cfg(feature = "flexbox")]
458impl<NodeContext, MeasureFunction> LayoutFlexboxContainer for TaffyView<'_, NodeContext, MeasureFunction>
459where
460    MeasureFunction:
461        FnMut(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&mut NodeContext>, &Style) -> Size<f32>,
462{
463    type FlexboxContainerStyle<'a>
464        = &'a Style
465    where
466        Self: 'a;
467    type FlexboxItemStyle<'a>
468        = &'a Style
469    where
470        Self: 'a;
471
472    #[inline(always)]
473    fn get_flexbox_container_style(&self, node_id: NodeId) -> Self::FlexboxContainerStyle<'_> {
474        &self.taffy.nodes[node_id.into()].style
475    }
476
477    #[inline(always)]
478    fn get_flexbox_child_style(&self, child_node_id: NodeId) -> Self::FlexboxItemStyle<'_> {
479        &self.taffy.nodes[child_node_id.into()].style
480    }
481}
482
483#[cfg(feature = "grid")]
484impl<NodeContext, MeasureFunction> LayoutGridContainer for TaffyView<'_, NodeContext, MeasureFunction>
485where
486    MeasureFunction:
487        FnMut(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&mut NodeContext>, &Style) -> Size<f32>,
488{
489    type GridContainerStyle<'a>
490        = &'a Style
491    where
492        Self: 'a;
493    type GridItemStyle<'a>
494        = &'a Style
495    where
496        Self: 'a;
497
498    #[inline(always)]
499    fn get_grid_container_style(&self, node_id: NodeId) -> Self::GridContainerStyle<'_> {
500        &self.taffy.nodes[node_id.into()].style
501    }
502
503    #[inline(always)]
504    fn get_grid_child_style(&self, child_node_id: NodeId) -> Self::GridItemStyle<'_> {
505        &self.taffy.nodes[child_node_id.into()].style
506    }
507
508    #[inline(always)]
509    #[cfg(feature = "detailed_layout_info")]
510    fn set_detailed_grid_info(&mut self, node_id: NodeId, detailed_grid_info: DetailedGridInfo) {
511        self.taffy.nodes[node_id.into()].detailed_layout_info = DetailedLayoutInfo::Grid(Box::new(detailed_grid_info));
512    }
513}
514
515// RoundTree impl for TaffyView
516impl<NodeContext, MeasureFunction> RoundTree for TaffyView<'_, NodeContext, MeasureFunction>
517where
518    MeasureFunction:
519        FnMut(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&mut NodeContext>, &Style) -> Size<f32>,
520{
521    #[inline(always)]
522    fn get_unrounded_layout(&self, node: NodeId) -> Layout {
523        self.taffy.nodes[node.into()].unrounded_layout
524    }
525
526    #[inline(always)]
527    fn set_final_layout(&mut self, node_id: NodeId, layout: &Layout) {
528        self.taffy.nodes[node_id.into()].final_layout = *layout;
529    }
530}
531
532#[allow(clippy::iter_cloned_collect)] // due to no-std support, we need to use `iter_cloned` instead of `collect`
533impl<NodeContext> TaffyTree<NodeContext> {
534    /// Creates a new [`TaffyTree`]
535    ///
536    /// The default capacity of a [`TaffyTree`] is 16 nodes.
537    #[must_use]
538    pub fn new() -> Self {
539        Self::with_capacity(16)
540    }
541
542    /// Creates a new [`TaffyTree`] that can store `capacity` nodes before reallocation
543    #[must_use]
544    pub fn with_capacity(capacity: usize) -> Self {
545        TaffyTree {
546            // TODO: make this method const upstream,
547            // so constructors here can be const
548            nodes: SlotMap::with_capacity(capacity),
549            children: SlotMap::with_capacity(capacity),
550            parents: SlotMap::with_capacity(capacity),
551            node_context_data: SecondaryMap::with_capacity(capacity),
552            config: TaffyConfig::default(),
553        }
554    }
555
556    /// Enable rounding of layout values. Rounding is enabled by default.
557    pub fn enable_rounding(&mut self) {
558        self.config.use_rounding = true;
559    }
560
561    /// Disable rounding of layout values. Rounding is enabled by default.
562    pub fn disable_rounding(&mut self) {
563        self.config.use_rounding = false;
564    }
565
566    /// Creates and adds a new unattached leaf node to the tree, and returns the node of the new node
567    pub fn new_leaf(&mut self, layout: Style) -> TaffyResult<NodeId> {
568        let id = self.nodes.insert(NodeData::new(layout));
569        let _ = self.children.insert(new_vec_with_capacity(0));
570        let _ = self.parents.insert(None);
571
572        Ok(id.into())
573    }
574
575    /// Creates and adds a new unattached leaf node to the tree, and returns the [`NodeId`] of the new node
576    ///
577    /// Creates and adds a new leaf node with a supplied context
578    pub fn new_leaf_with_context(&mut self, layout: Style, context: NodeContext) -> TaffyResult<NodeId> {
579        let mut data = NodeData::new(layout);
580        data.has_context = true;
581
582        let id = self.nodes.insert(data);
583        self.node_context_data.insert(id, context);
584
585        let _ = self.children.insert(new_vec_with_capacity(0));
586        let _ = self.parents.insert(None);
587
588        Ok(id.into())
589    }
590
591    /// Creates and adds a new node, which may have any number of `children`
592    pub fn new_with_children(&mut self, layout: Style, children: &[NodeId]) -> TaffyResult<NodeId> {
593        let id = NodeId::from(self.nodes.insert(NodeData::new(layout)));
594
595        for child in children {
596            self.parents[(*child).into()] = Some(id);
597        }
598
599        let _ = self.children.insert(children.iter().copied().collect::<_>());
600        let _ = self.parents.insert(None);
601
602        Ok(id)
603    }
604
605    /// Drops all nodes in the tree
606    pub fn clear(&mut self) {
607        self.nodes.clear();
608        self.children.clear();
609        self.parents.clear();
610    }
611
612    /// Remove a specific node from the tree and drop it
613    ///
614    /// Returns the id of the node removed.
615    pub fn remove(&mut self, node: NodeId) -> TaffyResult<NodeId> {
616        let key = node.into();
617        if let Some(parent) = self.parents[key] {
618            if let Some(children) = self.children.get_mut(parent.into()) {
619                children.retain(|f| *f != node);
620            }
621        }
622
623        // Remove "parent" references to a node when removing that node
624        if let Some(children) = self.children.get(key) {
625            for child in children.iter().copied() {
626                self.parents[child.into()] = None;
627            }
628        }
629
630        let _ = self.children.remove(key);
631        let _ = self.parents.remove(key);
632        let _ = self.nodes.remove(key);
633
634        Ok(node)
635    }
636
637    /// Sets the context data associated with the node
638    #[inline]
639    pub fn set_node_context(&mut self, node: NodeId, measure: Option<NodeContext>) -> TaffyResult<()> {
640        let key = node.into();
641        if let Some(measure) = measure {
642            self.nodes[key].has_context = true;
643            self.node_context_data.insert(key, measure);
644        } else {
645            self.nodes[key].has_context = false;
646            self.node_context_data.remove(key);
647        }
648
649        self.mark_dirty(node)?;
650
651        Ok(())
652    }
653
654    /// Gets a reference to the the context data associated with the node
655    #[inline]
656    pub fn get_node_context(&self, node: NodeId) -> Option<&NodeContext> {
657        self.node_context_data.get(node.into())
658    }
659
660    /// Gets a mutable reference to the the context data associated with the node
661    #[inline]
662    pub fn get_node_context_mut(&mut self, node: NodeId) -> Option<&mut NodeContext> {
663        self.node_context_data.get_mut(node.into())
664    }
665
666    /// Gets mutable references to the the context data associated with the nodes. All keys must be valid and disjoint, otherwise None is returned.
667    pub fn get_disjoint_node_context_mut<const N: usize>(
668        &mut self,
669        keys: [NodeId; N],
670    ) -> Option<[&mut NodeContext; N]> {
671        self.node_context_data.get_disjoint_mut(keys.map(|k| k.into()))
672    }
673
674    /// Adds a `child` node under the supplied `parent`
675    pub fn add_child(&mut self, parent: NodeId, child: NodeId) -> TaffyResult<()> {
676        let parent_key = parent.into();
677        let child_key = child.into();
678        self.parents[child_key] = Some(parent);
679        self.children[parent_key].push(child);
680        self.mark_dirty(parent)?;
681
682        Ok(())
683    }
684
685    /// Inserts a `child` node at the given `child_index` under the supplied `parent`, shifting all children after it to the right.
686    pub fn insert_child_at_index(&mut self, parent: NodeId, child_index: usize, child: NodeId) -> TaffyResult<()> {
687        let parent_key = parent.into();
688
689        let child_count = self.children[parent_key].len();
690        if child_index > child_count {
691            return Err(TaffyError::ChildIndexOutOfBounds { parent, child_index, child_count });
692        }
693
694        self.parents[child.into()] = Some(parent);
695        self.children[parent_key].insert(child_index, child);
696        self.mark_dirty(parent)?;
697
698        Ok(())
699    }
700
701    /// Directly sets the `children` of the supplied `parent`
702    pub fn set_children(&mut self, parent: NodeId, children: &[NodeId]) -> TaffyResult<()> {
703        let parent_key = parent.into();
704
705        // Remove node as parent from all its current children.
706        for child in &self.children[parent_key] {
707            self.parents[(*child).into()] = None;
708        }
709
710        // Build up relation node <-> child
711        for &child in children {
712            // Remove child from previous parent
713            if let Some(previous_parent) = self.parents[child.into()] {
714                self.remove_child(previous_parent, child).unwrap();
715            }
716            self.parents[child.into()] = Some(parent);
717        }
718
719        let parent_children = &mut self.children[parent_key];
720        parent_children.clear();
721        children.iter().for_each(|child| parent_children.push(*child));
722
723        self.mark_dirty(parent)?;
724
725        Ok(())
726    }
727
728    /// Removes the `child` of the parent `node`
729    ///
730    /// The child is not removed from the tree entirely, it is simply no longer attached to its previous parent.
731    pub fn remove_child(&mut self, parent: NodeId, child: NodeId) -> TaffyResult<NodeId> {
732        let index = self.children[parent.into()].iter().position(|n| *n == child).unwrap();
733        self.remove_child_at_index(parent, index)
734    }
735
736    /// Removes the child at the given `index` from the `parent`
737    ///
738    /// The child is not removed from the tree entirely, it is simply no longer attached to its previous parent.
739    pub fn remove_child_at_index(&mut self, parent: NodeId, child_index: usize) -> TaffyResult<NodeId> {
740        let parent_key = parent.into();
741        let child_count = self.children[parent_key].len();
742        if child_index >= child_count {
743            return Err(TaffyError::ChildIndexOutOfBounds { parent, child_index, child_count });
744        }
745
746        let child = self.children[parent_key].remove(child_index);
747        self.parents[child.into()] = None;
748
749        self.mark_dirty(parent)?;
750
751        Ok(child)
752    }
753
754    /// Removes children at the given range from the `parent`
755    ///
756    /// Children are not removed from the tree entirely, they are simply no longer attached to their previous parent.
757    ///
758    /// Function will panic if given range is invalid. See [`core::slice::range`]
759    pub fn remove_children_range<R>(&mut self, parent: NodeId, range: R) -> TaffyResult<()>
760    where
761        R: core::ops::RangeBounds<usize>,
762    {
763        let parent_key = parent.into();
764        for child in self.children[parent_key].drain(range) {
765            self.parents[child.into()] = None;
766        }
767
768        self.mark_dirty(parent)?;
769        Ok(())
770    }
771
772    /// Replaces the child at the given `child_index` from the `parent` node with the new `child` node
773    ///
774    /// The child is not removed from the tree entirely, it is simply no longer attached to its previous parent.
775    pub fn replace_child_at_index(
776        &mut self,
777        parent: NodeId,
778        child_index: usize,
779        new_child: NodeId,
780    ) -> TaffyResult<NodeId> {
781        let parent_key = parent.into();
782
783        let child_count = self.children[parent_key].len();
784        if child_index >= child_count {
785            return Err(TaffyError::ChildIndexOutOfBounds { parent, child_index, child_count });
786        }
787
788        self.parents[new_child.into()] = Some(parent);
789        let old_child = core::mem::replace(&mut self.children[parent_key][child_index], new_child);
790        self.parents[old_child.into()] = None;
791
792        self.mark_dirty(parent)?;
793
794        Ok(old_child)
795    }
796
797    /// Returns the child node of the parent `node` at the provided `child_index`
798    #[inline]
799    pub fn child_at_index(&self, parent: NodeId, child_index: usize) -> TaffyResult<NodeId> {
800        let parent_key = parent.into();
801        let child_count = self.children[parent_key].len();
802        if child_index >= child_count {
803            return Err(TaffyError::ChildIndexOutOfBounds { parent, child_index, child_count });
804        }
805
806        Ok(self.children[parent_key][child_index])
807    }
808
809    /// Returns the total number of nodes in the tree
810    #[inline]
811    pub fn total_node_count(&self) -> usize {
812        self.nodes.len()
813    }
814
815    /// Returns the `NodeId` of the parent node of the specified node (if it exists)
816    ///
817    /// - Return None if the specified node has no parent
818    /// - Panics if the specified node does not exist
819    #[inline]
820    pub fn parent(&self, child_id: NodeId) -> Option<NodeId> {
821        self.parents[child_id.into()]
822    }
823
824    /// Returns a list of children that belong to the parent node
825    pub fn children(&self, parent: NodeId) -> TaffyResult<Vec<NodeId>> {
826        Ok(self.children[parent.into()].clone())
827    }
828
829    /// Sets the [`Style`] of the provided `node`
830    #[inline]
831    pub fn set_style(&mut self, node: NodeId, style: Style) -> TaffyResult<()> {
832        self.nodes[node.into()].style = style;
833        self.mark_dirty(node)?;
834        Ok(())
835    }
836
837    /// Gets the [`Style`] of the provided `node`
838    #[inline]
839    pub fn style(&self, node: NodeId) -> TaffyResult<&Style> {
840        Ok(&self.nodes[node.into()].style)
841    }
842
843    /// Return this node layout relative to its parent
844    #[inline]
845    pub fn layout(&self, node: NodeId) -> TaffyResult<&Layout> {
846        if self.config.use_rounding {
847            Ok(&self.nodes[node.into()].final_layout)
848        } else {
849            Ok(&self.nodes[node.into()].unrounded_layout)
850        }
851    }
852
853    /// Returns this node layout with unrounded values relative to its parent.
854    #[inline]
855    pub fn unrounded_layout(&self, node: NodeId) -> &Layout {
856        &self.nodes[node.into()].unrounded_layout
857    }
858
859    /// Get the "detailed layout info" for a node.
860    ///
861    /// Currently this is only implemented for CSS Grid containers where it contains
862    /// the computed size of each grid track and the computed placement of each grid item
863    #[cfg(feature = "detailed_layout_info")]
864    #[inline]
865    pub fn detailed_layout_info(&self, node_id: NodeId) -> &DetailedLayoutInfo {
866        &self.nodes[node_id.into()].detailed_layout_info
867    }
868
869    /// Marks the layout of this node and its ancestors as outdated
870    pub fn mark_dirty(&mut self, node: NodeId) -> TaffyResult<()> {
871        fn mark_dirty_recursive(
872            nodes: &mut SlotMap<DefaultKey, NodeData>,
873            parents: &SlotMap<DefaultKey, Option<NodeId>>,
874            node_key: DefaultKey,
875        ) {
876            match nodes[node_key].mark_dirty() {
877                ClearState::AlreadyEmpty => {
878                    // Node was already marked as dirty.
879                    // No need to visit ancestors
880                    // as they should be marked as dirty already.
881                }
882                ClearState::Cleared => {
883                    if let Some(Some(node)) = parents.get(node_key) {
884                        mark_dirty_recursive(nodes, parents, (*node).into());
885                    }
886                }
887            }
888        }
889
890        mark_dirty_recursive(&mut self.nodes, &self.parents, node.into());
891
892        Ok(())
893    }
894
895    /// Indicates whether the layout of this node needs to be recomputed
896    #[inline]
897    pub fn dirty(&self, node: NodeId) -> TaffyResult<bool> {
898        Ok(self.nodes[node.into()].cache.is_empty())
899    }
900
901    /// Updates the stored layout of the provided `node` and its children
902    pub fn compute_layout_with_measure<MeasureFunction>(
903        &mut self,
904        node_id: NodeId,
905        available_space: Size<AvailableSpace>,
906        measure_function: MeasureFunction,
907    ) -> Result<(), TaffyError>
908    where
909        MeasureFunction:
910            FnMut(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&mut NodeContext>, &Style) -> Size<f32>,
911    {
912        let use_rounding = self.config.use_rounding;
913        let mut taffy_view = TaffyView { taffy: self, measure_function };
914        compute_root_layout(&mut taffy_view, node_id, available_space);
915        if use_rounding {
916            round_layout(&mut taffy_view, node_id);
917        }
918        Ok(())
919    }
920
921    /// Updates the stored layout of the provided `node` and its children
922    pub fn compute_layout(&mut self, node: NodeId, available_space: Size<AvailableSpace>) -> Result<(), TaffyError> {
923        self.compute_layout_with_measure(node, available_space, |_, _, _, _, _| Size::ZERO)
924    }
925
926    /// Prints a debug representation of the tree's layout
927    #[cfg(feature = "std")]
928    pub fn print_tree(&mut self, root: NodeId) {
929        crate::util::print_tree(self, root)
930    }
931
932    /// Returns an instance of LayoutTree representing the TaffyTree
933    #[cfg(test)]
934    pub(crate) fn as_layout_tree(&mut self) -> impl LayoutPartialTree + CacheTree + '_ {
935        TaffyView { taffy: self, measure_function: |_, _, _, _, _| Size::ZERO }
936    }
937}
938
939#[cfg(test)]
940mod tests {
941
942    use super::*;
943    use crate::style::{Dimension, Display, FlexDirection};
944    use crate::style_helpers::*;
945    use crate::util::sys;
946
947    fn size_measure_function(
948        known_dimensions: Size<Option<f32>>,
949        _available_space: Size<AvailableSpace>,
950        _node_id: NodeId,
951        node_context: Option<&mut Size<f32>>,
952        _style: &Style,
953    ) -> Size<f32> {
954        known_dimensions.unwrap_or(node_context.cloned().unwrap_or(Size::ZERO))
955    }
956
957    #[test]
958    fn new_should_allocate_default_capacity() {
959        const DEFAULT_CAPACITY: usize = 16; // This is the capacity defined in the `impl Default`
960        let taffy: TaffyTree<()> = TaffyTree::new();
961
962        assert!(taffy.children.capacity() >= DEFAULT_CAPACITY);
963        assert!(taffy.parents.capacity() >= DEFAULT_CAPACITY);
964        assert!(taffy.nodes.capacity() >= DEFAULT_CAPACITY);
965    }
966
967    #[test]
968    fn test_with_capacity() {
969        const CAPACITY: usize = 8;
970        let taffy: TaffyTree<()> = TaffyTree::with_capacity(CAPACITY);
971
972        assert!(taffy.children.capacity() >= CAPACITY);
973        assert!(taffy.parents.capacity() >= CAPACITY);
974        assert!(taffy.nodes.capacity() >= CAPACITY);
975    }
976
977    #[test]
978    fn test_new_leaf() {
979        let mut taffy: TaffyTree<()> = TaffyTree::new();
980
981        let res = taffy.new_leaf(Style::default());
982        assert!(res.is_ok());
983        let node = res.unwrap();
984
985        // node should be in the taffy tree and have no children
986        assert!(taffy.child_count(node) == 0);
987    }
988
989    #[test]
990    fn new_leaf_with_context() {
991        let mut taffy: TaffyTree<Size<f32>> = TaffyTree::new();
992
993        let res = taffy.new_leaf_with_context(Style::default(), Size::ZERO);
994        assert!(res.is_ok());
995        let node = res.unwrap();
996
997        // node should be in the taffy tree and have no children
998        assert!(taffy.child_count(node) == 0);
999    }
1000
1001    /// Test that new_with_children works as expected
1002    #[test]
1003    fn test_new_with_children() {
1004        let mut taffy: TaffyTree<()> = TaffyTree::new();
1005        let child0 = taffy.new_leaf(Style::default()).unwrap();
1006        let child1 = taffy.new_leaf(Style::default()).unwrap();
1007        let node = taffy.new_with_children(Style::default(), &[child0, child1]).unwrap();
1008
1009        // node should have two children
1010        assert_eq!(taffy.child_count(node), 2);
1011        assert_eq!(taffy.children(node).unwrap()[0], child0);
1012        assert_eq!(taffy.children(node).unwrap()[1], child1);
1013    }
1014
1015    #[test]
1016    fn remove_node_should_remove() {
1017        let mut taffy: TaffyTree<()> = TaffyTree::new();
1018
1019        let node = taffy.new_leaf(Style::default()).unwrap();
1020
1021        let _ = taffy.remove(node).unwrap();
1022    }
1023
1024    #[test]
1025    fn remove_node_should_detach_hierarchy() {
1026        let mut taffy: TaffyTree<()> = TaffyTree::new();
1027
1028        // Build a linear tree layout: <0> <- <1> <- <2>
1029        let node2 = taffy.new_leaf(Style::default()).unwrap();
1030        let node1 = taffy.new_with_children(Style::default(), &[node2]).unwrap();
1031        let node0 = taffy.new_with_children(Style::default(), &[node1]).unwrap();
1032
1033        // Both node0 and node1 should have 1 child nodes
1034        assert_eq!(taffy.children(node0).unwrap().as_slice(), &[node1]);
1035        assert_eq!(taffy.children(node1).unwrap().as_slice(), &[node2]);
1036
1037        // Disconnect the tree: <0> <2>
1038        let _ = taffy.remove(node1).unwrap();
1039
1040        // Both remaining nodes should have no child nodes
1041        assert!(taffy.children(node0).unwrap().is_empty());
1042        assert!(taffy.children(node2).unwrap().is_empty());
1043    }
1044
1045    #[test]
1046    fn remove_last_node() {
1047        let mut taffy: TaffyTree<()> = TaffyTree::new();
1048
1049        let parent = taffy.new_leaf(Style::default()).unwrap();
1050        let child = taffy.new_leaf(Style::default()).unwrap();
1051        taffy.add_child(parent, child).unwrap();
1052
1053        taffy.remove(child).unwrap();
1054        taffy.remove(parent).unwrap();
1055    }
1056
1057    #[test]
1058    fn set_measure() {
1059        let mut taffy: TaffyTree<Size<f32>> = TaffyTree::new();
1060        let node = taffy.new_leaf_with_context(Style::default(), Size { width: 200.0, height: 200.0 }).unwrap();
1061        taffy.compute_layout_with_measure(node, Size::MAX_CONTENT, size_measure_function).unwrap();
1062        assert_eq!(taffy.layout(node).unwrap().size.width, 200.0);
1063
1064        taffy.set_node_context(node, Some(Size { width: 100.0, height: 100.0 })).unwrap();
1065        taffy.compute_layout_with_measure(node, Size::MAX_CONTENT, size_measure_function).unwrap();
1066        assert_eq!(taffy.layout(node).unwrap().size.width, 100.0);
1067    }
1068
1069    #[test]
1070    fn set_measure_of_previously_unmeasured_node() {
1071        let mut taffy: TaffyTree<Size<f32>> = TaffyTree::new();
1072        let node = taffy.new_leaf(Style::default()).unwrap();
1073        taffy.compute_layout_with_measure(node, Size::MAX_CONTENT, size_measure_function).unwrap();
1074        assert_eq!(taffy.layout(node).unwrap().size.width, 0.0);
1075
1076        taffy.set_node_context(node, Some(Size { width: 100.0, height: 100.0 })).unwrap();
1077        taffy.compute_layout_with_measure(node, Size::MAX_CONTENT, size_measure_function).unwrap();
1078        assert_eq!(taffy.layout(node).unwrap().size.width, 100.0);
1079    }
1080
1081    /// Test that adding `add_child()` works
1082    #[test]
1083    fn add_child() {
1084        let mut taffy: TaffyTree<()> = TaffyTree::new();
1085        let node = taffy.new_leaf(Style::default()).unwrap();
1086        assert_eq!(taffy.child_count(node), 0);
1087
1088        let child0 = taffy.new_leaf(Style::default()).unwrap();
1089        taffy.add_child(node, child0).unwrap();
1090        assert_eq!(taffy.child_count(node), 1);
1091
1092        let child1 = taffy.new_leaf(Style::default()).unwrap();
1093        taffy.add_child(node, child1).unwrap();
1094        assert_eq!(taffy.child_count(node), 2);
1095    }
1096
1097    #[test]
1098    fn insert_child_at_index() {
1099        let mut taffy: TaffyTree<()> = TaffyTree::new();
1100
1101        let child0 = taffy.new_leaf(Style::default()).unwrap();
1102        let child1 = taffy.new_leaf(Style::default()).unwrap();
1103        let child2 = taffy.new_leaf(Style::default()).unwrap();
1104
1105        let node = taffy.new_leaf(Style::default()).unwrap();
1106        assert_eq!(taffy.child_count(node), 0);
1107
1108        taffy.insert_child_at_index(node, 0, child0).unwrap();
1109        assert_eq!(taffy.child_count(node), 1);
1110        assert_eq!(taffy.children(node).unwrap()[0], child0);
1111
1112        taffy.insert_child_at_index(node, 0, child1).unwrap();
1113        assert_eq!(taffy.child_count(node), 2);
1114        assert_eq!(taffy.children(node).unwrap()[0], child1);
1115        assert_eq!(taffy.children(node).unwrap()[1], child0);
1116
1117        taffy.insert_child_at_index(node, 1, child2).unwrap();
1118        assert_eq!(taffy.child_count(node), 3);
1119        assert_eq!(taffy.children(node).unwrap()[0], child1);
1120        assert_eq!(taffy.children(node).unwrap()[1], child2);
1121        assert_eq!(taffy.children(node).unwrap()[2], child0);
1122    }
1123
1124    #[test]
1125    fn set_children() {
1126        let mut taffy: TaffyTree<()> = TaffyTree::new();
1127
1128        let child0 = taffy.new_leaf(Style::default()).unwrap();
1129        let child1 = taffy.new_leaf(Style::default()).unwrap();
1130        let node = taffy.new_with_children(Style::default(), &[child0, child1]).unwrap();
1131
1132        assert_eq!(taffy.child_count(node), 2);
1133        assert_eq!(taffy.children(node).unwrap()[0], child0);
1134        assert_eq!(taffy.children(node).unwrap()[1], child1);
1135
1136        let child2 = taffy.new_leaf(Style::default()).unwrap();
1137        let child3 = taffy.new_leaf(Style::default()).unwrap();
1138        taffy.set_children(node, &[child2, child3]).unwrap();
1139
1140        assert_eq!(taffy.child_count(node), 2);
1141        assert_eq!(taffy.children(node).unwrap()[0], child2);
1142        assert_eq!(taffy.children(node).unwrap()[1], child3);
1143    }
1144
1145    /// Test that removing a child works
1146    #[test]
1147    fn remove_child() {
1148        let mut taffy: TaffyTree<()> = TaffyTree::new();
1149        let child0 = taffy.new_leaf(Style::default()).unwrap();
1150        let child1 = taffy.new_leaf(Style::default()).unwrap();
1151        let node = taffy.new_with_children(Style::default(), &[child0, child1]).unwrap();
1152
1153        assert_eq!(taffy.child_count(node), 2);
1154
1155        taffy.remove_child(node, child0).unwrap();
1156        assert_eq!(taffy.child_count(node), 1);
1157        assert_eq!(taffy.children(node).unwrap()[0], child1);
1158
1159        taffy.remove_child(node, child1).unwrap();
1160        assert_eq!(taffy.child_count(node), 0);
1161    }
1162
1163    #[test]
1164    fn remove_child_at_index() {
1165        let mut taffy: TaffyTree<()> = TaffyTree::new();
1166        let child0 = taffy.new_leaf(Style::default()).unwrap();
1167        let child1 = taffy.new_leaf(Style::default()).unwrap();
1168        let node = taffy.new_with_children(Style::default(), &[child0, child1]).unwrap();
1169
1170        assert_eq!(taffy.child_count(node), 2);
1171
1172        taffy.remove_child_at_index(node, 0).unwrap();
1173        assert_eq!(taffy.child_count(node), 1);
1174        assert_eq!(taffy.children(node).unwrap()[0], child1);
1175
1176        taffy.remove_child_at_index(node, 0).unwrap();
1177        assert_eq!(taffy.child_count(node), 0);
1178    }
1179
1180    #[test]
1181    fn remove_children_range() {
1182        let mut taffy: TaffyTree<()> = TaffyTree::new();
1183        let child0 = taffy.new_leaf(Style::default()).unwrap();
1184        let child1 = taffy.new_leaf(Style::default()).unwrap();
1185        let child2 = taffy.new_leaf(Style::default()).unwrap();
1186        let child3 = taffy.new_leaf(Style::default()).unwrap();
1187        let node = taffy.new_with_children(Style::default(), &[child0, child1, child2, child3]).unwrap();
1188
1189        assert_eq!(taffy.child_count(node), 4);
1190
1191        taffy.remove_children_range(node, 1..=2).unwrap();
1192        assert_eq!(taffy.child_count(node), 2);
1193        assert_eq!(taffy.children(node).unwrap(), [child0, child3]);
1194        for child in [child0, child3] {
1195            assert_eq!(taffy.parent(child), Some(node));
1196        }
1197        for child in [child1, child2] {
1198            assert_eq!(taffy.parent(child), None);
1199        }
1200    }
1201
1202    // Related to: https://github.com/DioxusLabs/taffy/issues/510
1203    #[test]
1204    fn remove_child_updates_parents() {
1205        let mut taffy: TaffyTree<()> = TaffyTree::new();
1206
1207        let parent = taffy.new_leaf(Style::default()).unwrap();
1208        let child = taffy.new_leaf(Style::default()).unwrap();
1209
1210        taffy.add_child(parent, child).unwrap();
1211
1212        taffy.remove(parent).unwrap();
1213
1214        // Once the parent is removed this shouldn't panic.
1215        assert!(taffy.set_children(child, &[]).is_ok());
1216    }
1217
1218    #[test]
1219    fn replace_child_at_index() {
1220        let mut taffy: TaffyTree<()> = TaffyTree::new();
1221
1222        let child0 = taffy.new_leaf(Style::default()).unwrap();
1223        let child1 = taffy.new_leaf(Style::default()).unwrap();
1224
1225        let node = taffy.new_with_children(Style::default(), &[child0]).unwrap();
1226        assert_eq!(taffy.child_count(node), 1);
1227        assert_eq!(taffy.children(node).unwrap()[0], child0);
1228
1229        taffy.replace_child_at_index(node, 0, child1).unwrap();
1230        assert_eq!(taffy.child_count(node), 1);
1231        assert_eq!(taffy.children(node).unwrap()[0], child1);
1232    }
1233    #[test]
1234    fn test_child_at_index() {
1235        let mut taffy: TaffyTree<()> = TaffyTree::new();
1236        let child0 = taffy.new_leaf(Style::default()).unwrap();
1237        let child1 = taffy.new_leaf(Style::default()).unwrap();
1238        let child2 = taffy.new_leaf(Style::default()).unwrap();
1239        let node = taffy.new_with_children(Style::default(), &[child0, child1, child2]).unwrap();
1240
1241        assert!(if let Ok(result) = taffy.child_at_index(node, 0) { result == child0 } else { false });
1242        assert!(if let Ok(result) = taffy.child_at_index(node, 1) { result == child1 } else { false });
1243        assert!(if let Ok(result) = taffy.child_at_index(node, 2) { result == child2 } else { false });
1244    }
1245    #[test]
1246    fn test_child_count() {
1247        let mut taffy: TaffyTree<()> = TaffyTree::new();
1248        let child0 = taffy.new_leaf(Style::default()).unwrap();
1249        let child1 = taffy.new_leaf(Style::default()).unwrap();
1250        let node = taffy.new_with_children(Style::default(), &[child0, child1]).unwrap();
1251
1252        assert!(taffy.child_count(node) == 2);
1253        assert!(taffy.child_count(child0) == 0);
1254        assert!(taffy.child_count(child1) == 0);
1255    }
1256
1257    #[allow(clippy::vec_init_then_push)]
1258    #[test]
1259    fn test_children() {
1260        let mut taffy: TaffyTree<()> = TaffyTree::new();
1261        let child0 = taffy.new_leaf(Style::default()).unwrap();
1262        let child1 = taffy.new_leaf(Style::default()).unwrap();
1263        let node = taffy.new_with_children(Style::default(), &[child0, child1]).unwrap();
1264
1265        let mut children = sys::Vec::new();
1266        children.push(child0);
1267        children.push(child1);
1268
1269        let children_result = taffy.children(node).unwrap();
1270        assert_eq!(children_result, children);
1271
1272        assert!(taffy.children(child0).unwrap().is_empty());
1273    }
1274    #[test]
1275    fn test_set_style() {
1276        let mut taffy: TaffyTree<()> = TaffyTree::new();
1277
1278        let node = taffy.new_leaf(Style::default()).unwrap();
1279        assert_eq!(taffy.style(node).unwrap().display, Display::Flex);
1280
1281        taffy.set_style(node, Style { display: Display::None, ..Style::default() }).unwrap();
1282        assert_eq!(taffy.style(node).unwrap().display, Display::None);
1283    }
1284    #[test]
1285    fn test_style() {
1286        let mut taffy: TaffyTree<()> = TaffyTree::new();
1287
1288        let style = Style { display: Display::None, flex_direction: FlexDirection::RowReverse, ..Default::default() };
1289
1290        let node = taffy.new_leaf(style.clone()).unwrap();
1291
1292        let res = taffy.style(node);
1293        assert!(res.is_ok());
1294        assert!(res.unwrap() == &style);
1295    }
1296    #[test]
1297    fn test_layout() {
1298        let mut taffy: TaffyTree<()> = TaffyTree::new();
1299        let node = taffy.new_leaf(Style::default()).unwrap();
1300
1301        // TODO: Improve this test?
1302        let res = taffy.layout(node);
1303        assert!(res.is_ok());
1304    }
1305
1306    #[test]
1307    fn test_mark_dirty() {
1308        let mut taffy: TaffyTree<()> = TaffyTree::new();
1309        let child0 = taffy.new_leaf(Style::default()).unwrap();
1310        let child1 = taffy.new_leaf(Style::default()).unwrap();
1311        let node = taffy.new_with_children(Style::default(), &[child0, child1]).unwrap();
1312
1313        taffy.compute_layout(node, Size::MAX_CONTENT).unwrap();
1314
1315        assert_eq!(taffy.dirty(child0), Ok(false));
1316        assert_eq!(taffy.dirty(child1), Ok(false));
1317        assert_eq!(taffy.dirty(node), Ok(false));
1318
1319        taffy.mark_dirty(node).unwrap();
1320        assert_eq!(taffy.dirty(child0), Ok(false));
1321        assert_eq!(taffy.dirty(child1), Ok(false));
1322        assert_eq!(taffy.dirty(node), Ok(true));
1323
1324        taffy.compute_layout(node, Size::MAX_CONTENT).unwrap();
1325        taffy.mark_dirty(child0).unwrap();
1326        assert_eq!(taffy.dirty(child0), Ok(true));
1327        assert_eq!(taffy.dirty(child1), Ok(false));
1328        assert_eq!(taffy.dirty(node), Ok(true));
1329    }
1330
1331    #[test]
1332    fn compute_layout_should_produce_valid_result() {
1333        let mut taffy: TaffyTree<()> = TaffyTree::new();
1334        let node_result = taffy.new_leaf(Style {
1335            size: Size { width: Dimension::from_length(10f32), height: Dimension::from_length(10f32) },
1336            ..Default::default()
1337        });
1338        assert!(node_result.is_ok());
1339        let node = node_result.unwrap();
1340        let layout_result = taffy.compute_layout(
1341            node,
1342            Size { width: AvailableSpace::Definite(100.), height: AvailableSpace::Definite(100.) },
1343        );
1344        assert!(layout_result.is_ok());
1345    }
1346
1347    #[test]
1348    fn make_sure_layout_location_is_top_left() {
1349        use crate::prelude::*;
1350
1351        let mut taffy: TaffyTree<()> = TaffyTree::new();
1352
1353        let node = taffy
1354            .new_leaf(Style {
1355                size: Size { width: Dimension::from_percent(1f32), height: Dimension::from_percent(1f32) },
1356                ..Default::default()
1357            })
1358            .unwrap();
1359
1360        let root = taffy
1361            .new_with_children(
1362                Style {
1363                    size: Size { width: Dimension::from_length(100f32), height: Dimension::from_length(100f32) },
1364                    padding: Rect {
1365                        left: length(10f32),
1366                        right: length(20f32),
1367                        top: length(30f32),
1368                        bottom: length(40f32),
1369                    },
1370                    ..Default::default()
1371                },
1372                &[node],
1373            )
1374            .unwrap();
1375
1376        taffy.compute_layout(root, Size::MAX_CONTENT).unwrap();
1377
1378        // If Layout::location represents top-left coord, 'node' location
1379        // must be (due applied 'root' padding): {x: 10, y: 30}.
1380        //
1381        // It's important, since result will be different for each other
1382        // coordinate space:
1383        // - bottom-left:  {x: 10, y: 40}
1384        // - top-right:    {x: 20, y: 30}
1385        // - bottom-right: {x: 20, y: 40}
1386        let layout = taffy.layout(node).unwrap();
1387        assert_eq!(layout.location.x, 10f32);
1388        assert_eq!(layout.location.y, 30f32);
1389    }
1390
1391    #[test]
1392    fn set_children_reparents() {
1393        let mut taffy: TaffyTree<()> = TaffyTree::new();
1394        let child = taffy.new_leaf(Style::default()).unwrap();
1395        let old_parent = taffy.new_with_children(Style::default(), &[child]).unwrap();
1396
1397        let new_parent = taffy.new_leaf(Style::default()).unwrap();
1398        taffy.set_children(new_parent, &[child]).unwrap();
1399
1400        assert!(taffy.children(old_parent).unwrap().is_empty());
1401    }
1402}