Skip to main content

taffy/style/
mod.rs

1//! A typed representation of [CSS style properties](https://css-tricks.com/snippets/css/a-guide-to-flexbox/) in Rust. Used as input to layout computation.
2mod alignment;
3mod available_space;
4mod compact_length;
5mod dimension;
6
7#[cfg(feature = "block_layout")]
8mod block;
9#[cfg(feature = "flexbox")]
10mod flex;
11#[cfg(feature = "float_layout")]
12mod float;
13#[cfg(feature = "grid")]
14mod grid;
15
16pub use self::alignment::{
17    AlignContent, AlignContentKeyword, AlignItems, AlignItemsKeyword, AlignSelf, AlignmentSafety, JustifyContent,
18    JustifyItems, JustifySelf,
19};
20pub use self::available_space::AvailableSpace;
21pub use self::compact_length::CompactLength;
22pub use self::dimension::{Dimension, LengthPercentage, LengthPercentageAuto};
23use crate::sys::DefaultCheapStr;
24
25#[cfg(feature = "block_layout")]
26pub use self::block::{BlockContainerStyle, BlockItemStyle, TextAlign};
27#[cfg(feature = "flexbox")]
28pub use self::flex::{FlexDirection, FlexWrap, FlexboxContainerStyle, FlexboxItemStyle};
29#[cfg(feature = "float_layout")]
30pub use self::float::{Clear, Float, FloatDirection};
31#[cfg(feature = "grid")]
32pub use self::grid::{
33    GenericGridPlacement, GenericGridTemplateComponent, GenericRepetition, GridAutoFlow, GridAutoTracks,
34    GridContainerStyle, GridItemStyle, GridPlacement, GridTemplateComponent, GridTemplateRepetition,
35    GridTemplateTracks, MaxTrackSizingFunction, MinTrackSizingFunction, RepetitionCount, TrackSizingFunction,
36};
37#[cfg(feature = "grid")]
38pub(crate) use self::grid::{GridAreaAxis, GridAreaEnd};
39#[cfg(feature = "grid")]
40pub use self::grid::{GridTemplateArea, NamedGridLine, TemplateLineNames};
41#[cfg(feature = "grid")]
42pub(crate) use self::grid::{NonNamedGridPlacement, OriginZeroGridPlacement};
43
44use crate::geometry::{Point, Rect, Size};
45use crate::style_helpers::TaffyAuto as _;
46use core::fmt::Debug;
47
48#[cfg(feature = "grid")]
49use crate::geometry::Line;
50#[cfg(feature = "serde")]
51use crate::style_helpers;
52#[cfg(feature = "grid")]
53use crate::util::sys::GridTrackVec;
54
55use crate::sys::String;
56
57/// Trait that represents a cheaply clonable string. If you're unsure what to use here
58/// consider `Arc<str>` or `string_cache::Atom`.
59#[cfg(any(feature = "alloc", feature = "std"))]
60pub trait CheapCloneStr:
61    AsRef<str> + for<'a> From<&'a str> + From<String> + PartialEq + Eq + Clone + Default + Debug + 'static
62{
63}
64#[cfg(any(feature = "alloc", feature = "std"))]
65impl<T> CheapCloneStr for T where
66    T: AsRef<str> + for<'a> From<&'a str> + From<String> + PartialEq + Eq + Clone + Default + Debug + 'static
67{
68}
69
70/// Trait that represents a cheaply clonable string. If you're unsure what to use here
71/// consider `Arc<str>` or `string_cache::Atom`.
72#[cfg(not(any(feature = "alloc", feature = "std")))]
73pub trait CheapCloneStr {}
74#[cfg(not(any(feature = "alloc", feature = "std")))]
75impl<T> CheapCloneStr for T {}
76
77/// The core set of styles that are shared between all CSS layout nodes
78///
79/// Note that all methods come with a default implementation which simply returns the default value for that style property
80/// but this is a just a convenience to save on boilerplate for styles that your implementation doesn't support. You will need
81/// to override the default implementation for each style property that your style type actually supports.
82pub trait CoreStyle {
83    /// The type of custom identifiers used to identify named grid lines and areas
84    type CustomIdent: CheapCloneStr;
85
86    /// Which box generation mode should be used
87    #[inline(always)]
88    fn box_generation_mode(&self) -> BoxGenerationMode {
89        BoxGenerationMode::DEFAULT
90    }
91    /// Is block layout?
92    #[inline(always)]
93    fn is_block(&self) -> bool {
94        false
95    }
96    /// Is it a compressible replaced element?
97    /// <https://drafts.csswg.org/css-sizing-3/#min-content-zero>
98    #[inline(always)]
99    fn is_compressible_replaced(&self) -> bool {
100        false
101    }
102    /// Which box do size styles apply to
103    #[inline(always)]
104    fn box_sizing(&self) -> BoxSizing {
105        BoxSizing::BorderBox
106    }
107
108    /// The direction of text, table and grid columns, and horizontal overflow.
109    #[inline(always)]
110    fn direction(&self) -> Direction {
111        Direction::Ltr
112    }
113
114    // Overflow properties
115    /// How children overflowing their container should affect layout
116    #[inline(always)]
117    fn overflow(&self) -> Point<Overflow> {
118        Style::<Self::CustomIdent>::DEFAULT.overflow
119    }
120    /// How much space (in points) should be reserved for the scrollbars of `Overflow::Scroll` and `Overflow::Auto` nodes.
121    #[inline(always)]
122    fn scrollbar_width(&self) -> f32 {
123        0.0
124    }
125
126    // Position properties
127    /// What should the `position` value of this struct use as a base offset?
128    #[inline(always)]
129    fn position(&self) -> Position {
130        Style::<Self::CustomIdent>::DEFAULT.position
131    }
132    /// How should the position of this element be tweaked relative to the layout defined?
133    #[inline(always)]
134    fn inset(&self) -> Rect<LengthPercentageAuto> {
135        Style::<Self::CustomIdent>::DEFAULT.inset
136    }
137
138    // Size properies
139    /// Sets the initial size of the item
140    #[inline(always)]
141    fn size(&self) -> Size<Dimension> {
142        Style::<Self::CustomIdent>::DEFAULT.size
143    }
144    /// Controls the minimum size of the item
145    #[inline(always)]
146    fn min_size(&self) -> Size<Dimension> {
147        Style::<Self::CustomIdent>::DEFAULT.min_size
148    }
149    /// Controls the maximum size of the item
150    #[inline(always)]
151    fn max_size(&self) -> Size<Dimension> {
152        Style::<Self::CustomIdent>::DEFAULT.max_size
153    }
154    /// Sets the preferred aspect ratio for the item
155    /// The ratio is calculated as width divided by height.
156    #[inline(always)]
157    fn aspect_ratio(&self) -> Option<f32> {
158        Style::<Self::CustomIdent>::DEFAULT.aspect_ratio
159    }
160
161    // Spacing Properties
162    /// How large should the margin be on each side?
163    #[inline(always)]
164    fn margin(&self) -> Rect<LengthPercentageAuto> {
165        Style::<Self::CustomIdent>::DEFAULT.margin
166    }
167    /// How large should the padding be on each side?
168    #[inline(always)]
169    fn padding(&self) -> Rect<LengthPercentage> {
170        Style::<Self::CustomIdent>::DEFAULT.padding
171    }
172    /// How large should the border be on each side?
173    #[inline(always)]
174    fn border(&self) -> Rect<LengthPercentage> {
175        Style::<Self::CustomIdent>::DEFAULT.border
176    }
177}
178
179/// Sets the layout used for the children of this node
180///
181/// The default values depends on on which feature flags are enabled. The order of precedence is: Flex, Grid, Block, None.
182#[derive(Copy, Clone, PartialEq, Eq, Debug)]
183#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
184pub enum Display {
185    /// The children will follow the block layout algorithm
186    #[cfg(feature = "block_layout")]
187    Block,
188    /// The children will follow the flexbox layout algorithm
189    #[cfg(feature = "flexbox")]
190    Flex,
191    /// The children will follow the CSS Grid layout algorithm
192    #[cfg(feature = "grid")]
193    Grid,
194    /// The node is hidden, and it's children will also be hidden
195    None,
196}
197
198impl Display {
199    /// The default Display mode
200    #[cfg(feature = "flexbox")]
201    pub const DEFAULT: Display = Display::Flex;
202
203    /// The default Display mode
204    #[cfg(all(feature = "grid", not(feature = "flexbox")))]
205    pub const DEFAULT: Display = Display::Grid;
206
207    /// The default Display mode
208    #[cfg(all(feature = "block_layout", not(feature = "flexbox"), not(feature = "grid")))]
209    pub const DEFAULT: Display = Display::Block;
210
211    /// The default Display mode
212    #[cfg(all(not(feature = "flexbox"), not(feature = "grid"), not(feature = "block_layout")))]
213    pub const DEFAULT: Display = Display::None;
214}
215
216impl Default for Display {
217    fn default() -> Self {
218        Self::DEFAULT
219    }
220}
221
222#[cfg(feature = "parse")]
223crate::util::parse::impl_parse_for_keyword_enum!(Display,
224    "none" => None,
225    #[cfg(feature = "flexbox")]
226    "flex" => Flex,
227    #[cfg(feature = "grid")]
228    "grid" => Grid,
229    #[cfg(feature = "block_layout")]
230    "block" => Block,
231);
232
233impl core::fmt::Display for Display {
234    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
235        match self {
236            Display::None => write!(f, "NONE"),
237            #[cfg(feature = "block_layout")]
238            Display::Block => write!(f, "BLOCK"),
239            #[cfg(feature = "flexbox")]
240            Display::Flex => write!(f, "FLEX"),
241            #[cfg(feature = "grid")]
242            Display::Grid => write!(f, "GRID"),
243        }
244    }
245}
246
247/// An abstracted version of the CSS `display` property where any value other than "none" is represented by "normal"
248/// See: <https://www.w3.org/TR/css-display-3/#box-generation>
249#[derive(Copy, Clone, PartialEq, Eq, Debug)]
250#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
251pub enum BoxGenerationMode {
252    /// The node generates a box in the regular way
253    Normal,
254    /// The node and it's descendants generate no boxes (they are hidden)
255    None,
256}
257
258impl BoxGenerationMode {
259    /// The default of BoxGenerationMode
260    pub const DEFAULT: BoxGenerationMode = BoxGenerationMode::Normal;
261}
262
263impl Default for BoxGenerationMode {
264    fn default() -> Self {
265        Self::DEFAULT
266    }
267}
268
269/// The positioning strategy for this item.
270///
271/// This controls both how the origin is determined for the [`Style::position`] field,
272/// and whether or not the item will be controlled by flexbox's layout algorithm.
273///
274/// WARNING: this enum follows the behavior of [CSS's `position` property](https://developer.mozilla.org/en-US/docs/Web/CSS/position),
275/// which can be unintuitive.
276///
277/// [`Position::Relative`] is the default value, in contrast to the default behavior in CSS.
278#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
279#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
280pub enum Position {
281    /// The offset is computed relative to the final position given by the layout algorithm.
282    /// Offsets do not affect the position of any other items; they are effectively a correction factor applied at the end.
283    #[default]
284    Relative,
285    /// The offset is computed relative to this item's closest positioned ancestor, if any.
286    /// Otherwise, it is placed relative to the origin.
287    /// No space is created for the item in the page layout, and its size will not be altered.
288    ///
289    /// WARNING: to opt-out of layouting entirely, you must use [`Display::None`] instead on your [`Style`] object.
290    Absolute,
291}
292
293#[cfg(feature = "parse")]
294crate::util::parse::impl_parse_for_keyword_enum!(Position,
295    "relative" => Relative,
296    "absolute" => Absolute,
297);
298
299/// Specifies whether size styles for this node are assigned to the node's "content box" or "border box"
300///
301/// - The "content box" is the node's inner size excluding padding, border and margin
302/// - The "border box" is the node's outer size including padding and border (but still excluding margin)
303///
304/// This property modifies the application of the following styles:
305///
306///   - `size`
307///   - `min_size`
308///   - `max_size`
309///   - `flex_basis`
310///
311/// See <https://developer.mozilla.org/en-US/docs/Web/CSS/box-sizing>
312#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
313#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
314pub enum BoxSizing {
315    /// Size styles such size, min_size, max_size specify the box's "border box" (the size excluding margin but including padding/border)
316    #[default]
317    BorderBox,
318    /// Size styles such size, min_size, max_size specify the box's "content box" (the size excluding padding/border/margin)
319    ContentBox,
320}
321
322#[cfg(feature = "parse")]
323crate::util::parse::impl_parse_for_keyword_enum!(BoxSizing,
324    "border-box" => BorderBox,
325    "content-box" => ContentBox,
326);
327
328/// How children overflowing their container should affect layout
329///
330/// In CSS the primary effect of this property is to control whether contents of a parent container that overflow that container should
331/// be displayed anyway, be clipped, or trigger the container to become a scroll container. However it also has secondary effects on layout,
332/// the main ones being:
333///
334///   - The automatic minimum size Flexbox/CSS Grid items with non-`Visible` overflow is `0` rather than being content based
335///   - `Overflow::Scroll` nodes have space in the layout reserved for a scrollbar (width controlled by the `scrollbar_width` property)
336///
337/// In Taffy, we only implement the layout related secondary effects as we are not concerned with drawing/painting. The amount of space reserved for
338/// a scrollbar is controlled by the `scrollbar_width` property. If this is `0` then `Scroll` behaves identically to `Hidden`.
339///
340/// <https://developer.mozilla.org/en-US/docs/Web/CSS/overflow>
341#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
342#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
343pub enum Overflow {
344    /// The automatic minimum size of this node as a flexbox/grid item should be based on the size of its content.
345    /// Content that overflows this node *should* contribute to the scroll region of its parent.
346    #[default]
347    Visible,
348    /// The automatic minimum size of this node as a flexbox/grid item should be based on the size of its content.
349    /// Content that overflows this node should *not* contribute to the scroll region of its parent.
350    Clip,
351    /// The automatic minimum size of this node as a flexbox/grid item should be `0`.
352    /// Content that overflows this node should *not* contribute to the scroll region of its parent.
353    Hidden,
354    /// The automatic minimum size of this node as a flexbox/grid item should be `0`. Additionally, space should be reserved
355    /// for a scrollbar. The amount of space reserved is controlled by the `scrollbar_width` property.
356    /// Content that overflows this node should *not* contribute to the scroll region of its parent.
357    Scroll,
358}
359
360impl Overflow {
361    /// Returns true for overflow modes that contain their contents (`Overflow::Hidden`, `Overflow::Scroll`, `Overflow::Auto`)
362    /// or else false for overflow modes that allow their contains to spill (`Overflow::Visible`).
363    #[inline(always)]
364    pub fn is_scroll_container(self) -> bool {
365        match self {
366            Self::Visible | Self::Clip => false,
367            Self::Hidden | Self::Scroll => true,
368        }
369    }
370
371    /// Returns `Some(0.0)` if the overflow mode would cause the automatic minimum size of a Flexbox or CSS Grid item
372    /// to be `0`. Else returns None.
373    #[inline(always)]
374    pub(crate) fn maybe_into_automatic_min_size(self) -> Option<f32> {
375        match self.is_scroll_container() {
376            true => Some(0.0),
377            false => None,
378        }
379    }
380}
381
382#[cfg(feature = "parse")]
383crate::util::parse::impl_parse_for_keyword_enum!(Overflow,
384    "visible" => Visible,
385    "hidden" => Hidden,
386    "clip" => Clip,
387    "scroll" => Scroll,
388);
389
390/// Sets the direction of text, table and grid columns, and horizontal overflow.
391/// <https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/direction>
392#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
393#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
394pub enum Direction {
395    #[default]
396    /// Left-to-right
397    Ltr,
398    /// Right-to-left
399    Rtl,
400}
401
402impl Direction {
403    /// Returns true if the direction is right-to-left
404    #[inline]
405    pub(crate) fn is_rtl(&self) -> bool {
406        matches!(self, Direction::Rtl)
407    }
408}
409
410#[cfg(feature = "parse")]
411crate::util::parse::impl_parse_for_keyword_enum!(Direction,
412    "ltr" => Ltr,
413    "rtl" => Rtl,
414);
415
416/// A typed representation of the CSS style information for a single node.
417///
418/// The most important idea in flexbox is the notion of a "main" and "cross" axis, which are always perpendicular to each other.
419/// The orientation of these axes are controlled via the [`FlexDirection`] field of this struct.
420///
421/// This struct follows the [CSS equivalent](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox) directly;
422/// information about the behavior on the web should transfer directly.
423///
424/// Detailed information about the exact behavior of each of these fields
425/// can be found on [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS) by searching for the field name.
426/// The distinction between margin, padding and border is explained well in
427/// this [introduction to the box model](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Model/Introduction_to_the_CSS_box_model).
428///
429/// If the behavior does not match the flexbox layout algorithm on the web, please file a bug!
430#[derive(Clone, PartialEq, Debug)]
431#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
432#[cfg_attr(feature = "serde", serde(default))]
433pub struct Style<S: CheapCloneStr = DefaultCheapStr> {
434    /// This is a dummy field which is necessary to make Taffy compile with the `grid` feature disabled
435    /// It should always be set to `core::marker::PhantomData`.
436    pub dummy: core::marker::PhantomData<S>,
437    /// What layout strategy should be used?
438    pub display: Display,
439    /// Whether a child is display:table or not. This affects children of block layouts.
440    /// This should really be part of `Display`, but it is currently seperate because table layout isn't implemented
441    pub item_is_table: bool,
442    /// Is it a replaced element like an image or form field?
443    /// <https://drafts.csswg.org/css-sizing-3/#min-content-zero>
444    pub item_is_replaced: bool,
445    /// Should size styles apply to the content box or the border box of the node
446    pub box_sizing: BoxSizing,
447    /// Sets the direction of text, table and grid columns, and horizontal overflow.
448    pub direction: Direction,
449
450    // Overflow properties
451    /// How children overflowing their container should affect layout
452    pub overflow: Point<Overflow>,
453    /// How much space (in points) should be reserved for the scrollbars of `Overflow::Scroll` and `Overflow::Auto` nodes.
454    pub scrollbar_width: f32,
455
456    #[cfg(feature = "float_layout")]
457    /// Should the box be floated
458    pub float: Float,
459    #[cfg(feature = "float_layout")]
460    /// Should the box clear floats
461    pub clear: Clear,
462
463    // Position properties
464    /// What should the `position` value of this struct use as a base offset?
465    pub position: Position,
466    /// How should the position of this element be tweaked relative to the layout defined?
467    #[cfg_attr(feature = "serde", serde(default = "style_helpers::auto"))]
468    pub inset: Rect<LengthPercentageAuto>,
469
470    // Size properties
471    /// Sets the initial size of the item
472    #[cfg_attr(feature = "serde", serde(default = "style_helpers::auto"))]
473    pub size: Size<Dimension>,
474    /// Controls the minimum size of the item
475    #[cfg_attr(feature = "serde", serde(default = "style_helpers::auto"))]
476    pub min_size: Size<Dimension>,
477    /// Controls the maximum size of the item
478    #[cfg_attr(feature = "serde", serde(default = "style_helpers::auto"))]
479    pub max_size: Size<Dimension>,
480    /// Sets the preferred aspect ratio for the item
481    ///
482    /// The ratio is calculated as width divided by height.
483    pub aspect_ratio: Option<f32>,
484
485    // Spacing Properties
486    /// How large should the margin be on each side?
487    #[cfg_attr(feature = "serde", serde(default = "style_helpers::zero"))]
488    pub margin: Rect<LengthPercentageAuto>,
489    /// How large should the padding be on each side?
490    #[cfg_attr(feature = "serde", serde(default = "style_helpers::zero"))]
491    pub padding: Rect<LengthPercentage>,
492    /// How large should the border be on each side?
493    #[cfg_attr(feature = "serde", serde(default = "style_helpers::zero"))]
494    pub border: Rect<LengthPercentage>,
495
496    // Alignment properties
497    /// How this node's children aligned in the cross/block axis?
498    #[cfg(any(feature = "flexbox", feature = "grid"))]
499    pub align_items: Option<AlignItems>,
500    /// How this node should be aligned in the cross/block axis
501    /// Falls back to the parents [`AlignItems`] if not set
502    #[cfg(any(feature = "flexbox", feature = "grid"))]
503    pub align_self: Option<AlignSelf>,
504    /// How this node's children should be aligned in the inline axis
505    #[cfg(feature = "grid")]
506    pub justify_items: Option<AlignItems>,
507    /// How this node should be aligned in the inline axis
508    /// Falls back to the parents [`JustifyItems`] if not set
509    #[cfg(feature = "grid")]
510    pub justify_self: Option<AlignSelf>,
511    /// How should content contained within this item be aligned in the cross/block axis
512    #[cfg(any(feature = "flexbox", feature = "grid", feature = "block_layout"))]
513    pub align_content: Option<AlignContent>,
514    /// How should content contained within this item be aligned in the main/inline axis
515    #[cfg(any(feature = "flexbox", feature = "grid"))]
516    pub justify_content: Option<JustifyContent>,
517    /// How large should the gaps between items in a grid or flex container be?
518    #[cfg(any(feature = "flexbox", feature = "grid"))]
519    #[cfg_attr(feature = "serde", serde(default = "style_helpers::zero"))]
520    pub gap: Size<LengthPercentage>,
521
522    // Block container properties
523    /// How items elements should aligned in the inline axis
524    #[cfg(feature = "block_layout")]
525    pub text_align: TextAlign,
526
527    // Flexbox container properties
528    /// Which direction does the main axis flow in?
529    #[cfg(feature = "flexbox")]
530    pub flex_direction: FlexDirection,
531    /// Should elements wrap, or stay in a single line?
532    #[cfg(feature = "flexbox")]
533    pub flex_wrap: FlexWrap,
534
535    // Flexbox item properties
536    /// Sets the initial main axis size of the item
537    #[cfg(feature = "flexbox")]
538    pub flex_basis: Dimension,
539    /// The relative rate at which this item grows when it is expanding to fill space
540    ///
541    /// 0.0 is the default value, and this value must be positive.
542    #[cfg(feature = "flexbox")]
543    pub flex_grow: f32,
544    /// The relative rate at which this item shrinks when it is contracting to fit into space
545    ///
546    /// 1.0 is the default value, and this value must be positive.
547    #[cfg(feature = "flexbox")]
548    pub flex_shrink: f32,
549
550    // Grid container properies
551    /// Defines the track sizing functions (heights) of the grid rows
552    #[cfg(feature = "grid")]
553    pub grid_template_rows: GridTrackVec<GridTemplateComponent<S>>,
554    /// Defines the track sizing functions (widths) of the grid columns
555    #[cfg(feature = "grid")]
556    pub grid_template_columns: GridTrackVec<GridTemplateComponent<S>>,
557    /// Defines the size of implicitly created rows
558    #[cfg(feature = "grid")]
559    pub grid_auto_rows: GridTrackVec<TrackSizingFunction>,
560    /// Defined the size of implicitly created columns
561    #[cfg(feature = "grid")]
562    pub grid_auto_columns: GridTrackVec<TrackSizingFunction>,
563    /// Controls how items get placed into the grid for auto-placed items
564    #[cfg(feature = "grid")]
565    pub grid_auto_flow: GridAutoFlow,
566
567    // Grid container named properties
568    /// Defines the rectangular grid areas
569    #[cfg(feature = "grid")]
570    pub grid_template_areas: GridTrackVec<GridTemplateArea<S>>,
571    /// The named lines between the columns
572    #[cfg(feature = "grid")]
573    pub grid_template_column_names: GridTrackVec<GridTrackVec<S>>,
574    /// The named lines between the rows
575    #[cfg(feature = "grid")]
576    pub grid_template_row_names: GridTrackVec<GridTrackVec<S>>,
577
578    // Grid child properties
579    /// Defines which row in the grid the item should start and end at
580    #[cfg(feature = "grid")]
581    pub grid_row: Line<GridPlacement<S>>,
582    /// Defines which column in the grid the item should start and end at
583    #[cfg(feature = "grid")]
584    pub grid_column: Line<GridPlacement<S>>,
585}
586
587impl<S: CheapCloneStr> Style<S> {
588    /// The [`Default`] layout, in a form that can be used in const functions
589    pub const DEFAULT: Style<S> = Style {
590        dummy: core::marker::PhantomData,
591        display: Display::DEFAULT,
592        item_is_table: false,
593        item_is_replaced: false,
594        box_sizing: BoxSizing::BorderBox,
595        direction: Direction::Ltr,
596        overflow: Point { x: Overflow::Visible, y: Overflow::Visible },
597        scrollbar_width: 0.0,
598        #[cfg(feature = "float_layout")]
599        float: Float::None,
600        #[cfg(feature = "float_layout")]
601        clear: Clear::None,
602        position: Position::Relative,
603        inset: Rect::auto(),
604        margin: Rect::zero(),
605        padding: Rect::zero(),
606        border: Rect::zero(),
607        size: Size::auto(),
608        min_size: Size::auto(),
609        max_size: Size::auto(),
610        aspect_ratio: None,
611        #[cfg(any(feature = "flexbox", feature = "grid"))]
612        gap: Size::zero(),
613        // Alignment
614        #[cfg(any(feature = "flexbox", feature = "grid"))]
615        align_items: None,
616        #[cfg(any(feature = "flexbox", feature = "grid"))]
617        align_self: None,
618        #[cfg(feature = "grid")]
619        justify_items: None,
620        #[cfg(feature = "grid")]
621        justify_self: None,
622        #[cfg(any(feature = "flexbox", feature = "grid", feature = "block_layout"))]
623        align_content: None,
624        #[cfg(any(feature = "flexbox", feature = "grid"))]
625        justify_content: None,
626        // Block
627        #[cfg(feature = "block_layout")]
628        text_align: TextAlign::Auto,
629        // Flexbox
630        #[cfg(feature = "flexbox")]
631        flex_direction: FlexDirection::Row,
632        #[cfg(feature = "flexbox")]
633        flex_wrap: FlexWrap::NoWrap,
634        #[cfg(feature = "flexbox")]
635        flex_grow: 0.0,
636        #[cfg(feature = "flexbox")]
637        flex_shrink: 1.0,
638        #[cfg(feature = "flexbox")]
639        flex_basis: Dimension::AUTO,
640        // Grid
641        #[cfg(feature = "grid")]
642        grid_template_rows: GridTrackVec::new(),
643        #[cfg(feature = "grid")]
644        grid_template_columns: GridTrackVec::new(),
645        #[cfg(feature = "grid")]
646        grid_template_areas: GridTrackVec::new(),
647        #[cfg(feature = "grid")]
648        grid_template_column_names: GridTrackVec::new(),
649        #[cfg(feature = "grid")]
650        grid_template_row_names: GridTrackVec::new(),
651        #[cfg(feature = "grid")]
652        grid_auto_rows: GridTrackVec::new(),
653        #[cfg(feature = "grid")]
654        grid_auto_columns: GridTrackVec::new(),
655        #[cfg(feature = "grid")]
656        grid_auto_flow: GridAutoFlow::Row,
657        #[cfg(feature = "grid")]
658        grid_row: Line { start: GridPlacement::<S>::Auto, end: GridPlacement::<S>::Auto },
659        #[cfg(feature = "grid")]
660        grid_column: Line { start: GridPlacement::<S>::Auto, end: GridPlacement::<S>::Auto },
661    };
662}
663
664impl<S: CheapCloneStr> Default for Style<S> {
665    fn default() -> Self {
666        Style::DEFAULT
667    }
668}
669
670impl<S: CheapCloneStr> CoreStyle for Style<S> {
671    type CustomIdent = S;
672
673    #[inline(always)]
674    fn box_generation_mode(&self) -> BoxGenerationMode {
675        match self.display {
676            Display::None => BoxGenerationMode::None,
677            _ => BoxGenerationMode::Normal,
678        }
679    }
680    #[inline(always)]
681    #[cfg(feature = "block_layout")]
682    fn is_block(&self) -> bool {
683        matches!(self.display, Display::Block)
684    }
685    #[inline(always)]
686    fn is_compressible_replaced(&self) -> bool {
687        self.item_is_replaced
688    }
689    #[inline(always)]
690    fn box_sizing(&self) -> BoxSizing {
691        self.box_sizing
692    }
693    #[inline(always)]
694    fn direction(&self) -> Direction {
695        self.direction
696    }
697    #[inline(always)]
698    fn overflow(&self) -> Point<Overflow> {
699        self.overflow
700    }
701    #[inline(always)]
702    fn scrollbar_width(&self) -> f32 {
703        self.scrollbar_width
704    }
705    #[inline(always)]
706    fn position(&self) -> Position {
707        self.position
708    }
709    #[inline(always)]
710    fn inset(&self) -> Rect<LengthPercentageAuto> {
711        self.inset
712    }
713    #[inline(always)]
714    fn size(&self) -> Size<Dimension> {
715        self.size
716    }
717    #[inline(always)]
718    fn min_size(&self) -> Size<Dimension> {
719        self.min_size
720    }
721    #[inline(always)]
722    fn max_size(&self) -> Size<Dimension> {
723        self.max_size
724    }
725    #[inline(always)]
726    fn aspect_ratio(&self) -> Option<f32> {
727        self.aspect_ratio
728    }
729    #[inline(always)]
730    fn margin(&self) -> Rect<LengthPercentageAuto> {
731        self.margin
732    }
733    #[inline(always)]
734    fn padding(&self) -> Rect<LengthPercentage> {
735        self.padding
736    }
737    #[inline(always)]
738    fn border(&self) -> Rect<LengthPercentage> {
739        self.border
740    }
741}
742
743impl<T: CoreStyle> CoreStyle for &'_ T {
744    type CustomIdent = T::CustomIdent;
745
746    #[inline(always)]
747    fn box_generation_mode(&self) -> BoxGenerationMode {
748        (*self).box_generation_mode()
749    }
750    #[inline(always)]
751    fn is_block(&self) -> bool {
752        (*self).is_block()
753    }
754    #[inline(always)]
755    fn is_compressible_replaced(&self) -> bool {
756        (*self).is_compressible_replaced()
757    }
758    #[inline(always)]
759    fn box_sizing(&self) -> BoxSizing {
760        (*self).box_sizing()
761    }
762    #[inline(always)]
763    fn direction(&self) -> Direction {
764        (*self).direction()
765    }
766    #[inline(always)]
767    fn overflow(&self) -> Point<Overflow> {
768        (*self).overflow()
769    }
770    #[inline(always)]
771    fn scrollbar_width(&self) -> f32 {
772        (*self).scrollbar_width()
773    }
774    #[inline(always)]
775    fn position(&self) -> Position {
776        (*self).position()
777    }
778    #[inline(always)]
779    fn inset(&self) -> Rect<LengthPercentageAuto> {
780        (*self).inset()
781    }
782    #[inline(always)]
783    fn size(&self) -> Size<Dimension> {
784        (*self).size()
785    }
786    #[inline(always)]
787    fn min_size(&self) -> Size<Dimension> {
788        (*self).min_size()
789    }
790    #[inline(always)]
791    fn max_size(&self) -> Size<Dimension> {
792        (*self).max_size()
793    }
794    #[inline(always)]
795    fn aspect_ratio(&self) -> Option<f32> {
796        (*self).aspect_ratio()
797    }
798    #[inline(always)]
799    fn margin(&self) -> Rect<LengthPercentageAuto> {
800        (*self).margin()
801    }
802    #[inline(always)]
803    fn padding(&self) -> Rect<LengthPercentage> {
804        (*self).padding()
805    }
806    #[inline(always)]
807    fn border(&self) -> Rect<LengthPercentage> {
808        (*self).border()
809    }
810}
811
812#[cfg(feature = "block_layout")]
813impl<S: CheapCloneStr> BlockContainerStyle for Style<S> {
814    #[inline(always)]
815    fn text_align(&self) -> TextAlign {
816        self.text_align
817    }
818
819    #[inline(always)]
820    fn align_content(&self) -> Option<AlignContent> {
821        self.align_content
822    }
823}
824
825#[cfg(feature = "block_layout")]
826impl<T: BlockContainerStyle> BlockContainerStyle for &'_ T {
827    #[inline(always)]
828    fn text_align(&self) -> TextAlign {
829        (*self).text_align()
830    }
831
832    #[inline(always)]
833    fn align_content(&self) -> Option<AlignContent> {
834        (*self).align_content()
835    }
836}
837
838#[cfg(feature = "block_layout")]
839impl<S: CheapCloneStr> BlockItemStyle for Style<S> {
840    #[inline(always)]
841    fn is_table(&self) -> bool {
842        self.item_is_table
843    }
844
845    #[cfg(feature = "float_layout")]
846    #[inline(always)]
847    fn float(&self) -> Float {
848        self.float
849    }
850
851    #[cfg(feature = "float_layout")]
852    #[inline(always)]
853    fn clear(&self) -> Clear {
854        self.clear
855    }
856}
857
858#[cfg(feature = "block_layout")]
859impl<T: BlockItemStyle> BlockItemStyle for &'_ T {
860    #[inline(always)]
861    fn is_table(&self) -> bool {
862        (*self).is_table()
863    }
864
865    #[cfg(feature = "float_layout")]
866    #[inline(always)]
867    fn float(&self) -> Float {
868        (*self).float()
869    }
870
871    #[cfg(feature = "float_layout")]
872    #[inline(always)]
873    fn clear(&self) -> Clear {
874        (*self).clear()
875    }
876}
877
878#[cfg(feature = "flexbox")]
879impl<S: CheapCloneStr> FlexboxContainerStyle for Style<S> {
880    #[inline(always)]
881    fn flex_direction(&self) -> FlexDirection {
882        self.flex_direction
883    }
884    #[inline(always)]
885    fn flex_wrap(&self) -> FlexWrap {
886        self.flex_wrap
887    }
888    #[inline(always)]
889    fn gap(&self) -> Size<LengthPercentage> {
890        self.gap
891    }
892    #[inline(always)]
893    fn align_content(&self) -> Option<AlignContent> {
894        self.align_content
895    }
896    #[inline(always)]
897    fn align_items(&self) -> Option<AlignItems> {
898        self.align_items
899    }
900    #[inline(always)]
901    fn justify_content(&self) -> Option<JustifyContent> {
902        self.justify_content
903    }
904}
905
906#[cfg(feature = "flexbox")]
907impl<T: FlexboxContainerStyle> FlexboxContainerStyle for &'_ T {
908    #[inline(always)]
909    fn flex_direction(&self) -> FlexDirection {
910        (*self).flex_direction()
911    }
912    #[inline(always)]
913    fn flex_wrap(&self) -> FlexWrap {
914        (*self).flex_wrap()
915    }
916    #[inline(always)]
917    fn gap(&self) -> Size<LengthPercentage> {
918        (*self).gap()
919    }
920    #[inline(always)]
921    fn align_content(&self) -> Option<AlignContent> {
922        (*self).align_content()
923    }
924    #[inline(always)]
925    fn align_items(&self) -> Option<AlignItems> {
926        (*self).align_items()
927    }
928    #[inline(always)]
929    fn justify_content(&self) -> Option<JustifyContent> {
930        (*self).justify_content()
931    }
932}
933
934#[cfg(feature = "flexbox")]
935impl<S: CheapCloneStr> FlexboxItemStyle for Style<S> {
936    #[inline(always)]
937    fn flex_basis(&self) -> Dimension {
938        self.flex_basis
939    }
940    #[inline(always)]
941    fn flex_grow(&self) -> f32 {
942        self.flex_grow
943    }
944    #[inline(always)]
945    fn flex_shrink(&self) -> f32 {
946        self.flex_shrink
947    }
948    #[inline(always)]
949    fn align_self(&self) -> Option<AlignSelf> {
950        self.align_self
951    }
952}
953
954#[cfg(feature = "flexbox")]
955impl<T: FlexboxItemStyle> FlexboxItemStyle for &'_ T {
956    #[inline(always)]
957    fn flex_basis(&self) -> Dimension {
958        (*self).flex_basis()
959    }
960    #[inline(always)]
961    fn flex_grow(&self) -> f32 {
962        (*self).flex_grow()
963    }
964    #[inline(always)]
965    fn flex_shrink(&self) -> f32 {
966        (*self).flex_shrink()
967    }
968    #[inline(always)]
969    fn align_self(&self) -> Option<AlignSelf> {
970        (*self).align_self()
971    }
972}
973
974#[cfg(feature = "grid")]
975impl<S: CheapCloneStr> GridContainerStyle for Style<S> {
976    type Repetition<'a>
977        = &'a GridTemplateRepetition<S>
978    where
979        Self: 'a;
980
981    type TemplateTrackList<'a>
982        = core::iter::Map<
983        core::slice::Iter<'a, GridTemplateComponent<S>>,
984        fn(&'a GridTemplateComponent<S>) -> GenericGridTemplateComponent<S, &'a GridTemplateRepetition<S>>,
985    >
986    where
987        Self: 'a;
988
989    type AutoTrackList<'a>
990        = core::iter::Copied<core::slice::Iter<'a, TrackSizingFunction>>
991    where
992        Self: 'a;
993
994    #[cfg(feature = "grid")]
995    type TemplateLineNames<'a>
996        = core::iter::Map<core::slice::Iter<'a, GridTrackVec<S>>, fn(&GridTrackVec<S>) -> core::slice::Iter<'_, S>>
997    where
998        Self: 'a;
999    #[cfg(feature = "grid")]
1000    type GridTemplateAreas<'a>
1001        = core::iter::Cloned<core::slice::Iter<'a, GridTemplateArea<S>>>
1002    where
1003        Self: 'a;
1004
1005    #[inline(always)]
1006    fn grid_template_rows(&self) -> Option<Self::TemplateTrackList<'_>> {
1007        Some(self.grid_template_rows.iter().map(|c| c.as_component_ref()))
1008    }
1009    #[inline(always)]
1010    fn grid_template_columns(&self) -> Option<Self::TemplateTrackList<'_>> {
1011        Some(self.grid_template_columns.iter().map(|c| c.as_component_ref()))
1012    }
1013    #[inline(always)]
1014    fn grid_auto_rows(&self) -> Self::AutoTrackList<'_> {
1015        self.grid_auto_rows.iter().copied()
1016    }
1017    #[inline(always)]
1018    fn grid_auto_columns(&self) -> Self::AutoTrackList<'_> {
1019        self.grid_auto_columns.iter().copied()
1020    }
1021    #[inline(always)]
1022    fn grid_auto_flow(&self) -> GridAutoFlow {
1023        self.grid_auto_flow
1024    }
1025    #[inline(always)]
1026    fn gap(&self) -> Size<LengthPercentage> {
1027        self.gap
1028    }
1029    #[inline(always)]
1030    fn align_content(&self) -> Option<AlignContent> {
1031        self.align_content
1032    }
1033    #[inline(always)]
1034    fn justify_content(&self) -> Option<JustifyContent> {
1035        self.justify_content
1036    }
1037    #[inline(always)]
1038    fn align_items(&self) -> Option<AlignItems> {
1039        self.align_items
1040    }
1041    #[inline(always)]
1042    fn justify_items(&self) -> Option<AlignItems> {
1043        self.justify_items
1044    }
1045
1046    #[inline(always)]
1047    #[cfg(feature = "grid")]
1048    fn grid_template_areas(&self) -> Option<Self::GridTemplateAreas<'_>> {
1049        Some(self.grid_template_areas.iter().cloned())
1050    }
1051
1052    #[inline(always)]
1053    #[cfg(feature = "grid")]
1054    fn grid_template_column_names(&self) -> Option<Self::TemplateLineNames<'_>> {
1055        Some(self.grid_template_column_names.iter().map(|names| names.iter()))
1056    }
1057
1058    #[inline(always)]
1059    #[cfg(feature = "grid")]
1060    fn grid_template_row_names(&self) -> Option<Self::TemplateLineNames<'_>> {
1061        Some(self.grid_template_row_names.iter().map(|names| names.iter()))
1062    }
1063}
1064
1065#[cfg(feature = "grid")]
1066impl<T: GridContainerStyle> GridContainerStyle for &'_ T {
1067    type Repetition<'a>
1068        = T::Repetition<'a>
1069    where
1070        Self: 'a;
1071
1072    type TemplateTrackList<'a>
1073        = T::TemplateTrackList<'a>
1074    where
1075        Self: 'a;
1076
1077    type AutoTrackList<'a>
1078        = T::AutoTrackList<'a>
1079    where
1080        Self: 'a;
1081
1082    /// The type returned by grid_template_row_names and grid_template_column_names
1083    #[cfg(feature = "grid")]
1084    type TemplateLineNames<'a>
1085        = T::TemplateLineNames<'a>
1086    where
1087        Self: 'a;
1088    #[cfg(feature = "grid")]
1089    type GridTemplateAreas<'a>
1090        = T::GridTemplateAreas<'a>
1091    where
1092        Self: 'a;
1093
1094    #[inline(always)]
1095    fn grid_template_rows(&self) -> Option<Self::TemplateTrackList<'_>> {
1096        (*self).grid_template_rows()
1097    }
1098    #[inline(always)]
1099    fn grid_template_columns(&self) -> Option<Self::TemplateTrackList<'_>> {
1100        (*self).grid_template_columns()
1101    }
1102    #[inline(always)]
1103    fn grid_auto_rows(&self) -> Self::AutoTrackList<'_> {
1104        (*self).grid_auto_rows()
1105    }
1106    #[inline(always)]
1107    fn grid_auto_columns(&self) -> Self::AutoTrackList<'_> {
1108        (*self).grid_auto_columns()
1109    }
1110    #[cfg(feature = "grid")]
1111    #[inline(always)]
1112    fn grid_template_areas(&self) -> Option<Self::GridTemplateAreas<'_>> {
1113        (*self).grid_template_areas()
1114    }
1115    #[cfg(feature = "grid")]
1116    #[inline(always)]
1117    fn grid_template_column_names(&self) -> Option<Self::TemplateLineNames<'_>> {
1118        (*self).grid_template_column_names()
1119    }
1120    #[cfg(feature = "grid")]
1121    #[inline(always)]
1122    fn grid_template_row_names(&self) -> Option<Self::TemplateLineNames<'_>> {
1123        (*self).grid_template_row_names()
1124    }
1125    #[inline(always)]
1126    fn grid_auto_flow(&self) -> GridAutoFlow {
1127        (*self).grid_auto_flow()
1128    }
1129    #[inline(always)]
1130    fn gap(&self) -> Size<LengthPercentage> {
1131        (*self).gap()
1132    }
1133    #[inline(always)]
1134    fn align_content(&self) -> Option<AlignContent> {
1135        (*self).align_content()
1136    }
1137    #[inline(always)]
1138    fn justify_content(&self) -> Option<JustifyContent> {
1139        (*self).justify_content()
1140    }
1141    #[inline(always)]
1142    fn align_items(&self) -> Option<AlignItems> {
1143        (*self).align_items()
1144    }
1145    #[inline(always)]
1146    fn justify_items(&self) -> Option<AlignItems> {
1147        (*self).justify_items()
1148    }
1149}
1150
1151#[cfg(feature = "grid")]
1152impl<S: CheapCloneStr> GridItemStyle for Style<S> {
1153    #[inline(always)]
1154    fn grid_row(&self) -> Line<GridPlacement<S>> {
1155        // TODO: Investigate eliminating clone
1156        self.grid_row.clone()
1157    }
1158    #[inline(always)]
1159    fn grid_column(&self) -> Line<GridPlacement<S>> {
1160        // TODO: Investigate eliminating clone
1161        self.grid_column.clone()
1162    }
1163    #[inline(always)]
1164    fn align_self(&self) -> Option<AlignSelf> {
1165        self.align_self
1166    }
1167    #[inline(always)]
1168    fn justify_self(&self) -> Option<AlignSelf> {
1169        self.justify_self
1170    }
1171}
1172
1173#[cfg(feature = "grid")]
1174impl<T: GridItemStyle> GridItemStyle for &'_ T {
1175    #[inline(always)]
1176    fn grid_row(&self) -> Line<GridPlacement<Self::CustomIdent>> {
1177        (*self).grid_row()
1178    }
1179    #[inline(always)]
1180    fn grid_column(&self) -> Line<GridPlacement<Self::CustomIdent>> {
1181        (*self).grid_column()
1182    }
1183    #[inline(always)]
1184    fn align_self(&self) -> Option<AlignSelf> {
1185        (*self).align_self()
1186    }
1187    #[inline(always)]
1188    fn justify_self(&self) -> Option<AlignSelf> {
1189        (*self).justify_self()
1190    }
1191}
1192
1193#[cfg(test)]
1194mod tests {
1195    use std::sync::Arc;
1196
1197    use super::Style;
1198    use crate::sys::DefaultCheapStr;
1199    use crate::{geometry::*, style_helpers::TaffyAuto as _};
1200
1201    #[test]
1202    fn defaults_match() {
1203        #[cfg(feature = "grid")]
1204        use super::GridPlacement;
1205
1206        let old_defaults: Style<DefaultCheapStr> = Style {
1207            dummy: core::marker::PhantomData,
1208            display: Default::default(),
1209            item_is_table: false,
1210            item_is_replaced: false,
1211            box_sizing: Default::default(),
1212            #[cfg(feature = "float_layout")]
1213            float: Default::default(),
1214            #[cfg(feature = "float_layout")]
1215            clear: Default::default(),
1216            direction: Default::default(),
1217            overflow: Default::default(),
1218            scrollbar_width: 0.0,
1219            position: Default::default(),
1220            #[cfg(feature = "flexbox")]
1221            flex_direction: Default::default(),
1222            #[cfg(feature = "flexbox")]
1223            flex_wrap: Default::default(),
1224            #[cfg(any(feature = "flexbox", feature = "grid"))]
1225            align_items: Default::default(),
1226            #[cfg(any(feature = "flexbox", feature = "grid"))]
1227            align_self: Default::default(),
1228            #[cfg(feature = "grid")]
1229            justify_items: Default::default(),
1230            #[cfg(feature = "grid")]
1231            justify_self: Default::default(),
1232            #[cfg(any(feature = "flexbox", feature = "grid", feature = "block_layout"))]
1233            align_content: Default::default(),
1234            #[cfg(any(feature = "flexbox", feature = "grid"))]
1235            justify_content: Default::default(),
1236            inset: Rect::auto(),
1237            margin: Rect::zero(),
1238            padding: Rect::zero(),
1239            border: Rect::zero(),
1240            gap: Size::zero(),
1241            #[cfg(feature = "block_layout")]
1242            text_align: Default::default(),
1243            #[cfg(feature = "flexbox")]
1244            flex_grow: 0.0,
1245            #[cfg(feature = "flexbox")]
1246            flex_shrink: 1.0,
1247            #[cfg(feature = "flexbox")]
1248            flex_basis: super::Dimension::AUTO,
1249            size: Size::auto(),
1250            min_size: Size::auto(),
1251            max_size: Size::auto(),
1252            aspect_ratio: Default::default(),
1253            #[cfg(feature = "grid")]
1254            grid_template_rows: Default::default(),
1255            #[cfg(feature = "grid")]
1256            grid_template_columns: Default::default(),
1257            #[cfg(feature = "grid")]
1258            grid_template_row_names: Default::default(),
1259            #[cfg(feature = "grid")]
1260            grid_template_column_names: Default::default(),
1261            #[cfg(feature = "grid")]
1262            grid_template_areas: Default::default(),
1263            #[cfg(feature = "grid")]
1264            grid_auto_rows: Default::default(),
1265            #[cfg(feature = "grid")]
1266            grid_auto_columns: Default::default(),
1267            #[cfg(feature = "grid")]
1268            grid_auto_flow: Default::default(),
1269            #[cfg(feature = "grid")]
1270            grid_row: Line { start: GridPlacement::Auto, end: GridPlacement::Auto },
1271            #[cfg(feature = "grid")]
1272            grid_column: Line { start: GridPlacement::Auto, end: GridPlacement::Auto },
1273        };
1274
1275        assert_eq!(Style::DEFAULT, Style::<DefaultCheapStr>::default());
1276        assert_eq!(Style::DEFAULT, old_defaults);
1277    }
1278
1279    // NOTE: Please feel free the update the sizes in this test as required. This test is here to prevent unintentional size changes
1280    // and to serve as accurate up-to-date documentation on the sizes.
1281    #[test]
1282    fn style_sizes() {
1283        use super::*;
1284        type S = crate::sys::DefaultCheapStr;
1285
1286        fn assert_type_size<T>(expected_size: usize) {
1287            let name = ::core::any::type_name::<T>();
1288            let name = name.replace("taffy::geometry::", "");
1289            let name = name.replace("taffy::style::dimension::", "");
1290            let name = name.replace("taffy::style::alignment::", "");
1291            let name = name.replace("taffy::style::flex::", "");
1292            let name = name.replace("taffy::style::grid::", "");
1293
1294            assert_eq!(
1295                ::core::mem::size_of::<T>(),
1296                expected_size,
1297                "Expected {} for be {} byte(s) but it was {} byte(s)",
1298                name,
1299                expected_size,
1300                ::core::mem::size_of::<T>(),
1301            );
1302        }
1303
1304        // Display and Position
1305        assert_type_size::<Display>(1);
1306        assert_type_size::<BoxSizing>(1);
1307        assert_type_size::<Position>(1);
1308        assert_type_size::<Overflow>(1);
1309
1310        // Dimensions and aggregations of Dimensions
1311        assert_type_size::<f32>(4);
1312        assert_type_size::<LengthPercentage>(8);
1313        assert_type_size::<LengthPercentageAuto>(8);
1314        assert_type_size::<Dimension>(8);
1315        assert_type_size::<Size<LengthPercentage>>(16);
1316        assert_type_size::<Size<LengthPercentageAuto>>(16);
1317        assert_type_size::<Size<Dimension>>(16);
1318        assert_type_size::<Rect<LengthPercentage>>(32);
1319        assert_type_size::<Rect<LengthPercentageAuto>>(32);
1320        assert_type_size::<Rect<Dimension>>(32);
1321
1322        // Alignment — `AlignContent` and `AlignItems` are structs of two `#[repr(u8)]` enums
1323        // (position keyword + safety modifier). Niche-packing in the safety byte (only 2 of
1324        // 256 values used) lets `Option<_>` stay the same size as the bare struct.
1325        assert_type_size::<AlignContentKeyword>(1);
1326        assert_type_size::<AlignItemsKeyword>(1);
1327        assert_type_size::<AlignmentSafety>(1);
1328        assert_type_size::<AlignContent>(2);
1329        assert_type_size::<AlignItems>(2);
1330        assert_type_size::<Option<AlignItems>>(2);
1331        assert_type_size::<Option<AlignContent>>(2);
1332
1333        // Flexbox Container
1334        assert_type_size::<FlexDirection>(1);
1335        assert_type_size::<FlexWrap>(1);
1336
1337        // CSS Grid Container
1338        assert_type_size::<GridAutoFlow>(1);
1339        assert_type_size::<MinTrackSizingFunction>(8);
1340        assert_type_size::<MaxTrackSizingFunction>(8);
1341        assert_type_size::<TrackSizingFunction>(16);
1342        assert_type_size::<Vec<TrackSizingFunction>>(24);
1343        assert_type_size::<Vec<GridTemplateComponent<S>>>(24);
1344
1345        // String-type dependent (String)
1346        assert_type_size::<GridTemplateComponent<String>>(56);
1347        assert_type_size::<GridPlacement<String>>(32);
1348        assert_type_size::<Line<GridPlacement<String>>>(64);
1349        assert_type_size::<Style<String>>(544);
1350
1351        // String-type dependent (Arc<str>)
1352        assert_type_size::<GridTemplateComponent<Arc<str>>>(56);
1353        assert_type_size::<GridPlacement<Arc<str>>>(24);
1354        assert_type_size::<Line<GridPlacement<Arc<str>>>>(48);
1355        assert_type_size::<Style<Arc<str>>>(512);
1356    }
1357}