tawasuyu

tawasuyu/taffy

A high performance rust-powered UI layout library

HTML 5544Rust 88Markdown 11TOML 91926 Definitions

Feature flag calc values (#806)

Signed-off-by: Nico Burns <nico@nicoburns.com>

8437796cc084de78ee04e2d940086954c924cb98 · by Nico Burns · (1 year ago) · parent bd0150f5f · browse the tree at this commit

Semantic delta · 16

src/compute/grid/track_sizing.rs

src/style/compact_length.rs

src/style/dimension.rs

src/style/grid.rs

src/tree/traits.rs

src/util/resolve.rs

8 files · +73 −15

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 2d9c89742..46148c410 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -78,6 +78,15 @@ jobs:
   test-features-default-except-content-size:
     name: "Test Suite [default except content_size]"
     runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v4
+      - uses: dtolnay/rust-toolchain@stable
+      - run: cargo build --no-default-features --features std,taffy_tree,grid,flexbox,block_layout
+      - run: cargo test --tests --no-default-features --features std,taffy_tree,grid,flexbox,block_layout,calc
+
+  test-features-default-except-calc:
+    name: "Test Suite [default except calc]"
+    runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v4
       - uses: dtolnay/rust-toolchain@stable
@@ -92,7 +101,7 @@ jobs:
       - uses: dtolnay/rust-toolchain@stable
       - run: cargo build --no-default-features --features std
       - run: cargo build --no-default-features --features std,taffy_tree
-      - run: cargo test --tests --no-default-features --features std,taffy_tree
+      - run: cargo test --tests --no-default-features --features std,taffy_tree,calc
 
   # With std feature
   test-features-flexbox:
diff --git a/Cargo.toml b/Cargo.toml
index c7bba5fa5..1a09ec92a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -40,6 +40,7 @@ default = [
     "flexbox",
     "grid",
     "block_layout",
+    "calc",
     "content_size",
     "detailed_layout_info",
 ]
@@ -53,6 +54,8 @@ block_layout = []
 flexbox = []
 ## Enables the CSS Grid layout algorithm. See [`compute_grid_layout`](crate::compute_grid_layout).
 grid = ["alloc", "dep:grid"]
+## Enables calc() values for all layout algorithms
+calc = []
 ## Causes all algorithms to compute and output a content size for each node
 content_size = []
 ## Causes algorithms to stores detailed information of the nodes in TaffyTree, with only CSS Grid supporting this.
diff --git a/src/compute/grid/track_sizing.rs b/src/compute/grid/track_sizing.rs
index 0b353b19a..49a09e365 100644
--- a/src/compute/grid/track_sizing.rs
+++ b/src/compute/grid/track_sizing.rs
@@ -612,6 +612,7 @@ fn resolve_intrinsic_track_sizes<Tree: LayoutPartialTree>(
                         track.base_size
                     }
                     // Handle calc() like percentage
+                    #[cfg(feature = "calc")]
                     _ if track.min_track_sizing_function.0.is_calc() => {
                         if axis_inner_node_size.is_none() {
                             f32_max(track.base_size, item_sizer.min_content_contribution(item))
diff --git a/src/style/compact_length.rs b/src/style/compact_length.rs
index 89280f621..0a4b7f799 100644
--- a/src/style/compact_length.rs
+++ b/src/style/compact_length.rs
@@ -41,12 +41,6 @@ mod compat {
 #[cfg(not(any(target_pointer_width = "32", target_pointer_width = "64")))]
 std::compile_error!("Taffy only supports targets with a pointer width of 32 or 64 bits");
 
-// /// Error serializing
-// enum SerializeErr {
-//     /// Serializing calc values is not supported
-//     CalcValue,
-// }
-
 /// CompactLengthInner implementation for 64 bit platforms
 #[cfg(target_pointer_width = "64")]
 mod inner {
@@ -92,6 +86,7 @@ mod inner {
 
         /// Get the calc tag (low 3 bits)
         #[inline(always)]
+        #[cfg(feature = "calc")]
         pub(super) fn calc_tag(self) -> usize {
             (self.tagged_ptr as usize) & CALC_TAG_MASK
         }
@@ -167,6 +162,7 @@ mod inner {
 
         /// Get the calc tag (low 3 bits)
         #[inline(always)]
+        #[cfg(feature = "calc")]
         pub(super) fn calc_tag(self) -> usize {
             self.tag
         }
@@ -214,6 +210,7 @@ pub struct CompactLength(CompactLengthInner);
 
 impl CompactLength {
     /// The tag indicating a calc() value
+    #[cfg(feature = "calc")]
     pub const CALC_TAG: usize = 0b000;
     /// The tag indicating a length value
     pub const LENGTH_TAG: usize = 0b0000_0001;
@@ -254,6 +251,7 @@ impl CompactLength {
     ///
     /// The low 3 bits are used as a tag value and will be returned as 0.
     #[inline]
+    #[cfg(feature = "calc")]
     pub fn calc(ptr: *const ()) -> Self {
         assert_ne!(ptr as u64, 0);
         assert_eq!(ptr as u64 & 0b111, 0);
@@ -332,12 +330,14 @@ impl CompactLength {
 
     /// Get the calc pointer of the `CompactLength`
     #[inline(always)]
+    #[cfg(feature = "calc")]
     pub fn calc_value(self) -> *const () {
         self.0.ptr()
     }
 
     /// Returns true if the value is 0 px
     #[inline(always)]
+    #[cfg(feature = "calc")]
     pub fn is_calc(self) -> bool {
         self.0.calc_tag() == 0
     }
@@ -426,8 +426,14 @@ impl CompactLength {
     /// Whether the track sizing functions depends on the size of the parent node
     #[inline(always)]
     pub fn uses_percentage(self) -> bool {
-        // TODO: handle calc() values
-        matches!(self.tag(), CompactLength::PERCENT_TAG | CompactLength::FIT_CONTENT_PERCENT_TAG) || self.is_calc()
+        #[cfg(feature = "calc")]
+        {
+            matches!(self.tag(), CompactLength::PERCENT_TAG | CompactLength::FIT_CONTENT_PERCENT_TAG) || self.is_calc()
+        }
+        #[cfg(not(feature = "calc"))]
+        {
+            matches!(self.tag(), CompactLength::PERCENT_TAG | CompactLength::FIT_CONTENT_PERCENT_TAG)
+        }
     }
 
     /// Resolve percentage values against the passed parent_size, returning Some(value)
@@ -440,6 +446,7 @@ impl CompactLength {
     ) -> Option<f32> {
         match self.tag() {
             CompactLength::PERCENT_TAG => Some(self.value() * parent_size),
+            #[cfg(feature = "calc")]
             _ if self.is_calc() => Some(calc_resolver(self.0.ptr(), parent_size)),
             _ => None,
         }
@@ -490,11 +497,17 @@ impl serde::Serialize for CompactLength {
     where
         S: serde::Serializer,
     {
-        if self.tag() == Self::CALC_TAG {
-            Err(serde::ser::Error::custom("Cannot serialize Calc value"))
-        } else {
-            serializer.serialize_u64(self.0.serialized())
+        #[cfg(feature = "calc")]
+        {
+            if self.tag() == Self::CALC_TAG {
+                Err(serde::ser::Error::custom("Cannot serialize Calc value"))
+            } else {
+                serializer.serialize_u64(self.0.serialized())
+            }
         }
+
+        #[cfg(not(feature = "calc"))]
+        serializer.serialize_u64(self.0.serialized())
     }
 }
 
diff --git a/src/style/dimension.rs b/src/style/dimension.rs
index 2391d5ba3..ad270e48c 100644
--- a/src/style/dimension.rs
+++ b/src/style/dimension.rs
@@ -43,6 +43,7 @@ impl LengthPercentage {
     ///
     /// The low 3 bits are used as a tag value and will be returned as 0.
     #[inline(always)]
+    #[cfg(feature = "calc")]
     pub fn calc(ptr: *const ()) -> Self {
         Self(CompactLength::calc(ptr))
     }
@@ -133,6 +134,7 @@ impl LengthPercentageAuto {
     ///
     /// The low 3 bits are used as a tag value and will be returned as 0.
     #[inline]
+    #[cfg(feature = "calc")]
     pub fn calc(ptr: *const ()) -> Self {
         Self(CompactLength::calc(ptr))
     }
@@ -160,6 +162,7 @@ impl LengthPercentageAuto {
             CompactLength::LENGTH_TAG => Some(self.0.value()),
             CompactLength::PERCENT_TAG => Some(context * self.0.value()),
             CompactLength::AUTO_TAG => None,
+            #[cfg(feature = "calc")]
             _ if self.0.is_calc() => Some(calc_resolver(self.0.calc_value(), context)),
             _ => unreachable!("LengthPercentageAuto values cannot be constructed with other tags"),
         }
@@ -249,6 +252,7 @@ impl Dimension {
     ///
     /// The low 3 bits are used as a tag value and will be returned as 0.
     #[inline]
+    #[cfg(feature = "calc")]
     pub fn calc(ptr: *const ()) -> Self {
         Self(CompactLength::calc(ptr))
     }
diff --git a/src/style/grid.rs b/src/style/grid.rs
index 9f800a25b..41f5bd09b 100644
--- a/src/style/grid.rs
+++ b/src/style/grid.rs
@@ -524,6 +524,7 @@ impl MaxTrackSizingFunction {
     ///
     /// The low 3 bits are used as a tag value and will be returned as 0.
     #[inline]
+    #[cfg(feature = "calc")]
     pub fn calc(ptr: *const ()) -> Self {
         Self(CompactLength::calc(ptr))
     }
@@ -597,6 +598,7 @@ impl MaxTrackSizingFunction {
         match self.0.tag() {
             CompactLength::LENGTH_TAG => true,
             CompactLength::PERCENT_TAG => parent_size.is_some(),
+            #[cfg(feature = "calc")]
             _ if self.0.is_calc() => parent_size.is_some(),
             _ => false,
         }
@@ -614,6 +616,7 @@ impl MaxTrackSizingFunction {
         match self.0.tag() {
             CompactLength::LENGTH_TAG => Some(self.0.value()),
             CompactLength::PERCENT_TAG => parent_size.map(|size| self.0.value() * size),
+            #[cfg(feature = "calc")]
             _ if self.0.is_calc() => parent_size.map(|size| calc_resolver(self.0.calc_value(), size)),
             _ => None,
         }
@@ -768,6 +771,7 @@ impl MinTrackSizingFunction {
     ///
     /// The low 3 bits are used as a tag value and will be returned as 0.
     #[inline]
+    #[cfg(feature = "calc")]
     pub fn calc(ptr: *const ()) -> Self {
         Self(CompactLength::calc(ptr))
     }
@@ -833,6 +837,7 @@ impl MinTrackSizingFunction {
         match self.0.tag() {
             CompactLength::LENGTH_TAG => Some(self.0.value()),
             CompactLength::PERCENT_TAG => parent_size.map(|size| self.0.value() * size),
+            #[cfg(feature = "calc")]
             _ if self.0.is_calc() => parent_size.map(|size| calc_resolver(self.0.calc_value(), size)),
             _ => None,
         }
@@ -852,7 +857,14 @@ impl MinTrackSizingFunction {
     /// Whether the track sizing functions depends on the size of the parent node
     #[inline(always)]
     pub fn uses_percentage(self) -> bool {
-        matches!(self.0.tag(), CompactLength::PERCENT_TAG) || self.0.is_calc()
+        #[cfg(feature = "calc")]
+        {
+            matches!(self.0.tag(), CompactLength::PERCENT_TAG) || self.0.is_calc()
+        }
+        #[cfg(not(feature = "calc"))]
+        {
+            matches!(self.0.tag(), CompactLength::PERCENT_TAG)
+        }
     }
 }
 
diff --git a/src/tree/traits.rs b/src/tree/traits.rs
index 191de42cb..a5b208b42 100644
--- a/src/tree/traits.rs
+++ b/src/tree/traits.rs
@@ -181,7 +181,12 @@ pub trait LayoutPartialTree: TraversePartialTree {
     fn get_core_container_style(&self, node_id: NodeId) -> Self::CoreContainerStyle<'_>;
 
     /// Resolve calc value
-    fn resolve_calc_value(&self, val: *const (), basis: f32) -> f32;
+    #[inline(always)]
+    fn resolve_calc_value(&self, val: *const (), basis: f32) -> f32 {
+        let _ = val;
+        let _ = basis;
+        0.0
+    }
 
     /// Set the node's unrounded layout
     fn set_unrounded_layout(&mut self, node_id: NodeId, layout: &Layout);
@@ -366,9 +371,17 @@ pub(crate) trait LayoutPartialTreeExt: LayoutPartialTree {
 
     /// Alias to `resolve_calc_value` with a shorter function name
     #[inline(always)]
+    #[cfg(feature = "calc")]
     fn calc(&self, val: *const (), basis: f32) -> f32 {
         self.resolve_calc_value(val, basis)
     }
+
+    /// Alias to `resolve_calc_value` with a shorter function name
+    #[inline(always)]
+    #[cfg(not(feature = "calc"))]
+    fn calc(&self, _val: *const (), _basis: f32) -> f32 {
+        0.0
+    }
 }
 
 impl<T: LayoutPartialTree> LayoutPartialTreeExt for T {}
diff --git a/src/util/resolve.rs b/src/util/resolve.rs
index a0e47b0ee..c40fec300 100644
--- a/src/util/resolve.rs
+++ b/src/util/resolve.rs
@@ -32,6 +32,7 @@ impl MaybeResolve<Option<f32>, Option<f32>> for LengthPercentage {
         match self.0.tag() {
             CompactLength::LENGTH_TAG => Some(self.0.value()),
             CompactLength::PERCENT_TAG => context.map(|dim| dim * self.0.value()),
+            #[cfg(feature = "calc")]
             _ if self.0.is_calc() => context.map(|dim| calc(self.0.calc_value(), dim)),
             _ => unreachable!(),
         }
@@ -46,6 +47,7 @@ impl MaybeResolve<Option<f32>, Option<f32>> for LengthPercentageAuto {
             CompactLength::AUTO_TAG => None,
             CompactLength::LENGTH_TAG => Some(self.0.value()),
             CompactLength::PERCENT_TAG => context.map(|dim| dim * self.0.value()),
+            #[cfg(feature = "calc")]
             _ if self.0.is_calc() => context.map(|dim| calc(self.0.calc_value(), dim)),
             _ => unreachable!(),
         }
@@ -61,6 +63,7 @@ impl MaybeResolve<Option<f32>, Option<f32>> for Dimension {
             CompactLength::AUTO_TAG => None,
             CompactLength::LENGTH_TAG => Some(self.0.value()),
             CompactLength::PERCENT_TAG => context.map(|dim| dim * self.0.value()),
+            #[cfg(feature = "calc")]
             _ if self.0.is_calc() => context.map(|dim| calc(self.0.calc_value(), dim)),
             _ => unreachable!(),
         }