taffy/
geometry.rs

1//! Geometric primitives useful for layout
2
3use crate::util::sys::f32_max;
4use crate::CompactLength;
5use crate::{style::Dimension, util::sys::f32_min};
6use core::ops::{Add, Sub};
7
8#[cfg(feature = "flexbox")]
9use crate::style::FlexDirection;
10
11/// The simple absolute horizontal and vertical axis
12#[derive(Copy, Clone, Debug, PartialEq, Eq)]
13pub enum AbsoluteAxis {
14    /// The horizontal axis
15    Horizontal,
16    /// The vertical axis
17    Vertical,
18}
19
20impl AbsoluteAxis {
21    /// Returns the other variant of the enum
22    #[inline]
23    pub const fn other_axis(&self) -> Self {
24        match *self {
25            AbsoluteAxis::Horizontal => AbsoluteAxis::Vertical,
26            AbsoluteAxis::Vertical => AbsoluteAxis::Horizontal,
27        }
28    }
29}
30
31impl<T> Size<T> {
32    #[inline(always)]
33    /// Get either the width or height depending on the AbsoluteAxis passed in
34    pub fn get_abs(self, axis: AbsoluteAxis) -> T {
35        match axis {
36            AbsoluteAxis::Horizontal => self.width,
37            AbsoluteAxis::Vertical => self.height,
38        }
39    }
40}
41
42impl<T: Add> Rect<T> {
43    #[inline(always)]
44    /// Get either the width or height depending on the AbsoluteAxis passed in
45    pub fn grid_axis_sum(self, axis: AbsoluteAxis) -> <T as Add>::Output {
46        match axis {
47            AbsoluteAxis::Horizontal => self.left + self.right,
48            AbsoluteAxis::Vertical => self.top + self.bottom,
49        }
50    }
51}
52
53/// The CSS abstract axis
54/// <https://www.w3.org/TR/css-writing-modes-3/#abstract-axes>
55#[derive(Copy, Clone, Debug, PartialEq, Eq)]
56pub enum AbstractAxis {
57    /// The axis in the inline dimension, i.e. the horizontal axis in horizontal writing modes and the vertical axis in vertical writing modes.
58    Inline,
59    /// The axis in the block dimension, i.e. the vertical axis in horizontal writing modes and the horizontal axis in vertical writing modes.
60    Block,
61}
62
63impl AbstractAxis {
64    /// Returns the other variant of the enum
65    #[inline]
66    pub fn other(&self) -> AbstractAxis {
67        match *self {
68            AbstractAxis::Inline => AbstractAxis::Block,
69            AbstractAxis::Block => AbstractAxis::Inline,
70        }
71    }
72
73    /// Convert an `AbstractAxis` into an `AbsoluteAxis` naively assuming that the Inline axis is Horizontal
74    /// This is currently always true, but will change if Taffy ever implements the `writing_mode` property
75    #[inline]
76    pub fn as_abs_naive(&self) -> AbsoluteAxis {
77        match self {
78            AbstractAxis::Inline => AbsoluteAxis::Horizontal,
79            AbstractAxis::Block => AbsoluteAxis::Vertical,
80        }
81    }
82}
83
84/// Container that holds an item in each absolute axis without specifying
85/// what kind of item it is.
86#[derive(Clone, Copy, Debug, PartialEq, Eq)]
87pub(crate) struct InBothAbsAxis<T> {
88    /// The item in the horizontal axis
89    pub horizontal: T,
90    /// The item in the vertical axis
91    pub vertical: T,
92}
93
94impl<T: Copy> InBothAbsAxis<T> {
95    #[cfg(feature = "grid")]
96    /// Get the contained item based on the AbsoluteAxis passed
97    pub fn get(&self, axis: AbsoluteAxis) -> T {
98        match axis {
99            AbsoluteAxis::Horizontal => self.horizontal,
100            AbsoluteAxis::Vertical => self.vertical,
101        }
102    }
103}
104
105/// An axis-aligned UI rectangle
106#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
107#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
108pub struct Rect<T> {
109    /// This can represent either the x-coordinate of the starting edge,
110    /// or the amount of padding on the starting side.
111    ///
112    /// The starting edge is the left edge when working with LTR text,
113    /// and the right edge when working with RTL text.
114    pub left: T,
115    /// This can represent either the x-coordinate of the ending edge,
116    /// or the amount of padding on the ending side.
117    ///
118    /// The ending edge is the right edge when working with LTR text,
119    /// and the left edge when working with RTL text.
120    pub right: T,
121    /// This can represent either the y-coordinate of the top edge,
122    /// or the amount of padding on the top side.
123    pub top: T,
124    /// This can represent either the y-coordinate of the bottom edge,
125    /// or the amount of padding on the bottom side.
126    pub bottom: T,
127}
128
129impl<U, T: Add<U>> Add<Rect<U>> for Rect<T> {
130    type Output = Rect<T::Output>;
131
132    fn add(self, rhs: Rect<U>) -> Self::Output {
133        Rect {
134            left: self.left + rhs.left,
135            right: self.right + rhs.right,
136            top: self.top + rhs.top,
137            bottom: self.bottom + rhs.bottom,
138        }
139    }
140}
141
142impl<T> Rect<T> {
143    /// Applies the function `f` to all four sides of the rect
144    ///
145    /// When applied to the left and right sides, the width is used
146    /// as the second parameter of `f`.
147    /// When applied to the top or bottom sides, the height is used instead.
148    #[cfg(any(feature = "flexbox", feature = "block_layout"))]
149    pub(crate) fn zip_size<R, F, U>(self, size: Size<U>, f: F) -> Rect<R>
150    where
151        F: Fn(T, U) -> R,
152        U: Copy,
153    {
154        Rect {
155            left: f(self.left, size.width),
156            right: f(self.right, size.width),
157            top: f(self.top, size.height),
158            bottom: f(self.bottom, size.height),
159        }
160    }
161
162    /// Applies the function `f` to the left, right, top, and bottom properties
163    ///
164    /// This is used to transform a `Rect<T>` into a `Rect<R>`.
165    pub fn map<R, F>(self, f: F) -> Rect<R>
166    where
167        F: Fn(T) -> R,
168    {
169        Rect { left: f(self.left), right: f(self.right), top: f(self.top), bottom: f(self.bottom) }
170    }
171
172    /// Returns a `Line<T>` representing the left and right properties of the Rect
173    pub fn horizontal_components(self) -> Line<T> {
174        Line { start: self.left, end: self.right }
175    }
176
177    /// Returns a `Line<T>` containing the top and bottom properties of the Rect
178    pub fn vertical_components(self) -> Line<T> {
179        Line { start: self.top, end: self.bottom }
180    }
181}
182
183impl<T, U> Rect<T>
184where
185    T: Add<Output = U> + Copy + Clone,
186{
187    /// The sum of [`Rect.start`](Rect) and [`Rect.end`](Rect)
188    ///
189    /// This is typically used when computing total padding.
190    ///
191    /// **NOTE:** this is *not* the width of the rectangle.
192    #[inline(always)]
193    pub(crate) fn horizontal_axis_sum(&self) -> U {
194        self.left + self.right
195    }
196
197    /// The sum of [`Rect.top`](Rect) and [`Rect.bottom`](Rect)
198    ///
199    /// This is typically used when computing total padding.
200    ///
201    /// **NOTE:** this is *not* the height of the rectangle.
202    #[inline(always)]
203    pub(crate) fn vertical_axis_sum(&self) -> U {
204        self.top + self.bottom
205    }
206
207    /// Both horizontal_axis_sum and vertical_axis_sum as a Size<T>
208    ///
209    /// **NOTE:** this is *not* the width/height of the rectangle.
210    #[inline(always)]
211    #[allow(dead_code)] // Fixes spurious clippy warning: this function is used!
212    pub(crate) fn sum_axes(&self) -> Size<U> {
213        Size { width: self.horizontal_axis_sum(), height: self.vertical_axis_sum() }
214    }
215
216    /// The sum of the two fields of the [`Rect`] representing the main axis.
217    ///
218    /// This is typically used when computing total padding.
219    ///
220    /// If the [`FlexDirection`] is [`FlexDirection::Row`] or [`FlexDirection::RowReverse`], this is [`Rect::horizontal`].
221    /// Otherwise, this is [`Rect::vertical`].
222    #[cfg(feature = "flexbox")]
223    pub(crate) fn main_axis_sum(&self, direction: FlexDirection) -> U {
224        if direction.is_row() {
225            self.horizontal_axis_sum()
226        } else {
227            self.vertical_axis_sum()
228        }
229    }
230
231    /// The sum of the two fields of the [`Rect`] representing the cross axis.
232    ///
233    /// If the [`FlexDirection`] is [`FlexDirection::Row`] or [`FlexDirection::RowReverse`], this is [`Rect::vertical`].
234    /// Otherwise, this is [`Rect::horizontal`].
235    #[cfg(feature = "flexbox")]
236    pub(crate) fn cross_axis_sum(&self, direction: FlexDirection) -> U {
237        if direction.is_row() {
238            self.vertical_axis_sum()
239        } else {
240            self.horizontal_axis_sum()
241        }
242    }
243}
244
245impl<T> Rect<T>
246where
247    T: Copy + Clone,
248{
249    /// The `start` or `top` value of the [`Rect`], from the perspective of the main layout axis
250    #[cfg(feature = "flexbox")]
251    pub(crate) fn main_start(&self, direction: FlexDirection) -> T {
252        if direction.is_row() {
253            self.left
254        } else {
255            self.top
256        }
257    }
258
259    /// The `end` or `bottom` value of the [`Rect`], from the perspective of the main layout axis
260    #[cfg(feature = "flexbox")]
261    pub(crate) fn main_end(&self, direction: FlexDirection) -> T {
262        if direction.is_row() {
263            self.right
264        } else {
265            self.bottom
266        }
267    }
268
269    /// The `start` or `top` value of the [`Rect`], from the perspective of the cross layout axis
270    #[cfg(feature = "flexbox")]
271    pub(crate) fn cross_start(&self, direction: FlexDirection) -> T {
272        if direction.is_row() {
273            self.top
274        } else {
275            self.left
276        }
277    }
278
279    /// The `end` or `bottom` value of the [`Rect`], from the perspective of the main layout axis
280    #[cfg(feature = "flexbox")]
281    pub(crate) fn cross_end(&self, direction: FlexDirection) -> T {
282        if direction.is_row() {
283            self.bottom
284        } else {
285            self.right
286        }
287    }
288}
289
290impl Rect<f32> {
291    /// Creates a new Rect with `0.0` as all parameters
292    pub const ZERO: Rect<f32> = Self { left: 0.0, right: 0.0, top: 0.0, bottom: 0.0 };
293
294    /// Creates a new Rect
295    #[must_use]
296    pub const fn new(start: f32, end: f32, top: f32, bottom: f32) -> Self {
297        Self { left: start, right: end, top, bottom }
298    }
299}
300
301/// An abstract "line". Represents any type that has a start and an end
302#[derive(Debug, Copy, Clone, PartialEq, Eq)]
303#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
304#[cfg_attr(feature = "serde", serde(default))]
305pub struct Line<T> {
306    /// The start position of a line
307    pub start: T,
308    /// The end position of a line
309    pub end: T,
310}
311
312impl<T> Line<T> {
313    /// Applies the function `f` to both the width and height
314    ///
315    /// This is used to transform a `Line<T>` into a `Line<R>`.
316    pub fn map<R, F>(self, f: F) -> Line<R>
317    where
318        F: Fn(T) -> R,
319    {
320        Line { start: f(self.start), end: f(self.end) }
321    }
322}
323
324impl Line<bool> {
325    /// A `Line<bool>` with both start and end set to `true`
326    pub const TRUE: Self = Line { start: true, end: true };
327    /// A `Line<bool>` with both start and end set to `false`
328    pub const FALSE: Self = Line { start: false, end: false };
329}
330
331impl<T: Add + Copy> Line<T> {
332    /// Adds the start and end values together and returns the result
333    pub fn sum(&self) -> <T as Add>::Output {
334        self.start + self.end
335    }
336}
337
338/// The width and height of a [`Rect`]
339#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
340#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
341pub struct Size<T> {
342    /// The x extent of the rectangle
343    pub width: T,
344    /// The y extent of the rectangle
345    pub height: T,
346}
347
348// Generic Add impl for Size<T> + Size<U> where T + U has an Add impl
349impl<U, T: Add<U>> Add<Size<U>> for Size<T> {
350    type Output = Size<<T as Add<U>>::Output>;
351
352    fn add(self, rhs: Size<U>) -> Self::Output {
353        Size { width: self.width + rhs.width, height: self.height + rhs.height }
354    }
355}
356
357// Generic Sub impl for Size<T> + Size<U> where T + U has an Sub impl
358impl<U, T: Sub<U>> Sub<Size<U>> for Size<T> {
359    type Output = Size<<T as Sub<U>>::Output>;
360
361    fn sub(self, rhs: Size<U>) -> Self::Output {
362        Size { width: self.width - rhs.width, height: self.height - rhs.height }
363    }
364}
365
366// Note: we allow dead_code here as we want to provide a complete API of helpers that is symmetrical in all axes,
367// but sometimes we only currently have a use for the helper in a single axis
368#[allow(dead_code)]
369impl<T> Size<T> {
370    /// Applies the function `f` to both the width and height
371    ///
372    /// This is used to transform a `Size<T>` into a `Size<R>`.
373    pub fn map<R, F>(self, f: F) -> Size<R>
374    where
375        F: Fn(T) -> R,
376    {
377        Size { width: f(self.width), height: f(self.height) }
378    }
379
380    /// Applies the function `f` to the width
381    pub fn map_width<F>(self, f: F) -> Size<T>
382    where
383        F: Fn(T) -> T,
384    {
385        Size { width: f(self.width), height: self.height }
386    }
387
388    /// Applies the function `f` to the height
389    pub fn map_height<F>(self, f: F) -> Size<T>
390    where
391        F: Fn(T) -> T,
392    {
393        Size { width: self.width, height: f(self.height) }
394    }
395
396    /// Applies the function `f` to both the width and height
397    /// of this value and another passed value
398    pub fn zip_map<Other, Ret, Func>(self, other: Size<Other>, f: Func) -> Size<Ret>
399    where
400        Func: Fn(T, Other) -> Ret,
401    {
402        Size { width: f(self.width, other.width), height: f(self.height, other.height) }
403    }
404
405    /// Sets the extent of the main layout axis
406    ///
407    /// Whether this is the width or height depends on the `direction` provided
408    #[cfg(feature = "flexbox")]
409    pub(crate) fn set_main(&mut self, direction: FlexDirection, value: T) {
410        if direction.is_row() {
411            self.width = value
412        } else {
413            self.height = value
414        }
415    }
416
417    /// Sets the extent of the cross layout axis
418    ///
419    /// Whether this is the width or height depends on the `direction` provided
420    #[cfg(feature = "flexbox")]
421    pub(crate) fn set_cross(&mut self, direction: FlexDirection, value: T) {
422        if direction.is_row() {
423            self.height = value
424        } else {
425            self.width = value
426        }
427    }
428
429    /// Creates a new value of type Self with the main axis set to value provided
430    ///
431    /// Whether this is the width or height depends on the `direction` provided
432    #[cfg(feature = "flexbox")]
433    pub(crate) fn with_main(self, direction: FlexDirection, value: T) -> Self {
434        let mut new = self;
435        if direction.is_row() {
436            new.width = value
437        } else {
438            new.height = value
439        }
440        new
441    }
442
443    /// Creates a new value of type Self with the cross axis set to value provided
444    ///
445    /// Whether this is the width or height depends on the `direction` provided
446    #[cfg(feature = "flexbox")]
447    pub(crate) fn with_cross(self, direction: FlexDirection, value: T) -> Self {
448        let mut new = self;
449        if direction.is_row() {
450            new.height = value
451        } else {
452            new.width = value
453        }
454        new
455    }
456
457    /// Creates a new value of type Self with the main axis modified by the callback provided
458    ///
459    /// Whether this is the width or height depends on the `direction` provided
460    #[cfg(feature = "flexbox")]
461    pub(crate) fn map_main(self, direction: FlexDirection, mapper: impl FnOnce(T) -> T) -> Self {
462        let mut new = self;
463        if direction.is_row() {
464            new.width = mapper(new.width);
465        } else {
466            new.height = mapper(new.height);
467        }
468        new
469    }
470
471    /// Creates a new value of type Self with the cross axis modified by the callback provided
472    ///
473    /// Whether this is the width or height depends on the `direction` provided
474    #[cfg(feature = "flexbox")]
475    pub(crate) fn map_cross(self, direction: FlexDirection, mapper: impl FnOnce(T) -> T) -> Self {
476        let mut new = self;
477        if direction.is_row() {
478            new.height = mapper(new.height);
479        } else {
480            new.width = mapper(new.width);
481        }
482        new
483    }
484
485    /// Gets the extent of the main layout axis
486    ///
487    /// Whether this is the width or height depends on the `direction` provided
488    #[cfg(feature = "flexbox")]
489    pub(crate) fn main(self, direction: FlexDirection) -> T {
490        if direction.is_row() {
491            self.width
492        } else {
493            self.height
494        }
495    }
496
497    /// Gets the extent of the cross layout axis
498    ///
499    /// Whether this is the width or height depends on the `direction` provided
500    #[cfg(feature = "flexbox")]
501    pub(crate) fn cross(self, direction: FlexDirection) -> T {
502        if direction.is_row() {
503            self.height
504        } else {
505            self.width
506        }
507    }
508
509    /// Gets the extent of the specified layout axis
510    /// Whether this is the width or height depends on the `GridAxis` provided
511    #[cfg(feature = "grid")]
512    pub(crate) fn get(self, axis: AbstractAxis) -> T {
513        match axis {
514            AbstractAxis::Inline => self.width,
515            AbstractAxis::Block => self.height,
516        }
517    }
518
519    /// Sets the extent of the specified layout axis
520    /// Whether this is the width or height depends on the `GridAxis` provided
521    #[cfg(feature = "grid")]
522    pub(crate) fn set(&mut self, axis: AbstractAxis, value: T) {
523        match axis {
524            AbstractAxis::Inline => self.width = value,
525            AbstractAxis::Block => self.height = value,
526        }
527    }
528}
529
530impl Size<f32> {
531    /// A [`Size`] with zero width and height
532    pub const ZERO: Size<f32> = Self { width: 0.0, height: 0.0 };
533
534    /// Applies f32_max to each component separately
535    #[inline(always)]
536    pub fn f32_max(self, rhs: Size<f32>) -> Size<f32> {
537        Size { width: f32_max(self.width, rhs.width), height: f32_max(self.height, rhs.height) }
538    }
539
540    /// Applies f32_min to each component separately
541    #[inline(always)]
542    pub fn f32_min(self, rhs: Size<f32>) -> Size<f32> {
543        Size { width: f32_min(self.width, rhs.width), height: f32_min(self.height, rhs.height) }
544    }
545
546    /// Return true if both width and height are greater than 0 else false
547    #[inline(always)]
548    pub fn has_non_zero_area(self) -> bool {
549        self.width > 0.0 && self.height > 0.0
550    }
551}
552
553impl Size<Option<f32>> {
554    /// A [`Size`] with `None` width and height
555    pub const NONE: Size<Option<f32>> = Self { width: None, height: None };
556
557    /// A [`Size<Option<f32>>`] with `Some(width)` and `Some(height)` as parameters
558    #[must_use]
559    pub const fn new(width: f32, height: f32) -> Self {
560        Size { width: Some(width), height: Some(height) }
561    }
562
563    /// Creates a new [`Size<Option<f32>>`] with either the width or height set based on the provided `direction`
564    #[cfg(feature = "flexbox")]
565    pub fn from_cross(direction: FlexDirection, value: Option<f32>) -> Self {
566        let mut new = Self::NONE;
567        if direction.is_row() {
568            new.height = value
569        } else {
570            new.width = value
571        }
572        new
573    }
574
575    /// Applies aspect_ratio (if one is supplied) to the Size:
576    ///   - If width is `Some` but height is `None`, then height is computed from width and aspect_ratio
577    ///   - If height is `Some` but width is `None`, then width is computed from height and aspect_ratio
578    ///
579    /// If aspect_ratio is `None` then this function simply returns self.
580    pub fn maybe_apply_aspect_ratio(self, aspect_ratio: Option<f32>) -> Size<Option<f32>> {
581        match aspect_ratio {
582            Some(ratio) => match (self.width, self.height) {
583                (Some(width), None) => Size { width: Some(width), height: Some(width / ratio) },
584                (None, Some(height)) => Size { width: Some(height * ratio), height: Some(height) },
585                _ => self,
586            },
587            None => self,
588        }
589    }
590}
591
592impl<T> Size<Option<T>> {
593    /// Performs Option::unwrap_or on each component separately
594    pub fn unwrap_or(self, alt: Size<T>) -> Size<T> {
595        Size { width: self.width.unwrap_or(alt.width), height: self.height.unwrap_or(alt.height) }
596    }
597
598    /// Performs Option::or on each component separately
599    pub fn or(self, alt: Size<Option<T>>) -> Size<Option<T>> {
600        Size { width: self.width.or(alt.width), height: self.height.or(alt.height) }
601    }
602
603    /// Return true if both components are Some, else false.
604    #[inline(always)]
605    pub fn both_axis_defined(&self) -> bool {
606        self.width.is_some() && self.height.is_some()
607    }
608}
609
610impl Size<Dimension> {
611    /// Generates a [`Size<Dimension>`] using length values
612    #[must_use]
613    pub const fn from_lengths(width: f32, height: f32) -> Self {
614        Size { width: Dimension(CompactLength::length(width)), height: Dimension(CompactLength::length(height)) }
615    }
616
617    /// Generates a [`Size<Dimension>`] using percentage values
618    #[must_use]
619    pub const fn from_percent(width: f32, height: f32) -> Self {
620        Size { width: Dimension(CompactLength::percent(width)), height: Dimension(CompactLength::percent(height)) }
621    }
622}
623
624/// A 2-dimensional coordinate.
625///
626/// When used in association with a [`Rect`], represents the top-left corner.
627#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
628#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
629pub struct Point<T> {
630    /// The x-coordinate
631    pub x: T,
632    /// The y-coordinate
633    pub y: T,
634}
635
636impl Point<f32> {
637    /// A [`Point`] with values (0,0), representing the origin
638    pub const ZERO: Self = Self { x: 0.0, y: 0.0 };
639}
640
641impl Point<Option<f32>> {
642    /// A [`Point`] with values (None, None)
643    pub const NONE: Self = Self { x: None, y: None };
644}
645
646// Generic Add impl for Point<T> + Point<U> where T + U has an Add impl
647impl<U, T: Add<U>> Add<Point<U>> for Point<T> {
648    type Output = Point<<T as Add<U>>::Output>;
649
650    fn add(self, rhs: Point<U>) -> Self::Output {
651        Point { x: self.x + rhs.x, y: self.y + rhs.y }
652    }
653}
654
655impl<T> Point<T> {
656    /// Applies the function `f` to both the x and y
657    ///
658    /// This is used to transform a `Point<T>` into a `Point<R>`.
659    pub fn map<R, F>(self, f: F) -> Point<R>
660    where
661        F: Fn(T) -> R,
662    {
663        Point { x: f(self.x), y: f(self.y) }
664    }
665
666    /// Gets the extent of the specified layout axis
667    /// Whether this is the width or height depends on the `GridAxis` provided
668    #[cfg(feature = "grid")]
669    pub fn get(self, axis: AbstractAxis) -> T {
670        match axis {
671            AbstractAxis::Inline => self.x,
672            AbstractAxis::Block => self.y,
673        }
674    }
675
676    /// Swap x and y components
677    pub fn transpose(self) -> Point<T> {
678        Point { x: self.y, y: self.x }
679    }
680
681    /// Sets the extent of the specified layout axis
682    /// Whether this is the width or height depends on the `GridAxis` provided
683    #[cfg(feature = "grid")]
684    pub fn set(&mut self, axis: AbstractAxis, value: T) {
685        match axis {
686            AbstractAxis::Inline => self.x = value,
687            AbstractAxis::Block => self.y = value,
688        }
689    }
690
691    /// Gets the component in the main layout axis
692    ///
693    /// Whether this is the x or y depends on the `direction` provided
694    #[cfg(feature = "flexbox")]
695    pub(crate) fn main(self, direction: FlexDirection) -> T {
696        if direction.is_row() {
697            self.x
698        } else {
699            self.y
700        }
701    }
702
703    /// Gets the component in the cross layout axis
704    ///
705    /// Whether this is the x or y depends on the `direction` provided
706    #[cfg(feature = "flexbox")]
707    pub(crate) fn cross(self, direction: FlexDirection) -> T {
708        if direction.is_row() {
709            self.y
710        } else {
711            self.x
712        }
713    }
714}
715
716impl<T> From<Point<T>> for Size<T> {
717    fn from(value: Point<T>) -> Self {
718        Size { width: value.x, height: value.y }
719    }
720}
721
722/// Generic struct which holds a "min" value and a "max" value
723#[derive(Debug, Copy, Clone, PartialEq, Eq)]
724#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
725pub struct MinMax<Min, Max> {
726    /// The value representing the minimum
727    pub min: Min,
728    /// The value representing the maximum
729    pub max: Max,
730}