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