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