From bb77d1e1967efc8a70009d4c2f09f3a300b1a894 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Fri, 1 Aug 2025 23:49:27 +0100 Subject: [PATCH 1/3] Units trait WIP Signed-off-by: Nico Burns --- src/compute/grid/placement.rs | 6 +- src/style/block.rs | 2 +- src/style/flex.rs | 24 ++++---- src/style/grid.rs | 32 +++++----- src/style/mod.rs | 112 +++++++++++++++++++++------------- 5 files changed, 101 insertions(+), 75 deletions(-) diff --git a/src/compute/grid/placement.rs b/src/compute/grid/placement.rs index dbc4037a1..34de5ad5f 100644 --- a/src/compute/grid/placement.rs +++ b/src/compute/grid/placement.rs @@ -4,10 +4,10 @@ use super::types::{CellOccupancyMatrix, CellOccupancyState, GridItem}; use super::{NamedLineResolver, OriginZeroLine}; use crate::geometry::Line; use crate::geometry::{AbsoluteAxis, InBothAbsAxis}; -use crate::style::{AlignItems, GridAutoFlow, OriginZeroGridPlacement}; +use crate::style::{AlignItems, GridAutoFlow, OriginZeroGridPlacement, Units}; use crate::tree::NodeId; use crate::util::sys::Vec; -use crate::{CoreStyle, GridItemStyle}; +use crate::GridItemStyle; /// 8.5. Grid Item Placement Algorithm /// Place items into the grid, generating new rows/column into the implicit grid as required @@ -20,7 +20,7 @@ pub(super) fn place_grid_items<'a, S, ChildIter>( grid_auto_flow: GridAutoFlow, align_items: AlignItems, justify_items: AlignItems, - named_line_resolver: &NamedLineResolver<::CustomIdent>, + named_line_resolver: &NamedLineResolver<::Str>, ) where S: GridItemStyle + 'a, ChildIter: Iterator, diff --git a/src/style/block.rs b/src/style/block.rs index 187698e54..b9242cb74 100644 --- a/src/style/block.rs +++ b/src/style/block.rs @@ -6,7 +6,7 @@ pub trait BlockContainerStyle: CoreStyle { /// Defines which row in the grid the item should start and end at #[inline(always)] fn text_align(&self) -> TextAlign { - Style::::DEFAULT.text_align + Style::::DEFAULT.text_align } } diff --git a/src/style/flex.rs b/src/style/flex.rs index 1bbcb8f14..804b92641 100644 --- a/src/style/flex.rs +++ b/src/style/flex.rs @@ -1,5 +1,7 @@ //! Style types for Flexbox layout -use super::{AlignContent, AlignItems, AlignSelf, CoreStyle, Dimension, JustifyContent, LengthPercentage, Style}; +use super::{ + AlignContent, AlignItems, AlignSelf, CoreStyle, Dimension, JustifyContent, LengthPercentage, Style, Units, +}; use crate::geometry::Size; /// The set of styles required for a Flexbox container @@ -7,18 +9,18 @@ pub trait FlexboxContainerStyle: CoreStyle { /// Which direction does the main axis flow in? #[inline(always)] fn flex_direction(&self) -> FlexDirection { - Style::::DEFAULT.flex_direction + Style::::DEFAULT.flex_direction } /// Should elements wrap, or stay in a single line? #[inline(always)] fn flex_wrap(&self) -> FlexWrap { - Style::::DEFAULT.flex_wrap + Style::::DEFAULT.flex_wrap } /// How large should the gaps between items in a grid or flex container be? #[inline(always)] fn gap(&self) -> Size { - Style::::DEFAULT.gap + Style::::DEFAULT.gap } // Alignment properties @@ -26,17 +28,17 @@ pub trait FlexboxContainerStyle: CoreStyle { /// How should content contained within this item be aligned in the cross/block axis #[inline(always)] fn align_content(&self) -> Option { - Style::::DEFAULT.align_content + Style::::DEFAULT.align_content } /// How this node's children aligned in the cross/block axis? #[inline(always)] fn align_items(&self) -> Option { - Style::::DEFAULT.align_items + Style::::DEFAULT.align_items } /// How this node's children should be aligned in the inline axis #[inline(always)] fn justify_content(&self) -> Option { - Style::::DEFAULT.justify_content + Style::::DEFAULT.justify_content } } @@ -45,24 +47,24 @@ pub trait FlexboxItemStyle: CoreStyle { /// Sets the initial main axis size of the item #[inline(always)] fn flex_basis(&self) -> Dimension { - Style::::DEFAULT.flex_basis + Style::::DEFAULT.flex_basis } /// The relative rate at which this item grows when it is expanding to fill space #[inline(always)] fn flex_grow(&self) -> f32 { - Style::::DEFAULT.flex_grow + Style::::DEFAULT.flex_grow } /// The relative rate at which this item shrinks when it is contracting to fit into space #[inline(always)] fn flex_shrink(&self) -> f32 { - Style::::DEFAULT.flex_shrink + Style::::DEFAULT.flex_shrink } /// How this node should be aligned in the cross/block axis /// Falls back to the parents [`AlignItems`] if not set #[inline(always)] fn align_self(&self) -> Option { - Style::::DEFAULT.align_self + Style::::DEFAULT.align_self } } diff --git a/src/style/grid.rs b/src/style/grid.rs index 9f949d61d..4e724cb87 100644 --- a/src/style/grid.rs +++ b/src/style/grid.rs @@ -1,7 +1,7 @@ //! Style types for CSS Grid layout use super::{ AlignContent, AlignItems, AlignSelf, CheapCloneStr, CompactLength, CoreStyle, Dimension, JustifyContent, - LengthPercentage, LengthPercentageAuto, Style, + LengthPercentage, LengthPercentageAuto, Style, Units, }; use crate::compute::grid::{GridCoordinate, GridLine, OriginZeroLine}; use crate::geometry::{AbsoluteAxis, AbstractAxis, Line, MinMax, Size}; @@ -130,12 +130,12 @@ where /// The set of styles required for a CSS Grid container pub trait GridContainerStyle: CoreStyle { /// The type for a `repeat()` within a grid_template_rows or grid_template_columns - type Repetition<'a>: GenericRepetition + type Repetition<'a>: GenericRepetition::Str> where Self: 'a; /// The type returned by grid_template_rows and grid_template_columns - type TemplateTrackList<'a>: Iterator>> + type TemplateTrackList<'a>: Iterator::Str, Self::Repetition<'a>>> + ExactSizeIterator + Clone where @@ -148,12 +148,12 @@ pub trait GridContainerStyle: CoreStyle { /// The type returned by grid_template_row_names and grid_template_column_names //IntoIterator> - type TemplateLineNames<'a>: TemplateLineNames<'a, Self::CustomIdent> + type TemplateLineNames<'a>: TemplateLineNames<'a, ::Str> where Self: 'a; /// The type of custom identifiers used to identify named grid lines and areas - type GridTemplateAreas<'a>: IntoIterator> + type GridTemplateAreas<'a>: IntoIterator::Str>> where Self: 'a; @@ -179,13 +179,13 @@ pub trait GridContainerStyle: CoreStyle { /// Controls how items get placed into the grid for auto-placed items #[inline(always)] fn grid_auto_flow(&self) -> GridAutoFlow { - Style::::DEFAULT.grid_auto_flow + Style::::DEFAULT.grid_auto_flow } /// How large should the gaps between items in a grid or flex container be? #[inline(always)] fn gap(&self) -> Size { - Style::::DEFAULT.gap + Style::::DEFAULT.gap } // Alignment properties @@ -193,22 +193,22 @@ pub trait GridContainerStyle: CoreStyle { /// How should content contained within this item be aligned in the cross/block axis #[inline(always)] fn align_content(&self) -> Option { - Style::::DEFAULT.align_content + Style::::DEFAULT.align_content } /// How should contained within this item be aligned in the main/inline axis #[inline(always)] fn justify_content(&self) -> Option { - Style::::DEFAULT.justify_content + Style::::DEFAULT.justify_content } /// How this node's children aligned in the cross/block axis? #[inline(always)] fn align_items(&self) -> Option { - Style::::DEFAULT.align_items + Style::::DEFAULT.align_items } /// How this node's children should be aligned in the inline axis #[inline(always)] fn justify_items(&self) -> Option { - Style::::DEFAULT.justify_items + Style::::DEFAULT.justify_items } /// Get a grid item's row or column placement depending on the axis passed @@ -234,12 +234,12 @@ pub trait GridContainerStyle: CoreStyle { pub trait GridItemStyle: CoreStyle { /// Defines which row in the grid the item should start and end at #[inline(always)] - fn grid_row(&self) -> Line> { + fn grid_row(&self) -> Line::Str>> { Default::default() } /// Defines which column in the grid the item should start and end at #[inline(always)] - fn grid_column(&self) -> Line> { + fn grid_column(&self) -> Line::Str>> { Default::default() } @@ -247,18 +247,18 @@ pub trait GridItemStyle: CoreStyle { /// Falls back to the parents [`AlignItems`] if not set #[inline(always)] fn align_self(&self) -> Option { - Style::::DEFAULT.align_self + Style::::DEFAULT.align_self } /// How this node should be aligned in the inline axis /// Falls back to the parents [`super::JustifyItems`] if not set #[inline(always)] fn justify_self(&self) -> Option { - Style::::DEFAULT.justify_self + Style::::DEFAULT.justify_self } /// Get a grid item's row or column placement depending on the axis passed #[inline(always)] - fn grid_placement(&self, axis: AbsoluteAxis) -> Line> { + fn grid_placement(&self, axis: AbsoluteAxis) -> Line::Str>> { match axis { AbsoluteAxis::Horizontal => self.grid_column(), AbsoluteAxis::Vertical => self.grid_row(), diff --git a/src/style/mod.rs b/src/style/mod.rs index e44d06b74..69a304a91 100644 --- a/src/style/mod.rs +++ b/src/style/mod.rs @@ -60,6 +60,25 @@ impl CheapCloneStr for T where { } +/// Allows Taffy to abstract of the types it uses to represent strings and calc expressions. +/// In future it may be extended to abstract the scalar number type (currently f32) +pub trait Units { + /// Trait that represents a cheaply clonable string. If you're unsure what to use here + /// consider `Arc` or `string_cache::Atom`. + type Str: CheapCloneStr; + + /// Type representing a calc expression. + /// If you're not using Calc then you can just use `()` + type Calc: 'static; +} + +pub struct DefaultUnits; + +impl Units for DefaultUnits { + type Str = String; + type Calc = (); +} + /// Trait that represents a cheaply clonable string. If you're unsure what to use here /// consider `Arc` or `string_cache::Atom`. #[cfg(not(any(feature = "alloc", feature = "std")))] @@ -74,7 +93,7 @@ impl CheapCloneStr for T {} /// to override the default implementation for each style property that your style type actually supports. pub trait CoreStyle { /// The type of custom identifiers used to identify named grid lines and areas - type CustomIdent: CheapCloneStr; + type Units: Units; /// Which box generation mode should be used #[inline(always)] @@ -102,7 +121,7 @@ pub trait CoreStyle { /// How children overflowing their container should affect layout #[inline(always)] fn overflow(&self) -> Point { - Style::::DEFAULT.overflow + Style::::DEFAULT.overflow } /// How much space (in points) should be reserved for the scrollbars of `Overflow::Scroll` and `Overflow::Auto` nodes. #[inline(always)] @@ -114,52 +133,52 @@ pub trait CoreStyle { /// What should the `position` value of this struct use as a base offset? #[inline(always)] fn position(&self) -> Position { - Style::::DEFAULT.position + Style::::DEFAULT.position } /// How should the position of this element be tweaked relative to the layout defined? #[inline(always)] fn inset(&self) -> Rect { - Style::::DEFAULT.inset + Style::::DEFAULT.inset } // Size properies /// Sets the initial size of the item #[inline(always)] fn size(&self) -> Size { - Style::::DEFAULT.size + Style::::DEFAULT.size } /// Controls the minimum size of the item #[inline(always)] fn min_size(&self) -> Size { - Style::::DEFAULT.min_size + Style::::DEFAULT.min_size } /// Controls the maximum size of the item #[inline(always)] fn max_size(&self) -> Size { - Style::::DEFAULT.max_size + Style::::DEFAULT.max_size } /// Sets the preferred aspect ratio for the item /// The ratio is calculated as width divided by height. #[inline(always)] fn aspect_ratio(&self) -> Option { - Style::::DEFAULT.aspect_ratio + Style::::DEFAULT.aspect_ratio } // Spacing Properties /// How large should the margin be on each side? #[inline(always)] fn margin(&self) -> Rect { - Style::::DEFAULT.margin + Style::::DEFAULT.margin } /// How large should the padding be on each side? #[inline(always)] fn padding(&self) -> Rect { - Style::::DEFAULT.padding + Style::::DEFAULT.padding } /// How large should the border be on each side? #[inline(always)] fn border(&self) -> Rect { - Style::::DEFAULT.border + Style::::DEFAULT.border } } @@ -370,10 +389,10 @@ impl Overflow { #[derive(Clone, PartialEq, Debug)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(default))] -pub struct Style { +pub struct Style { /// This is a dummy field which is necessary to make Taffy compile with the `grid` feature disabled /// It should always be set to `core::marker::PhantomData`. - pub dummy: core::marker::PhantomData, + pub dummy: core::marker::PhantomData, /// What layout strategy should be used? pub display: Display, /// Whether a child is display:table or not. This affects children of block layouts. @@ -481,10 +500,10 @@ pub struct Style { // Grid container properies /// Defines the track sizing functions (heights) of the grid rows #[cfg(feature = "grid")] - pub grid_template_rows: GridTrackVec>, + pub grid_template_rows: GridTrackVec>, /// Defines the track sizing functions (widths) of the grid columns #[cfg(feature = "grid")] - pub grid_template_columns: GridTrackVec>, + pub grid_template_columns: GridTrackVec>, /// Defines the size of implicitly created rows #[cfg(feature = "grid")] pub grid_auto_rows: GridTrackVec, @@ -498,26 +517,26 @@ pub struct Style { // Grid container named properties /// Defines the rectangular grid areas #[cfg(feature = "grid")] - pub grid_template_areas: GridTrackVec>, + pub grid_template_areas: GridTrackVec>, /// The named lines between the columns #[cfg(feature = "grid")] - pub grid_template_column_names: GridTrackVec>, + pub grid_template_column_names: GridTrackVec>, /// The named lines between the rows #[cfg(feature = "grid")] - pub grid_template_row_names: GridTrackVec>, + pub grid_template_row_names: GridTrackVec>, // Grid child properties /// Defines which row in the grid the item should start and end at #[cfg(feature = "grid")] - pub grid_row: Line>, + pub grid_row: Line>, /// Defines which column in the grid the item should start and end at #[cfg(feature = "grid")] - pub grid_column: Line>, + pub grid_column: Line>, } -impl Style { +impl Style { /// The [`Default`] layout, in a form that can be used in const functions - pub const DEFAULT: Style = Style { + pub const DEFAULT: Style = Style { dummy: core::marker::PhantomData, display: Display::DEFAULT, item_is_table: false, @@ -581,20 +600,20 @@ impl Style { #[cfg(feature = "grid")] grid_auto_flow: GridAutoFlow::Row, #[cfg(feature = "grid")] - grid_row: Line { start: GridPlacement::::Auto, end: GridPlacement::::Auto }, + grid_row: Line { start: GridPlacement::::Auto, end: GridPlacement::::Auto }, #[cfg(feature = "grid")] - grid_column: Line { start: GridPlacement::::Auto, end: GridPlacement::::Auto }, + grid_column: Line { start: GridPlacement::::Auto, end: GridPlacement::::Auto }, }; } -impl Default for Style { +impl Default for Style { fn default() -> Self { Style::DEFAULT } } -impl CoreStyle for Style { - type CustomIdent = S; +impl CoreStyle for Style { + type Units = U; #[inline(always)] fn box_generation_mode(&self) -> BoxGenerationMode { @@ -663,7 +682,7 @@ impl CoreStyle for Style { } impl CoreStyle for &'_ T { - type CustomIdent = T::CustomIdent; + type Units = T::Units; #[inline(always)] fn box_generation_mode(&self) -> BoxGenerationMode { @@ -728,7 +747,7 @@ impl CoreStyle for &'_ T { } #[cfg(feature = "block_layout")] -impl BlockContainerStyle for Style { +impl BlockContainerStyle for Style { #[inline(always)] fn text_align(&self) -> TextAlign { self.text_align @@ -744,7 +763,7 @@ impl BlockContainerStyle for &'_ T { } #[cfg(feature = "block_layout")] -impl BlockItemStyle for Style { +impl BlockItemStyle for Style { #[inline(always)] fn is_table(&self) -> bool { self.item_is_table @@ -760,7 +779,7 @@ impl BlockItemStyle for &'_ T { } #[cfg(feature = "flexbox")] -impl FlexboxContainerStyle for Style { +impl FlexboxContainerStyle for Style { #[inline(always)] fn flex_direction(&self) -> FlexDirection { self.flex_direction @@ -816,7 +835,7 @@ impl FlexboxContainerStyle for &'_ T { } #[cfg(feature = "flexbox")] -impl FlexboxItemStyle for Style { +impl FlexboxItemStyle for Style { #[inline(always)] fn flex_basis(&self) -> Dimension { self.flex_basis @@ -856,16 +875,18 @@ impl FlexboxItemStyle for &'_ T { } #[cfg(feature = "grid")] -impl GridContainerStyle for Style { +impl GridContainerStyle for Style { type Repetition<'a> - = &'a GridTemplateRepetition + = &'a GridTemplateRepetition where Self: 'a; type TemplateTrackList<'a> = core::iter::Map< - core::slice::Iter<'a, GridTemplateComponent>, - fn(&'a GridTemplateComponent) -> GenericGridTemplateComponent>, + core::slice::Iter<'a, GridTemplateComponent>, + fn( + &'a GridTemplateComponent, + ) -> GenericGridTemplateComponent>, > where Self: 'a; @@ -877,12 +898,15 @@ impl GridContainerStyle for Style { #[cfg(feature = "grid")] type TemplateLineNames<'a> - = core::iter::Map>, fn(&GridTrackVec) -> core::slice::Iter<'_, S>> + = core::iter::Map< + core::slice::Iter<'a, GridTrackVec>, + fn(&GridTrackVec) -> core::slice::Iter<'_, U::Str>, + > where Self: 'a; #[cfg(feature = "grid")] type GridTemplateAreas<'a> - = core::iter::Cloned>> + = core::iter::Cloned>> where Self: 'a; @@ -1033,14 +1057,14 @@ impl GridContainerStyle for &'_ T { } #[cfg(feature = "grid")] -impl GridItemStyle for Style { +impl GridItemStyle for Style { #[inline(always)] - fn grid_row(&self) -> Line> { + fn grid_row(&self) -> Line> { // TODO: Investigate eliminating clone self.grid_row.clone() } #[inline(always)] - fn grid_column(&self) -> Line> { + fn grid_column(&self) -> Line> { // TODO: Investigate eliminating clone self.grid_column.clone() } @@ -1057,11 +1081,11 @@ impl GridItemStyle for Style { #[cfg(feature = "grid")] impl GridItemStyle for &'_ T { #[inline(always)] - fn grid_row(&self) -> Line> { + fn grid_row(&self) -> Line::Str>> { (*self).grid_row() } #[inline(always)] - fn grid_column(&self) -> Line> { + fn grid_column(&self) -> Line::Str>> { (*self).grid_column() } #[inline(always)] @@ -1213,7 +1237,7 @@ mod tests { assert_type_size::(8); assert_type_size::(16); assert_type_size::>(24); - assert_type_size::>>(24); + assert_type_size::>>(24); // String-type dependent (String) assert_type_size::>(56); From 23399dd816a12758fc7ba405371075926f1ee454 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Sat, 2 Aug 2025 00:33:41 +0100 Subject: [PATCH 2/3] Introduce a `Units` trait Signed-off-by: Nico Burns --- examples/custom_tree_owned_partial.rs | 4 +-- examples/custom_tree_owned_unsafe.rs | 4 +-- examples/custom_tree_vec.rs | 4 +-- src/compute/grid/explicit_grid.rs | 22 ++++++++-------- src/compute/grid/implicit_grid.rs | 6 ++--- src/compute/grid/placement.rs | 4 +-- src/compute/grid/types/named.rs | 38 +++++++++++++-------------- src/compute/grid/util/test_helpers.rs | 4 +-- src/style/flex.rs | 4 +-- src/style/mod.rs | 32 +++++++++++++--------- src/tree/taffy_tree.rs | 5 ++-- src/tree/traits.rs | 11 ++++---- 12 files changed, 70 insertions(+), 68 deletions(-) diff --git a/examples/custom_tree_owned_partial.rs b/examples/custom_tree_owned_partial.rs index e69b26eb5..356f35266 100644 --- a/examples/custom_tree_owned_partial.rs +++ b/examples/custom_tree_owned_partial.rs @@ -13,7 +13,7 @@ use common::image::{image_measure_function, ImageContext}; use common::text::{text_measure_function, FontMetrics, TextContext, WritingMode, LOREM_IPSUM}; use taffy::{ compute_cached_layout, compute_flexbox_layout, compute_grid_layout, compute_leaf_layout, compute_root_layout, - prelude::*, Cache, CacheTree, Layout, Style, + prelude::*, Cache, CacheTree, DefaultUnits, Layout, Style, }; #[derive(Debug, Copy, Clone)] @@ -138,7 +138,7 @@ impl taffy::LayoutPartialTree for Node { where Self: 'a; - type CustomIdent = String; + type Units = DefaultUnits; fn get_core_container_style(&self, node_id: NodeId) -> Self::CoreContainerStyle<'_> { &self.node_from_id(node_id).style diff --git a/examples/custom_tree_owned_unsafe.rs b/examples/custom_tree_owned_unsafe.rs index d0138ba95..9fb628973 100644 --- a/examples/custom_tree_owned_unsafe.rs +++ b/examples/custom_tree_owned_unsafe.rs @@ -9,7 +9,7 @@ use taffy::tree::Cache; use taffy::util::print_tree; use taffy::{ compute_cached_layout, compute_flexbox_layout, compute_grid_layout, compute_leaf_layout, compute_root_layout, - prelude::*, round_layout, CacheTree, + prelude::*, round_layout, CacheTree, DefaultUnits, }; #[derive(Debug, Copy, Clone)] @@ -136,7 +136,7 @@ impl LayoutPartialTree for StatelessLayoutTree { where Self: 'a; - type CustomIdent = String; + type Units = DefaultUnits; fn get_core_container_style(&self, node_id: NodeId) -> Self::CoreContainerStyle<'_> { unsafe { &node_from_id(node_id).style } diff --git a/examples/custom_tree_vec.rs b/examples/custom_tree_vec.rs index 5659bd174..a53c67bcb 100644 --- a/examples/custom_tree_vec.rs +++ b/examples/custom_tree_vec.rs @@ -7,7 +7,7 @@ use common::text::{text_measure_function, FontMetrics, TextContext, WritingMode, use taffy::util::print_tree; use taffy::{ compute_cached_layout, compute_flexbox_layout, compute_grid_layout, compute_leaf_layout, compute_root_layout, - prelude::*, round_layout, Cache, CacheTree, + prelude::*, round_layout, Cache, CacheTree, DefaultUnits, }; #[derive(Debug, Copy, Clone)] @@ -139,7 +139,7 @@ impl taffy::TraversePartialTree for Tree { impl taffy::TraverseTree for Tree {} impl taffy::LayoutPartialTree for Tree { - type CustomIdent = String; + type Units = DefaultUnits; type CoreContainerStyle<'a> = &'a Style diff --git a/src/compute/grid/explicit_grid.rs b/src/compute/grid/explicit_grid.rs index 5e5c02aca..812d00294 100644 --- a/src/compute/grid/explicit_grid.rs +++ b/src/compute/grid/explicit_grid.rs @@ -323,7 +323,7 @@ mod test { use crate::compute::grid::util::*; use crate::geometry::AbsoluteAxis; use crate::prelude::*; - use crate::sys::DefaultCheapStr; + use crate::DefaultUnits; #[test] fn explicit_grid_sizing_no_repeats() { @@ -352,7 +352,7 @@ mod test { #[test] fn explicit_grid_sizing_auto_fill_exact_fit() { use RepetitionCount::AutoFill; - let grid_style: Style = Style { + let grid_style: Style = Style { display: Display::Grid, size: Size { width: length(120.0), height: length(80.0) }, grid_template_columns: vec![repeat(AutoFill, vec![length(40.0)])], @@ -383,7 +383,7 @@ mod test { #[test] fn explicit_grid_sizing_auto_fill_non_exact_fit() { use RepetitionCount::AutoFill; - let grid_style: Style = Style { + let grid_style: Style = Style { display: Display::Grid, size: Size { width: length(140.0), height: length(90.0) }, grid_template_columns: vec![repeat(AutoFill, vec![length(40.0)])], @@ -414,7 +414,7 @@ mod test { #[test] fn explicit_grid_sizing_auto_fill_min_size_exact_fit() { use RepetitionCount::AutoFill; - let grid_style: Style = Style { + let grid_style: Style = Style { display: Display::Grid, min_size: Size { width: length(120.0), height: length(80.0) }, grid_template_columns: vec![repeat(AutoFill, vec![length(40.0)])], @@ -445,7 +445,7 @@ mod test { #[test] fn explicit_grid_sizing_auto_fill_min_size_non_exact_fit() { use RepetitionCount::AutoFill; - let grid_style: Style = Style { + let grid_style: Style = Style { display: Display::Grid, min_size: Size { width: length(140.0), height: length(90.0) }, grid_template_columns: vec![repeat(AutoFill, vec![length(40.0)])], @@ -476,7 +476,7 @@ mod test { #[test] fn explicit_grid_sizing_auto_fill_multiple_repeated_tracks() { use RepetitionCount::AutoFill; - let grid_style: Style = Style { + let grid_style: Style = Style { display: Display::Grid, size: Size { width: length(140.0), height: length(100.0) }, grid_template_columns: vec![repeat(AutoFill, vec![length(40.0), length(20.0)])], @@ -507,7 +507,7 @@ mod test { #[test] fn explicit_grid_sizing_auto_fill_gap() { use RepetitionCount::AutoFill; - let grid_style: Style = Style { + let grid_style: Style = Style { display: Display::Grid, size: Size { width: length(140.0), height: length(100.0) }, grid_template_columns: vec![repeat(AutoFill, vec![length(40.0)])], @@ -539,7 +539,7 @@ mod test { #[test] fn explicit_grid_sizing_no_defined_size() { use RepetitionCount::AutoFill; - let grid_style: Style = Style { + let grid_style: Style = Style { display: Display::Grid, grid_template_columns: vec![repeat(AutoFill, vec![length(40.0), percent(0.5), length(20.0)])], grid_template_rows: vec![repeat(AutoFill, vec![length(20.0)])], @@ -570,7 +570,7 @@ mod test { #[test] fn explicit_grid_sizing_mix_repeated_and_non_repeated() { use RepetitionCount::AutoFill; - let grid_style: Style = Style { + let grid_style: Style = Style { display: Display::Grid, size: Size { width: length(140.0), height: length(100.0) }, grid_template_columns: vec![length(20.0), repeat(AutoFill, vec![length(40.0)])], @@ -602,7 +602,7 @@ mod test { #[test] fn explicit_grid_sizing_mix_with_padding() { use RepetitionCount::AutoFill; - let grid_style: Style = Style { + let grid_style: Style = Style { display: Display::Grid, size: Size { width: length(120.0), height: length(120.0) }, padding: Rect { left: length(10.0), right: length(10.0), top: length(20.0), bottom: length(20.0) }, @@ -642,7 +642,7 @@ mod test { let maxpx100 = MaxTrackSizingFunction::from_length(100.0); // Setup test - let grid_style: Style = Style { + let grid_style: Style = Style { display: Display::Grid, gap: length(20.0), grid_template_columns: vec![length(100.0), minmax(length(100.0), fr(2.0)), fr(1.0)], diff --git a/src/compute/grid/implicit_grid.rs b/src/compute/grid/implicit_grid.rs index 8cc35ff1f..27f3ae638 100644 --- a/src/compute/grid/implicit_grid.rs +++ b/src/compute/grid/implicit_grid.rs @@ -2,7 +2,7 @@ //! to reduce the number of allocations required when creating a grid. use crate::geometry::Line; use crate::style::{GenericGridPlacement, GridPlacement}; -use crate::{CheapCloneStr, GridItemStyle}; +use crate::{CheapCloneStr, GridItemStyle, Units}; use core::cmp::{max, min}; use super::types::TrackCounts; @@ -72,9 +72,9 @@ fn get_known_child_positions<'a, S: GridItemStyle + 'a>( // Note: that the children reference the lines in between (and around) the tracks not tracks themselves, // and thus we must subtract 1 to get an accurate estimate of the number of tracks let (child_col_min, child_col_max, child_col_span) = - child_min_line_max_line_span::(child_style.grid_column(), explicit_col_count); + child_min_line_max_line_span::<::Str>(child_style.grid_column(), explicit_col_count); let (child_row_min, child_row_max, child_row_span) = - child_min_line_max_line_span::(child_style.grid_row(), explicit_row_count); + child_min_line_max_line_span::<::Str>(child_style.grid_row(), explicit_row_count); col_min = min(col_min, child_col_min); col_max = max(col_max, child_col_max); col_max_span = max(col_max_span, child_col_span); diff --git a/src/compute/grid/placement.rs b/src/compute/grid/placement.rs index 34de5ad5f..447ac6a8e 100644 --- a/src/compute/grid/placement.rs +++ b/src/compute/grid/placement.rs @@ -4,7 +4,7 @@ use super::types::{CellOccupancyMatrix, CellOccupancyState, GridItem}; use super::{NamedLineResolver, OriginZeroLine}; use crate::geometry::Line; use crate::geometry::{AbsoluteAxis, InBothAbsAxis}; -use crate::style::{AlignItems, GridAutoFlow, OriginZeroGridPlacement, Units}; +use crate::style::{AlignItems, GridAutoFlow, OriginZeroGridPlacement}; use crate::tree::NodeId; use crate::util::sys::Vec; use crate::GridItemStyle; @@ -20,7 +20,7 @@ pub(super) fn place_grid_items<'a, S, ChildIter>( grid_auto_flow: GridAutoFlow, align_items: AlignItems, justify_items: AlignItems, - named_line_resolver: &NamedLineResolver<::Str>, + named_line_resolver: &NamedLineResolver, ) where S: GridItemStyle + 'a, ChildIter: Iterator, diff --git a/src/compute/grid/types/named.rs b/src/compute/grid/types/named.rs index 9b784c002..6c44b3d2c 100644 --- a/src/compute/grid/types/named.rs +++ b/src/compute/grid/types/named.rs @@ -2,7 +2,7 @@ use crate::{ CheapCloneStr, GenericGridTemplateComponent, GenericRepetition as _, GridAreaAxis, GridAreaEnd, GridContainerStyle, - GridPlacement, GridTemplateArea, Line, NonNamedGridPlacement, RepetitionCount, + GridPlacement, GridTemplateArea, Line, NonNamedGridPlacement, RepetitionCount, Units, }; use core::{borrow::Borrow, cmp::Ordering, fmt::Debug}; @@ -44,15 +44,15 @@ impl Borrow for StrHasher { /// Resolver that takes grid lines names and area names as input and can then be used to /// resolve line names of grid placement properties into line numbers. -pub(crate) struct NamedLineResolver { +pub(crate) struct NamedLineResolver { /// Map of row line names to line numbers. Each line name may correspond to multiple lines /// so we store a `Vec` - row_lines: Map, Vec>, + row_lines: Map, Vec>, /// Map of column line names to line numbers. Each line name may correspond to multiple lines /// so we store a `Vec` - column_lines: Map, Vec>, + column_lines: Map, Vec>, /// Map of area names to area definitions (start and end lines numbers in each axis) - areas: Map, GridTemplateArea>, + areas: Map, GridTemplateArea>, /// Number of columns implied by grid area definitions area_column_count: u16, /// Number of rows implied by grid area definitions @@ -70,16 +70,16 @@ fn upsert_line_name_map(map: &mut Map, Vec>, map.entry(StrHasher(key)).and_modify(|lines| lines.push(value)).or_insert_with(|| single_value_vec(value)); } -impl NamedLineResolver { +impl NamedLineResolver { /// Create and initialise a new `NamedLineResolver` pub(crate) fn new( - style: &impl GridContainerStyle, + style: &impl GridContainerStyle, column_auto_repetitions: u16, row_auto_repetitions: u16, ) -> Self { - let mut areas: Map, GridTemplateArea<_>> = Map::new(); - let mut column_lines: Map, Vec> = Map::new(); - let mut row_lines: Map, Vec> = Map::new(); + let mut areas: Map, GridTemplateArea<_>> = Map::new(); + let mut column_lines: Map, Vec> = Map::new(); + let mut row_lines: Map, Vec> = Map::new(); let mut area_column_count = 0; let mut area_row_count = 0; @@ -91,13 +91,13 @@ impl NamedLineResolver { area_column_count = area_column_count.max(area.column_end.max(1) - 1); area_row_count = area_row_count.max(area.row_end.max(1) - 1); - let col_start_name = S::from(format!("{}-start", area.name.as_ref())); + let col_start_name = U::Str::from(format!("{}-start", area.name.as_ref())); upsert_line_name_map(&mut column_lines, col_start_name, area.column_start); - let col_end_name = S::from(format!("{}-end", area.name.as_ref())); + let col_end_name = U::Str::from(format!("{}-end", area.name.as_ref())); upsert_line_name_map(&mut column_lines, col_end_name, area.column_end); - let row_start_name = S::from(format!("{}-start", area.name.as_ref())); + let row_start_name = U::Str::from(format!("{}-start", area.name.as_ref())); upsert_line_name_map(&mut row_lines, row_start_name, area.row_start); - let row_end_name = S::from(format!("{}-end", area.name.as_ref())); + let row_end_name = U::Str::from(format!("{}-end", area.name.as_ref())); upsert_line_name_map(&mut row_lines, row_end_name, area.row_end); } } @@ -197,13 +197,13 @@ impl NamedLineResolver { /// Resolve named lines for both the `start` and `end` of a row-axis grid placement #[inline(always)] - pub(crate) fn resolve_row_names(&self, line: &Line>) -> Line { + pub(crate) fn resolve_row_names(&self, line: &Line>) -> Line { self.resolve_line_names(line, GridAreaAxis::Row) } /// Resolve named lines for both the `start` and `end` of a column-axis grid placement #[inline(always)] - pub(crate) fn resolve_column_names(&self, line: &Line>) -> Line { + pub(crate) fn resolve_column_names(&self, line: &Line>) -> Line { self.resolve_line_names(line, GridAreaAxis::Column) } @@ -211,7 +211,7 @@ impl NamedLineResolver { #[inline(always)] pub(crate) fn resolve_line_names( &self, - line: &Line>, + line: &Line>, axis: GridAreaAxis, ) -> Line { let start_holder; @@ -293,7 +293,7 @@ impl NamedLineResolver { /// Resolve the grid line for a named grid line or span fn find_line_index( &self, - name: &S, + name: &U::Str, idx: i16, axis: GridAreaAxis, end: GridAreaEnd, @@ -390,7 +390,7 @@ impl NamedLineResolver { } } -impl Debug for NamedLineResolver { +impl Debug for NamedLineResolver { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { writeln!(f, "Grid Areas:")?; for area in self.areas.values() { diff --git a/src/compute/grid/util/test_helpers.rs b/src/compute/grid/util/test_helpers.rs index 8830550ea..b4c045680 100644 --- a/src/compute/grid/util/test_helpers.rs +++ b/src/compute/grid/util/test_helpers.rs @@ -1,7 +1,7 @@ //! Helpers for use in unit tests within the grid module use super::super::OriginZeroLine; -use crate::prelude::*; use crate::style::{Dimension, GridPlacement, Style}; +use crate::{prelude::*, DefaultUnits}; pub(crate) trait CreateParentTestNode { fn into_grid(self) -> Style; @@ -23,7 +23,7 @@ pub(crate) trait CreateChildTestNode { impl CreateChildTestNode for (GridPlacement, GridPlacement, GridPlacement, GridPlacement) { - fn into_grid_child(self) -> Style { + fn into_grid_child(self) -> Style { Style { display: Display::Grid, grid_column: Line { start: self.0, end: self.1 }, diff --git a/src/style/flex.rs b/src/style/flex.rs index 804b92641..77e7fb698 100644 --- a/src/style/flex.rs +++ b/src/style/flex.rs @@ -1,7 +1,5 @@ //! Style types for Flexbox layout -use super::{ - AlignContent, AlignItems, AlignSelf, CoreStyle, Dimension, JustifyContent, LengthPercentage, Style, Units, -}; +use super::{AlignContent, AlignItems, AlignSelf, CoreStyle, Dimension, JustifyContent, LengthPercentage, Style}; use crate::geometry::Size; /// The set of styles required for a Flexbox container diff --git a/src/style/mod.rs b/src/style/mod.rs index 69a304a91..4a88c061c 100644 --- a/src/style/mod.rs +++ b/src/style/mod.rs @@ -15,7 +15,6 @@ pub use self::alignment::{AlignContent, AlignItems, AlignSelf, JustifyContent, J pub use self::available_space::AvailableSpace; pub use self::compact_length::CompactLength; pub use self::dimension::{Dimension, LengthPercentage, LengthPercentageAuto}; -use crate::sys::DefaultCheapStr; #[cfg(feature = "block_layout")] pub use self::block::{BlockContainerStyle, BlockItemStyle, TextAlign}; @@ -60,6 +59,10 @@ impl CheapCloneStr for T where { } +/// Trait that represent a `calc()` expression +pub trait Calc: Clone + Debug + 'static {} +impl Calc for T where T: Clone + Debug + 'static {} + /// Allows Taffy to abstract of the types it uses to represent strings and calc expressions. /// In future it may be extended to abstract the scalar number type (currently f32) pub trait Units { @@ -69,9 +72,11 @@ pub trait Units { /// Type representing a calc expression. /// If you're not using Calc then you can just use `()` - type Calc: 'static; + type Calc: Calc; } +/// A default implementation of the [`Units`] trait +#[derive(Debug, Copy, Clone, Default, Eq, PartialEq)] pub struct DefaultUnits; impl Units for DefaultUnits { @@ -389,7 +394,7 @@ impl Overflow { #[derive(Clone, PartialEq, Debug)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(default))] -pub struct Style { +pub struct Style { /// This is a dummy field which is necessary to make Taffy compile with the `grid` feature disabled /// It should always be set to `core::marker::PhantomData`. pub dummy: core::marker::PhantomData, @@ -520,10 +525,10 @@ pub struct Style { pub grid_template_areas: GridTrackVec>, /// The named lines between the columns #[cfg(feature = "grid")] - pub grid_template_column_names: GridTrackVec>, + pub grid_template_column_names: GridTrackVec>, /// The named lines between the rows #[cfg(feature = "grid")] - pub grid_template_row_names: GridTrackVec>, + pub grid_template_row_names: GridTrackVec>, // Grid child properties /// Defines which row in the grid the item should start and end at @@ -600,9 +605,9 @@ impl Style { #[cfg(feature = "grid")] grid_auto_flow: GridAutoFlow::Row, #[cfg(feature = "grid")] - grid_row: Line { start: GridPlacement::::Auto, end: GridPlacement::::Auto }, + grid_row: Line { start: GridPlacement::::Auto, end: GridPlacement::::Auto }, #[cfg(feature = "grid")] - grid_column: Line { start: GridPlacement::::Auto, end: GridPlacement::::Auto }, + grid_column: Line { start: GridPlacement::::Auto, end: GridPlacement::::Auto }, }; } @@ -1103,7 +1108,7 @@ mod tests { use std::sync::Arc; use super::Style; - use crate::sys::DefaultCheapStr; + use crate::DefaultUnits; use crate::{geometry::*, style_helpers::TaffyAuto as _}; #[test] @@ -1111,7 +1116,7 @@ mod tests { #[cfg(feature = "grid")] use super::GridPlacement; - let old_defaults: Style = Style { + let old_defaults: Style = Style { dummy: core::marker::PhantomData, display: Default::default(), item_is_table: false, @@ -1175,7 +1180,7 @@ mod tests { grid_column: Line { start: GridPlacement::Auto, end: GridPlacement::Auto }, }; - assert_eq!(Style::DEFAULT, Style::::default()); + assert_eq!(Style::DEFAULT, Style::::default()); assert_eq!(Style::DEFAULT, old_defaults); } @@ -1237,18 +1242,19 @@ mod tests { assert_type_size::(8); assert_type_size::(16); assert_type_size::>(24); - assert_type_size::>>(24); + assert_type_size::>>(24); // String-type dependent (String) assert_type_size::>(56); assert_type_size::>(32); assert_type_size::>>(64); - assert_type_size::>(536); // String-type dependent (Arc) assert_type_size::>>(56); assert_type_size::>>(24); assert_type_size::>>>(48); - assert_type_size::>>(504); + + // Overall size (default units) + assert_type_size::>(536); } } diff --git a/src/tree/taffy_tree.rs b/src/tree/taffy_tree.rs index af343aebf..2fdaac91c 100644 --- a/src/tree/taffy_tree.rs +++ b/src/tree/taffy_tree.rs @@ -7,7 +7,6 @@ use slotmap::{DefaultKey, SlotMap}; use crate::geometry::Size; use crate::style::{AvailableSpace, Display, Style}; -use crate::sys::DefaultCheapStr; use crate::tree::{ Cache, ClearState, Layout, LayoutInput, LayoutOutput, LayoutPartialTree, NodeId, PrintTree, RoundTree, RunMode, TraversePartialTree, TraverseTree, @@ -18,13 +17,13 @@ use crate::util::sys::{new_vec_with_capacity, ChildrenVec, Vec}; use crate::compute::{ compute_cached_layout, compute_hidden_layout, compute_leaf_layout, compute_root_layout, round_layout, }; -use crate::CacheTree; #[cfg(feature = "block_layout")] use crate::{compute::compute_block_layout, LayoutBlockContainer}; #[cfg(feature = "flexbox")] use crate::{compute::compute_flexbox_layout, LayoutFlexboxContainer}; #[cfg(feature = "grid")] use crate::{compute::compute_grid_layout, LayoutGridContainer}; +use crate::{CacheTree, DefaultUnits}; #[cfg(all(feature = "detailed_layout_info", feature = "grid"))] use crate::compute::grid::DetailedGridInfo; @@ -328,7 +327,7 @@ where where Self: 'a; - type CustomIdent = DefaultCheapStr; + type Units = DefaultUnits; #[inline(always)] fn get_core_container_style(&self, node_id: NodeId) -> Self::CoreContainerStyle<'_> { diff --git a/src/tree/traits.rs b/src/tree/traits.rs index d90d1e9e0..d243d266d 100644 --- a/src/tree/traits.rs +++ b/src/tree/traits.rs @@ -130,12 +130,11 @@ use super::{Layout, LayoutInput, LayoutOutput, NodeId, RequestedAxis, RunMode, S #[cfg(feature = "detailed_layout_info")] use crate::debug::debug_log; use crate::geometry::{AbsoluteAxis, Line, Size}; -use crate::style::{AvailableSpace, CoreStyle}; +use crate::style::{AvailableSpace, CoreStyle, Units}; #[cfg(feature = "flexbox")] use crate::style::{FlexboxContainerStyle, FlexboxItemStyle}; #[cfg(feature = "grid")] use crate::style::{GridContainerStyle, GridItemStyle}; -use crate::CheapCloneStr; #[cfg(feature = "block_layout")] use crate::{BlockContainerStyle, BlockItemStyle}; @@ -174,13 +173,13 @@ pub trait TraverseTree: TraversePartialTree {} pub trait LayoutPartialTree: TraversePartialTree { /// The style type representing the core container styles that all containers should have /// Used when laying out the root node of a tree - type CoreContainerStyle<'a>: CoreStyle + type CoreContainerStyle<'a>: CoreStyle where Self: 'a; /// String type for representing "custom identifiers" (for example, named grid lines or areas) /// If you are unsure what to use here then consider `Arc`. - type CustomIdent: CheapCloneStr; + type Units: Units; /// Get core style fn get_core_container_style(&self, node_id: NodeId) -> Self::CoreContainerStyle<'_>; @@ -271,12 +270,12 @@ pub trait LayoutFlexboxContainer: LayoutPartialTree { /// Extends [`LayoutPartialTree`] with getters for the styles required for CSS Grid layout pub trait LayoutGridContainer: LayoutPartialTree { /// The style type representing the CSS Grid container's styles - type GridContainerStyle<'a>: GridContainerStyle + type GridContainerStyle<'a>: GridContainerStyle where Self: 'a; /// The style type representing each CSS Grid item's styles - type GridItemStyle<'a>: GridItemStyle + type GridItemStyle<'a>: GridItemStyle where Self: 'a; From e9da76a597461b0e9072d7808d7db6af21b022e8 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Sat, 2 Aug 2025 01:10:03 +0100 Subject: [PATCH 3/3] Fix serde feature with Units trait Signed-off-by: Nico Burns --- src/style/mod.rs | 5 +++++ tests/serde.rs | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/style/mod.rs b/src/style/mod.rs index 4a88c061c..39eeb4de1 100644 --- a/src/style/mod.rs +++ b/src/style/mod.rs @@ -68,7 +68,12 @@ impl Calc for T where T: Clone + Debug + 'static {} pub trait Units { /// Trait that represents a cheaply clonable string. If you're unsure what to use here /// consider `Arc` or `string_cache::Atom`. + #[cfg(not(feature = "serde"))] type Str: CheapCloneStr; + /// Trait that represents a cheaply clonable string. If you're unsure what to use here + /// consider `Arc` or `string_cache::Atom`. + #[cfg(feature = "serde")] + type Str: CheapCloneStr + serde::Serialize + for<'a> serde::Deserialize<'a>; /// Type representing a calc expression. /// If you're not using Calc then you can just use `()` diff --git a/tests/serde.rs b/tests/serde.rs index 0ddce2ba0..f2f9ecf7a 100644 --- a/tests/serde.rs +++ b/tests/serde.rs @@ -2,11 +2,11 @@ #[cfg(feature = "serde")] mod serde { use serde_json::{self, Value}; - use taffy::style::Style; + use taffy::{DefaultUnits, Style}; #[test] fn serde_can_serialize() { - let style: Style = Style::DEFAULT; + let style: Style = Style::DEFAULT; let _ = serde_json::to_string(&style).unwrap(); }