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