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