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::forest::Forest;
5use crate::geometry::Size;
6use crate::layout::Layout;
7use crate::number::Number;
8use crate::style::Style;
9#[cfg(any(feature = "std", feature = "alloc"))]
10use crate::sys::Box;
11use crate::sys::{new_map_with_capacity, ChildrenVec, Map, Vec};
12use crate::Error;
13use core::sync::atomic::{AtomicUsize, Ordering};
14
15/// A function that can be applied to a `Size<Number>` to obtain a `Size<f32>`
16pub enum MeasureFunc {
17 /// Stores an unboxed function
18 Raw(fn(Size<Number>) -> Size<f32>),
19 /// Stores a boxed function
20 #[cfg(any(feature = "std", feature = "alloc"))]
21 Boxed(Box<dyn Fn(Size<Number>) -> Size<f32>>),
22}
23
24/// Global taffy instance id allocator.
25static INSTANCE_ALLOCATOR: Allocator = Allocator::new();
26
27/// An [`Id`]-containing identifier
28#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
29#[cfg_attr(not(any(feature = "std", feature = "alloc")), derive(hash32_derive::Hash32))]
30pub struct Node {
31 /// The id of the forest that this node lives with
32 instance: Id,
33 /// The identifier of this particular node within the tree
34 local: Id,
35}
36
37/// A forest of UI [`Nodes`](`Node`), suitable for UI layout
38pub struct Taffy {
39 /// The ID of the root node
40 id: Id,
41 /// A monotonically-increasing index that tracks the [`Id`] of the next node
42 allocator: Allocator,
43 /// A map from Node -> NodeId
44 nodes_to_ids: Map<Node, NodeId>,
45 /// A map from NodeId -> Node
46 ids_to_nodes: Map<NodeId, Node>,
47 /// An efficient data structure that stores the node trees
48 forest: Forest,
49}
50
51impl Default for Taffy {
52 fn default() -> Self {
53 Self::with_capacity(16)
54 }
55}
56
57impl Taffy {
58 /// Creates a new [`Taffy`]
59 ///
60 /// The default capacity of a [`Taffy`] is 16 nodes.
61 #[must_use]
62 pub fn new() -> Self {
63 Default::default()
64 }
65
66 /// Creates a new [`Taffy`] that can store `capacity` nodes before reallocation
67 pub fn with_capacity(capacity: usize) -> Self {
68 Self {
69 id: INSTANCE_ALLOCATOR.allocate(),
70 allocator: Allocator::new(),
71 nodes_to_ids: new_map_with_capacity(capacity),
72 ids_to_nodes: new_map_with_capacity(capacity),
73 forest: Forest::with_capacity(capacity),
74 }
75 }
76
77 /// Allocates memory for a new node, and returns a matching generated [`Node`]
78 fn allocate_node(&mut self) -> Node {
79 let local = self.allocator.allocate();
80 Node { instance: self.id, local }
81 }
82
83 /// Stores a new node in the tree
84 fn add_node(&mut self, node: Node, id: NodeId) {
85 let _ = self.nodes_to_ids.insert(node, id);
86 let _ = self.ids_to_nodes.insert(id, node);
87 }
88
89 /// Returns the `NodeId` of the provided node within the forest
90 fn find_node(&self, node: Node) -> Result<NodeId, Error> {
91 match self.nodes_to_ids.get(&node) {
92 Some(id) => Ok(*id),
93 None => Err(Error::InvalidNode(node)),
94 }
95 }
96
97 /// Adds a new leaf node, which does not have any children
98 pub fn new_leaf(&mut self, style: Style, measure: MeasureFunc) -> Result<Node, Error> {
99 let node = self.allocate_node();
100 let id = self.forest.new_leaf(style, measure);
101 self.add_node(node, id);
102 Ok(node)
103 }
104
105 /// Adds a new node, which may have any number of `children`
106 pub fn new_node(&mut self, style: Style, children: &[Node]) -> Result<Node, Error> {
107 let node = self.allocate_node();
108 let children =
109 children.iter().map(|child| self.find_node(*child)).collect::<Result<ChildrenVec<_>, Error>>()?;
110 let id = self.forest.new_node(style, children);
111 self.add_node(node, id);
112 Ok(node)
113 }
114
115 /// Removes all nodes
116 ///
117 /// All associated [`Id`] will be rendered invalid.
118 pub fn clear(&mut self) {
119 self.nodes_to_ids.clear();
120 self.ids_to_nodes.clear();
121 self.forest.clear();
122 }
123
124 /// Remove a specific [`Node`] from the tree
125 ///
126 /// Its [`Id`] is marked as invalid.
127 pub fn remove(&mut self, node: Node) {
128 let id = if let Ok(id) = self.find_node(node) { id } else { return };
129
130 self.nodes_to_ids.remove(&node);
131 self.ids_to_nodes.remove(&id);
132
133 if let Some(new_id) = self.forest.swap_remove(id) {
134 let new = self.ids_to_nodes.remove(&new_id).unwrap();
135 let _ = self.nodes_to_ids.insert(new, id);
136 let _ = self.ids_to_nodes.insert(id, new);
137 }
138 }
139
140 /// Sets the [`MeasureFunc`] of the associated node
141 pub fn set_measure(&mut self, node: Node, measure: Option<MeasureFunc>) -> Result<(), Error> {
142 let id = self.find_node(node)?;
143 self.forest.nodes[id].measure = measure;
144 self.forest.mark_dirty(id);
145 Ok(())
146 }
147
148 /// Adds a `child` [`Node`] under the supplied `parent`
149 pub fn add_child(&mut self, parent: Node, child: Node) -> Result<(), Error> {
150 let node_id = self.find_node(parent)?;
151 let child_id = self.find_node(child)?;
152
153 self.forest.add_child(node_id, child_id);
154 Ok(())
155 }
156
157 /// Directly sets the `children` of the supplied `parent`
158 pub fn set_children(&mut self, parent: Node, children: &[Node]) -> Result<(), Error> {
159 let node_id = self.find_node(parent)?;
160 let children_id = children.iter().map(|child| self.find_node(*child)).collect::<Result<ChildrenVec<_>, _>>()?;
161
162 // Remove node as parent from all its current children.
163 for child in &self.forest.children[node_id] {
164 self.forest.parents[*child].retain(|p| *p != node_id);
165 }
166
167 // Build up relation node <-> child
168 for child in &children_id {
169 self.forest.parents[*child].push(node_id);
170 }
171 self.forest.children[node_id] = children_id;
172
173 self.forest.mark_dirty(node_id);
174 Ok(())
175 }
176
177 /// Removes the `child` of the parent `node`
178 ///
179 /// The child is not removed from the forest entirely, it is simply no longer attached to its previous parent.
180 pub fn remove_child(&mut self, parent: Node, child: Node) -> Result<Node, Error> {
181 let node_id = self.find_node(parent)?;
182 let child_id = self.find_node(child)?;
183
184 let prev_id = self.forest.remove_child(node_id, child_id);
185 Ok(self.ids_to_nodes[&prev_id])
186 }
187
188 /// Removes the child at the given `index` from the `parent`
189 ///
190 /// The child is not removed from the forest entirely, it is simply no longer attached to its previous parent.
191 pub fn remove_child_at_index(&mut self, parent: Node, child_index: usize) -> Result<Node, Error> {
192 let node_id = self.find_node(parent)?;
193 // TODO: index check
194
195 let prev_id = self.forest.remove_child_at_index(node_id, child_index);
196 Ok(self.ids_to_nodes[&prev_id])
197 }
198
199 /// Replaces the child at the given `child_index` from the `parent` node with the new `child` node
200 ///
201 /// The child is not removed from the forest entirely, it is simply no longer attached to its previous parent.
202 pub fn replace_child_at_index(&mut self, parent: Node, child_index: usize, new_child: Node) -> Result<Node, Error> {
203 let node_id = self.find_node(parent)?;
204 let child_id = self.find_node(new_child)?;
205 // TODO: index check
206
207 self.forest.parents[child_id].push(node_id);
208 let old_child = core::mem::replace(&mut self.forest.children[node_id][child_index], child_id);
209 self.forest.parents[old_child].retain(|p| *p != node_id);
210
211 self.forest.mark_dirty(node_id);
212
213 Ok(self.ids_to_nodes[&old_child])
214 }
215
216 /// Returns the child [`Node`] of the parent `node` at the provided `child_index`
217 pub fn child_at_index(&self, parent: Node, child_index: usize) -> Result<Node, Error> {
218 let id = self.find_node(parent)?;
219 Ok(self.ids_to_nodes[&self.forest.children[id][child_index]])
220 }
221
222 /// Returns the number of children of the `parent` [`Node`]
223 pub fn child_count(&self, parent: Node) -> Result<usize, Error> {
224 let id = self.find_node(parent)?;
225 Ok(self.forest.children[id].len())
226 }
227
228 /// Returns a list of children that belong to the [`Parent`]
229 pub fn children(&self, parent: Node) -> Result<Vec<Node>, Error> {
230 let id = self.find_node(parent)?;
231 Ok(self.forest.children[id].iter().map(|child| self.ids_to_nodes[child]).collect())
232 }
233
234 /// Sets the [`Style`] of the provided `node`
235 pub fn set_style(&mut self, node: Node, style: Style) -> Result<(), Error> {
236 let id = self.find_node(node)?;
237 self.forest.nodes[id].style = style;
238 self.forest.mark_dirty(id);
239 Ok(())
240 }
241
242 /// Gets the [`Style`] of the provided `node`
243 pub fn style(&self, node: Node) -> Result<&Style, Error> {
244 let id = self.find_node(node)?;
245 Ok(&self.forest.nodes[id].style)
246 }
247
248 /// Return this node layout relative to its parent
249 pub fn layout(&self, node: Node) -> Result<&Layout, Error> {
250 let id = self.find_node(node)?;
251 Ok(&self.forest.nodes[id].layout)
252 }
253
254 /// Marks the layout computation of this node and its children as outdated
255 pub fn mark_dirty(&mut self, node: Node) -> Result<(), Error> {
256 let id = self.find_node(node)?;
257 self.forest.mark_dirty(id);
258 Ok(())
259 }
260
261 /// Indicates whether the layout of this node (and its children) need to be recomputed
262 pub fn dirty(&self, node: Node) -> Result<bool, Error> {
263 let id = self.find_node(node)?;
264 Ok(self.forest.nodes[id].is_dirty)
265 }
266
267 /// Updates the stored layout of the provided `node` and its children
268 pub fn compute_layout(&mut self, node: Node, size: Size<Number>) -> Result<(), Error> {
269 let id = self.find_node(node)?;
270 self.forest.compute_layout(id, size);
271 Ok(())
272 }
273}
274
275/// Internal node id.
276pub(crate) type NodeId = usize;
277
278/// The identifier of a [`Node`]
279#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
280#[cfg_attr(not(any(feature = "std", feature = "alloc")), derive(hash32_derive::Hash32))]
281pub(crate) struct Id(usize);
282
283/// An bump-allocator index that tracks how many [`Nodes`](Node) have been allocated in a [`Taffy`].
284pub(crate) struct Allocator {
285 /// The last reserved [`NodeId`]
286 last_id: AtomicUsize,
287}
288
289impl Allocator {
290 /// Creates a fresh [`Allocator`]
291 #[must_use]
292 pub const fn new() -> Self {
293 Self { last_id: AtomicUsize::new(0) }
294 }
295
296 /// Allocates space for one more [`Node`]
297 pub fn allocate(&self) -> Id {
298 Id(self.last_id.fetch_add(1, Ordering::Relaxed))
299 }
300}