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