1#[cfg(not(feature = "std"))]
3use slotmap::SecondaryMap;
4#[cfg(feature = "std")]
5use slotmap::SparseSecondaryMap as SecondaryMap;
6use slotmap::{DefaultKey, SlotMap};
7
8#[cfg(feature = "block_layout")]
9use crate::block::BlockContext;
10use crate::geometry::Size;
11use crate::style::{AvailableSpace, Display, Style};
12use crate::sys::DefaultCheapStr;
13use crate::tree::{
14 Cache, ClearState, Layout, LayoutContainingBlock, LayoutInput, LayoutOutput, LayoutPartialTree, NodeId, PrintTree,
15 RoundTree, RunMode, TraversePartialTree, TraverseTree,
16};
17use crate::util::debug::{debug_log, debug_log_node};
18use crate::util::sys::{new_const_children_vec, new_vec_with_capacity, Box, ChildrenVec, Vec};
19
20use crate::compute::{
21 compute_cached_layout, compute_hidden_layout, compute_leaf_layout, compute_oof_layout, compute_root_layout,
22 round_layout,
23};
24use crate::CacheTree;
25
26#[cfg(feature = "block_layout")]
27use crate::{compute::compute_block_layout, LayoutBlockContainer};
28#[cfg(feature = "flexbox")]
29use crate::{compute::compute_flexbox_layout, LayoutFlexboxContainer};
30#[cfg(feature = "grid")]
31use crate::{compute::compute_grid_layout, LayoutGridContainer};
32
33#[cfg(feature = "grid")]
34use crate::compute::grid::DetailedGridInfo;
35use crate::tree::layout::DetailedLayoutInfo;
36
37pub type TakiaResult<T> = Result<T, TakiaError>;
39
40#[derive(Debug, Clone, PartialEq, Eq)]
42pub enum TakiaError {
43 ChildIndexOutOfBounds {
45 parent: NodeId,
47 child_index: usize,
49 child_count: usize,
51 },
52 InvalidParentNode(NodeId),
54 InvalidChildNode(NodeId),
56 InvalidInputNode(NodeId),
58}
59
60impl core::fmt::Display for TakiaError {
61 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
62 match self {
63 TakiaError::ChildIndexOutOfBounds { parent, child_index, child_count } => {
64 write!(f, "Index (is {child_index}) should be < child_count ({child_count}) for parent node {parent:?}")
65 }
66 TakiaError::InvalidParentNode(parent) => {
67 write!(f, "Parent Node {parent:?} is not in the TakiaTree instance")
68 }
69 TakiaError::InvalidChildNode(child) => write!(f, "Child Node {child:?} is not in the TakiaTree instance"),
70 TakiaError::InvalidInputNode(node) => write!(f, "Supplied Node {node:?} is not in the TakiaTree instance"),
71 }
72 }
73}
74
75#[cfg(feature = "std")]
76impl std::error::Error for TakiaError {}
77
78#[derive(Debug, Clone, Copy)]
80pub(crate) struct TakiaConfig {
81 pub(crate) use_rounding: bool,
83}
84
85impl Default for TakiaConfig {
86 fn default() -> Self {
87 Self { use_rounding: true }
88 }
89}
90
91#[derive(Debug, Clone, PartialEq)]
95struct NodeData {
96 pub(crate) style: Style,
98
99 pub(crate) unrounded_layout: Layout,
102
103 pub(crate) final_layout: Layout,
106
107 pub(crate) has_context: bool,
109
110 pub(crate) hoisted_children: ChildrenVec<NodeId>,
113
114 pub(crate) cache: Cache,
116
117 pub(crate) detailed_layout_info: DetailedLayoutInfo,
119}
120
121impl NodeData {
122 #[must_use]
124 pub const fn new(style: Style) -> Self {
125 Self {
126 style,
127 cache: Cache::new(),
128 unrounded_layout: Layout::new(),
129 final_layout: Layout::new(),
130 has_context: false,
131 hoisted_children: new_const_children_vec(),
132 detailed_layout_info: DetailedLayoutInfo::None,
133 }
134 }
135
136 #[inline]
141 pub fn mark_dirty(&mut self) -> ClearState {
142 self.cache.clear()
143 }
144}
145
146#[derive(Debug, Clone)]
150pub struct TakiaTree<NodeContext = ()> {
151 nodes: SlotMap<DefaultKey, NodeData>,
153
154 node_context_data: SecondaryMap<DefaultKey, NodeContext>,
156
157 children: SlotMap<DefaultKey, ChildrenVec<NodeId>>,
161
162 parents: SlotMap<DefaultKey, Option<NodeId>>,
166
167 config: TakiaConfig,
169}
170
171impl Default for TakiaTree {
172 fn default() -> TakiaTree<()> {
173 TakiaTree::new()
174 }
175}
176
177pub struct TakiaTreeChildIter<'a>(core::slice::Iter<'a, NodeId>);
179impl Iterator for TakiaTreeChildIter<'_> {
180 type Item = NodeId;
181
182 #[inline]
183 fn next(&mut self) -> Option<Self::Item> {
184 self.0.next().copied()
185 }
186}
187
188impl<NodeContext> TraversePartialTree for TakiaTree<NodeContext> {
190 type ChildIter<'a>
191 = TakiaTreeChildIter<'a>
192 where
193 Self: 'a;
194
195 #[inline(always)]
196 fn child_ids(&self, parent_node_id: NodeId) -> Self::ChildIter<'_> {
197 TakiaTreeChildIter(self.children[parent_node_id.into()].iter())
198 }
199
200 #[inline(always)]
201 fn child_count(&self, parent_node_id: NodeId) -> usize {
202 self.children[parent_node_id.into()].len()
203 }
204
205 #[inline(always)]
206 fn get_child_id(&self, parent_node_id: NodeId, id: usize) -> NodeId {
207 self.children[parent_node_id.into()][id]
208 }
209}
210
211impl<NodeContext> TraverseTree for TakiaTree<NodeContext> {}
213
214impl<NodeContext> CacheTree for TakiaTree<NodeContext> {
216 fn cache_get(&mut self, node_id: NodeId, input: &LayoutInput) -> Option<LayoutOutput> {
217 self.nodes[node_id.into()].cache.get(input)
218 }
219
220 fn cache_store(&mut self, node_id: NodeId, input: &LayoutInput, layout_output: LayoutOutput) {
221 self.nodes[node_id.into()].cache.store(input, layout_output)
222 }
223
224 fn cache_clear(&mut self, node_id: NodeId) {
225 self.nodes[node_id.into()].cache.clear();
226 }
227}
228
229impl<NodeContext> PrintTree for TakiaTree<NodeContext> {
231 #[inline(always)]
232 fn get_debug_label(&self, node_id: NodeId) -> &'static str {
233 let node = &self.nodes[node_id.into()];
234 let display = node.style.display;
235 let num_children = self.child_count(node_id);
236
237 match (num_children, display) {
238 (_, Display::None) => "NONE",
239 (0, _) => "LEAF",
240 #[cfg(feature = "block_layout")]
241 (_, Display::Block) => "BLOCK",
242 #[cfg(feature = "block_layout")]
243 (_, Display::FlowRoot) => "FLOW-ROOT",
244 #[cfg(feature = "flexbox")]
245 (_, Display::Flex) => {
246 use crate::FlexDirection;
247 match node.style.flex_direction {
248 FlexDirection::Row | FlexDirection::RowReverse => "FLEX ROW",
249 FlexDirection::Column | FlexDirection::ColumnReverse => "FLEX COL",
250 }
251 }
252 #[cfg(feature = "grid")]
253 (_, Display::Grid) => "GRID",
254 }
255 }
256
257 #[inline(always)]
258 fn get_final_layout(&self, node_id: NodeId) -> Layout {
259 if self.config.use_rounding {
260 self.nodes[node_id.into()].final_layout
261 } else {
262 self.nodes[node_id.into()].unrounded_layout
263 }
264 }
265}
266
267pub(crate) struct TakiaView<'t, NodeContext, MeasureFunction>
271where
272 MeasureFunction: FnMut(LayoutInput, NodeId, Option<&mut NodeContext>, &Style) -> LayoutOutput,
273{
274 pub(crate) takia: &'t mut TakiaTree<NodeContext>,
276 pub(crate) measure_function: MeasureFunction,
278}
279
280impl<NodeContext, MeasureFunction> TakiaView<'_, NodeContext, MeasureFunction>
281where
282 MeasureFunction: FnMut(LayoutInput, NodeId, Option<&mut NodeContext>, &Style) -> LayoutOutput,
283{
284 #[inline(always)]
285 fn compute_child_layout(
288 &mut self,
289 node_id: NodeId,
290 inputs: LayoutInput,
291 #[cfg(feature = "block_layout")] block_ctx: Option<&mut BlockContext<'_>>,
292 ) -> LayoutOutput {
293 if inputs.run_mode == RunMode::PerformHiddenLayout {
296 debug_log!("HIDDEN");
297 self.takia.nodes[node_id.into()].final_layout = Layout::with_order(0);
301 return compute_hidden_layout(self, node_id);
302 }
303
304 compute_cached_layout(self, node_id, inputs, |tree, node_id, inputs| {
310 let display_mode = tree.takia.nodes[node_id.into()].style.display;
311 let has_children = tree.child_count(node_id) > 0;
312
313 debug_log!(display_mode);
314 debug_log_node!(inputs);
315
316 let mut output = match (display_mode, has_children) {
318 (Display::None, _) => compute_hidden_layout(tree, node_id),
319 #[cfg(feature = "block_layout")]
320 (Display::Block, true) => compute_block_layout(tree, node_id, inputs, block_ctx),
321 #[cfg(feature = "block_layout")]
322 (Display::FlowRoot, true) => compute_block_layout(tree, node_id, inputs, None),
323 #[cfg(feature = "flexbox")]
324 (Display::Flex, true) => compute_flexbox_layout(tree, node_id, inputs),
325 #[cfg(feature = "grid")]
326 (Display::Grid, true) => compute_grid_layout(tree, node_id, inputs),
327 (_, false) => {
328 let node_key = node_id.into();
329 let style = &tree.takia.nodes[node_key].style;
330 let has_context = tree.takia.nodes[node_key].has_context;
331 let node_context = has_context.then(|| tree.takia.node_context_data.get_mut(node_key)).flatten();
332 (tree.measure_function)(inputs, node_id, node_context, style)
333 }
334 };
335
336 if inputs.run_mode == RunMode::PerformLayout {
342 compute_oof_layout(tree, node_id, &mut output);
343 }
344
345 output
346 })
347 }
348}
349
350impl<NodeContext, MeasureFunction> TraversePartialTree for TakiaView<'_, NodeContext, MeasureFunction>
352where
353 MeasureFunction: FnMut(LayoutInput, NodeId, Option<&mut NodeContext>, &Style) -> LayoutOutput,
354{
355 type ChildIter<'a>
356 = TakiaTreeChildIter<'a>
357 where
358 Self: 'a;
359
360 #[inline(always)]
361 fn child_ids(&self, parent_node_id: NodeId) -> Self::ChildIter<'_> {
362 self.takia.child_ids(parent_node_id)
363 }
364
365 #[inline(always)]
366 fn child_count(&self, parent_node_id: NodeId) -> usize {
367 self.takia.child_count(parent_node_id)
368 }
369
370 #[inline(always)]
371 fn get_child_id(&self, parent_node_id: NodeId, child_index: usize) -> NodeId {
372 self.takia.get_child_id(parent_node_id, child_index)
373 }
374}
375
376impl<NodeContext, MeasureFunction> TraverseTree for TakiaView<'_, NodeContext, MeasureFunction> where
378 MeasureFunction: FnMut(LayoutInput, NodeId, Option<&mut NodeContext>, &Style) -> LayoutOutput
379{
380}
381
382impl<NodeContext, MeasureFunction> LayoutPartialTree for TakiaView<'_, NodeContext, MeasureFunction>
384where
385 MeasureFunction: FnMut(LayoutInput, NodeId, Option<&mut NodeContext>, &Style) -> LayoutOutput,
386{
387 type CoreContainerStyle<'a>
388 = &'a Style
389 where
390 Self: 'a;
391
392 type CustomIdent = DefaultCheapStr;
393
394 #[inline(always)]
395 fn get_core_container_style(&self, node_id: NodeId) -> Self::CoreContainerStyle<'_> {
396 &self.takia.nodes[node_id.into()].style
397 }
398
399 #[inline(always)]
400 fn set_unrounded_layout(&mut self, node_id: NodeId, layout: &Layout) {
401 self.takia.nodes[node_id.into()].unrounded_layout = *layout;
402 }
403
404 #[inline(always)]
405 fn resolve_calc_value(&self, _val: *const (), _basis: f32) -> f32 {
406 0.0
407 }
408
409 #[inline(always)]
410 fn compute_child_layout(&mut self, node_id: NodeId, inputs: LayoutInput) -> LayoutOutput {
411 self.compute_child_layout(
412 node_id,
413 inputs,
414 #[cfg(feature = "block_layout")]
415 None,
416 )
417 }
418}
419
420impl<NodeContext, MeasureFunction> LayoutContainingBlock for TakiaView<'_, NodeContext, MeasureFunction>
421where
422 MeasureFunction: FnMut(LayoutInput, NodeId, Option<&mut NodeContext>, &Style) -> LayoutOutput,
423{
424 type OofItemStyle<'a>
425 = &'a Style
426 where
427 Self: 'a;
428
429 #[inline(always)]
430 fn get_oof_item_style(&self, node_id: NodeId) -> Self::OofItemStyle<'_> {
431 &self.takia.nodes[node_id.into()].style
432 }
433
434 #[inline(always)]
435 fn clear_hoisted_children(&mut self, node_id: NodeId) {
436 self.takia.nodes[node_id.into()].hoisted_children.clear();
437 }
438
439 #[inline(always)]
440 fn add_hoisted_children(&mut self, node_id: NodeId, hoisted: &[NodeId]) {
441 self.takia.nodes[node_id.into()].hoisted_children.extend_from_slice(hoisted);
442 }
443
444 #[inline(always)]
445 fn get_detailed_layout_info(&self, node_id: NodeId) -> &DetailedLayoutInfo {
446 &self.takia.nodes[node_id.into()].detailed_layout_info
447 }
448}
449
450impl<NodeContext, MeasureFunction> CacheTree for TakiaView<'_, NodeContext, MeasureFunction>
451where
452 MeasureFunction: FnMut(LayoutInput, NodeId, Option<&mut NodeContext>, &Style) -> LayoutOutput,
453{
454 fn cache_get(&mut self, node_id: NodeId, input: &LayoutInput) -> Option<LayoutOutput> {
455 self.takia.nodes[node_id.into()].cache.get(input)
456 }
457
458 fn cache_store(&mut self, node_id: NodeId, input: &LayoutInput, layout_output: LayoutOutput) {
459 self.takia.nodes[node_id.into()].cache.store(input, layout_output)
460 }
461
462 fn cache_clear(&mut self, node_id: NodeId) {
463 self.takia.nodes[node_id.into()].cache.clear();
464 }
465}
466
467#[cfg(feature = "block_layout")]
468impl<NodeContext, MeasureFunction> LayoutBlockContainer for TakiaView<'_, NodeContext, MeasureFunction>
469where
470 MeasureFunction: FnMut(LayoutInput, NodeId, Option<&mut NodeContext>, &Style) -> LayoutOutput,
471{
472 type BlockContainerStyle<'a>
473 = &'a Style
474 where
475 Self: 'a;
476 type BlockItemStyle<'a>
477 = &'a Style
478 where
479 Self: 'a;
480
481 #[inline(always)]
482 fn get_block_container_style(&self, node_id: NodeId) -> Self::BlockContainerStyle<'_> {
483 self.get_core_container_style(node_id)
484 }
485
486 #[inline(always)]
487 fn get_block_child_style(&self, child_node_id: NodeId) -> Self::BlockItemStyle<'_> {
488 self.get_core_container_style(child_node_id)
489 }
490
491 #[inline(always)]
492 fn compute_block_child_layout(
493 &mut self,
494 node_id: NodeId,
495 inputs: LayoutInput,
496 block_ctx: Option<&mut BlockContext<'_>>,
497 ) -> LayoutOutput {
498 self.compute_child_layout(node_id, inputs, block_ctx)
499 }
500}
501
502#[cfg(feature = "flexbox")]
503impl<NodeContext, MeasureFunction> LayoutFlexboxContainer for TakiaView<'_, NodeContext, MeasureFunction>
504where
505 MeasureFunction: FnMut(LayoutInput, NodeId, Option<&mut NodeContext>, &Style) -> LayoutOutput,
506{
507 type FlexboxContainerStyle<'a>
508 = &'a Style
509 where
510 Self: 'a;
511 type FlexboxItemStyle<'a>
512 = &'a Style
513 where
514 Self: 'a;
515
516 #[inline(always)]
517 fn get_flexbox_container_style(&self, node_id: NodeId) -> Self::FlexboxContainerStyle<'_> {
518 &self.takia.nodes[node_id.into()].style
519 }
520
521 #[inline(always)]
522 fn get_flexbox_child_style(&self, child_node_id: NodeId) -> Self::FlexboxItemStyle<'_> {
523 &self.takia.nodes[child_node_id.into()].style
524 }
525}
526
527#[cfg(feature = "grid")]
528impl<NodeContext, MeasureFunction> LayoutGridContainer for TakiaView<'_, NodeContext, MeasureFunction>
529where
530 MeasureFunction: FnMut(LayoutInput, NodeId, Option<&mut NodeContext>, &Style) -> LayoutOutput,
531{
532 type GridContainerStyle<'a>
533 = &'a Style
534 where
535 Self: 'a;
536 type GridItemStyle<'a>
537 = &'a Style
538 where
539 Self: 'a;
540
541 #[inline(always)]
542 fn get_grid_container_style(&self, node_id: NodeId) -> Self::GridContainerStyle<'_> {
543 &self.takia.nodes[node_id.into()].style
544 }
545
546 #[inline(always)]
547 fn get_grid_child_style(&self, child_node_id: NodeId) -> Self::GridItemStyle<'_> {
548 &self.takia.nodes[child_node_id.into()].style
549 }
550
551 #[inline(always)]
552 fn set_detailed_grid_info(&mut self, node_id: NodeId, detailed_grid_info: DetailedGridInfo) {
553 self.takia.nodes[node_id.into()].detailed_layout_info = DetailedLayoutInfo::Grid(Box::new(detailed_grid_info));
554 }
555}
556
557impl<NodeContext, MeasureFunction> RoundTree for TakiaView<'_, NodeContext, MeasureFunction>
559where
560 MeasureFunction: FnMut(LayoutInput, NodeId, Option<&mut NodeContext>, &Style) -> LayoutOutput,
561{
562 #[inline(always)]
563 fn get_unrounded_layout(&self, node: NodeId) -> Layout {
564 self.takia.nodes[node.into()].unrounded_layout
565 }
566
567 #[inline(always)]
568 fn set_final_layout(&mut self, node_id: NodeId, layout: &Layout) {
569 self.takia.nodes[node_id.into()].final_layout = *layout;
570 }
571
572 #[inline(always)]
573 fn is_out_of_flow(&self, node_id: NodeId) -> bool {
574 let node = &self.takia.nodes[node_id.into()];
575 node.style.position.is_out_of_flow() && node.style.display != crate::style::Display::None
576 }
577
578 #[inline(always)]
579 fn hoisted_child_count(&self, node_id: NodeId) -> usize {
580 self.takia.nodes[node_id.into()].hoisted_children.len()
581 }
582
583 #[inline(always)]
584 fn get_hoisted_child_id(&self, node_id: NodeId, index: usize) -> NodeId {
585 self.takia.nodes[node_id.into()].hoisted_children[index]
586 }
587}
588
589#[allow(clippy::iter_cloned_collect)] impl<NodeContext> TakiaTree<NodeContext> {
591 #[must_use]
595 pub fn new() -> Self {
596 Self::with_capacity(16)
597 }
598
599 #[must_use]
601 pub fn with_capacity(capacity: usize) -> Self {
602 TakiaTree {
603 nodes: SlotMap::with_capacity(capacity),
606 children: SlotMap::with_capacity(capacity),
607 parents: SlotMap::with_capacity(capacity),
608 node_context_data: SecondaryMap::with_capacity(capacity),
609 config: TakiaConfig::default(),
610 }
611 }
612
613 pub fn enable_rounding(&mut self) {
615 self.config.use_rounding = true;
616 }
617
618 pub fn disable_rounding(&mut self) {
620 self.config.use_rounding = false;
621 }
622
623 pub fn new_leaf(&mut self, layout: Style) -> TakiaResult<NodeId> {
625 let id = self.nodes.insert(NodeData::new(layout));
626 let _ = self.children.insert(new_vec_with_capacity(0));
627 let _ = self.parents.insert(None);
628
629 Ok(id.into())
630 }
631
632 pub fn new_leaf_with_context(&mut self, layout: Style, context: NodeContext) -> TakiaResult<NodeId> {
636 let mut data = NodeData::new(layout);
637 data.has_context = true;
638
639 let id = self.nodes.insert(data);
640 self.node_context_data.insert(id, context);
641
642 let _ = self.children.insert(new_vec_with_capacity(0));
643 let _ = self.parents.insert(None);
644
645 Ok(id.into())
646 }
647
648 pub fn new_with_children(&mut self, layout: Style, children: &[NodeId]) -> TakiaResult<NodeId> {
650 let id = NodeId::from(self.nodes.insert(NodeData::new(layout)));
651
652 for child in children {
653 self.parents[(*child).into()] = Some(id);
654 }
655
656 let _ = self.children.insert(children.iter().copied().collect::<_>());
657 let _ = self.parents.insert(None);
658
659 Ok(id)
660 }
661
662 pub fn clear(&mut self) {
664 self.nodes.clear();
665 self.children.clear();
666 self.parents.clear();
667 self.node_context_data.clear();
671 }
672
673 pub fn remove(&mut self, node: NodeId) -> TakiaResult<NodeId> {
677 let key = node.into();
678 if let Some(parent) = self.parents[key] {
679 if let Some(children) = self.children.get_mut(parent.into()) {
680 children.retain(|f| *f != node);
681 }
682 self.mark_dirty(parent)?;
683 }
684
685 if let Some(children) = self.children.get(key) {
687 for child in children.iter().copied() {
688 self.parents[child.into()] = None;
689 }
690 }
691
692 let _ = self.children.remove(key);
693 let _ = self.parents.remove(key);
694 let _ = self.nodes.remove(key);
695 let _ = self.node_context_data.remove(key);
696
697 Ok(node)
698 }
699
700 #[inline]
702 pub fn set_node_context(&mut self, node: NodeId, measure: Option<NodeContext>) -> TakiaResult<()> {
703 let key = node.into();
704 if let Some(measure) = measure {
705 self.nodes[key].has_context = true;
706 self.node_context_data.insert(key, measure);
707 } else {
708 self.nodes[key].has_context = false;
709 self.node_context_data.remove(key);
710 }
711
712 self.mark_dirty(node)?;
713
714 Ok(())
715 }
716
717 #[inline]
719 pub fn get_node_context(&self, node: NodeId) -> Option<&NodeContext> {
720 self.node_context_data.get(node.into())
721 }
722
723 #[inline]
725 pub fn get_node_context_mut(&mut self, node: NodeId) -> Option<&mut NodeContext> {
726 self.node_context_data.get_mut(node.into())
727 }
728
729 pub fn get_disjoint_node_context_mut<const N: usize>(
731 &mut self,
732 keys: [NodeId; N],
733 ) -> Option<[&mut NodeContext; N]> {
734 self.node_context_data.get_disjoint_mut(keys.map(|k| k.into()))
735 }
736
737 pub fn add_child(&mut self, parent: NodeId, child: NodeId) -> TakiaResult<()> {
739 let parent_key = parent.into();
740 let child_key = child.into();
741 self.parents[child_key] = Some(parent);
742 self.children[parent_key].push(child);
743 self.mark_dirty(parent)?;
744
745 Ok(())
746 }
747
748 pub fn insert_child_at_index(&mut self, parent: NodeId, child_index: usize, child: NodeId) -> TakiaResult<()> {
750 let parent_key = parent.into();
751
752 let child_count = self.children[parent_key].len();
753 if child_index > child_count {
754 return Err(TakiaError::ChildIndexOutOfBounds { parent, child_index, child_count });
755 }
756
757 self.parents[child.into()] = Some(parent);
758 self.children[parent_key].insert(child_index, child);
759 self.mark_dirty(parent)?;
760
761 Ok(())
762 }
763
764 pub fn set_children(&mut self, parent: NodeId, children: &[NodeId]) -> TakiaResult<()> {
766 let parent_key = parent.into();
767
768 for child in &self.children[parent_key] {
770 self.parents[(*child).into()] = None;
771 }
772
773 for &child in children {
775 if let Some(previous_parent) = self.parents[child.into()] {
777 self.remove_child(previous_parent, child).unwrap();
778 }
779 self.parents[child.into()] = Some(parent);
780 }
781
782 let parent_children = &mut self.children[parent_key];
783 parent_children.clear();
784 children.iter().for_each(|child| parent_children.push(*child));
785
786 self.mark_dirty(parent)?;
787
788 Ok(())
789 }
790
791 pub fn remove_child(&mut self, parent: NodeId, child: NodeId) -> TakiaResult<NodeId> {
795 let index = self.children[parent.into()].iter().position(|n| *n == child).unwrap();
796 self.remove_child_at_index(parent, index)
797 }
798
799 pub fn remove_child_at_index(&mut self, parent: NodeId, child_index: usize) -> TakiaResult<NodeId> {
803 let parent_key = parent.into();
804 let child_count = self.children[parent_key].len();
805 if child_index >= child_count {
806 return Err(TakiaError::ChildIndexOutOfBounds { parent, child_index, child_count });
807 }
808
809 let child = self.children[parent_key].remove(child_index);
810 self.parents[child.into()] = None;
811
812 self.mark_dirty(parent)?;
813
814 Ok(child)
815 }
816
817 pub fn remove_children_range<R>(&mut self, parent: NodeId, range: R) -> TakiaResult<()>
823 where
824 R: core::ops::RangeBounds<usize>,
825 {
826 let parent_key = parent.into();
827 for child in self.children[parent_key].drain(range) {
828 self.parents[child.into()] = None;
829 }
830
831 self.mark_dirty(parent)?;
832 Ok(())
833 }
834
835 pub fn replace_child_at_index(
839 &mut self,
840 parent: NodeId,
841 child_index: usize,
842 new_child: NodeId,
843 ) -> TakiaResult<NodeId> {
844 let parent_key = parent.into();
845
846 let child_count = self.children[parent_key].len();
847 if child_index >= child_count {
848 return Err(TakiaError::ChildIndexOutOfBounds { parent, child_index, child_count });
849 }
850
851 self.parents[new_child.into()] = Some(parent);
852 let old_child = core::mem::replace(&mut self.children[parent_key][child_index], new_child);
853 self.parents[old_child.into()] = None;
854
855 self.mark_dirty(parent)?;
856
857 Ok(old_child)
858 }
859
860 #[inline]
862 pub fn child_at_index(&self, parent: NodeId, child_index: usize) -> TakiaResult<NodeId> {
863 let parent_key = parent.into();
864 let child_count = self.children[parent_key].len();
865 if child_index >= child_count {
866 return Err(TakiaError::ChildIndexOutOfBounds { parent, child_index, child_count });
867 }
868
869 Ok(self.children[parent_key][child_index])
870 }
871
872 #[inline]
874 pub fn total_node_count(&self) -> usize {
875 self.nodes.len()
876 }
877
878 #[inline]
883 pub fn parent(&self, child_id: NodeId) -> Option<NodeId> {
884 self.parents[child_id.into()]
885 }
886
887 pub fn children(&self, parent: NodeId) -> TakiaResult<Vec<NodeId>> {
889 Ok(self.children[parent.into()].clone())
890 }
891
892 pub fn hoisted_children(&self, node: NodeId) -> TakiaResult<&[NodeId]> {
896 Ok(&self.nodes[node.into()].hoisted_children)
897 }
898
899 #[inline]
901 pub fn set_style(&mut self, node: NodeId, style: Style) -> TakiaResult<()> {
902 self.nodes[node.into()].style = style;
903 self.mark_dirty(node)?;
904 Ok(())
905 }
906
907 #[inline]
909 pub fn style(&self, node: NodeId) -> TakiaResult<&Style> {
910 Ok(&self.nodes[node.into()].style)
911 }
912
913 #[inline]
915 pub fn layout(&self, node: NodeId) -> TakiaResult<&Layout> {
916 if self.config.use_rounding {
917 Ok(&self.nodes[node.into()].final_layout)
918 } else {
919 Ok(&self.nodes[node.into()].unrounded_layout)
920 }
921 }
922
923 #[inline]
925 pub fn unrounded_layout(&self, node: NodeId) -> &Layout {
926 &self.nodes[node.into()].unrounded_layout
927 }
928
929 #[inline]
934 pub fn detailed_layout_info(&self, node_id: NodeId) -> &DetailedLayoutInfo {
935 &self.nodes[node_id.into()].detailed_layout_info
936 }
937
938 pub fn mark_dirty(&mut self, node: NodeId) -> TakiaResult<()> {
940 fn mark_dirty_recursive(
941 nodes: &mut SlotMap<DefaultKey, NodeData>,
942 parents: &SlotMap<DefaultKey, Option<NodeId>>,
943 node_key: DefaultKey,
944 ) {
945 match nodes[node_key].mark_dirty() {
946 ClearState::AlreadyEmpty => {
947 }
951 ClearState::Cleared => {
952 if let Some(Some(node)) = parents.get(node_key) {
953 mark_dirty_recursive(nodes, parents, (*node).into());
954 }
955 }
956 }
957 }
958
959 mark_dirty_recursive(&mut self.nodes, &self.parents, node.into());
960
961 Ok(())
962 }
963
964 #[inline]
966 pub fn dirty(&self, node: NodeId) -> TakiaResult<bool> {
967 Ok(self.nodes[node.into()].cache.is_empty())
968 }
969
970 pub fn compute_layout_with_measure<MeasureFunction>(
972 &mut self,
973 node_id: NodeId,
974 available_space: Size<AvailableSpace>,
975 measure_function: MeasureFunction,
976 ) -> Result<(), TakiaError>
977 where
978 MeasureFunction: FnMut(LayoutInput, NodeId, Option<&mut NodeContext>, &Style) -> LayoutOutput,
979 {
980 let use_rounding = self.config.use_rounding;
981 let mut takia_view = TakiaView { takia: self, measure_function };
982 compute_root_layout(&mut takia_view, node_id, available_space);
983 if use_rounding {
984 round_layout(&mut takia_view, node_id);
985 }
986 Ok(())
987 }
988
989 pub fn compute_layout(&mut self, node: NodeId, available_space: Size<AvailableSpace>) -> Result<(), TakiaError> {
991 self.compute_layout_with_measure(node, available_space, |inputs, _, _, style| {
992 compute_leaf_layout(inputs, style, |_, _| 0.0, |_, _| Size::ZERO)
993 })
994 }
995
996 #[cfg(feature = "std")]
998 pub fn print_tree(&mut self, root: NodeId) {
999 crate::util::print_tree(self, root)
1000 }
1001
1002 #[cfg(test)]
1004 pub(crate) fn as_layout_tree(&mut self) -> impl LayoutPartialTree + CacheTree + '_ {
1005 TakiaView {
1006 takia: self,
1007 measure_function: |inputs, _, _, style| compute_leaf_layout(inputs, style, |_, _| 0.0, |_, _| Size::ZERO),
1008 }
1009 }
1010}
1011
1012#[cfg(test)]
1013mod tests {
1014
1015 use super::*;
1016 use crate::style::{Dimension, Display, FlexDirection};
1017 use crate::style_helpers::*;
1018 use crate::util::sys;
1019
1020 fn size_measure_function(
1021 inputs: LayoutInput,
1022 _node_id: NodeId,
1023 node_context: Option<&mut Size<f32>>,
1024 style: &Style,
1025 ) -> LayoutOutput {
1026 compute_leaf_layout(
1027 inputs,
1028 style,
1029 |_, _| 0.0,
1030 |known_dimensions, _available_space| {
1031 known_dimensions.unwrap_or(node_context.cloned().unwrap_or(Size::ZERO))
1032 },
1033 )
1034 }
1035
1036 #[test]
1037 fn new_should_allocate_default_capacity() {
1038 const DEFAULT_CAPACITY: usize = 16; let takia: TakiaTree<()> = TakiaTree::new();
1040
1041 assert!(takia.children.capacity() >= DEFAULT_CAPACITY);
1042 assert!(takia.parents.capacity() >= DEFAULT_CAPACITY);
1043 assert!(takia.nodes.capacity() >= DEFAULT_CAPACITY);
1044 }
1045
1046 #[test]
1047 fn test_with_capacity() {
1048 const CAPACITY: usize = 8;
1049 let takia: TakiaTree<()> = TakiaTree::with_capacity(CAPACITY);
1050
1051 assert!(takia.children.capacity() >= CAPACITY);
1052 assert!(takia.parents.capacity() >= CAPACITY);
1053 assert!(takia.nodes.capacity() >= CAPACITY);
1054 }
1055
1056 #[test]
1057 fn test_new_leaf() {
1058 let mut takia: TakiaTree<()> = TakiaTree::new();
1059
1060 let res = takia.new_leaf(Style::default());
1061 assert!(res.is_ok());
1062 let node = res.unwrap();
1063
1064 assert!(takia.child_count(node) == 0);
1066 }
1067
1068 #[test]
1069 fn new_leaf_with_context() {
1070 let mut takia: TakiaTree<Size<f32>> = TakiaTree::new();
1071
1072 let res = takia.new_leaf_with_context(Style::default(), Size::ZERO);
1073 assert!(res.is_ok());
1074 let node = res.unwrap();
1075
1076 assert!(takia.child_count(node) == 0);
1078 }
1079
1080 #[test]
1082 fn test_new_with_children() {
1083 let mut takia: TakiaTree<()> = TakiaTree::new();
1084 let child0 = takia.new_leaf(Style::default()).unwrap();
1085 let child1 = takia.new_leaf(Style::default()).unwrap();
1086 let node = takia.new_with_children(Style::default(), &[child0, child1]).unwrap();
1087
1088 assert_eq!(takia.child_count(node), 2);
1090 assert_eq!(takia.children(node).unwrap()[0], child0);
1091 assert_eq!(takia.children(node).unwrap()[1], child1);
1092 }
1093
1094 #[test]
1095 fn remove_node_should_remove() {
1096 let mut takia: TakiaTree<()> = TakiaTree::new();
1097
1098 let node = takia.new_leaf(Style::default()).unwrap();
1099
1100 let _ = takia.remove(node).unwrap();
1101 }
1102
1103 #[test]
1104 fn remove_node_should_detach_hierarchy() {
1105 let mut takia: TakiaTree<()> = TakiaTree::new();
1106
1107 let node2 = takia.new_leaf(Style::default()).unwrap();
1109 let node1 = takia.new_with_children(Style::default(), &[node2]).unwrap();
1110 let node0 = takia.new_with_children(Style::default(), &[node1]).unwrap();
1111
1112 assert_eq!(takia.children(node0).unwrap().as_slice(), &[node1]);
1114 assert_eq!(takia.children(node1).unwrap().as_slice(), &[node2]);
1115
1116 let _ = takia.remove(node1).unwrap();
1118
1119 assert!(takia.children(node0).unwrap().is_empty());
1121 assert!(takia.children(node2).unwrap().is_empty());
1122 }
1123
1124 #[test]
1125 fn remove_last_node() {
1126 let mut takia: TakiaTree<()> = TakiaTree::new();
1127
1128 let parent = takia.new_leaf(Style::default()).unwrap();
1129 let child = takia.new_leaf(Style::default()).unwrap();
1130 takia.add_child(parent, child).unwrap();
1131
1132 takia.remove(child).unwrap();
1133 takia.remove(parent).unwrap();
1134 }
1135
1136 #[test]
1138 fn remove_node_marks_parent_dirty() {
1139 use crate::prelude::*;
1140
1141 let mut takia: TakiaTree<()> = TakiaTree::new();
1142
1143 let child = takia
1145 .new_leaf(Style { border: Rect { bottom: length(1f32), ..Rect::zero() }, ..Default::default() })
1146 .unwrap();
1147 let root = takia.new_with_children(Style::default(), &[child]).unwrap();
1148
1149 takia.compute_layout(root, Size::MIN_CONTENT).unwrap();
1150 assert_eq!(takia.layout(root).unwrap().size.height, 1f32);
1151
1152 takia.remove(child).unwrap();
1153 assert_eq!(takia.dirty(root), Ok(true));
1154
1155 takia.compute_layout(root, Size::MIN_CONTENT).unwrap();
1157 assert_eq!(takia.layout(root).unwrap().size.height, 0f32);
1158 }
1159
1160 #[test]
1161 fn set_measure() {
1162 let mut takia: TakiaTree<Size<f32>> = TakiaTree::new();
1163 let node = takia.new_leaf_with_context(Style::default(), Size { width: 200.0, height: 200.0 }).unwrap();
1164 takia.compute_layout_with_measure(node, Size::MAX_CONTENT, size_measure_function).unwrap();
1165 assert_eq!(takia.layout(node).unwrap().size.width, 200.0);
1166
1167 takia.set_node_context(node, Some(Size { width: 100.0, height: 100.0 })).unwrap();
1168 takia.compute_layout_with_measure(node, Size::MAX_CONTENT, size_measure_function).unwrap();
1169 assert_eq!(takia.layout(node).unwrap().size.width, 100.0);
1170 }
1171
1172 #[test]
1173 fn set_measure_of_previously_unmeasured_node() {
1174 let mut takia: TakiaTree<Size<f32>> = TakiaTree::new();
1175 let node = takia.new_leaf(Style::default()).unwrap();
1176 takia.compute_layout_with_measure(node, Size::MAX_CONTENT, size_measure_function).unwrap();
1177 assert_eq!(takia.layout(node).unwrap().size.width, 0.0);
1178
1179 takia.set_node_context(node, Some(Size { width: 100.0, height: 100.0 })).unwrap();
1180 takia.compute_layout_with_measure(node, Size::MAX_CONTENT, size_measure_function).unwrap();
1181 assert_eq!(takia.layout(node).unwrap().size.width, 100.0);
1182 }
1183
1184 #[test]
1186 fn add_child() {
1187 let mut takia: TakiaTree<()> = TakiaTree::new();
1188 let node = takia.new_leaf(Style::default()).unwrap();
1189 assert_eq!(takia.child_count(node), 0);
1190
1191 let child0 = takia.new_leaf(Style::default()).unwrap();
1192 takia.add_child(node, child0).unwrap();
1193 assert_eq!(takia.child_count(node), 1);
1194
1195 let child1 = takia.new_leaf(Style::default()).unwrap();
1196 takia.add_child(node, child1).unwrap();
1197 assert_eq!(takia.child_count(node), 2);
1198 }
1199
1200 #[test]
1201 fn insert_child_at_index() {
1202 let mut takia: TakiaTree<()> = TakiaTree::new();
1203
1204 let child0 = takia.new_leaf(Style::default()).unwrap();
1205 let child1 = takia.new_leaf(Style::default()).unwrap();
1206 let child2 = takia.new_leaf(Style::default()).unwrap();
1207
1208 let node = takia.new_leaf(Style::default()).unwrap();
1209 assert_eq!(takia.child_count(node), 0);
1210
1211 takia.insert_child_at_index(node, 0, child0).unwrap();
1212 assert_eq!(takia.child_count(node), 1);
1213 assert_eq!(takia.children(node).unwrap()[0], child0);
1214
1215 takia.insert_child_at_index(node, 0, child1).unwrap();
1216 assert_eq!(takia.child_count(node), 2);
1217 assert_eq!(takia.children(node).unwrap()[0], child1);
1218 assert_eq!(takia.children(node).unwrap()[1], child0);
1219
1220 takia.insert_child_at_index(node, 1, child2).unwrap();
1221 assert_eq!(takia.child_count(node), 3);
1222 assert_eq!(takia.children(node).unwrap()[0], child1);
1223 assert_eq!(takia.children(node).unwrap()[1], child2);
1224 assert_eq!(takia.children(node).unwrap()[2], child0);
1225 }
1226
1227 #[test]
1228 fn set_children() {
1229 let mut takia: TakiaTree<()> = TakiaTree::new();
1230
1231 let child0 = takia.new_leaf(Style::default()).unwrap();
1232 let child1 = takia.new_leaf(Style::default()).unwrap();
1233 let node = takia.new_with_children(Style::default(), &[child0, child1]).unwrap();
1234
1235 assert_eq!(takia.child_count(node), 2);
1236 assert_eq!(takia.children(node).unwrap()[0], child0);
1237 assert_eq!(takia.children(node).unwrap()[1], child1);
1238
1239 let child2 = takia.new_leaf(Style::default()).unwrap();
1240 let child3 = takia.new_leaf(Style::default()).unwrap();
1241 takia.set_children(node, &[child2, child3]).unwrap();
1242
1243 assert_eq!(takia.child_count(node), 2);
1244 assert_eq!(takia.children(node).unwrap()[0], child2);
1245 assert_eq!(takia.children(node).unwrap()[1], child3);
1246 }
1247
1248 #[test]
1250 fn remove_child() {
1251 let mut takia: TakiaTree<()> = TakiaTree::new();
1252 let child0 = takia.new_leaf(Style::default()).unwrap();
1253 let child1 = takia.new_leaf(Style::default()).unwrap();
1254 let node = takia.new_with_children(Style::default(), &[child0, child1]).unwrap();
1255
1256 assert_eq!(takia.child_count(node), 2);
1257
1258 takia.remove_child(node, child0).unwrap();
1259 assert_eq!(takia.child_count(node), 1);
1260 assert_eq!(takia.children(node).unwrap()[0], child1);
1261
1262 takia.remove_child(node, child1).unwrap();
1263 assert_eq!(takia.child_count(node), 0);
1264 }
1265
1266 #[test]
1267 fn remove_child_at_index() {
1268 let mut takia: TakiaTree<()> = TakiaTree::new();
1269 let child0 = takia.new_leaf(Style::default()).unwrap();
1270 let child1 = takia.new_leaf(Style::default()).unwrap();
1271 let node = takia.new_with_children(Style::default(), &[child0, child1]).unwrap();
1272
1273 assert_eq!(takia.child_count(node), 2);
1274
1275 takia.remove_child_at_index(node, 0).unwrap();
1276 assert_eq!(takia.child_count(node), 1);
1277 assert_eq!(takia.children(node).unwrap()[0], child1);
1278
1279 takia.remove_child_at_index(node, 0).unwrap();
1280 assert_eq!(takia.child_count(node), 0);
1281 }
1282
1283 #[test]
1284 fn remove_children_range() {
1285 let mut takia: TakiaTree<()> = TakiaTree::new();
1286 let child0 = takia.new_leaf(Style::default()).unwrap();
1287 let child1 = takia.new_leaf(Style::default()).unwrap();
1288 let child2 = takia.new_leaf(Style::default()).unwrap();
1289 let child3 = takia.new_leaf(Style::default()).unwrap();
1290 let node = takia.new_with_children(Style::default(), &[child0, child1, child2, child3]).unwrap();
1291
1292 assert_eq!(takia.child_count(node), 4);
1293
1294 takia.remove_children_range(node, 1..=2).unwrap();
1295 assert_eq!(takia.child_count(node), 2);
1296 assert_eq!(takia.children(node).unwrap(), [child0, child3]);
1297 for child in [child0, child3] {
1298 assert_eq!(takia.parent(child), Some(node));
1299 }
1300 for child in [child1, child2] {
1301 assert_eq!(takia.parent(child), None);
1302 }
1303 }
1304
1305 #[test]
1307 fn remove_child_updates_parents() {
1308 let mut takia: TakiaTree<()> = TakiaTree::new();
1309
1310 let parent = takia.new_leaf(Style::default()).unwrap();
1311 let child = takia.new_leaf(Style::default()).unwrap();
1312
1313 takia.add_child(parent, child).unwrap();
1314
1315 takia.remove(parent).unwrap();
1316
1317 assert!(takia.set_children(child, &[]).is_ok());
1319 }
1320
1321 #[test]
1322 fn replace_child_at_index() {
1323 let mut takia: TakiaTree<()> = TakiaTree::new();
1324
1325 let child0 = takia.new_leaf(Style::default()).unwrap();
1326 let child1 = takia.new_leaf(Style::default()).unwrap();
1327
1328 let node = takia.new_with_children(Style::default(), &[child0]).unwrap();
1329 assert_eq!(takia.child_count(node), 1);
1330 assert_eq!(takia.children(node).unwrap()[0], child0);
1331
1332 takia.replace_child_at_index(node, 0, child1).unwrap();
1333 assert_eq!(takia.child_count(node), 1);
1334 assert_eq!(takia.children(node).unwrap()[0], child1);
1335 }
1336 #[test]
1337 fn test_child_at_index() {
1338 let mut takia: TakiaTree<()> = TakiaTree::new();
1339 let child0 = takia.new_leaf(Style::default()).unwrap();
1340 let child1 = takia.new_leaf(Style::default()).unwrap();
1341 let child2 = takia.new_leaf(Style::default()).unwrap();
1342 let node = takia.new_with_children(Style::default(), &[child0, child1, child2]).unwrap();
1343
1344 assert!(if let Ok(result) = takia.child_at_index(node, 0) { result == child0 } else { false });
1345 assert!(if let Ok(result) = takia.child_at_index(node, 1) { result == child1 } else { false });
1346 assert!(if let Ok(result) = takia.child_at_index(node, 2) { result == child2 } else { false });
1347 }
1348 #[test]
1349 fn test_child_count() {
1350 let mut takia: TakiaTree<()> = TakiaTree::new();
1351 let child0 = takia.new_leaf(Style::default()).unwrap();
1352 let child1 = takia.new_leaf(Style::default()).unwrap();
1353 let node = takia.new_with_children(Style::default(), &[child0, child1]).unwrap();
1354
1355 assert!(takia.child_count(node) == 2);
1356 assert!(takia.child_count(child0) == 0);
1357 assert!(takia.child_count(child1) == 0);
1358 }
1359
1360 #[allow(clippy::vec_init_then_push)]
1361 #[test]
1362 fn test_children() {
1363 let mut takia: TakiaTree<()> = TakiaTree::new();
1364 let child0 = takia.new_leaf(Style::default()).unwrap();
1365 let child1 = takia.new_leaf(Style::default()).unwrap();
1366 let node = takia.new_with_children(Style::default(), &[child0, child1]).unwrap();
1367
1368 let mut children = sys::Vec::new();
1369 children.push(child0);
1370 children.push(child1);
1371
1372 let children_result = takia.children(node).unwrap();
1373 assert_eq!(children_result, children);
1374
1375 assert!(takia.children(child0).unwrap().is_empty());
1376 }
1377 #[test]
1378 fn test_set_style() {
1379 let mut takia: TakiaTree<()> = TakiaTree::new();
1380
1381 let node = takia.new_leaf(Style::default()).unwrap();
1382 assert_eq!(takia.style(node).unwrap().display, Display::Flex);
1383
1384 takia.set_style(node, Style { display: Display::None, ..Style::default() }).unwrap();
1385 assert_eq!(takia.style(node).unwrap().display, Display::None);
1386 }
1387 #[test]
1388 fn test_style() {
1389 let mut takia: TakiaTree<()> = TakiaTree::new();
1390
1391 let style = Style { display: Display::None, flex_direction: FlexDirection::RowReverse, ..Default::default() };
1392
1393 let node = takia.new_leaf(style.clone()).unwrap();
1394
1395 let res = takia.style(node);
1396 assert!(res.is_ok());
1397 assert!(res.unwrap() == &style);
1398 }
1399 #[test]
1400 fn test_layout() {
1401 let mut takia: TakiaTree<()> = TakiaTree::new();
1402 let node = takia.new_leaf(Style::default()).unwrap();
1403
1404 let res = takia.layout(node);
1406 assert!(res.is_ok());
1407 }
1408
1409 #[test]
1410 fn test_mark_dirty() {
1411 let mut takia: TakiaTree<()> = TakiaTree::new();
1412 let child0 = takia.new_leaf(Style::default()).unwrap();
1413 let child1 = takia.new_leaf(Style::default()).unwrap();
1414 let node = takia.new_with_children(Style::default(), &[child0, child1]).unwrap();
1415
1416 takia.compute_layout(node, Size::MAX_CONTENT).unwrap();
1417
1418 assert_eq!(takia.dirty(child0), Ok(false));
1419 assert_eq!(takia.dirty(child1), Ok(false));
1420 assert_eq!(takia.dirty(node), Ok(false));
1421
1422 takia.mark_dirty(node).unwrap();
1423 assert_eq!(takia.dirty(child0), Ok(false));
1424 assert_eq!(takia.dirty(child1), Ok(false));
1425 assert_eq!(takia.dirty(node), Ok(true));
1426
1427 takia.compute_layout(node, Size::MAX_CONTENT).unwrap();
1428 takia.mark_dirty(child0).unwrap();
1429 assert_eq!(takia.dirty(child0), Ok(true));
1430 assert_eq!(takia.dirty(child1), Ok(false));
1431 assert_eq!(takia.dirty(node), Ok(true));
1432 }
1433
1434 #[test]
1435 fn compute_layout_should_produce_valid_result() {
1436 let mut takia: TakiaTree<()> = TakiaTree::new();
1437 let node_result = takia.new_leaf(Style {
1438 size: Size { width: Dimension::from_length(10f32), height: Dimension::from_length(10f32) },
1439 ..Default::default()
1440 });
1441 assert!(node_result.is_ok());
1442 let node = node_result.unwrap();
1443 let layout_result = takia.compute_layout(
1444 node,
1445 Size { width: AvailableSpace::Definite(100.), height: AvailableSpace::Definite(100.) },
1446 );
1447 assert!(layout_result.is_ok());
1448 }
1449
1450 #[test]
1451 fn make_sure_layout_location_is_top_left() {
1452 use crate::prelude::*;
1453
1454 let mut takia: TakiaTree<()> = TakiaTree::new();
1455
1456 let node = takia
1457 .new_leaf(Style {
1458 size: Size { width: Dimension::from_percent(1f32), height: Dimension::from_percent(1f32) },
1459 ..Default::default()
1460 })
1461 .unwrap();
1462
1463 let root = takia
1464 .new_with_children(
1465 Style {
1466 size: Size { width: Dimension::from_length(100f32), height: Dimension::from_length(100f32) },
1467 padding: Rect {
1468 left: length(10f32),
1469 right: length(20f32),
1470 top: length(30f32),
1471 bottom: length(40f32),
1472 },
1473 ..Default::default()
1474 },
1475 &[node],
1476 )
1477 .unwrap();
1478
1479 takia.compute_layout(root, Size::MAX_CONTENT).unwrap();
1480
1481 let layout = takia.layout(node).unwrap();
1490 assert_eq!(layout.location.x, 10f32);
1491 assert_eq!(layout.location.y, 30f32);
1492 }
1493
1494 #[test]
1495 fn set_children_reparents() {
1496 let mut takia: TakiaTree<()> = TakiaTree::new();
1497 let child = takia.new_leaf(Style::default()).unwrap();
1498 let old_parent = takia.new_with_children(Style::default(), &[child]).unwrap();
1499
1500 let new_parent = takia.new_leaf(Style::default()).unwrap();
1501 takia.set_children(new_parent, &[child]).unwrap();
1502
1503 assert!(takia.children(old_parent).unwrap().is_empty());
1504 }
1505
1506 struct DropCounted(&'static core::sync::atomic::AtomicUsize);
1509
1510 impl Drop for DropCounted {
1511 fn drop(&mut self) {
1512 self.0.fetch_add(1, core::sync::atomic::Ordering::SeqCst);
1513 }
1514 }
1515
1516 #[test]
1517 fn remove_drops_the_nodes_context() {
1518 static DROPS: core::sync::atomic::AtomicUsize = core::sync::atomic::AtomicUsize::new(0);
1519 let mut takia: TakiaTree<DropCounted> = TakiaTree::new();
1520 let node = takia.new_leaf_with_context(Style::DEFAULT, DropCounted(&DROPS)).unwrap();
1521
1522 takia.remove(node).unwrap();
1523
1524 assert_eq!(
1525 DROPS.load(core::sync::atomic::Ordering::SeqCst),
1526 1,
1527 "removing a node must drop its context rather than strand it in node_context_data"
1528 );
1529 }
1530
1531 #[test]
1532 fn clear_drops_every_nodes_context() {
1533 static DROPS: core::sync::atomic::AtomicUsize = core::sync::atomic::AtomicUsize::new(0);
1534 let mut takia: TakiaTree<DropCounted> = TakiaTree::new();
1535 for _ in 0..8 {
1536 takia.new_leaf_with_context(Style::DEFAULT, DropCounted(&DROPS)).unwrap();
1537 }
1538
1539 takia.clear();
1540
1541 assert_eq!(
1542 DROPS.load(core::sync::atomic::Ordering::SeqCst),
1543 8,
1544 "clear() drops all nodes, so it must drop their contexts too"
1545 );
1546 }
1547}