gioser

tawasuyu/taffy

A high performance rust-powered UI layout library

Rust 501HTML 254C 19JavaScript 81414 Definiciones

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 · por Martijn Arts · (hace 3 años) · padre 6ce86a9e5 · ver el árbol en este commit

Delta semántico · 170

src/compute/leaf.rs

src/compute/mod.rs

src/compute/taffy_tree.rs

src/tree/measure_func.rs

src/tree/mod.rs

src/tree/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

src/util/debug.rs

15 archivos · +1071 −1013

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);
     }