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