1//! UI [`Node`] types and related data structures.
2//!
3//! Layouts are composed of multiple nodes, which live in a forest-like data structure.
4use crate::error;
5use crate::forest::Forest;
6use crate::geometry::Size;
7use crate::layout::Layout;
8use crate::style::FlexboxLayout;
9#[cfg(any(feature = "std", feature = "alloc"))]
10use crate::sys::Box;
11use crate::sys::{new_map_with_capacity, ChildrenVec, Map, Vec};
12use core::sync::atomic::{AtomicUsize, Ordering};
13
14/// Internal node id.
15pub(crate) type NodeId = usize;
16
17/// The identifier of a [`Node`]
18#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
19#[cfg_attr(not(any(feature = "std", feature = "alloc")), derive(hash32_derive::Hash32))]
20pub(crate) struct Id(usize);
21
22/// An bump-allocator index that tracks how many [`Nodes`](Node) have been allocated in a [`Taffy`].
23pub(crate) struct Allocator {
24 /// The last reserved [`NodeId`]
25 last_id: AtomicUsize,
26}
27
28impl Allocator {
29 /// Creates a fresh [`Allocator`]
30 #[must_use]
31 pub const fn new() -> Self {
32 Self { last_id: AtomicUsize::new(0) }
33 }
34
35 /// Allocates space for one more [`Node`]
36 pub fn allocate(&self) -> Id {
37 Id(self.last_id.fetch_add(1, Ordering::Relaxed))
38 }
39}
40
41/// A function type that can be used in a [`MeasureFunc`]
42///
43/// This trait is automatically implemented for all types (including closures) that define a function with the appropriate type signature.
44pub trait Measurable: Send + Sync + Fn(Size<Option<f32>>) -> Size<f32> {}
45
46impl<F: Send + Sync + Fn(Size<Option<f32>>) -> Size<f32>> Measurable for F {}
47
48/// A function that can be used to compute the intrinsic size of a node
49pub enum MeasureFunc {
50 /// Stores an unboxed function
51 Raw(fn(Size<Option<f32>>) -> Size<f32>),
52 /// Stores a boxed function
53 #[cfg(any(feature = "std", feature = "alloc"))]
54 Boxed(Box<dyn Measurable>),
55}
56
57/// Global taffy instance id allocator.
58static INSTANCE_ALLOCATOR: Allocator = Allocator::new();
59
60/// An [`Id`]-containing identifier
61#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
62#[cfg_attr(not(any(feature = "std", feature = "alloc")), derive(hash32_derive::Hash32))]
63pub struct Node {
64 /// The id of the forest that this node lives with
65 instance: Id,
66 /// The identifier of this particular node within the tree
67 local: Id,
68}
69
70/// A forest of UI [`Nodes`](`Node`), suitable for UI layout
71pub struct Taffy {
72 /// The ID of the root node
73 id: Id,
74 /// A monotonically-increasing index that tracks the [`Id`] of the next node
75 allocator: Allocator,
76 /// A map from Node -> NodeId
77 nodes_to_ids: Map<Node, NodeId>,
78 /// A map from NodeId -> Node
79 ids_to_nodes: Map<NodeId, Node>,
80 /// An efficient data structure that stores the node trees
81 forest: Forest,
82}
83
84impl Default for Taffy {
85 fn default() -> Self {
86 Self::with_capacity(16)
87 }
88}
89
90impl Taffy {
91 /// Creates a new [`Taffy`]
92 ///
93 /// The default capacity of a [`Taffy`] is 16 nodes.
94 #[must_use]
95 pub fn new() -> Self {
96 Default::default()
97 }
98
99 /// Creates a new [`Taffy`] that can store `capacity` nodes before reallocation
100 pub fn with_capacity(capacity: usize) -> Self {
101 Self {
102 id: INSTANCE_ALLOCATOR.allocate(),
103 allocator: Allocator::new(),
104 nodes_to_ids: new_map_with_capacity(capacity),
105 ids_to_nodes: new_map_with_capacity(capacity),
106 forest: Forest::with_capacity(capacity),
107 }
108 }
109
110 /// Allocates memory for a new node, and returns a matching generated [`Node`]
111 fn allocate_node(&mut self) -> Node {
112 let local = self.allocator.allocate();
113 Node { instance: self.id, local }
114 }
115
116 /// Stores a new node in the tree
117 fn add_node(&mut self, node: Node, id: NodeId) {
118 let _ = self.nodes_to_ids.insert(node, id);
119 let _ = self.ids_to_nodes.insert(id, node);
120 }
121
122 /// Returns the `NodeId` of the provided node within the forest
123 fn find_node(&self, node: Node) -> Result<NodeId, error::InvalidNode> {
124 match self.nodes_to_ids.get(&node) {
125 Some(id) => Ok(*id),
126 None => Err(error::InvalidNode(node)),
127 }
128 }
129
130 /// Creates and adds a new leaf node
131 pub fn new_leaf(&mut self, layout: FlexboxLayout) -> Result<Node, error::InvalidNode> {
132 let node = self.allocate_node();
133 let id = self.forest.new_leaf(layout);
134 self.add_node(node, id);
135 Ok(node)
136 }
137
138 /// Creates and adds a new leaf node with a supplied [`MeasureFunc`]
139 pub fn new_leaf_with_measure(
140 &mut self,
141 layout: FlexboxLayout,
142 measure: MeasureFunc,
143 ) -> Result<Node, error::InvalidNode> {
144 let node = self.allocate_node();
145 let id = self.forest.new_leaf_with_measure(layout, measure);
146 self.add_node(node, id);
147 Ok(node)
148 }
149
150 /// Creates and adds a new node, which may have any number of `children`
151 pub fn new_with_children(&mut self, layout: FlexboxLayout, children: &[Node]) -> Result<Node, error::InvalidNode> {
152 let node = self.allocate_node();
153 let children = children
154 .iter()
155 .map(|child| self.find_node(*child))
156 .collect::<Result<ChildrenVec<_>, error::InvalidNode>>()?;
157 let id = self.forest.new_with_children(layout, children);
158 self.add_node(node, id);
159 Ok(node)
160 }
161
162 /// Removes all nodes
163 ///
164 /// All associated [`Id`] will be rendered invalid.
165 pub fn clear(&mut self) {
166 self.nodes_to_ids.clear();
167 self.ids_to_nodes.clear();
168 self.forest.clear();
169 }
170
171 /// Remove a specific [`Node`] from the tree
172 ///
173 /// Its [`Id`] is marked as invalid. Returns the id of the node removed.
174 pub fn remove(&mut self, node: Node) -> Result<usize, error::InvalidNode> {
175 let id = self.find_node(node)?;
176
177 self.nodes_to_ids.remove(&node);
178 self.ids_to_nodes.remove(&id);
179
180 if let Some(new_id) = self.forest.swap_remove(id) {
181 let new = self.ids_to_nodes.remove(&new_id).unwrap();
182 let _ = self.nodes_to_ids.insert(new, id);
183 let _ = self.ids_to_nodes.insert(id, new);
184 }
185
186 Ok(id)
187 }
188
189 /// Sets the [`MeasureFunc`] of the associated node
190 pub fn set_measure(&mut self, node: Node, measure: Option<MeasureFunc>) -> Result<(), error::InvalidNode> {
191 let id = self.find_node(node)?;
192 self.forest.nodes[id].measure = measure;
193 self.forest.mark_dirty(id);
194 Ok(())
195 }
196
197 /// Adds a `child` [`Node`] under the supplied `parent`
198 pub fn add_child(&mut self, parent: Node, child: Node) -> Result<(), error::InvalidNode> {
199 let node_id = self.find_node(parent)?;
200 let child_id = self.find_node(child)?;
201
202 self.forest.add_child(node_id, child_id);
203 Ok(())
204 }
205
206 /// Directly sets the `children` of the supplied `parent`
207 pub fn set_children(&mut self, parent: Node, children: &[Node]) -> Result<(), error::InvalidNode> {
208 let node_id = self.find_node(parent)?;
209 let children_id = children.iter().map(|child| self.find_node(*child)).collect::<Result<ChildrenVec<_>, _>>()?;
210
211 // Remove node as parent from all its current children.
212 for child in &self.forest.children[node_id] {
213 self.forest.parents[*child].retain(|p| *p != node_id);
214 }
215
216 // Build up relation node <-> child
217 for child in &children_id {
218 self.forest.parents[*child].push(node_id);
219 }
220 self.forest.children[node_id] = children_id;
221
222 self.forest.mark_dirty(node_id);
223 Ok(())
224 }
225
226 /// Removes the `child` of the parent `node`
227 ///
228 /// The child is not removed from the forest entirely, it is simply no longer attached to its previous parent.
229 pub fn remove_child(&mut self, parent: Node, child: Node) -> Result<Node, error::InvalidNode> {
230 let node_id = self.find_node(parent)?;
231 let child_id = self.find_node(child)?;
232
233 let prev_id = self.forest.remove_child(node_id, child_id);
234 Ok(self.ids_to_nodes[&prev_id])
235 }
236
237 /// Removes the child at the given `index` from the `parent`
238 ///
239 /// The child is not removed from the forest entirely, it is simply no longer attached to its previous parent.
240 pub fn remove_child_at_index(&mut self, parent: Node, child_index: usize) -> Result<Node, error::InvalidChild> {
241 let node_id = self.find_node(parent).map_err(|e| error::InvalidChild::InvalidParentNode(e.0))?;
242
243 let child_count = self.forest.children[node_id].len();
244 if child_index >= child_count {
245 return Err(error::InvalidChild::ChildIndexOutOfBounds { parent, child_index, child_count });
246 }
247
248 let prev_id = self.forest.remove_child_at_index(node_id, child_index);
249 Ok(self.ids_to_nodes[&prev_id])
250 }
251
252 /// Replaces the child at the given `child_index` from the `parent` node with the new `child` node
253 ///
254 /// The child is not removed from the forest entirely, it is simply no longer attached to its previous parent.
255 pub fn replace_child_at_index(
256 &mut self,
257 parent: Node,
258 child_index: usize,
259 new_child: Node,
260 ) -> Result<Node, error::InvalidChild> {
261 let node_id = self.find_node(parent).map_err(|e| error::InvalidChild::InvalidParentNode(e.0))?;
262 let child_id = self.find_node(new_child).map_err(|e| error::InvalidChild::InvalidChildNode(e.0))?;
263
264 let child_count = self.forest.children[node_id].len();
265 if child_index >= child_count {
266 return Err(error::InvalidChild::ChildIndexOutOfBounds { parent, child_index, child_count });
267 }
268
269 self.forest.parents[child_id].push(node_id);
270 let old_child = core::mem::replace(&mut self.forest.children[node_id][child_index], child_id);
271 self.forest.parents[old_child].retain(|p| *p != node_id);
272
273 self.forest.mark_dirty(node_id);
274
275 Ok(self.ids_to_nodes[&old_child])
276 }
277
278 /// Returns the child [`Node`] of the parent `node` at the provided `child_index`
279 pub fn child_at_index(&self, parent: Node, child_index: usize) -> Result<Node, error::InvalidChild> {
280 let id = self.find_node(parent).map_err(|e| error::InvalidChild::InvalidParentNode(e.0))?;
281
282 let child_count = self.forest.children[id].len();
283 if child_index >= child_count {
284 return Err(error::InvalidChild::ChildIndexOutOfBounds { parent, child_index, child_count });
285 }
286
287 Ok(self.ids_to_nodes[&self.forest.children[id][child_index]])
288 }
289
290 /// Returns the number of children of the `parent` [`Node`]
291 pub fn child_count(&self, parent: Node) -> Result<usize, error::InvalidNode> {
292 let id = self.find_node(parent)?;
293 Ok(self.forest.children[id].len())
294 }
295
296 /// Returns a list of children that belong to the [`Parent`]
297 pub fn children(&self, parent: Node) -> Result<Vec<Node>, error::InvalidNode> {
298 let id = self.find_node(parent)?;
299 Ok(self.forest.children[id].iter().map(|child| self.ids_to_nodes[child]).collect())
300 }
301
302 /// Sets the [`Style`] of the provided `node`
303 pub fn set_style(&mut self, node: Node, style: FlexboxLayout) -> Result<(), error::InvalidNode> {
304 let id = self.find_node(node)?;
305 self.forest.nodes[id].style = style;
306 self.forest.mark_dirty(id);
307 Ok(())
308 }
309
310 /// Gets the [`Style`] of the provided `node`
311 pub fn style(&self, node: Node) -> Result<&FlexboxLayout, error::InvalidNode> {
312 let id = self.find_node(node)?;
313 Ok(&self.forest.nodes[id].style)
314 }
315
316 /// Return this node layout relative to its parent
317 pub fn layout(&self, node: Node) -> Result<&Layout, error::InvalidNode> {
318 let id = self.find_node(node)?;
319 Ok(&self.forest.nodes[id].layout)
320 }
321
322 /// Marks the layout computation of this node and its children as outdated
323 pub fn mark_dirty(&mut self, node: Node) -> Result<(), error::InvalidNode> {
324 let id = self.find_node(node)?;
325 self.forest.mark_dirty(id);
326 Ok(())
327 }
328
329 /// Indicates whether the layout of this node (and its children) need to be recomputed
330 pub fn dirty(&self, node: Node) -> Result<bool, error::InvalidNode> {
331 let id = self.find_node(node)?;
332 Ok(self.forest.nodes[id].is_dirty)
333 }
334
335 /// Updates the stored layout of the provided `node` and its children
336 pub fn compute_layout(&mut self, node: Node, size: Size<Option<f32>>) -> Result<(), error::InvalidNode> {
337 let id = self.find_node(node)?;
338 self.forest.compute(id, size);
339 Ok(())
340 }
341}
342
343#[cfg(test)]
344mod tests {
345 use super::*;
346 use crate::{
347 style::{Dimension, Display, FlexDirection},
348 sys,
349 };
350
351 #[test]
352 fn new_should_allocate_default_capacity() {
353 const DEFAULT_CAPACITY: usize = 16; // This is the capacity defined in the `impl Default`
354 let taffy = Taffy::new();
355
356 assert!(taffy.nodes_to_ids.capacity() >= DEFAULT_CAPACITY);
357 assert!(taffy.ids_to_nodes.capacity() >= DEFAULT_CAPACITY);
358 assert!(taffy.forest.children.capacity() >= DEFAULT_CAPACITY);
359 assert!(taffy.forest.parents.capacity() >= DEFAULT_CAPACITY);
360 assert!(taffy.forest.nodes.capacity() >= DEFAULT_CAPACITY);
361 }
362
363 #[test]
364 fn test_with_capacity() {
365 const CAPACITY: usize = 8;
366 let taffy = Taffy::with_capacity(CAPACITY);
367
368 assert!(taffy.nodes_to_ids.capacity() >= CAPACITY);
369 assert!(taffy.ids_to_nodes.capacity() >= CAPACITY);
370 assert!(taffy.forest.children.capacity() >= CAPACITY);
371 assert!(taffy.forest.parents.capacity() >= CAPACITY);
372 assert!(taffy.forest.nodes.capacity() >= CAPACITY);
373 }
374
375 #[test]
376 fn add_node() {
377 let mut taffy = Taffy::new();
378 let node = taffy.allocate_node();
379 let id = taffy.forest.new_leaf(FlexboxLayout::default());
380
381 // Should not contain nodes
382 assert!(!taffy.nodes_to_ids.contains_key(&node));
383 assert!(!taffy.ids_to_nodes.contains_key(&id));
384
385 taffy.add_node(node, id);
386
387 // Should contain nodes
388 assert!(taffy.nodes_to_ids.contains_key(&node));
389 assert!(taffy.ids_to_nodes.contains_key(&id));
390 }
391
392 #[test]
393 fn find_node() {
394 let mut taffy = Taffy::new();
395
396 let child0 = taffy.new_leaf(FlexboxLayout::default()).unwrap();
397 let child1 = taffy.new_leaf(FlexboxLayout::default()).unwrap();
398 let node = taffy.new_with_children(FlexboxLayout::default(), &[child0, child1]).unwrap();
399
400 // Should find the nodes
401 assert!(if let Ok(node_id) = taffy.find_node(node) { node_id == node.local.0 } else { false });
402 assert!(if let Ok(node_id) = taffy.find_node(child0) { node_id == child0.local.0 } else { false });
403 assert!(if let Ok(node_id) = taffy.find_node(child1) { node_id == child1.local.0 } else { false });
404
405 let _ = taffy.remove(node);
406 let _ = taffy.remove(child0);
407 let _ = taffy.remove(child1);
408
409 // Should not find the nodes
410 assert!(taffy.find_node(node).is_err());
411 assert!(taffy.find_node(child0).is_err());
412 assert!(taffy.find_node(child1).is_err());
413 }
414
415 #[test]
416 fn test_new_leaf() {
417 let mut taffy = Taffy::new();
418
419 let res = taffy.new_leaf(FlexboxLayout::default());
420 assert!(res.is_ok());
421 let node = res.unwrap();
422
423 // node should be in the taffy tree and have no children
424 assert!(taffy.find_node(node).is_ok());
425 assert!(taffy.child_count(node).unwrap() == 0);
426 }
427
428 #[test]
429 fn new_leaf_with_measure() {
430 let mut taffy = Taffy::new();
431
432 let res = taffy.new_leaf_with_measure(FlexboxLayout::default(), MeasureFunc::Raw(|_| Size::ZERO));
433 assert!(res.is_ok());
434 let node = res.unwrap();
435
436 // node should be in the taffy tree and have no children
437 assert!(taffy.find_node(node).is_ok());
438 assert!(taffy.child_count(node).unwrap() == 0);
439 }
440
441 /// Test that new_with_children works as expected
442 #[test]
443 fn test_new_with_children() {
444 let mut taffy = Taffy::new();
445 let child0 = taffy.new_leaf(FlexboxLayout::default()).unwrap();
446 let child1 = taffy.new_leaf(FlexboxLayout::default()).unwrap();
447 let node = taffy.new_with_children(FlexboxLayout::default(), &[child0, child1]).unwrap();
448
449 // node should have two children
450 assert_eq!(taffy.child_count(node).unwrap(), 2);
451 assert_eq!(taffy.children(node).unwrap()[0], child0);
452 assert_eq!(taffy.children(node).unwrap()[1], child1);
453 }
454
455 #[test]
456 fn clear_should_clear_nodes() {
457 let mut taffy = Taffy::new();
458 let child0 = taffy.new_leaf(FlexboxLayout::default()).unwrap();
459 let child1 = taffy.new_leaf(FlexboxLayout::default()).unwrap();
460 let node = taffy.new_with_children(FlexboxLayout::default(), &[child0, child1]).unwrap();
461
462 // Nodes should be present
463 assert!(taffy.find_node(node).is_ok());
464 assert!(taffy.find_node(child0).is_ok());
465 assert!(taffy.find_node(child1).is_ok());
466
467 taffy.clear();
468
469 // nodes should not be present
470 assert!(taffy.find_node(node).is_err());
471 assert!(taffy.find_node(child0).is_err());
472 assert!(taffy.find_node(child1).is_err());
473 }
474
475 #[test]
476 fn remove_node_should_remove() {
477 let mut taffy = Taffy::new();
478
479 let node = taffy.new_leaf(FlexboxLayout::default()).unwrap();
480
481 // node should exist
482 assert!(taffy.find_node(node).is_ok());
483
484 let _ = taffy.remove(node).unwrap();
485
486 // node should no longer exist
487 assert!(taffy.find_node(node).is_err());
488 }
489
490 #[test]
491 fn remove_node_should_detach_herarchy() {
492 let mut taffy = Taffy::new();
493
494 // Build a linear tree layout: <0> <- <1> <- <2>
495 let node2 = taffy.new_leaf(FlexboxLayout::default()).unwrap();
496 let node1 = taffy.new_with_children(FlexboxLayout::default(), &[node2]).unwrap();
497 let node0 = taffy.new_with_children(FlexboxLayout::default(), &[node1]).unwrap();
498
499 // Node1 should exist
500 assert!(taffy.find_node(node1).is_ok());
501
502 // Both node0 and node1 should have 1 child nodes
503 assert_eq!(taffy.children(node0).unwrap().as_slice(), &[node1]);
504 assert_eq!(taffy.children(node1).unwrap().as_slice(), &[node2]);
505
506 // Disconnect the tree: <0> <2>
507 let _ = taffy.remove(node1).unwrap();
508
509 // Node1 should no longer exist
510 assert!(taffy.find_node(node1).is_err());
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(FlexboxLayout::default()).unwrap();
522 let child = taffy.new_leaf(FlexboxLayout::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(FlexboxLayout::default(), MeasureFunc::Raw(|_| Size { width: 200.0, height: 200.0 }))
534 .unwrap();
535 taffy.compute_layout(node, Size::undefined()).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::undefined()).unwrap();
540 assert_eq!(taffy.layout(node).unwrap().size.width, 100.0);
541 }
542
543 /// Test that adding `add_child()` works
544 #[test]
545 fn add_child() {
546 let mut taffy = Taffy::new();
547 let node = taffy.new_leaf(FlexboxLayout::default()).unwrap();
548 assert_eq!(taffy.child_count(node).unwrap(), 0);
549
550 let child0 = taffy.new_leaf(FlexboxLayout::default()).unwrap();
551 taffy.add_child(node, child0).unwrap();
552 assert_eq!(taffy.child_count(node).unwrap(), 1);
553
554 let child1 = taffy.new_leaf(FlexboxLayout::default()).unwrap();
555 taffy.add_child(node, child1).unwrap();
556 assert_eq!(taffy.child_count(node).unwrap(), 2);
557 }
558
559 #[test]
560 fn set_children() {
561 let mut taffy = Taffy::new();
562
563 let child0 = taffy.new_leaf(FlexboxLayout::default()).unwrap();
564 let child1 = taffy.new_leaf(FlexboxLayout::default()).unwrap();
565 let node = taffy.new_with_children(FlexboxLayout::default(), &[child0, child1]).unwrap();
566
567 assert_eq!(taffy.child_count(node).unwrap(), 2);
568 assert_eq!(taffy.children(node).unwrap()[0], child0);
569 assert_eq!(taffy.children(node).unwrap()[1], child1);
570
571 let child2 = taffy.new_leaf(FlexboxLayout::default()).unwrap();
572 let child3 = taffy.new_leaf(FlexboxLayout::default()).unwrap();
573 taffy.set_children(node, &[child2, child3]).unwrap();
574
575 assert_eq!(taffy.child_count(node).unwrap(), 2);
576 assert_eq!(taffy.children(node).unwrap()[0], child2);
577 assert_eq!(taffy.children(node).unwrap()[1], child3);
578 }
579
580 /// Test that removing a child works
581 #[test]
582 fn remove_child() {
583 let mut taffy = Taffy::new();
584 let child0 = taffy.new_leaf(FlexboxLayout::default()).unwrap();
585 let child1 = taffy.new_leaf(FlexboxLayout::default()).unwrap();
586 let node = taffy.new_with_children(FlexboxLayout::default(), &[child0, child1]).unwrap();
587
588 assert_eq!(taffy.child_count(node).unwrap(), 2);
589
590 taffy.remove_child(node, child0).unwrap();
591 assert_eq!(taffy.child_count(node).unwrap(), 1);
592 assert_eq!(taffy.children(node).unwrap()[0], child1);
593
594 taffy.remove_child(node, child1).unwrap();
595 assert_eq!(taffy.child_count(node).unwrap(), 0);
596 }
597
598 #[test]
599 fn remove_child_at_index() {
600 let mut taffy = Taffy::new();
601 let child0 = taffy.new_leaf(FlexboxLayout::default()).unwrap();
602 let child1 = taffy.new_leaf(FlexboxLayout::default()).unwrap();
603 let node = taffy.new_with_children(FlexboxLayout::default(), &[child0, child1]).unwrap();
604
605 assert_eq!(taffy.child_count(node).unwrap(), 2);
606
607 taffy.remove_child_at_index(node, 0).unwrap();
608 assert_eq!(taffy.child_count(node).unwrap(), 1);
609 assert_eq!(taffy.children(node).unwrap()[0], child1);
610
611 taffy.remove_child_at_index(node, 0).unwrap();
612 assert_eq!(taffy.child_count(node).unwrap(), 0);
613 }
614
615 #[test]
616 fn replace_child_at_index() {
617 let mut taffy = Taffy::new();
618
619 let child0 = taffy.new_leaf(FlexboxLayout::default()).unwrap();
620 let child1 = taffy.new_leaf(FlexboxLayout::default()).unwrap();
621
622 let node = taffy.new_with_children(FlexboxLayout::default(), &[child0]).unwrap();
623 assert_eq!(taffy.child_count(node).unwrap(), 1);
624 assert_eq!(taffy.children(node).unwrap()[0], child0);
625
626 taffy.replace_child_at_index(node, 0, child1).unwrap();
627 assert_eq!(taffy.child_count(node).unwrap(), 1);
628 assert_eq!(taffy.children(node).unwrap()[0], child1);
629 }
630 #[test]
631 fn test_child_at_index() {
632 let mut taffy = Taffy::new();
633 let child0 = taffy.new_leaf(FlexboxLayout::default()).unwrap();
634 let child1 = taffy.new_leaf(FlexboxLayout::default()).unwrap();
635 let child2 = taffy.new_leaf(FlexboxLayout::default()).unwrap();
636 let node = taffy.new_with_children(FlexboxLayout::default(), &[child0, child1, child2]).unwrap();
637
638 assert!(if let Ok(result) = taffy.child_at_index(node, 0) { result == child0 } else { false });
639 assert!(if let Ok(result) = taffy.child_at_index(node, 1) { result == child1 } else { false });
640 assert!(if let Ok(result) = taffy.child_at_index(node, 2) { result == child2 } else { false });
641 }
642 #[test]
643 fn test_child_count() {
644 let mut taffy = Taffy::new();
645 let child0 = taffy.new_leaf(FlexboxLayout::default()).unwrap();
646 let child1 = taffy.new_leaf(FlexboxLayout::default()).unwrap();
647 let node = taffy.new_with_children(FlexboxLayout::default(), &[child0, child1]).unwrap();
648
649 assert!(if let Ok(count) = taffy.child_count(node) { count == 2 } else { false });
650 assert!(if let Ok(count) = taffy.child_count(child0) { count == 0 } else { false });
651 assert!(if let Ok(count) = taffy.child_count(child1) { count == 0 } else { false });
652 }
653 #[test]
654 fn test_children() {
655 let mut taffy = Taffy::new();
656 let child0 = taffy.new_leaf(FlexboxLayout::default()).unwrap();
657 let child1 = taffy.new_leaf(FlexboxLayout::default()).unwrap();
658 let node = taffy.new_with_children(FlexboxLayout::default(), &[child0, child1]).unwrap();
659
660 let mut children: sys::Vec<Node> = sys::Vec::new();
661 children.push(child0);
662 children.push(child1);
663
664 let children_result = taffy.children(node).unwrap();
665 assert_eq!(children_result, children);
666
667 assert!(taffy.children(child0).unwrap().len() == 0);
668 }
669 #[test]
670 fn test_set_style() {
671 let mut taffy = Taffy::new();
672
673 let node = taffy.new_leaf(FlexboxLayout::default()).unwrap();
674 assert_eq!(taffy.style(node).unwrap().display, Display::Flex);
675
676 taffy.set_style(node, FlexboxLayout { display: Display::None, ..FlexboxLayout::default() }).unwrap();
677 assert_eq!(taffy.style(node).unwrap().display, Display::None);
678 }
679 #[test]
680 fn test_style() {
681 let mut taffy = Taffy::new();
682
683 let style =
684 FlexboxLayout { display: Display::None, flex_direction: FlexDirection::RowReverse, ..Default::default() };
685
686 let node = taffy.new_leaf(style).unwrap();
687
688 let res = taffy.style(node);
689 assert!(res.is_ok());
690 assert!(res.unwrap() == &style);
691 }
692 #[test]
693 fn test_layout() {
694 let mut taffy = Taffy::new();
695 let node = taffy.new_leaf(FlexboxLayout::default()).unwrap();
696
697 // TODO: Improve this test?
698 let res = taffy.layout(node);
699 assert!(res.is_ok());
700 }
701
702 #[test]
703 fn test_mark_dirty() {
704 let mut taffy = Taffy::new();
705 let child0 = taffy.new_leaf(FlexboxLayout::default()).unwrap();
706 let child1 = taffy.new_leaf(FlexboxLayout::default()).unwrap();
707 let node = taffy.new_with_children(FlexboxLayout::default(), &[child0, child1]).unwrap();
708
709 taffy.compute_layout(node, Size::undefined()).unwrap();
710
711 assert_eq!(taffy.dirty(child0).unwrap(), false);
712 assert_eq!(taffy.dirty(child1).unwrap(), false);
713 assert_eq!(taffy.dirty(node).unwrap(), false);
714
715 taffy.mark_dirty(node).unwrap();
716 assert_eq!(taffy.dirty(child0).unwrap(), false);
717 assert_eq!(taffy.dirty(child1).unwrap(), false);
718 assert_eq!(taffy.dirty(node).unwrap(), true);
719
720 taffy.compute_layout(node, Size::undefined()).unwrap();
721 taffy.mark_dirty(child0).unwrap();
722 assert_eq!(taffy.dirty(child0).unwrap(), true);
723 assert_eq!(taffy.dirty(child1).unwrap(), false);
724 assert_eq!(taffy.dirty(node).unwrap(), true);
725 }
726
727 #[test]
728 fn compute_layout_should_produce_valid_result() {
729 let mut taffy = Taffy::new();
730 let node_result = taffy.new_leaf(FlexboxLayout {
731 size: Size { width: Dimension::Points(10f32), height: Dimension::Points(10f32) },
732 ..Default::default()
733 });
734 assert!(node_result.is_ok());
735 let node = node_result.unwrap();
736 let layout_result = taffy.compute_layout(node, Size { width: Some(100.), height: Some(100.) });
737 assert!(layout_result.is_ok());
738 }
739
740 #[test]
741 fn measure_func_is_send_and_sync() {
742 fn is_send_and_sync<T: Send + Sync>() {}
743 is_send_and_sync::<MeasureFunc>();
744 }
745}