Semantic delta · 49
src/compute/grid/alignment.rs
src/compute/grid/track_sizing.rs
src/compute/grid/types/grid_item.rs
diff --git a/Cargo.toml b/Cargo.toml
index 64e68ee6b..1b461556d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -21,6 +21,7 @@ num-traits = { version = "0.2", default-features = false }
serde = { version = "1.0", default-features = false, optional = true, features = ["serde_derive"] }
slotmap = { version = "1.0.6", default-features = false, optional = true }
grid = { version = "0.13.0", default-features = false, optional = true }
+rayon = "1.10.0"
### FEATURES #################################################################
diff --git a/src/compute/block.rs b/src/compute/block.rs
index 7e6d300be..5ff45891e 100644
--- a/src/compute/block.rs
+++ b/src/compute/block.rs
@@ -57,7 +57,7 @@ struct BlockItem {
}
/// Computes the layout of [`LayoutPartialTree`] according to the block layout algorithm
-pub fn compute_block_layout(tree: &mut impl LayoutPartialTree, node_id: NodeId, inputs: LayoutInput) -> LayoutOutput {
+pub fn compute_block_layout(tree: &impl LayoutPartialTree, node_id: NodeId, inputs: LayoutInput) -> LayoutOutput {
let LayoutInput { known_dimensions, parent_size, available_space, run_mode, .. } = inputs;
let style = tree.get_style(node_id);
@@ -104,7 +104,7 @@ pub fn compute_block_layout(tree: &mut impl LayoutPartialTree, node_id: NodeId,
}
/// Computes the layout of [`LayoutPartialTree`] according to the block layout algorithm
-fn compute_inner(tree: &mut impl LayoutPartialTree, node_id: NodeId, inputs: LayoutInput) -> LayoutOutput {
+fn compute_inner(tree: &impl LayoutPartialTree, node_id: NodeId, inputs: LayoutInput) -> LayoutOutput {
let LayoutInput {
known_dimensions, parent_size, available_space, run_mode, vertical_margins_are_collapsible, ..
} = inputs;
@@ -298,7 +298,7 @@ fn generate_item_list(
/// Compute the content-based width in the case that the width of the container is not known
#[inline]
fn determine_content_based_container_width(
- tree: &mut impl LayoutPartialTree,
+ tree: &impl LayoutPartialTree,
items: &[BlockItem],
available_width: AvailableSpace,
) -> f32 {
@@ -333,7 +333,7 @@ fn determine_content_based_container_width(
/// Compute each child's final size and position
#[inline]
fn perform_final_layout_on_in_flow_children(
- tree: &mut impl LayoutPartialTree,
+ tree: &impl LayoutPartialTree,
items: &mut [BlockItem],
container_outer_width: f32,
content_box_inset: Rect<f32>,
@@ -488,7 +488,7 @@ fn perform_final_layout_on_in_flow_children(
/// Perform absolute layout on all absolutely positioned children.
#[inline]
fn perform_absolute_layout_on_absolute_children(
- tree: &mut impl LayoutPartialTree,
+ tree: &impl LayoutPartialTree,
items: &[BlockItem],
area_size: Size<f32>,
area_offset: Point<f32>,
diff --git a/src/compute/flexbox.rs b/src/compute/flexbox.rs
index 143a1dea3..03bfc12ff 100644
--- a/src/compute/flexbox.rs
+++ b/src/compute/flexbox.rs
@@ -13,6 +13,7 @@ use crate::util::debug::debug_log;
use crate::util::sys::{f32_max, new_vec_with_capacity, Vec};
use crate::util::MaybeMath;
use crate::util::{MaybeResolve, ResolveOrZero};
+use rayon::prelude::*;
#[cfg(feature = "content_size")]
use super::common::content_size::compute_content_size_contribution;
@@ -152,7 +153,7 @@ struct AlgoConstants {
}
/// Computes the layout of [`LayoutPartialTree`] according to the flexbox algorithm
-pub fn compute_flexbox_layout(tree: &mut impl LayoutPartialTree, node: NodeId, inputs: LayoutInput) -> LayoutOutput {
+pub fn compute_flexbox_layout(tree: &impl LayoutPartialTree, node: NodeId, inputs: LayoutInput) -> LayoutOutput {
let LayoutInput { known_dimensions, parent_size, run_mode, .. } = inputs;
let style = tree.get_style(node);
@@ -186,7 +187,7 @@ pub fn compute_flexbox_layout(tree: &mut impl LayoutPartialTree, node: NodeId, i
}
/// Compute a preliminary size for an item
-fn compute_preliminary(tree: &mut impl LayoutPartialTree, node: NodeId, inputs: LayoutInput) -> LayoutOutput {
+fn compute_preliminary(tree: &impl LayoutPartialTree, node: NodeId, inputs: LayoutInput) -> LayoutOutput {
let LayoutInput { known_dimensions, parent_size, available_space, run_mode, .. } = inputs;
// Define some general constants we will need for the remainder of the algorithm.
@@ -562,14 +563,15 @@ fn determine_available_space(
/// (For example, an item with a specified size of zero, positive padding, and box-sizing: border-box will have an outer flex base size of zero—and hence a negative inner flex base size.)
#[inline]
fn determine_flex_base_size(
- tree: &mut impl LayoutPartialTree,
+ tree: &impl LayoutPartialTree,
constants: &AlgoConstants,
available_space: Size<AvailableSpace>,
flex_items: &mut [FlexItem],
) {
let dir = constants.dir;
- for child in flex_items.iter_mut() {
+ let block_size = (flex_items.len() / 8).max(1);
+ flex_items.par_iter_mut().by_uniform_blocks(block_size).for_each(|child| {
let child_style = tree.get_style(child.node);
// Parent size for child sizing
@@ -717,7 +719,7 @@ fn determine_flex_base_size(
min_content_main_size.maybe_min(child.size.main(dir)).maybe_min(child.max_size.main(dir));
clamped_min_content_size.maybe_max(padding_border_axes_sums.main(dir))
});
- }
+ });
}
/// Collect flex items into flex lines.
@@ -802,7 +804,7 @@ fn collect_flex_lines<'a>(
/// Determine the container's main size (if not already known)
fn determine_container_main_size(
- tree: &mut impl LayoutPartialTree,
+ tree: &impl LayoutPartialTree,
available_space: Size<AvailableSpace>,
lines: &mut [FlexLine<'_>],
constants: &mut AlgoConstants,
@@ -1208,7 +1210,7 @@ fn resolve_flexible_lengths(line: &mut FlexLine, constants: &AlgoConstants, orig
/// by performing layout with the used main size and the available space, treating auto as fit-content.
#[inline]
fn determine_hypothetical_cross_size(
- tree: &mut impl LayoutPartialTree,
+ tree: &impl LayoutPartialTree,
line: &mut FlexLine,
constants: &AlgoConstants,
available_space: Size<AvailableSpace>,
@@ -1258,7 +1260,7 @@ fn determine_hypothetical_cross_size(
/// Calculate the base lines of the children.
#[inline]
fn calculate_children_base_lines(
- tree: &mut impl LayoutPartialTree,
+ tree: &impl LayoutPartialTree,
node_size: Size<Option<f32>>,
available_space: Size<AvailableSpace>,
flex_lines: &mut [FlexLine],
@@ -1722,7 +1724,7 @@ fn align_flex_lines_per_align_content(flex_lines: &mut [FlexLine], constants: &A
/// Calculates the layout for a flex-item
#[allow(clippy::too_many_arguments)]
fn calculate_flex_item(
- tree: &mut impl LayoutPartialTree,
+ tree: &impl LayoutPartialTree,
item: &mut FlexItem,
total_offset_main: &mut f32,
total_offset_cross: f32,
@@ -1803,7 +1805,7 @@ fn calculate_flex_item(
/// Calculates the layout line
#[allow(clippy::too_many_arguments)]
fn calculate_layout_line(
- tree: &mut impl LayoutPartialTree,
+ tree: &impl LayoutPartialTree,
line: &mut FlexLine,
total_offset_cross: &mut f32,
#[cfg(feature = "content_size")] content_size: &mut Size<f32>,
@@ -1815,8 +1817,11 @@ fn calculate_layout_line(
let mut total_offset_main = padding_border.main_start(direction);
let line_offset_cross = line.offset_cross;
+ let block_size = (line.items.len() / 8).max(1);
if direction.is_reverse() {
- for item in line.items.iter_mut().rev() {
+ line.items.par_iter_mut().rev().by_uniform_blocks(block_size).for_each(|item| {
+ let mut total_offset_main = 0.0;
+ let mut content_size = &mut Size::ZERO;
calculate_flex_item(
tree,
item,
@@ -1829,9 +1834,11 @@ fn calculate_layout_line(
node_inner_size,
direction,
);
- }
+ });
} else {
- for item in line.items.iter_mut() {
+ line.items.par_iter_mut().by_uniform_blocks(block_size).for_each(|item| {
+ let mut total_offset_main = 0.0;
+ let mut content_size = &mut Size::ZERO;
calculate_flex_item(
tree,
item,
@@ -1844,7 +1851,7 @@ fn calculate_layout_line(
node_inner_size,
direction,
);
- }
+ });
}
*total_offset_cross += line_offset_cross + line.cross_size;
@@ -1853,7 +1860,7 @@ fn calculate_layout_line(
/// Do a final layout pass and collect the resulting layouts.
#[inline]
fn final_layout_pass(
- tree: &mut impl LayoutPartialTree,
+ tree: &impl LayoutPartialTree,
flex_lines: &mut [FlexLine],
constants: &AlgoConstants,
) -> Size<f32> {
@@ -1898,7 +1905,7 @@ fn final_layout_pass(
/// Perform absolute layout on all absolutely positioned children.
#[inline]
fn perform_absolute_layout_on_absolute_children(
- tree: &mut impl LayoutPartialTree,
+ tree: &impl LayoutPartialTree,
node: NodeId,
constants: &AlgoConstants,
) -> Size<f32> {
diff --git a/src/compute/grid/alignment.rs b/src/compute/grid/alignment.rs
index 9a38c7ba6..723af8685 100644
--- a/src/compute/grid/alignment.rs
+++ b/src/compute/grid/alignment.rs
@@ -54,7 +54,7 @@ pub(super) fn align_tracks(
/// Align and size a grid item into it's final position
pub(super) fn align_and_position_item(
- tree: &mut impl LayoutPartialTree,
+ tree: &impl LayoutPartialTree,
node: NodeId,
order: u32,
grid_area: Rect<f32>,
diff --git a/src/compute/grid/mod.rs b/src/compute/grid/mod.rs
index cc755769e..ffc70aed8 100644
--- a/src/compute/grid/mod.rs
+++ b/src/compute/grid/mod.rs
@@ -35,7 +35,7 @@ mod util;
/// - Placing items (which also resolves the implicit grid)
/// - Track (row/column) sizing
/// - Alignment & Final item placement
-pub fn compute_grid_layout(tree: &mut impl LayoutPartialTree, node: NodeId, inputs: LayoutInput) -> LayoutOutput {
+pub fn compute_grid_layout(tree: &impl LayoutPartialTree, node: NodeId, inputs: LayoutInput) -> LayoutOutput {
let LayoutInput { known_dimensions, parent_size, available_space, run_mode, .. } = inputs;
let get_child_styles_iter = |node| tree.child_ids(node).map(|child_node: NodeId| tree.get_style(child_node));
diff --git a/src/compute/grid/track_sizing.rs b/src/compute/grid/track_sizing.rs
index 8e5c73c9d..9dd0a9d19 100644
--- a/src/compute/grid/track_sizing.rs
+++ b/src/compute/grid/track_sizing.rs
@@ -71,7 +71,7 @@ where
EstimateFunction: Fn(&GridTrack, Option<f32>) -> Option<f32>,
{
/// The layout tree
- tree: &'tree mut Tree,
+ tree: &'tree Tree,
/// The tracks in the opposite axis to the one we are currently sizing
other_axis_tracks: &'oat [GridTrack],
/// A function that computes an estimate of an other-axis track's size which is passed to
@@ -261,7 +261,7 @@ pub(super) fn determine_if_item_crosses_flexible_or_intrinsic_tracks(
/// Note: Gutters are treated as empty fixed-size tracks for the purpose of the track sizing algorithm.
#[allow(clippy::too_many_arguments)]
pub(super) fn track_sizing_algorithm<Tree: LayoutPartialTree>(
- tree: &mut Tree,
+ tree: &Tree,
axis: AbstractAxis,
axis_min_size: Option<f32>,
axis_max_size: Option<f32>,
@@ -435,7 +435,7 @@ fn initialize_track_sizes(axis_tracks: &mut [GridTrack], axis_inner_node_size: O
/// 11.5.1 Shim baseline-aligned items so their intrinsic size contributions reflect their baseline alignment.
fn resolve_item_baselines(
- tree: &mut impl LayoutPartialTree,
+ tree: &impl LayoutPartialTree,
axis: AbstractAxis,
items: &mut [GridItem],
inner_node_size: Size<Option<f32>>,
@@ -508,7 +508,7 @@ fn resolve_item_baselines(
/// 11.5 Resolve Intrinsic Track Sizes
#[allow(clippy::too_many_arguments)]
fn resolve_intrinsic_track_sizes(
- tree: &mut impl LayoutPartialTree,
+ tree: &impl LayoutPartialTree,
axis: AbstractAxis,
axis_tracks: &mut [GridTrack],
other_axis_tracks: &[GridTrack],
@@ -1139,7 +1139,7 @@ fn maximise_tracks(
#[allow(clippy::too_many_arguments)]
#[inline(always)]
fn expand_flexible_tracks(
- tree: &mut impl LayoutPartialTree,
+ tree: &impl LayoutPartialTree,
axis: AbstractAxis,
axis_tracks: &mut [GridTrack],
items: &mut [GridItem],
diff --git a/src/compute/grid/types/grid_item.rs b/src/compute/grid/types/grid_item.rs
index 5f0e7906b..98c83409d 100644
--- a/src/compute/grid/types/grid_item.rs
+++ b/src/compute/grid/types/grid_item.rs
@@ -340,7 +340,7 @@ impl GridItem {
pub fn min_content_contribution(
&self,
axis: AbstractAxis,
- tree: &mut impl LayoutPartialTree,
+ tree: &impl LayoutPartialTree,
available_space: Size<Option<f32>>,
inner_node_size: Size<Option<f32>>,
) -> f32 {
@@ -364,7 +364,7 @@ impl GridItem {
pub fn min_content_contribution_cached(
&mut self,
axis: AbstractAxis,
- tree: &mut impl LayoutPartialTree,
+ tree: &impl LayoutPartialTree,
available_space: Size<Option<f32>>,
inner_node_size: Size<Option<f32>>,
) -> f32 {
@@ -379,7 +379,7 @@ impl GridItem {
pub fn max_content_contribution(
&self,
axis: AbstractAxis,
- tree: &mut impl LayoutPartialTree,
+ tree: &impl LayoutPartialTree,
available_space: Size<Option<f32>>,
inner_node_size: Size<Option<f32>>,
) -> f32 {
@@ -403,7 +403,7 @@ impl GridItem {
pub fn max_content_contribution_cached(
&mut self,
axis: AbstractAxis,
- tree: &mut impl LayoutPartialTree,
+ tree: &impl LayoutPartialTree,
available_space: Size<Option<f32>>,
inner_node_size: Size<Option<f32>>,
) -> f32 {
@@ -423,7 +423,7 @@ impl GridItem {
/// See: https://www.w3.org/TR/css-grid-1/#min-size-auto
pub fn minimum_contribution(
&mut self,
- tree: &mut impl LayoutPartialTree,
+ tree: &impl LayoutPartialTree,
axis: AbstractAxis,
axis_tracks: &[GridTrack],
known_dimensions: Size<Option<f32>>,
@@ -482,7 +482,7 @@ impl GridItem {
#[inline(always)]
pub fn minimum_contribution_cached(
&mut self,
- tree: &mut impl LayoutPartialTree,
+ tree: &impl LayoutPartialTree,
axis: AbstractAxis,
axis_tracks: &[GridTrack],
known_dimensions: Size<Option<f32>>,
diff --git a/src/compute/mod.rs b/src/compute/mod.rs
index f78a22df9..beeea4d0d 100644
--- a/src/compute/mod.rs
+++ b/src/compute/mod.rs
@@ -2,7 +2,7 @@
//!
//! ### Layout functions
//!
-//! The layout functions all take an [`&mut impl LayoutPartialTree`](crate::LayoutPartialTree) parameter, which represents a single container node and it's direct children.
+//! The layout functions all take an [`&impl LayoutPartialTree`](crate::LayoutPartialTree) parameter, which represents a single container node and it's direct children.
//!
//! | Function | Purpose |
//! | --- | --- |
@@ -54,7 +54,7 @@ use crate::util::sys::round;
use crate::util::ResolveOrZero;
/// Compute layout for the root node in the tree
-pub fn compute_root_layout(tree: &mut impl LayoutPartialTree, root: NodeId, available_space: Size<AvailableSpace>) {
+pub fn compute_root_layout(tree: &impl LayoutPartialTree, root: NodeId, available_space: Size<AvailableSpace>) {
// Recursively compute node layout
let output = tree.perform_child_layout(
root,
@@ -93,13 +93,13 @@ pub fn compute_root_layout(tree: &mut impl LayoutPartialTree, root: NodeId, avai
/// Uses the provided closure to compute the layout (and then stores the result in the cache) if no cached layout is found.
#[inline(always)]
pub fn compute_cached_layout<Tree: LayoutPartialTree + ?Sized, ComputeFunction>(
- tree: &mut Tree,
+ tree: &Tree,
node: NodeId,
inputs: LayoutInput,
mut compute_uncached: ComputeFunction,
) -> LayoutOutput
where
- ComputeFunction: FnMut(&mut Tree, NodeId, LayoutInput) -> LayoutOutput,
+ ComputeFunction: FnMut(&Tree, NodeId, LayoutInput) -> LayoutOutput,
{
debug_push_node!(node);
let LayoutInput { known_dimensions, available_space, run_mode, .. } = inputs;
@@ -194,7 +194,7 @@ pub fn round_layout(tree: &mut impl RoundTree, node_id: NodeId) {
/// Creates a layout for this node and its children, recursively.
/// Each hidden node has zero size and is placed at the origin
-pub fn compute_hidden_layout(tree: &mut impl LayoutPartialTree, node: NodeId) -> LayoutOutput {
+pub fn compute_hidden_layout(tree: &impl LayoutPartialTree, node: NodeId) -> LayoutOutput {
// Clear cache and set zeroed-out layout for the node
tree.get_cache_mut(node).clear();
tree.set_unrounded_layout(node, &Layout::with_order(0));
diff --git a/src/lib.rs b/src/lib.rs
index 577abf778..4f4ce8e1e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -58,8 +58,6 @@
//! - [custom_tree_owned_unsafe](https://github.com/DioxusLabs/taffy/blob/main/examples/custom_tree_owned_unsafe.rs) which implements a custom Taffy tree using directly owned children with NodeId's being pointers.
#![cfg_attr(not(feature = "std"), no_std)]
-#![deny(unsafe_code)]
-#![forbid(unsafe_code)]
#![warn(missing_docs)]
#![warn(clippy::missing_docs_in_private_items)]
diff --git a/src/tree/taffy_tree.rs b/src/tree/taffy_tree.rs
index b465bed5a..f1e71f83f 100644
--- a/src/tree/taffy_tree.rs
+++ b/src/tree/taffy_tree.rs
@@ -1,4 +1,6 @@
//! Contains [TaffyTree](crate::tree::TaffyTree): the default implementation of [LayoutTree](crate::tree::LayoutTree), and the error type for Taffy.
+use core::cell::UnsafeCell;
+
#[cfg(not(feature = "std"))]
use slotmap::SecondaryMap;
#[cfg(feature = "std")]
@@ -86,7 +88,7 @@ struct NodeData {
/// The always unrounded results of the layout computation. We must store this separately from the rounded
/// layout to avoid errors from rounding already-rounded values. See <https://github.com/DioxusLabs/taffy/issues/501>.
- pub(crate) unrounded_layout: Layout,
+ pub(crate) unrounded_layout: UnsafeCell<Layout>,
/// The final results of the layout computation.
/// These may be rounded or unrounded depending on what the `use_rounding` config setting is set to.
@@ -96,17 +98,20 @@ struct NodeData {
pub(crate) has_context: bool,
/// The cached results of the layout computation
- pub(crate) cache: Cache,
+ pub(crate) cache: UnsafeCell<Cache>,
}
+unsafe impl Send for NodeData {}
+unsafe impl Sync for NodeData {}
+
impl NodeData {
/// Create the data for a new node
#[must_use]
pub const fn new(style: Style) -> Self {
Self {
style,
- cache: Cache::new(),
- unrounded_layout: Layout::new(),
+ cache: UnsafeCell::new(Cache::new()),
+ unrounded_layout: UnsafeCell::new(Layout::new()),
final_layout: Layout::new(),
has_context: false,
}
@@ -116,15 +121,15 @@ impl NodeData {
///
/// This clears any cached data and signals that the data must be recomputed.
#[inline]
- pub fn mark_dirty(&mut self) {
- self.cache.clear()
+ pub fn mark_dirty(&self) {
+ unsafe { &mut *self.cache.get() }.clear()
}
}
/// An entire tree of UI nodes. The entry point to Taffy's high-level API.
///
/// Allows you to build a tree of UI nodes, run Taffy's layout algorithms over that tree, and then access the resultant layout.
-pub struct TaffyTree<NodeContext = ()> {
+pub struct TaffyTree<NodeContext: Send + Sync = ()> {
/// The [`NodeData`] for each node stored in this tree
nodes: SlotMap<DefaultKey, NodeData>,
@@ -162,7 +167,7 @@ impl<'a> Iterator for TaffyTreeChildIter<'a> {
}
// TraversePartialTree impl for TaffyTree
-impl<NodeContext> TraversePartialTree for TaffyTree<NodeContext> {
+impl<NodeContext: Send + Sync> TraversePartialTree for TaffyTree<NodeContext> {
type ChildIter<'a> = TaffyTreeChildIter<'a> where Self: 'a;
#[inline(always)]
@@ -182,10 +187,10 @@ impl<NodeContext> TraversePartialTree for TaffyTree<NodeContext> {
}
// TraverseTree impl for TaffyTree
-impl<NodeContext> TraverseTree for TaffyTree<NodeContext> {}
+impl<NodeContext: Send + Sync> TraverseTree for TaffyTree<NodeContext> {}
// PrintTree impl for TaffyTree
-impl<NodeContext> PrintTree for TaffyTree<NodeContext> {
+impl<NodeContext: Send + Sync> PrintTree for TaffyTree<NodeContext> {
#[inline(always)]
fn get_debug_label(&self, node_id: NodeId) -> &'static str {
let node = &self.nodes[node_id.into()];
@@ -221,7 +226,8 @@ impl<NodeContext> PrintTree for TaffyTree<NodeContext> {
/// which makes the lifetimes of the context much more flexible.
pub(crate) struct TaffyView<'t, NodeContext, MeasureFunction>
where
- MeasureFunction: FnMut(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&mut NodeContext>) -> Size<f32>,
+ MeasureFunction: Fn(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&NodeContext>) -> Size<f32> + Send + Sync,
+ NodeContext: Send + Sync,
{
/// A reference to the TaffyTree
pub(crate) taffy: &'t mut TaffyTree<NodeContext>,
@@ -232,7 +238,8 @@ where
// TraversePartialTree impl for TaffyView
impl<'t, NodeContext, MeasureFunction> TraversePartialTree for TaffyView<'t, NodeContext, MeasureFunction>
where
- MeasureFunction: FnMut(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&mut NodeContext>) -> Size<f32>,
+ MeasureFunction: Fn(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&NodeContext>) -> Size<f32> + Send + Sync,
+ NodeContext: Send + Sync,
{
type ChildIter<'a> = TaffyTreeChildIter<'a> where Self: 'a;
@@ -254,14 +261,16 @@ where
// TraverseTree impl for TaffyView
impl<'t, NodeContext, MeasureFunction> TraverseTree for TaffyView<'t, NodeContext, MeasureFunction> where
- MeasureFunction: FnMut(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&mut NodeContext>) -> Size<f32>
+ MeasureFunction: Fn(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&NodeContext>) -> Size<f32> + Send + Sync,
+ NodeContext: Send + Sync,
{
}
// LayoutPartialTree impl for TaffyView
impl<'t, NodeContext, MeasureFunction> LayoutPartialTree for TaffyView<'t, NodeContext, MeasureFunction>
where
- MeasureFunction: FnMut(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&mut NodeContext>) -> Size<f32>,
+ MeasureFunction: Fn(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&NodeContext>) -> Size<f32> + Send + Sync,
+ NodeContext: Send + Sync,
{
#[inline(always)]
fn get_style(&self, node: NodeId) -> &Style {
@@ -269,17 +278,17 @@ where
}
#[inline(always)]
- fn get_cache_mut(&mut self, node: NodeId) -> &mut Cache {
- &mut self.taffy.nodes[node.into()].cache
+ fn get_cache_mut(&self, node: NodeId) -> &mut Cache {
+ unsafe { &mut*self.taffy.nodes[node.into()].cache.get() }
}
#[inline(always)]
- fn set_unrounded_layout(&mut self, node_id: NodeId, layout: &Layout) {
- self.taffy.nodes[node_id.into()].unrounded_layout = *layout;
+ fn set_unrounded_layout(&self, node_id: NodeId, layout: &Layout) {
+ unsafe { *self.taffy.nodes[node_id.into()].unrounded_layout.get() = *layout };
}
#[inline(always)]
- fn compute_child_layout(&mut self, node: NodeId, inputs: LayoutInput) -> LayoutOutput {
+ fn compute_child_layout(&self, node: NodeId, inputs: LayoutInput) -> LayoutOutput {
// If RunMode is PerformHiddenLayout then this indicates that an ancestor node is `Display::None`
// and thus that we should lay out this node using hidden layout regardless of it's own display style.
if inputs.run_mode == RunMode::PerformHiddenLayout {
@@ -318,7 +327,7 @@ where
let node_key = node.into();
let style = &tree.taffy.nodes[node_key].style;
let has_context = tree.taffy.nodes[node_key].has_context;
- let node_context = has_context.then(|| tree.taffy.node_context_data.get_mut(node_key)).flatten();
+ let node_context = has_context.then(|| tree.taffy.node_context_data.get(node_key)).flatten();
let measure_function = |known_dimensions, available_space| {
(tree.measure_function)(known_dimensions, available_space, node, node_context)
};
@@ -332,11 +341,12 @@ where
// RoundTree impl for TaffyView
impl<'t, NodeContext, MeasureFunction> RoundTree for TaffyView<'t, NodeContext, MeasureFunction>
where
- MeasureFunction: FnMut(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&mut NodeContext>) -> Size<f32>,
+ MeasureFunction: Fn(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&NodeContext>) -> Size<f32> + Send + Sync,
+ NodeContext: Send + Sync,
{
#[inline(always)]
fn get_unrounded_layout(&self, node: NodeId) -> &Layout {
- &self.taffy.nodes[node.into()].unrounded_layout
+ unsafe { &*self.taffy.nodes[node.into()].unrounded_layout.get() }
}
#[inline(always)]
@@ -346,7 +356,7 @@ where
}
#[allow(clippy::iter_cloned_collect)] // due to no-std support, we need to use `iter_cloned` instead of `collect`
-impl<NodeContext> TaffyTree<NodeContext> {
+impl<NodeContext: Send + Sync> TaffyTree<NodeContext> {
/// Creates a new [`TaffyTree`]
///
/// The default capacity of a [`TaffyTree`] is 16 nodes.
@@ -631,7 +641,7 @@ impl<NodeContext> TaffyTree<NodeContext> {
if self.config.use_rounding {
Ok(&self.nodes[node.into()].final_layout)
} else {
- Ok(&self.nodes[node.into()].unrounded_layout)
+ Ok(unsafe { &*self.nodes[node.into()].unrounded_layout.get() })
}
}
@@ -661,7 +671,7 @@ impl<NodeContext> TaffyTree<NodeContext> {
/// Indicates whether the layout of this node (and its children) need to be recomputed
pub fn dirty(&self, node: NodeId) -> TaffyResult<bool> {
- Ok(self.nodes[node.into()].cache.is_empty())
+ Ok(unsafe { &*self.nodes[node.into()].cache.get() }.is_empty())
}
/// Updates the stored layout of the provided `node` and its children
@@ -672,7 +682,8 @@ impl<NodeContext> TaffyTree<NodeContext> {
measure_function: MeasureFunction,
) -> Result<(), TaffyError>
where
- MeasureFunction: FnMut(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&mut NodeContext>) -> Size<f32>,
+ MeasureFunction: Fn(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&NodeContext>) -> Size<f32> + Send + Sync,
+ NodeContext: Send + Sync,
{
let use_rounding = self.config.use_rounding;
let mut taffy_view = TaffyView { taffy: self, measure_function };
@@ -713,7 +724,7 @@ mod tests {
known_dimensions: Size<Option<f32>>,
_available_space: Size<AvailableSpace>,
_node_id: NodeId,
- node_context: Option<&mut Size<f32>>,
+ node_context: Option<&Size<f32>>,
) -> Size<f32> {
known_dimensions.unwrap_or(node_context.cloned().unwrap_or(Size::ZERO))
}
diff --git a/src/tree/traits.rs b/src/tree/traits.rs
index ce6688294..31f8ab43f 100644
--- a/src/tree/traits.rs
+++ b/src/tree/traits.rs
@@ -156,18 +156,18 @@ pub trait TraverseTree: TraversePartialTree {}
///
/// Note that this trait extends [`TraversePartialTree`] (not [`TraverseTree`]). Taffy's algorithm implementations have been designed such that they can be used for a laying out a single
/// node that only has access to it's immediate children.
-pub trait LayoutPartialTree: TraversePartialTree {
+pub trait LayoutPartialTree: TraversePartialTree + Send + Sync {
/// Get a reference to the [`Style`] for this node.
fn get_style(&self, node_id: NodeId) -> &Style;
/// Set the node's unrounded layout
- fn set_unrounded_layout(&mut self, node_id: NodeId, layout: &Layout);
+ fn set_unrounded_layout(&self, node_id: NodeId, layout: &Layout);
/// Get a mutable reference to the [`Cache`] for this node.
- fn get_cache_mut(&mut self, node_id: NodeId) -> &mut Cache;
+ fn get_cache_mut(&self, node_id: NodeId) -> &mut Cache;
/// Compute the specified node's size or full layout given the specified constraints
- fn compute_child_layout(&mut self, node_id: NodeId, inputs: LayoutInput) -> LayoutOutput;
+ fn compute_child_layout(&self, node_id: NodeId, inputs: LayoutInput) -> LayoutOutput;
}
/// Trait used by the `round_layout` method which takes a tree of unrounded float-valued layouts and performs
@@ -200,7 +200,7 @@ pub(crate) trait LayoutPartialTreeExt: LayoutPartialTree {
#[inline(always)]
#[allow(clippy::too_many_arguments)]
fn measure_child_size(
- &mut self,
+ &self,
node_id: NodeId,
known_dimensions: Size<Option<f32>>,
parent_size: Size<Option<f32>>,
@@ -228,7 +228,7 @@ pub(crate) trait LayoutPartialTreeExt: LayoutPartialTree {
/// Perform a full layout on the node given the specified constraints
#[inline(always)]
fn perform_child_layout(
- &mut self,
+ &self,
node_id: NodeId,
known_dimensions: Size<Option<f32>>,
parent_size: Size<Option<f32>>,
diff --git a/tests/fixtures.rs b/tests/fixtures.rs
index e1f1b8851..92721dc76 100644
--- a/tests/fixtures.rs
+++ b/tests/fixtures.rs
@@ -22,7 +22,7 @@ fn test_measure_function(
known_dimensions: taffy::geometry::Size<Option<f32>>,
available_space: taffy::geometry::Size<taffy::style::AvailableSpace>,
_node_id: taffy::tree::NodeId,
- node_context: Option<&mut TextMeasure>,
+ node_context: Option<&TextMeasure>,
) -> taffy::geometry::Size<f32> {
use taffy::geometry::AbsoluteAxis;
use taffy::prelude::*;