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