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