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