Add `taffy_tree` feature to opt-out of default Taffy tree (#448)
* Quick first draft
* Create separate non-cached node computation
* Revert "Create separate non-cached node computation"
This reverts commit c974efb3b3efd070cf24c754812e961340f05a4b.
* Move Taffy-specific stuff into taffy_tree module
* Export leaf::compute()
* fmt and clippy
* Remove useless use_rounding method
* Fix broken doc reference
* Sync Measurable is the only Measurable
* Move computation back into compute mod
* Rename feature to taffy_tree
* Optional slotmap
* didn't check feature-gated deps properly
* Make debug not rely on slotmap
* Formatting
fda1f88edd2bb6de8a7eb2611be94fc81485726d · by Martijn Arts · (3 years ago) · parent 6ce86a9e5 · browse the tree at this commit
Semantic delta · 170
src/compute/taffy_tree.rs
src/tree/taffy_tree/error.rs
src/tree/taffy_tree/mod.rs
src/tree/taffy_tree/tree.rs
src/tree/taffy_tree_error.rs
diff --git a/Cargo.toml b/Cargo.toml
index 82ef5b708..dc3086bbe 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -18,11 +18,11 @@ arrayvec = { version = "0.7", default-features = false }
num-traits = { version = "0.2", default-features = false }
rand = { version = "0.8.5", optional = true }
serde = { version = "1.0", optional = true, features = ["serde_derive"] }
-slotmap = "1.0.6"
+slotmap = { version = "1.0.6", optional = true }
grid = { version = "0.9.0", optional = true }
[features]
-default = ["std", "flexbox", "grid"]
+default = ["std", "flexbox", "grid", "taffy_tree"]
flexbox = []
grid = ["alloc", "dep:grid"]
alloc = []
@@ -32,6 +32,7 @@ random = ["dep:rand"]
yoga_benchmark = []
debug = []
profile = []
+taffy_tree = ["dep:slotmap"]
[dev-dependencies]
criterion = "0.4"
diff --git a/src/compute/leaf.rs b/src/compute/leaf.rs
index 3e701d5be..84e60b94d 100644
--- a/src/compute/leaf.rs
+++ b/src/compute/leaf.rs
@@ -1,9 +1,8 @@
//! Computes size using styles and measure functions
use crate::geometry::{Point, Size};
-use crate::style::AvailableSpace;
-use crate::tree::NodeId;
-use crate::tree::Taffy;
+use crate::style::{AvailableSpace, Style};
+use crate::tree::Measurable;
use crate::tree::{SizeAndBaselines, SizingMode};
use crate::util::sys::f32_max;
use crate::util::MaybeMath;
@@ -14,40 +13,37 @@ use crate::util::debug::NODE_LOGGER;
/// Perform full layout on a leaf node
pub(crate) fn perform_layout(
- tree: &mut Taffy,
- node: NodeId,
+ style: &Style,
+ measurable: Option<&impl Measurable>,
known_dimensions: Size<Option<f32>>,
parent_size: Size<Option<f32>>,
available_space: Size<AvailableSpace>,
sizing_mode: SizingMode,
) -> SizeAndBaselines {
- compute(tree, node, known_dimensions, parent_size, available_space, sizing_mode)
+ compute(style, measurable, known_dimensions, parent_size, available_space, sizing_mode)
}
/// Measure a leaf node's size
pub(crate) fn measure_size(
- tree: &mut Taffy,
- node: NodeId,
+ style: &Style,
+ measurable: Option<&impl Measurable>,
known_dimensions: Size<Option<f32>>,
parent_size: Size<Option<f32>>,
available_space: Size<AvailableSpace>,
sizing_mode: SizingMode,
) -> Size<f32> {
- compute(tree, node, known_dimensions, parent_size, available_space, sizing_mode).size
+ compute(style, measurable, known_dimensions, parent_size, available_space, sizing_mode).size
}
/// Compute the size of a leaf node (node with no children)
-pub(crate) fn compute(
- tree: &mut Taffy,
- node: NodeId,
+pub fn compute(
+ style: &Style,
+ measurable: Option<&impl Measurable>,
known_dimensions: Size<Option<f32>>,
parent_size: Size<Option<f32>>,
available_space: Size<AvailableSpace>,
sizing_mode: SizingMode,
) -> SizeAndBaselines {
- let key = node.into();
- let style = tree.style(node).unwrap();
-
// Resolve node's preferred/min/max sizes (width/heights) against the available space (percentages resolve to pixel values)
// For ContentSize mode, we pretend that the node has no size styles as these should be ignored.
let (node_size, node_min_size, node_max_size, aspect_ratio) = match sizing_mode {
@@ -91,7 +87,7 @@ pub(crate) fn compute(
return SizeAndBaselines { size, first_baselines: Point::NONE };
};
- if tree.nodes[key].needs_measure {
+ if let Some(measurable) = measurable {
// Compute available space
let available_space = Size {
width: available_space
@@ -107,7 +103,7 @@ pub(crate) fn compute(
};
// Measure node
- let measured_size = tree.measure_funcs[key].measure(known_dimensions, available_space);
+ let measured_size = measurable.measure(known_dimensions, available_space);
let measured_size = Size {
width: measured_size.width,
diff --git a/src/compute/mod.rs b/src/compute/mod.rs
index 20d7e496c..63f227846 100644
--- a/src/compute/mod.rs
+++ b/src/compute/mod.rs
@@ -3,6 +3,8 @@
pub(crate) mod common;
pub(crate) mod leaf;
+pub use leaf::compute;
+
#[cfg(feature = "flexbox")]
pub(crate) mod flexbox;
@@ -10,9 +12,8 @@ pub(crate) mod flexbox;
pub(crate) mod grid;
use crate::geometry::{Point, Size};
-use crate::style::{AvailableSpace, Display};
-use crate::tree::{Layout, LayoutTree, NodeId, RunMode, SizeAndBaselines, SizingMode, Taffy, TaffyError};
-use crate::util::sys::round;
+use crate::style::AvailableSpace;
+use crate::tree::{Layout, LayoutTree, NodeId, SizeAndBaselines, SizingMode};
#[cfg(feature = "flexbox")]
pub use self::flexbox::FlexboxAlgorithm;
@@ -20,36 +21,12 @@ pub use self::flexbox::FlexboxAlgorithm;
#[cfg(feature = "grid")]
pub use self::grid::CssGridAlgorithm;
+#[cfg(feature = "taffy_tree")]
+pub(crate) mod taffy_tree;
+
#[cfg(any(feature = "debug", feature = "profile"))]
use crate::util::debug::NODE_LOGGER;
-/// Updates the stored layout of the provided `node` and its children
-pub(crate) fn compute_layout(
- taffy: &mut Taffy,
- root: NodeId,
- available_space: Size<AvailableSpace>,
-) -> Result<(), TaffyError> {
- // Recursively compute node layout
- let size_and_baselines = perform_node_layout(
- taffy,
- root,
- Size::NONE,
- available_space.into_options(),
- available_space,
- SizingMode::InherentSize,
- );
-
- let layout = Layout { order: 0, size: size_and_baselines.size, location: Point::ZERO };
- *taffy.layout_mut(root) = layout;
-
- // If rounding is enabled, recursively round the layout's of this node and all children
- if taffy.config.use_rounding {
- round_layout(taffy, root, 0.0, 0.0);
- }
-
- Ok(())
-}
-
/// A common interface that all Taffy layout algorithms conform to
pub trait LayoutAlgorithm {
/// The name of the algorithm (mainly used for debug purposes)
@@ -76,142 +53,6 @@ pub trait LayoutAlgorithm {
) -> SizeAndBaselines;
}
-/// Perform full layout on a node. Chooses which algorithm to use based on the `display` property.
-pub(crate) fn perform_node_layout(
- tree: &mut Taffy,
- node: NodeId,
- known_dimensions: Size<Option<f32>>,
- parent_size: Size<Option<f32>>,
- available_space: Size<AvailableSpace>,
- sizing_mode: SizingMode,
-) -> SizeAndBaselines {
- compute_node_layout(tree, node, known_dimensions, parent_size, available_space, RunMode::PeformLayout, sizing_mode)
-}
-
-/// Measure a node's size. Chooses which algorithm to use based on the `display` property.
-pub(crate) fn measure_node_size(
- tree: &mut Taffy,
- node: NodeId,
- known_dimensions: Size<Option<f32>>,
- parent_size: Size<Option<f32>>,
- available_space: Size<AvailableSpace>,
- sizing_mode: SizingMode,
-) -> Size<f32> {
- compute_node_layout(tree, node, known_dimensions, parent_size, available_space, RunMode::ComputeSize, sizing_mode)
- .size
-}
-
-/// Updates the stored layout of the provided `node` and its children
-fn compute_node_layout(
- tree: &mut Taffy,
- node: NodeId,
- known_dimensions: Size<Option<f32>>,
- parent_size: Size<Option<f32>>,
- available_space: Size<AvailableSpace>,
- run_mode: RunMode,
- sizing_mode: SizingMode,
-) -> SizeAndBaselines {
- #[cfg(any(feature = "debug", feature = "profile"))]
- NODE_LOGGER.push_node(node);
- #[cfg(feature = "debug")]
- println!();
-
- let node_key = node.into();
- let has_children = !tree.children[node_key].is_empty();
-
- // First we check if we have a cached result for the given input
- let cache_run_mode = if !has_children { RunMode::PeformLayout } else { run_mode };
- if let Some(cached_size_and_baselines) =
- tree.nodes[node_key].cache.get(known_dimensions, available_space, cache_run_mode)
- {
- #[cfg(feature = "debug")]
- NODE_LOGGER.labelled_debug_log("CACHE", cached_size_and_baselines.size);
- #[cfg(feature = "debug")]
- debug_log_node(known_dimensions, parent_size, available_space, run_mode, sizing_mode);
- #[cfg(any(feature = "debug", feature = "profile"))]
- NODE_LOGGER.pop_node();
- return cached_size_and_baselines;
- }
-
- #[cfg(feature = "debug")]
- debug_log_node(known_dimensions, parent_size, available_space, run_mode, sizing_mode);
-
- /// Inlined function generic over the LayoutAlgorithm to reduce code duplication
- #[inline(always)]
- fn perform_computations<Algorithm: LayoutAlgorithm>(
- tree: &mut impl LayoutTree,
- node: NodeId,
- known_dimensions: Size<Option<f32>>,
- parent_size: Size<Option<f32>>,
- available_space: Size<AvailableSpace>,
- run_mode: RunMode,
- sizing_mode: SizingMode,
- ) -> SizeAndBaselines {
- #[cfg(feature = "debug")]
- NODE_LOGGER.log(Algorithm::NAME);
-
- match run_mode {
- RunMode::PeformLayout => {
- Algorithm::perform_layout(tree, node, known_dimensions, parent_size, available_space, sizing_mode)
- }
- RunMode::ComputeSize => {
- Algorithm::measure_size(tree, node, known_dimensions, parent_size, available_space, sizing_mode).into()
- }
- }
- }
-
- let display_mode = tree.nodes[node_key].style.display;
- let computed_size_and_baselines = match (display_mode, has_children) {
- (Display::None, _) => perform_computations::<HiddenAlgorithm>(
- tree,
- node,
- known_dimensions,
- parent_size,
- available_space,
- run_mode,
- sizing_mode,
- ),
- #[cfg(feature = "flexbox")]
- (Display::Flex, true) => perform_computations::<FlexboxAlgorithm>(
- tree,
- node,
- known_dimensions,
- parent_size,
- available_space,
- run_mode,
- sizing_mode,
- ),
- #[cfg(feature = "grid")]
- (Display::Grid, true) => perform_computations::<CssGridAlgorithm>(
- tree,
- node,
- known_dimensions,
- parent_size,
- available_space,
- run_mode,
- sizing_mode,
- ),
- (_, false) => match run_mode {
- RunMode::PeformLayout => {
- leaf::perform_layout(tree, node, known_dimensions, parent_size, available_space, sizing_mode)
- }
- RunMode::ComputeSize => {
- leaf::measure_size(tree, node, known_dimensions, parent_size, available_space, sizing_mode).into()
- }
- },
- };
-
- // Cache result
- tree.nodes[node_key].cache.store(known_dimensions, available_space, cache_run_mode, computed_size_and_baselines);
-
- #[cfg(feature = "debug")]
- NODE_LOGGER.labelled_debug_log("RESULT", computed_size_and_baselines.size);
- #[cfg(any(feature = "debug", feature = "profile"))]
- NODE_LOGGER.pop_node();
-
- computed_size_and_baselines
-}
-
#[cfg(feature = "debug")]
fn debug_log_node(
known_dimensions: Size<Option<f32>>,
@@ -228,7 +69,7 @@ fn debug_log_node(
}
/// The public interface to Taffy's hidden node algorithm implementation
-struct HiddenAlgorithm;
+pub struct HiddenAlgorithm;
impl LayoutAlgorithm for HiddenAlgorithm {
const NAME: &'static str = "NONE";
@@ -272,30 +113,6 @@ fn perform_hidden_layout(tree: &mut impl LayoutTree, node: NodeId) {
}
}
-/// Rounds the calculated [`Layout`] to exact pixel values
-/// In order to ensure that no gaps in the layout are introduced we:
-/// - Always round based on the absolute coordinates rather than parent-relative coordinates
-/// - Compute width/height by first rounding the top/bottom/left/right and then computing the difference
-/// rather than rounding the width/height directly
-///
-/// See <https://github.com/facebook/yoga/commit/aa5b296ac78f7a22e1aeaf4891243c6bb76488e2> for more context
-fn round_layout(tree: &mut impl LayoutTree, node: NodeId, abs_x: f32, abs_y: f32) {
- let layout = tree.layout_mut(node);
- let abs_x = abs_x + layout.location.x;
- let abs_y = abs_y + layout.location.y;
-
- layout.location.x = round(layout.location.x);
- layout.location.y = round(layout.location.y);
- layout.size.width = round(abs_x + layout.size.width) - round(abs_x);
- layout.size.height = round(abs_y + layout.size.height) - round(abs_y);
-
- let child_count = tree.child_count(node);
- for index in 0..child_count {
- let child = tree.child(node, index);
- round_layout(tree, child, abs_x, abs_y);
- }
-}
-
#[cfg(test)]
mod tests {
use super::perform_hidden_layout;
diff --git a/src/compute/taffy_tree.rs b/src/compute/taffy_tree.rs
new file mode 100644
index 000000000..d9cf43c73
--- /dev/null
+++ b/src/compute/taffy_tree.rs
@@ -0,0 +1,212 @@
+//! Computation specific for the default `Taffy` tree implementation
+
+use crate::{
+ compute::{
+ leaf::{measure_size, perform_layout},
+ HiddenAlgorithm,
+ },
+ geometry::Point,
+ prelude::{Layout, NodeId, Size},
+ style::{AvailableSpace, Display},
+ tree::{RunMode, SizeAndBaselines, SizingMode},
+ util::sys::round,
+ CssGridAlgorithm, FlexboxAlgorithm, LayoutAlgorithm, LayoutTree, Taffy, TaffyError,
+};
+
+/// Updates the stored layout of the provided `node` and its children
+pub(crate) fn compute_layout(
+ taffy: &mut Taffy,
+ root: NodeId,
+ available_space: Size<AvailableSpace>,
+) -> Result<(), TaffyError> {
+ // Recursively compute node layout
+ let size_and_baselines = perform_node_layout(
+ taffy,
+ root,
+ Size::NONE,
+ available_space.into_options(),
+ available_space,
+ SizingMode::InherentSize,
+ );
+
+ let layout = Layout { order: 0, size: size_and_baselines.size, location: Point::ZERO };
+ *taffy.layout_mut(root) = layout;
+
+ // If rounding is enabled, recursively round the layout's of this node and all children
+ if taffy.config.use_rounding {
+ round_layout(taffy, root, 0.0, 0.0);
+ }
+
+ Ok(())
+}
+
+/// Perform full layout on a node. Chooses which algorithm to use based on the `display` property.
+pub(crate) fn perform_node_layout(
+ tree: &mut Taffy,
+ node: NodeId,
+ known_dimensions: Size<Option<f32>>,
+ parent_size: Size<Option<f32>>,
+ available_space: Size<AvailableSpace>,
+ sizing_mode: SizingMode,
+) -> SizeAndBaselines {
+ compute_node_layout(tree, node, known_dimensions, parent_size, available_space, RunMode::PeformLayout, sizing_mode)
+}
+
+/// Measure a node's size. Chooses which algorithm to use based on the `display` property.
+pub(crate) fn measure_node_size(
+ tree: &mut Taffy,
+ node: NodeId,
+ known_dimensions: Size<Option<f32>>,
+ parent_size: Size<Option<f32>>,
+ available_space: Size<AvailableSpace>,
+ sizing_mode: SizingMode,
+) -> Size<f32> {
+ compute_node_layout(tree, node, known_dimensions, parent_size, available_space, RunMode::ComputeSize, sizing_mode)
+ .size
+}
+
+/// Updates the stored layout of the provided `node` and its children
+fn compute_node_layout(
+ tree: &mut Taffy,
+ node: NodeId,
+ known_dimensions: Size<Option<f32>>,
+ parent_size: Size<Option<f32>>,
+ available_space: Size<AvailableSpace>,
+ run_mode: RunMode,
+ sizing_mode: SizingMode,
+) -> SizeAndBaselines {
+ #[cfg(any(feature = "debug", feature = "profile"))]
+ NODE_LOGGER.push_node(node);
+ #[cfg(feature = "debug")]
+ println!();
+
+ let node_key = node.into();
+ let has_children = !tree.children[node_key].is_empty();
+
+ // First we check if we have a cached result for the given input
+ let cache_run_mode = if !has_children { RunMode::PeformLayout } else { run_mode };
+ if let Some(cached_size_and_baselines) =
+ tree.nodes[node_key].cache.get(known_dimensions, available_space, cache_run_mode)
+ {
+ #[cfg(feature = "debug")]
+ NODE_LOGGER.labelled_debug_log("CACHE", cached_size_and_baselines.size);
+ #[cfg(feature = "debug")]
+ debug_log_node(known_dimensions, parent_size, available_space, run_mode, sizing_mode);
+ #[cfg(any(feature = "debug", feature = "profile"))]
+ NODE_LOGGER.pop_node();
+ return cached_size_and_baselines;
+ }
+
+ #[cfg(feature = "debug")]
+ debug_log_node(known_dimensions, parent_size, available_space, run_mode, sizing_mode);
+
+ /// Inlined function generic over the LayoutAlgorithm to reduce code duplication
+ #[inline(always)]
+ fn perform_computations<Algorithm: LayoutAlgorithm>(
+ tree: &mut impl LayoutTree,
+ node: NodeId,
+ known_dimensions: Size<Option<f32>>,
+ parent_size: Size<Option<f32>>,
+ available_space: Size<AvailableSpace>,
+ run_mode: RunMode,
+ sizing_mode: SizingMode,
+ ) -> SizeAndBaselines {
+ #[cfg(feature = "debug")]
+ NODE_LOGGER.log(Algorithm::NAME);
+
+ match run_mode {
+ RunMode::PeformLayout => {
+ Algorithm::perform_layout(tree, node, known_dimensions, parent_size, available_space, sizing_mode)
+ }
+ RunMode::ComputeSize => {
+ Algorithm::measure_size(tree, node, known_dimensions, parent_size, available_space, sizing_mode).into()
+ }
+ }
+ }
+
+ let display_mode = tree.nodes[node_key].style.display;
+ let computed_size_and_baselines = match (display_mode, has_children) {
+ (Display::None, _) => perform_computations::<HiddenAlgorithm>(
+ tree,
+ node,
+ known_dimensions,
+ parent_size,
+ available_space,
+ run_mode,
+ sizing_mode,
+ ),
+ #[cfg(feature = "flexbox")]
+ (Display::Flex, true) => perform_computations::<FlexboxAlgorithm>(
+ tree,
+ node,
+ known_dimensions,
+ parent_size,
+ available_space,
+ run_mode,
+ sizing_mode,
+ ),
+ #[cfg(feature = "grid")]
+ (Display::Grid, true) => perform_computations::<CssGridAlgorithm>(
+ tree,
+ node,
+ known_dimensions,
+ parent_size,
+ available_space,
+ run_mode,
+ sizing_mode,
+ ),
+ (_, false) => match run_mode {
+ RunMode::PeformLayout => perform_layout(
+ &tree.nodes[node_key].style,
+ tree.nodes[node_key].needs_measure.then(|| &tree.measure_funcs[node_key]),
+ known_dimensions,
+ parent_size,
+ available_space,
+ sizing_mode,
+ ),
+ RunMode::ComputeSize => measure_size(
+ &tree.nodes[node_key].style,
+ tree.nodes[node_key].needs_measure.then(|| &tree.measure_funcs[node_key]),
+ known_dimensions,
+ parent_size,
+ available_space,
+ sizing_mode,
+ )
+ .into(),
+ },
+ };
+
+ // Cache result
+ tree.nodes[node_key].cache.store(known_dimensions, available_space, cache_run_mode, computed_size_and_baselines);
+
+ #[cfg(feature = "debug")]
+ NODE_LOGGER.labelled_debug_log("RESULT", computed_size_and_baselines.size);
+ #[cfg(any(feature = "debug", feature = "profile"))]
+ NODE_LOGGER.pop_node();
+
+ computed_size_and_baselines
+}
+
+/// Rounds the calculated [`Layout`] to exact pixel values
+/// In order to ensure that no gaps in the layout are introduced we:
+/// - Always round based on the absolute coordinates rather than parent-relative coordinates
+/// - Compute width/height by first rounding the top/bottom/left/right and then computing the difference
+/// rather than rounding the width/height directly
+///
+/// See <https://github.com/facebook/yoga/commit/aa5b296ac78f7a22e1aeaf4891243c6bb76488e2> for more context
+fn round_layout(tree: &mut impl LayoutTree, node: NodeId, abs_x: f32, abs_y: f32) {
+ let layout = tree.layout_mut(node);
+ let abs_x = abs_x + layout.location.x;
+ let abs_y = abs_y + layout.location.y;
+
+ layout.location.x = round(layout.location.x);
+ layout.location.y = round(layout.location.y);
+ layout.size.width = round(abs_x + layout.size.width) - round(abs_x);
+ layout.size.height = round(abs_y + layout.size.height) - round(abs_y);
+
+ let child_count = tree.child_count(node);
+ for index in 0..child_count {
+ let child = tree.child(node, index);
+ round_layout(tree, child, abs_x, abs_y);
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index e58bb32a2..b90036474 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -31,4 +31,6 @@ pub use crate::compute::flexbox::FlexboxAlgorithm;
#[cfg(feature = "grid")]
pub use crate::compute::grid::CssGridAlgorithm;
pub use crate::compute::LayoutAlgorithm;
-pub use crate::tree::{LayoutTree, Taffy, TaffyError, TaffyResult};
+pub use crate::tree::LayoutTree;
+#[cfg(feature = "taffy_tree")]
+pub use crate::tree::{Taffy, TaffyError, TaffyResult};
diff --git a/src/prelude.rs b/src/prelude.rs
index b7edd0db8..cad2615ae 100644
--- a/src/prelude.rs
+++ b/src/prelude.rs
@@ -10,7 +10,7 @@ pub use crate::{
auto, fit_content, max_content, min_content, percent, points, zero, FromFlex, FromPercent, FromPoints,
TaffyAuto, TaffyFitContent, TaffyMaxContent, TaffyMinContent, TaffyZero,
},
- tree::{Layout, LayoutTree, NodeId, Taffy},
+ tree::{Layout, LayoutTree, NodeId},
};
#[cfg(feature = "flexbox")]
@@ -25,3 +25,6 @@ pub use crate::style::{
pub use crate::style_helpers::{
evenly_sized_tracks, flex, fr, line, minmax, repeat, span, TaffyGridLine, TaffyGridSpan,
};
+
+#[cfg(feature = "taffy_tree")]
+pub use crate::Taffy;
diff --git a/src/tree/measure_func.rs b/src/tree/measure_func.rs
index df41e9db9..0b2d9ae82 100644
--- a/src/tree/measure_func.rs
+++ b/src/tree/measure_func.rs
@@ -8,8 +8,10 @@ use crate::util::sys::Box;
/// A function type that can be used in a [`MeasureFunc`]
///
/// This trait is automatically implemented for all types (including closures) that define a function with the appropriate type signature.
-pub trait Measurable: Send + Sync + Fn(Size<Option<f32>>, Size<AvailableSpace>) -> Size<f32> {}
-impl<F: Send + Sync + Fn(Size<Option<f32>>, Size<AvailableSpace>) -> Size<f32>> Measurable for F {}
+pub trait Measurable: Send + Sync {
+ /// Measure node
+ fn measure(&self, known_dimensions: Size<Option<f32>>, available_space: Size<AvailableSpace>) -> Size<f32>;
+}
/// A function that can be used to compute the intrinsic size of a node
pub enum MeasureFunc {
@@ -21,14 +23,25 @@ pub enum MeasureFunc {
Boxed(Box<dyn Measurable>),
}
-impl MeasureFunc {
+impl Measurable for MeasureFunc {
/// Call the measure function to measure to the node
#[inline(always)]
- pub fn measure(&self, known_dimensions: Size<Option<f32>>, available_space: Size<AvailableSpace>) -> Size<f32> {
+ fn measure(&self, known_dimensions: Size<Option<f32>>, available_space: Size<AvailableSpace>) -> Size<f32> {
match self {
- MeasureFunc::Raw(measure) => measure(known_dimensions, available_space),
+ Self::Raw(measure) => measure(known_dimensions, available_space),
#[cfg(any(feature = "std", feature = "alloc"))]
- MeasureFunc::Boxed(measure) => (measure as &dyn Fn(_, _) -> _)(known_dimensions, available_space),
+ Self::Boxed(measurable) => measurable.measure(known_dimensions, available_space),
}
}
}
+
+#[cfg(test)]
+mod test {
+ use super::MeasureFunc;
+
+ #[test]
+ fn measure_func_is_send_and_sync() {
+ fn is_send_and_sync<T: Send + Sync>() {}
+ is_send_and_sync::<MeasureFunc>();
+ }
+}
diff --git a/src/tree/mod.rs b/src/tree/mod.rs
index 6e8f96fff..f4a387575 100644
--- a/src/tree/mod.rs
+++ b/src/tree/mod.rs
@@ -9,12 +9,13 @@ pub use cache::{Cache, CacheEntry};
mod measure_func;
pub use measure_func::{Measurable, MeasureFunc};
mod node;
+#[cfg(feature = "taffy_tree")]
pub(self) use node::NodeData;
pub use node::NodeId;
+#[cfg(feature = "taffy_tree")]
mod taffy_tree;
-mod taffy_tree_error;
-pub use taffy_tree::{Taffy, TaffyChildIter};
-pub use taffy_tree_error::{TaffyError, TaffyResult};
+#[cfg(feature = "taffy_tree")]
+pub use taffy_tree::{Taffy, TaffyChildIter, TaffyError, TaffyResult};
mod layout;
/// Any item that implements the LayoutTree can be layed out using Taffy's algorithms.
@@ -39,6 +40,9 @@ pub trait LayoutTree {
/// Get the [`Style`] for this node.
fn style(&self, node: NodeId) -> &Style;
+ /// Get a reference to the node's output layout
+ fn layout(&self, node: NodeId) -> &Layout;
+
/// Modify the node's output layout
fn layout_mut(&mut self, node: NodeId) -> &mut Layout;
diff --git a/src/tree/node.rs b/src/tree/node.rs
index 55f48f918..db1bc84b5 100644
--- a/src/tree/node.rs
+++ b/src/tree/node.rs
@@ -4,6 +4,8 @@
use crate::style::Style;
use crate::tree::Cache;
use crate::tree::Layout;
+
+#[cfg(feature = "taffy_tree")]
use slotmap::{DefaultKey, Key, KeyData};
/// A type representing the id of a single node in a tree of nodes
@@ -43,12 +45,16 @@ impl From<NodeId> for usize {
id.0 as usize
}
}
+
+#[cfg(feature = "taffy_tree")]
impl From<DefaultKey> for NodeId {
#[inline]
fn from(key: DefaultKey) -> Self {
Self(key.data().as_ffi())
}
}
+
+#[cfg(feature = "taffy_tree")]
impl From<NodeId> for DefaultKey {
#[inline]
fn from(key: NodeId) -> Self {
diff --git a/src/tree/taffy_tree_error.rs b/src/tree/taffy_tree/error.rs
similarity index 100%
rename from src/tree/taffy_tree_error.rs
rename to src/tree/taffy_tree/error.rs
diff --git a/src/tree/taffy_tree/mod.rs b/src/tree/taffy_tree/mod.rs
new file mode 100644
index 000000000..64f7fce4e
--- /dev/null
+++ b/src/tree/taffy_tree/mod.rs
@@ -0,0 +1,7 @@
+//! Contains the default implementation of [LayoutTree](crate::tree::LayoutTree), [Taffy](crate::tree::Taffy), and the error type for Taffy.
+
+mod error;
+mod tree;
+
+pub use error::{TaffyError, TaffyResult};
+pub use tree::{Taffy, TaffyChildIter};
diff --git a/src/tree/taffy_tree.rs b/src/tree/taffy_tree/tree.rs
similarity index 98%
rename from src/tree/taffy_tree.rs
rename to src/tree/taffy_tree/tree.rs
index e68242e34..7004777f3 100644
--- a/src/tree/taffy_tree.rs
+++ b/src/tree/taffy_tree/tree.rs
@@ -3,13 +3,15 @@
//! Layouts are composed of multiple nodes, which live in a tree-like data structure.
use slotmap::{DefaultKey, SlotMap, SparseSecondaryMap};
-use super::{Layout, MeasureFunc, NodeData, NodeId, SizeAndBaselines, SizingMode, TaffyError, TaffyResult};
-use crate::compute::{measure_node_size, perform_node_layout};
+use crate::compute::taffy_tree::{compute_layout, measure_node_size, perform_node_layout};
use crate::geometry::Size;
use crate::prelude::LayoutTree;
use crate::style::{AvailableSpace, Style};
+use crate::tree::{Layout, MeasureFunc, NodeData, NodeId, SizeAndBaselines, SizingMode};
use crate::util::sys::{new_vec_with_capacity, ChildrenVec, Vec};
+use super::{TaffyError, TaffyResult};
+
/// Global configuration values for a Taffy instance
pub(crate) struct TaffyConfig {
/// Whether to round layout values
@@ -78,6 +80,11 @@ impl LayoutTree for Taffy {
&self.nodes[node.into()].style
}
+ #[inline(always)]
+ fn layout(&self, node: NodeId) -> &Layout {
+ &self.nodes[node.into()].layout
+ }
+
#[inline(always)]
fn layout_mut(&mut self, node: NodeId) -> &mut Layout {
&mut self.nodes[node.into()].layout
@@ -381,7 +388,7 @@ impl Taffy {
/// Updates the stored layout of the provided `node` and its children
pub fn compute_layout(&mut self, node: NodeId, available_space: Size<AvailableSpace>) -> Result<(), TaffyError> {
- crate::compute::compute_layout(self, node, available_space)
+ compute_layout(self, node, available_space)
}
}
@@ -720,10 +727,4 @@ mod tests {
);
assert!(layout_result.is_ok());
}
-
- #[test]
- fn measure_func_is_send_and_sync() {
- fn is_send_and_sync<T: Send + Sync>() {}
- is_send_and_sync::<MeasureFunc>();
- }
}
diff --git a/src/util/debug.rs b/src/util/debug.rs
index 4cc50dbdb..cbe230615 100644
--- a/src/util/debug.rs
+++ b/src/util/debug.rs
@@ -1,24 +1,20 @@
#![allow(dead_code)]
+use crate::tree::NodeId;
+use crate::{style, LayoutTree};
use core::fmt::{Debug, Display, Write};
-use slotmap::{DefaultKey, Key};
use std::sync::Mutex;
-use crate::style;
-use crate::tree::NodeId;
-use crate::tree::Taffy;
-
/// Prints a debug representation of the computed layout for a tree of nodes, starting with the passed root node.
-pub fn print_tree(tree: &Taffy, root: NodeId) {
+pub fn print_tree(tree: &impl LayoutTree, root: NodeId) {
println!("TREE");
print_node(tree, root, false, String::new());
}
-fn print_node(tree: &Taffy, node: NodeId, has_sibling: bool, lines_string: String) {
- let key = DefaultKey::from(node);
- let layout = &tree.nodes[key].layout;
- let style = &tree.nodes[key].style;
- let num_children = tree.children[key].len();
+fn print_node(tree: &impl LayoutTree, node: NodeId, has_sibling: bool, lines_string: String) {
+ let layout = &tree.layout(node);
+ let style = &tree.style(node);
+ let num_children = tree.child_count(node);
let display = match (num_children, style.display) {
(_, style::Display::None) => "NONE",
@@ -39,15 +35,15 @@ fn print_node(tree: &Taffy, node: NodeId, has_sibling: bool, lines_string: Strin
y = layout.location.y,
width = layout.size.width,
height = layout.size.height,
- key = key.data(),
+ key = node,
);
let bar = if has_sibling { "│ " } else { " " };
let new_string = lines_string + bar;
// Recurse into children
- for (index, child) in tree.children[key].iter().enumerate() {
+ for (index, child) in tree.children(node).enumerate() {
let has_sibling = index < num_children - 1;
- print_node(tree, *child, has_sibling, new_string.clone());
+ print_node(tree, child, has_sibling, new_string.clone());
}
}
@@ -62,10 +58,10 @@ impl DebugLogger {
Self { stack: Mutex::new(Vec::new()) }
}
- pub fn push_node(&self, new_key: impl Key) {
+ pub fn push_node(&self, new_key: NodeId) {
let mut stack = self.stack.lock().unwrap();
let mut key_string = String::new();
- write!(&mut key_string, "{:?}", new_key.data()).unwrap();
+ write!(&mut key_string, "{:?}", new_key).unwrap();
stack.push(key_string);
}