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