1#[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
34pub type TaffyResult<T> = Result<T, TaffyError>;
36
37#[derive(Debug, Clone, PartialEq, Eq)]
39pub enum TaffyError {
40 ChildIndexOutOfBounds {
42 parent: NodeId,
44 child_index: usize,
46 child_count: usize,
48 },
49 InvalidParentNode(NodeId),
51 InvalidChildNode(NodeId),
53 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#[derive(Debug, Clone, Copy)]
77pub(crate) struct TaffyConfig {
78 pub(crate) use_rounding: bool,
80}
81
82impl Default for TaffyConfig {
83 fn default() -> Self {
84 Self { use_rounding: true }
85 }
86}
87
88#[derive(Debug, Clone, PartialEq)]
92struct NodeData {
93 pub(crate) style: Style,
95
96 pub(crate) unrounded_layout: Layout,
99
100 pub(crate) final_layout: Layout,
103
104 pub(crate) has_context: bool,
106
107 pub(crate) cache: Cache,
109
110 #[cfg(feature = "detailed_layout_info")]
112 pub(crate) detailed_layout_info: DetailedLayoutInfo,
113}
114
115impl NodeData {
116 #[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 #[inline]
135 pub fn mark_dirty(&mut self) -> ClearState {
136 self.cache.clear()
137 }
138}
139
140#[derive(Debug, Clone)]
144pub struct TaffyTree<NodeContext = ()> {
145 nodes: SlotMap<DefaultKey, NodeData>,
147
148 node_context_data: SecondaryMap<DefaultKey, NodeContext>,
150
151 children: SlotMap<DefaultKey, ChildrenVec<NodeId>>,
155
156 parents: SlotMap<DefaultKey, Option<NodeId>>,
160
161 config: TaffyConfig,
163}
164
165impl Default for TaffyTree {
166 fn default() -> TaffyTree<()> {
167 TaffyTree::new()
168 }
169}
170
171pub 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
182impl<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
205impl<NodeContext> TraverseTree for TaffyTree<NodeContext> {}
207
208impl<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
236impl<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
272pub(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 pub(crate) taffy: &'t mut TaffyTree<NodeContext>,
282 pub(crate) measure_function: MeasureFunction,
284}
285
286impl<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
313impl<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
320impl<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 inputs.run_mode == RunMode::PerformHiddenLayout {
353 debug_log!("HIDDEN");
354 return compute_hidden_layout(self, node);
355 }
356
357 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 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 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
515impl<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)] impl<NodeContext> TaffyTree<NodeContext> {
534 #[must_use]
538 pub fn new() -> Self {
539 Self::with_capacity(16)
540 }
541
542 #[must_use]
544 pub fn with_capacity(capacity: usize) -> Self {
545 TaffyTree {
546 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 pub fn enable_rounding(&mut self) {
558 self.config.use_rounding = true;
559 }
560
561 pub fn disable_rounding(&mut self) {
563 self.config.use_rounding = false;
564 }
565
566 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 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 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 pub fn clear(&mut self) {
607 self.nodes.clear();
608 self.children.clear();
609 self.parents.clear();
610 }
611
612 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 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 #[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 #[inline]
656 pub fn get_node_context(&self, node: NodeId) -> Option<&NodeContext> {
657 self.node_context_data.get(node.into())
658 }
659
660 #[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 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 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 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 pub fn set_children(&mut self, parent: NodeId, children: &[NodeId]) -> TaffyResult<()> {
703 let parent_key = parent.into();
704
705 for child in &self.children[parent_key] {
707 self.parents[(*child).into()] = None;
708 }
709
710 for &child in children {
712 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 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 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 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 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 #[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 #[inline]
811 pub fn total_node_count(&self) -> usize {
812 self.nodes.len()
813 }
814
815 #[inline]
820 pub fn parent(&self, child_id: NodeId) -> Option<NodeId> {
821 self.parents[child_id.into()]
822 }
823
824 pub fn children(&self, parent: NodeId) -> TaffyResult<Vec<NodeId>> {
826 Ok(self.children[parent.into()].clone())
827 }
828
829 #[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 #[inline]
839 pub fn style(&self, node: NodeId) -> TaffyResult<&Style> {
840 Ok(&self.nodes[node.into()].style)
841 }
842
843 #[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 #[inline]
855 pub fn unrounded_layout(&self, node: NodeId) -> &Layout {
856 &self.nodes[node.into()].unrounded_layout
857 }
858
859 #[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 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 }
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 #[inline]
897 pub fn dirty(&self, node: NodeId) -> TaffyResult<bool> {
898 Ok(self.nodes[node.into()].cache.is_empty())
899 }
900
901 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 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 #[cfg(feature = "std")]
928 pub fn print_tree(&mut self, root: NodeId) {
929 crate::util::print_tree(self, root)
930 }
931
932 #[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; 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 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 assert!(taffy.child_count(node) == 0);
999 }
1000
1001 #[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 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 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 assert_eq!(taffy.children(node0).unwrap().as_slice(), &[node1]);
1035 assert_eq!(taffy.children(node1).unwrap().as_slice(), &[node2]);
1036
1037 let _ = taffy.remove(node1).unwrap();
1039
1040 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]
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]
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 #[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 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 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 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}