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