float_pigment_layout/
types.rs

1use core::{fmt::Display, ops::Deref};
2
3use euclid::UnknownUnit;
4use float_pigment_css::typing::WritingMode;
5
6use crate::LayoutTreeNode;
7pub(crate) use float_pigment_css::length_num::{length_sum, LengthNum};
8
9/// Position with size.
10pub type Rect<L> = euclid::Rect<L, UnknownUnit>;
11
12/// Size.
13pub type Size<L> = euclid::Size2D<L, UnknownUnit>;
14
15/// Size, but each value can be `None` for undetermined.
16pub type OptionSize<L> = euclid::Size2D<OptionNum<L>, UnknownUnit>;
17
18/// 2D Vector.
19pub type Vector<L> = euclid::Vector2D<L, euclid::UnknownUnit>;
20
21/// Position.
22pub type Point<L> = euclid::Point2D<L, euclid::UnknownUnit>;
23
24pub(crate) trait PointGetter<T> {
25    fn main_axis(&self, dir: AxisDirection) -> T;
26    fn cross_axis(&self, dir: AxisDirection) -> T;
27}
28
29impl<L: LengthNum> PointGetter<L> for Point<L> {
30    fn main_axis(&self, dir: AxisDirection) -> L {
31        match dir {
32            AxisDirection::Horizontal => self.x,
33            AxisDirection::Vertical => self.y,
34        }
35    }
36    fn cross_axis(&self, dir: AxisDirection) -> L {
37        match dir {
38            AxisDirection::Horizontal => self.y,
39            AxisDirection::Vertical => self.x,
40        }
41    }
42}
43
44pub(crate) trait SizeGetter<T: Copy> {
45    fn main_size(&self, dir: AxisDirection) -> T;
46    fn cross_size(&self, dir: AxisDirection) -> T;
47}
48
49pub(crate) trait SizeSetter<T> {
50    fn set_main_size(&mut self, dir: AxisDirection, value: T);
51    fn set_cross_size(&mut self, dir: AxisDirection, value: T);
52}
53
54impl<T: Copy> SizeGetter<T> for euclid::Size2D<T, UnknownUnit> {
55    #[inline]
56    fn main_size(&self, dir: AxisDirection) -> T {
57        match dir {
58            AxisDirection::Horizontal => self.width,
59            AxisDirection::Vertical => self.height,
60        }
61    }
62
63    #[inline]
64    fn cross_size(&self, dir: AxisDirection) -> T {
65        match dir {
66            AxisDirection::Horizontal => self.height,
67            AxisDirection::Vertical => self.width,
68        }
69    }
70}
71
72impl<T> SizeSetter<T> for euclid::Size2D<T, UnknownUnit> {
73    #[inline]
74    fn set_main_size(&mut self, dir: AxisDirection, value: T) {
75        match dir {
76            AxisDirection::Horizontal => self.width = value,
77            AxisDirection::Vertical => self.height = value,
78        }
79    }
80
81    #[inline]
82    fn set_cross_size(&mut self, dir: AxisDirection, value: T) {
83        match dir {
84            AxisDirection::Horizontal => self.height = value,
85            AxisDirection::Vertical => self.width = value,
86        }
87    }
88}
89
90pub(crate) trait SizeProxy<T> {
91    fn new_with_dir(dir: AxisDirection, main_size: T, cross_size: T) -> Self;
92}
93
94impl<T> SizeProxy<T> for euclid::Size2D<T, UnknownUnit> {
95    #[inline(always)]
96    fn new_with_dir(dir: AxisDirection, main_size: T, cross_size: T) -> Self {
97        let (width, height) = match dir {
98            AxisDirection::Horizontal => (main_size, cross_size),
99            AxisDirection::Vertical => (cross_size, main_size),
100        };
101        Self::new(width, height)
102    }
103}
104
105pub(crate) trait OrZero<L: LengthNum>: Sized {
106    fn or_zero(&self) -> Size<L>;
107}
108
109impl<L: LengthNum> OrZero<L> for OptionSize<L> {
110    #[inline(always)]
111    fn or_zero(&self) -> Size<L> {
112        Size::new(self.width.or_zero(), self.height.or_zero())
113    }
114}
115
116pub(crate) trait VectorGetter<T> {
117    #[allow(unused)]
118    fn main_axis(&self, dir: AxisDirection) -> T;
119    fn cross_axis(&self, dir: AxisDirection) -> T;
120}
121
122impl<L: LengthNum> VectorGetter<L> for Vector<L> {
123    #[inline]
124    fn main_axis(&self, dir: AxisDirection) -> L {
125        match dir {
126            AxisDirection::Horizontal => self.x,
127            AxisDirection::Vertical => self.y,
128        }
129    }
130    #[inline]
131    fn cross_axis(&self, dir: AxisDirection) -> L {
132        match dir {
133            AxisDirection::Horizontal => self.y,
134            AxisDirection::Vertical => self.x,
135        }
136    }
137}
138
139pub(crate) trait VectorSetter<T> {
140    fn set_main_axis(&mut self, dir: AxisDirection, value: T);
141    fn set_cross_axis(&mut self, dir: AxisDirection, value: T);
142}
143
144impl<L: LengthNum> VectorSetter<L> for Vector<L> {
145    #[inline(always)]
146    fn set_main_axis(&mut self, dir: AxisDirection, value: L) {
147        match dir {
148            AxisDirection::Horizontal => self.x = value,
149            AxisDirection::Vertical => self.y = value,
150        }
151    }
152    #[inline(always)]
153    fn set_cross_axis(&mut self, dir: AxisDirection, value: L) {
154        match dir {
155            AxisDirection::Horizontal => self.y = value,
156            AxisDirection::Vertical => self.x = value,
157        }
158    }
159}
160
161pub(crate) trait VectorProxy<T> {
162    fn new_with_dir(dir: AxisDirection, main_axis: T, cross_axis: T) -> Self;
163}
164
165impl<L: LengthNum> VectorProxy<L> for Vector<L> {
166    fn new_with_dir(dir: AxisDirection, main_axis: L, cross_axis: L) -> Self {
167        let (x, y) = match dir {
168            AxisDirection::Horizontal => (main_axis, cross_axis),
169            AxisDirection::Vertical => (cross_axis, main_axis),
170        };
171        Self::new(x, y)
172    }
173}
174
175/// A length type that can be undefined or auto.
176#[derive(Debug, Clone, Copy, PartialEq)]
177pub enum DefLength<L: LengthNum, T: PartialEq = i32> {
178    /// The length is undetermined.
179    Undefined,
180
181    /// The length is auto.
182    Auto,
183
184    /// A fixed value.
185    Points(L),
186
187    /// A ratio.
188    Percent(f32),
189
190    /// Custom length value.
191    ///
192    /// Will be resolved by `LayoutTreeNode::resolve_custom_length`.
193    Custom(T),
194}
195
196impl<L: LengthNum, T: PartialEq + Display> Display for DefLength<L, T> {
197    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
198        match self {
199            Self::Undefined => write!(f, "Undefined"),
200            Self::Auto => write!(f, "Auto"),
201            Self::Points(x) => write!(f, "Points({})", L::to_f32(*x)),
202            Self::Percent(x) => write!(f, "Percent({})", *x),
203            Self::Custom(x) => write!(f, "Custom({})", *x),
204        }
205    }
206}
207
208impl<L: LengthNum, T: PartialEq> Default for DefLength<L, T> {
209    fn default() -> Self {
210        Self::Undefined
211    }
212}
213
214impl<L: LengthNum, T: PartialEq> DefLength<L, T> {
215    pub(crate) fn resolve<N: LayoutTreeNode<Length = L, LengthCustom = T>>(
216        &self,
217        parent: OptionNum<L>,
218        node: &N,
219    ) -> OptionNum<L> {
220        match self {
221            Self::Undefined => OptionNum::none(),
222            Self::Auto => OptionNum::none(),
223            Self::Points(x) => OptionNum::some(*x),
224            Self::Percent(x) => parent * *x,
225            Self::Custom(x) => {
226                OptionNum::some(node.resolve_custom_length(x, parent.unwrap_or(L::zero())))
227            }
228        }
229    }
230
231    pub(crate) fn resolve_with_auto<N: LayoutTreeNode<Length = L, LengthCustom = T>>(
232        &self,
233        parent: OptionNum<L>,
234        node: &N,
235    ) -> OptionNum<L> {
236        match self {
237            Self::Undefined => OptionNum::some(L::zero()),
238            Self::Auto => OptionNum::none(),
239            Self::Points(x) => OptionNum::some(*x),
240            Self::Percent(x) => parent * *x,
241            Self::Custom(x) => {
242                OptionNum::some(node.resolve_custom_length(x, parent.unwrap_or(L::zero())))
243            }
244        }
245    }
246
247    pub(crate) fn resolve_num<N: LayoutTreeNode<Length = L, LengthCustom = T>>(
248        &self,
249        parent: L,
250        node: &N,
251    ) -> OptionNum<L> {
252        match self {
253            Self::Undefined => OptionNum::none(),
254            Self::Auto => OptionNum::none(),
255            Self::Points(x) => OptionNum::some(*x),
256            Self::Percent(x) => OptionNum::some(parent.mul_f32(*x)),
257            Self::Custom(x) => OptionNum::some(node.resolve_custom_length(x, parent)),
258        }
259    }
260}
261
262/// A number or undetermined.
263#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
264pub struct OptionNum<L>(Option<L>);
265
266impl<L: LengthNum> OptionNum<L> {
267    /// Convert to a hashable value.
268    pub fn to_hashable(&self) -> OptionNum<L::Hashable> {
269        match self.0 {
270            None => OptionNum(None),
271            Some(x) => OptionNum(Some(x.to_hashable())),
272        }
273    }
274
275    /// New undetermined value.
276    #[inline]
277    pub fn none() -> Self {
278        Self(None)
279    }
280
281    /// New number.
282    #[inline]
283    pub fn some(v: L) -> Self {
284        Self(Some(v))
285    }
286
287    /// New zero value.
288    #[inline]
289    pub fn zero() -> Self {
290        Self(Some(L::zero()))
291    }
292
293    /// Return `true` for undetermined value.
294    #[inline]
295    pub fn is_none(&self) -> bool {
296        self.0.is_none()
297    }
298
299    /// Return `true` for number.
300    #[inline]
301    pub fn is_some(&self) -> bool {
302        self.0.is_some()
303    }
304
305    /// Convert to a number with `Option`.
306    #[inline]
307    pub fn val(&self) -> Option<L> {
308        self.0
309    }
310
311    /// Unwrap to a number, default to `rhs`.
312    #[inline]
313    pub fn unwrap_or(self, rhs: L) -> L {
314        self.0.unwrap_or(rhs)
315    }
316
317    /// If `self` is undetermined, return `rhs`.
318    #[inline]
319    pub fn or(self, rhs: Self) -> Self {
320        Self(self.0.or(rhs.0))
321    }
322
323    /// Unwrap to a number, default to zero.
324    #[inline]
325    pub fn or_zero(self) -> L {
326        self.0.unwrap_or_else(L::zero)
327    }
328
329    /// Map the number.
330    #[inline]
331    pub fn map(self, f: impl FnOnce(L) -> L) -> Self {
332        Self(self.0.map(f))
333    }
334}
335
336impl<L: LengthNum> core::ops::Add<L> for OptionNum<L> {
337    type Output = Self;
338
339    fn add(self, rhs: L) -> Self {
340        self.map(|x| x + rhs)
341    }
342}
343
344impl<L: LengthNum> core::ops::Sub<L> for OptionNum<L> {
345    type Output = Self;
346
347    fn sub(self, rhs: L) -> Self {
348        self.map(|x| x - rhs)
349    }
350}
351
352impl<L: LengthNum> core::ops::Mul<f32> for OptionNum<L> {
353    type Output = Self;
354
355    fn mul(self, rhs: f32) -> Self {
356        self.map(|x| x.mul_f32(rhs))
357    }
358}
359
360impl<L: LengthNum> core::ops::Mul<i32> for OptionNum<L> {
361    type Output = Self;
362
363    fn mul(self, rhs: i32) -> Self {
364        self.map(|x| x.mul_i32(rhs))
365    }
366}
367
368impl<L: LengthNum> core::ops::Add<Self> for OptionNum<L> {
369    type Output = Self;
370
371    fn add(self, rhs: Self) -> Self {
372        match rhs.val() {
373            Some(x) => self + x,
374            None => self,
375        }
376    }
377}
378
379impl<L: LengthNum> core::ops::Sub<Self> for OptionNum<L> {
380    type Output = Self;
381
382    fn sub(self, rhs: Self) -> Self {
383        match rhs.val() {
384            Some(x) => self - x,
385            None => self,
386        }
387    }
388}
389
390pub(crate) trait MinMax {
391    fn min(self, rhs: Self) -> Self;
392    fn max(self, rhs: Self) -> Self;
393}
394
395impl<L: LengthNum> MinMax for L {
396    fn min(self, rhs: Self) -> Self {
397        if self < rhs {
398            self
399        } else {
400            rhs
401        }
402    }
403
404    fn max(self, rhs: Self) -> Self {
405        if self > rhs {
406            self
407        } else {
408            rhs
409        }
410    }
411}
412
413pub(crate) trait MaybeMinMax<In, Out> {
414    fn maybe_min(self, rhs: In) -> Out;
415    fn maybe_max(self, rhs: In) -> Out;
416}
417
418impl<L: LengthNum> MaybeMinMax<OptionNum<L>, L> for L {
419    fn maybe_min(self, rhs: OptionNum<L>) -> L {
420        match rhs.val() {
421            None => self,
422            Some(x) => self.min(x),
423        }
424    }
425
426    fn maybe_max(self, rhs: OptionNum<L>) -> L {
427        match rhs.val() {
428            None => self,
429            Some(x) => self.max(x),
430        }
431    }
432}
433
434impl<L: LengthNum> MaybeMinMax<Self, Self> for OptionNum<L> {
435    fn maybe_min(self, rhs: Self) -> Self {
436        match self.val() {
437            None => OptionNum::none(),
438            Some(x) => match rhs.val() {
439                None => self,
440                Some(y) => OptionNum::some(x.min(y)),
441            },
442        }
443    }
444
445    fn maybe_max(self, rhs: Self) -> Self {
446        match self.val() {
447            None => OptionNum::none(),
448            Some(x) => match rhs.val() {
449                None => self,
450                Some(y) => OptionNum::some(x.max(y)),
451            },
452        }
453    }
454}
455
456impl<L: LengthNum> MaybeMinMax<L, Self> for OptionNum<L> {
457    fn maybe_min(self, rhs: L) -> OptionNum<L> {
458        match self.val() {
459            None => OptionNum::none(),
460            Some(x) => OptionNum::some(x.min(rhs)),
461        }
462    }
463
464    fn maybe_max(self, rhs: L) -> OptionNum<L> {
465        match self.val() {
466            None => OptionNum::none(),
467            Some(x) => OptionNum::some(x.max(rhs)),
468        }
469    }
470}
471
472impl<L: LengthNum> MaybeMinMax<OptionSize<L>, Size<L>> for Size<L> {
473    fn maybe_min(self, rhs: OptionSize<L>) -> Size<L> {
474        let width = match rhs.width.val() {
475            None => self.width,
476            Some(x) => self.width.min(x),
477        };
478        let height = match rhs.height.val() {
479            None => self.height,
480            Some(x) => self.height.min(x),
481        };
482        Size::new(width, height)
483    }
484
485    fn maybe_max(self, rhs: OptionSize<L>) -> Size<L> {
486        let width = match rhs.width.val() {
487            None => self.width,
488            Some(x) => self.width.max(x),
489        };
490        let height = match rhs.height.val() {
491            None => self.height,
492            Some(x) => self.height.max(x),
493        };
494        Size::new(width, height)
495    }
496}
497
498/// Four edge lengths.
499#[allow(missing_docs)]
500#[derive(Debug, Clone, Copy, PartialEq)]
501pub struct Edge<L: LengthNum> {
502    pub left: L,
503    pub right: L,
504    pub top: L,
505    pub bottom: L,
506}
507
508impl<L: LengthNum> Edge<L> {
509    /// New zero-length edges.
510    #[inline(always)]
511    pub fn zero() -> Self {
512        Self {
513            left: L::zero(),
514            right: L::zero(),
515            top: L::zero(),
516            bottom: L::zero(),
517        }
518    }
519
520    /// Get the sum of horizontal lengths.
521    #[inline(always)]
522    pub fn horizontal(&self) -> L {
523        self.left + self.right
524    }
525
526    /// Get the sum of vertical lengths.
527    #[inline(always)]
528    pub fn vertical(&self) -> L {
529        self.top + self.bottom
530    }
531
532    #[inline(always)]
533    pub(crate) fn main_axis_sum(&self, dir: AxisDirection) -> L {
534        match dir {
535            AxisDirection::Vertical => self.vertical(),
536            AxisDirection::Horizontal => self.horizontal(),
537        }
538    }
539
540    #[inline(always)]
541    pub(crate) fn cross_axis_sum(&self, dir: AxisDirection) -> L {
542        match dir {
543            AxisDirection::Vertical => self.horizontal(),
544            AxisDirection::Horizontal => self.vertical(),
545        }
546    }
547
548    #[inline(always)]
549    pub(crate) fn main_axis_start(&self, dir: AxisDirection, rev: AxisReverse) -> L {
550        match (dir, rev) {
551            (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.left,
552            (AxisDirection::Horizontal, AxisReverse::Reversed) => self.right,
553            (AxisDirection::Vertical, AxisReverse::NotReversed) => self.top,
554            (AxisDirection::Vertical, AxisReverse::Reversed) => self.bottom,
555        }
556    }
557
558    #[allow(unused)]
559    #[inline(always)]
560    pub(crate) fn main_axis_end(&self, dir: AxisDirection, rev: AxisReverse) -> L {
561        match (dir, rev) {
562            (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.right,
563            (AxisDirection::Horizontal, AxisReverse::Reversed) => self.left,
564            (AxisDirection::Vertical, AxisReverse::NotReversed) => self.bottom,
565            (AxisDirection::Vertical, AxisReverse::Reversed) => self.top,
566        }
567    }
568
569    #[inline(always)]
570    pub(crate) fn cross_axis_start(&self, dir: AxisDirection, rev: AxisReverse) -> L {
571        match (dir, rev) {
572            (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.top,
573            (AxisDirection::Horizontal, AxisReverse::Reversed) => self.bottom,
574            (AxisDirection::Vertical, AxisReverse::NotReversed) => self.left,
575            (AxisDirection::Vertical, AxisReverse::Reversed) => self.right,
576        }
577    }
578
579    #[allow(unused)]
580    #[inline(always)]
581    pub(crate) fn cross_axis_end(&self, dir: AxisDirection, rev: AxisReverse) -> L {
582        match (dir, rev) {
583            (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.bottom,
584            (AxisDirection::Horizontal, AxisReverse::Reversed) => self.top,
585            (AxisDirection::Vertical, AxisReverse::NotReversed) => self.right,
586            (AxisDirection::Vertical, AxisReverse::Reversed) => self.left,
587        }
588    }
589}
590
591impl<L: LengthNum> core::ops::Add<Edge<L>> for Edge<L> {
592    type Output = Self;
593
594    fn add(self, rhs: Edge<L>) -> Self {
595        Self {
596            left: self.left + rhs.left,
597            right: self.right + rhs.right,
598            top: self.top + rhs.top,
599            bottom: self.bottom + rhs.bottom,
600        }
601    }
602}
603
604impl<L: LengthNum> core::ops::Sub<Edge<L>> for Edge<L> {
605    type Output = Self;
606    fn sub(self, rhs: Edge<L>) -> Self {
607        Self {
608            left: self.left - rhs.left,
609            right: self.right - rhs.right,
610            top: self.top - rhs.top,
611            bottom: self.bottom - rhs.bottom,
612        }
613    }
614}
615
616/// Four edge lengths, each edge can be undetermined.
617#[allow(missing_docs)]
618#[derive(Debug, Clone, Copy, PartialEq)]
619pub struct EdgeOption<L: LengthNum> {
620    pub left: OptionNum<L>,
621    pub right: OptionNum<L>,
622    pub top: OptionNum<L>,
623    pub bottom: OptionNum<L>,
624}
625
626impl<L: LengthNum> EdgeOption<L> {
627    /// Unwrap to `Edge`, default to zero.
628    #[inline(always)]
629    pub fn or_zero(&self) -> Edge<L> {
630        Edge {
631            left: self.left.or_zero(),
632            right: self.right.or_zero(),
633            top: self.top.or_zero(),
634            bottom: self.bottom.or_zero(),
635        }
636    }
637
638    /// Get the sum of horizontal lengths, default to zero.
639    #[inline(always)]
640    pub fn horizontal(&self) -> L {
641        self.left.or_zero() + self.right.or_zero()
642    }
643
644    /// Get the sum of vertical lengths, default to zero.
645    #[inline(always)]
646    pub fn vertical(&self) -> L {
647        self.top.or_zero() + self.bottom.or_zero()
648    }
649
650    pub(crate) fn is_left_right_either_none(&self) -> bool {
651        self.left.is_none() || self.right.is_none()
652    }
653
654    pub(crate) fn is_top_bottom_either_none(&self) -> bool {
655        self.top.is_none() || self.bottom.is_none()
656    }
657
658    #[inline(always)]
659    pub(crate) fn main_axis_sum(&self, dir: AxisDirection) -> L {
660        match dir {
661            AxisDirection::Horizontal => self.horizontal(),
662            AxisDirection::Vertical => self.vertical(),
663        }
664    }
665
666    #[inline(always)]
667    pub(crate) fn cross_axis_sum(&self, dir: AxisDirection) -> L {
668        match dir {
669            AxisDirection::Horizontal => self.vertical(),
670            AxisDirection::Vertical => self.horizontal(),
671        }
672    }
673
674    #[inline(always)]
675    pub(crate) fn main_axis_start(&self, dir: AxisDirection, rev: AxisReverse) -> OptionNum<L> {
676        match (dir, rev) {
677            (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.left,
678            (AxisDirection::Horizontal, AxisReverse::Reversed) => self.right,
679            (AxisDirection::Vertical, AxisReverse::NotReversed) => self.top,
680            (AxisDirection::Vertical, AxisReverse::Reversed) => self.bottom,
681        }
682    }
683
684    #[inline(always)]
685    pub(crate) fn set_main_axis_start(
686        &mut self,
687        dir: AxisDirection,
688        rev: AxisReverse,
689        value: OptionNum<L>,
690    ) {
691        match (dir, rev) {
692            (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.left = value,
693            (AxisDirection::Horizontal, AxisReverse::Reversed) => self.right = value,
694            (AxisDirection::Vertical, AxisReverse::NotReversed) => self.top = value,
695            (AxisDirection::Vertical, AxisReverse::Reversed) => self.bottom = value,
696        }
697    }
698
699    #[inline(always)]
700    pub(crate) fn main_axis_end(&self, dir: AxisDirection, rev: AxisReverse) -> OptionNum<L> {
701        match (dir, rev) {
702            (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.right,
703            (AxisDirection::Horizontal, AxisReverse::Reversed) => self.left,
704            (AxisDirection::Vertical, AxisReverse::NotReversed) => self.bottom,
705            (AxisDirection::Vertical, AxisReverse::Reversed) => self.top,
706        }
707    }
708
709    #[inline(always)]
710    pub(crate) fn set_main_axis_end(
711        &mut self,
712        dir: AxisDirection,
713        rev: AxisReverse,
714        value: OptionNum<L>,
715    ) {
716        match (dir, rev) {
717            (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.right = value,
718            (AxisDirection::Horizontal, AxisReverse::Reversed) => self.left = value,
719            (AxisDirection::Vertical, AxisReverse::NotReversed) => self.bottom = value,
720            (AxisDirection::Vertical, AxisReverse::Reversed) => self.top = value,
721        }
722    }
723
724    #[inline(always)]
725    pub(crate) fn cross_axis_start(&self, dir: AxisDirection, rev: AxisReverse) -> OptionNum<L> {
726        match (dir, rev) {
727            (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.top,
728            (AxisDirection::Horizontal, AxisReverse::Reversed) => self.bottom,
729            (AxisDirection::Vertical, AxisReverse::NotReversed) => self.left,
730            (AxisDirection::Vertical, AxisReverse::Reversed) => self.right,
731        }
732    }
733
734    #[inline(always)]
735    pub(crate) fn set_cross_axis_start(
736        &mut self,
737        dir: AxisDirection,
738        rev: AxisReverse,
739        value: OptionNum<L>,
740    ) {
741        match (dir, rev) {
742            (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.top = value,
743            (AxisDirection::Horizontal, AxisReverse::Reversed) => self.bottom = value,
744            (AxisDirection::Vertical, AxisReverse::NotReversed) => self.left = value,
745            (AxisDirection::Vertical, AxisReverse::Reversed) => self.right = value,
746        }
747    }
748
749    #[inline(always)]
750    pub(crate) fn cross_axis_end(&self, dir: AxisDirection, rev: AxisReverse) -> OptionNum<L> {
751        match (dir, rev) {
752            (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.bottom,
753            (AxisDirection::Horizontal, AxisReverse::Reversed) => self.top,
754            (AxisDirection::Vertical, AxisReverse::NotReversed) => self.right,
755            (AxisDirection::Vertical, AxisReverse::Reversed) => self.left,
756        }
757    }
758
759    #[inline(always)]
760    pub(crate) fn set_cross_axis_end(
761        &mut self,
762        dir: AxisDirection,
763        rev: AxisReverse,
764        value: OptionNum<L>,
765    ) {
766        match (dir, rev) {
767            (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.bottom = value,
768            (AxisDirection::Horizontal, AxisReverse::Reversed) => self.top = value,
769            (AxisDirection::Vertical, AxisReverse::NotReversed) => self.right = value,
770            (AxisDirection::Vertical, AxisReverse::Reversed) => self.left = value,
771        }
772    }
773}
774
775#[derive(Debug, Clone, Copy, PartialEq)]
776pub(crate) enum AxisDirection {
777    Horizontal,
778    Vertical,
779}
780
781#[derive(Debug, Clone, Copy, PartialEq, Hash)]
782pub(crate) enum AxisReverse {
783    NotReversed,
784    Reversed,
785}
786
787#[derive(Debug, Clone, Copy, PartialEq)]
788pub(crate) struct AxisInfo {
789    pub(crate) dir: AxisDirection,
790    pub(crate) main_dir_rev: AxisReverse,
791    pub(crate) cross_dir_rev: AxisReverse,
792}
793
794impl AxisInfo {
795    pub(crate) fn from_writing_mode(writing_mode: WritingMode) -> Self {
796        let (dir, main_dir_rev, cross_dir_rev) = match writing_mode {
797            WritingMode::HorizontalTb => (
798                AxisDirection::Vertical,
799                AxisReverse::NotReversed,
800                AxisReverse::NotReversed,
801            ),
802            WritingMode::VerticalLr => (
803                AxisDirection::Horizontal,
804                AxisReverse::NotReversed,
805                AxisReverse::NotReversed,
806            ),
807            WritingMode::VerticalRl => (
808                AxisDirection::Horizontal,
809                AxisReverse::Reversed,
810                AxisReverse::NotReversed,
811            ),
812        };
813        Self {
814            dir,
815            main_dir_rev,
816            cross_dir_rev,
817        }
818    }
819}
820#[derive(Debug, Clone, Copy, PartialEq)]
821pub(crate) struct MinMaxSize<L: LengthNum> {
822    pub(crate) min_width: OptionNum<L>,
823    pub(crate) max_width: OptionNum<L>,
824    pub(crate) min_height: OptionNum<L>,
825    pub(crate) max_height: OptionNum<L>,
826}
827
828#[derive(Debug, Clone, Copy, PartialEq)]
829pub(crate) struct MinMaxLimit<L: LengthNum> {
830    pub(crate) min_width: L,
831    pub(crate) max_width: OptionNum<L>,
832    pub(crate) min_height: L,
833    pub(crate) max_height: OptionNum<L>,
834}
835
836impl<L: LengthNum> MinMaxLimit<L> {
837    pub(crate) fn normalized_size(&self, v: OptionSize<L>) -> Normalized<OptionSize<L>> {
838        Normalized(OptionSize::new(
839            v.width
840                .map(|x| x.maybe_min(self.max_width).max(self.min_width)),
841            v.height
842                .map(|x| x.maybe_min(self.max_height).max(self.min_height)),
843        ))
844    }
845
846    pub(crate) fn width(&self, x: L) -> L {
847        x.maybe_min(self.max_width).max(self.min_width)
848    }
849
850    pub(crate) fn height(&self, x: L) -> L {
851        x.maybe_min(self.max_height).max(self.min_height)
852    }
853
854    pub(crate) fn maybe(&self) -> MinMaxLimitMaybe<L> {
855        MinMaxLimitMaybe(self)
856    }
857
858    #[inline(always)]
859    pub(crate) fn main_size(&self, x: L, dir: AxisDirection) -> L {
860        match dir {
861            AxisDirection::Horizontal => self.width(x),
862            AxisDirection::Vertical => self.height(x),
863        }
864    }
865
866    #[inline(always)]
867    pub(crate) fn cross_size(&self, x: L, dir: AxisDirection) -> L {
868        match dir {
869            AxisDirection::Horizontal => self.height(x),
870            AxisDirection::Vertical => self.width(x),
871        }
872    }
873
874    #[inline(always)]
875    pub(crate) fn min_main_size(&self, dir: AxisDirection) -> L {
876        match dir {
877            AxisDirection::Horizontal => self.min_width,
878            AxisDirection::Vertical => self.min_height,
879        }
880    }
881
882    #[inline(always)]
883    #[allow(unused)]
884    pub(crate) fn max_main_size(&self, dir: AxisDirection) -> OptionNum<L> {
885        match dir {
886            AxisDirection::Horizontal => self.max_width,
887            AxisDirection::Vertical => self.max_height,
888        }
889    }
890
891    #[inline(always)]
892    #[allow(unused)]
893    pub(crate) fn min_cross_size(&self, dir: AxisDirection) -> L {
894        match dir {
895            AxisDirection::Horizontal => self.min_height,
896            AxisDirection::Vertical => self.min_width,
897        }
898    }
899
900    #[inline(always)]
901    #[allow(unused)]
902    pub(crate) fn max_cross_size(&self, dir: AxisDirection) -> OptionNum<L> {
903        match dir {
904            AxisDirection::Horizontal => self.max_height,
905            AxisDirection::Vertical => self.max_width,
906        }
907    }
908
909    #[inline(always)]
910    #[allow(unused)]
911    pub(crate) fn set_min_cross_size(&mut self, x: L, dir: AxisDirection) {
912        match dir {
913            AxisDirection::Horizontal => self.min_height = x,
914            AxisDirection::Vertical => self.min_width = x,
915        }
916    }
917
918    #[inline(always)]
919    #[allow(unused)]
920    pub(crate) fn set_max_cross_size(&mut self, x: OptionNum<L>, dir: AxisDirection) {
921        match dir {
922            AxisDirection::Horizontal => self.max_height = x,
923            AxisDirection::Vertical => self.max_width = x,
924        }
925    }
926
927    #[inline(always)]
928    #[allow(unused)]
929    pub(crate) fn set_min_main_size(&mut self, x: L, dir: AxisDirection) {
930        match dir {
931            AxisDirection::Horizontal => self.min_width = x,
932            AxisDirection::Vertical => self.min_height = x,
933        }
934    }
935
936    #[inline(always)]
937    #[allow(unused)]
938    pub(crate) fn set_max_main_size(&mut self, x: OptionNum<L>, dir: AxisDirection) {
939        match dir {
940            AxisDirection::Horizontal => self.max_width = x,
941            AxisDirection::Vertical => self.max_height = x,
942        }
943    }
944}
945
946pub(crate) struct MinMaxLimitMaybe<'a, L: LengthNum>(&'a MinMaxLimit<L>);
947
948impl<'a, L: LengthNum> MinMaxLimitMaybe<'a, L> {
949    pub(crate) fn width(&self, v: OptionNum<L>) -> OptionNum<L> {
950        v.map(|x| x.maybe_min(self.0.max_width).max(self.0.min_width))
951    }
952
953    pub(crate) fn height(&self, v: OptionNum<L>) -> OptionNum<L> {
954        v.map(|x| x.maybe_min(self.0.max_height).max(self.0.min_height))
955    }
956
957    #[inline(always)]
958    #[allow(unused)]
959    pub(crate) fn main_size(&self, dir: AxisDirection, v: OptionNum<L>) -> OptionNum<L> {
960        match dir {
961            AxisDirection::Horizontal => self.width(v),
962            AxisDirection::Vertical => self.height(v),
963        }
964    }
965
966    #[inline(always)]
967    pub(crate) fn cross_size(&self, dir: AxisDirection, v: OptionNum<L>) -> OptionNum<L> {
968        match dir {
969            AxisDirection::Horizontal => self.height(v),
970            AxisDirection::Vertical => self.width(v),
971        }
972    }
973}
974
975#[derive(Debug, Clone, Copy, PartialEq, Hash)]
976pub(crate) struct Normalized<T>(pub(crate) T);
977
978impl<T> Deref for Normalized<T> {
979    type Target = T;
980
981    fn deref(&self) -> &Self::Target {
982        &self.0
983    }
984}
985
986#[inline(always)]
987pub(crate) fn size_to_option<L: LengthNum>(size: Size<L>) -> OptionSize<L> {
988    OptionSize::new(OptionNum::some(size.width), OptionNum::some(size.height))
989}
990
991#[cfg(test)]
992mod test {
993
994    use crate::{AxisDirection, Normalized, OptionSize, Size, SizeGetter, SizeSetter};
995
996    #[test]
997    fn option_size_get_main_size() {
998        let os = OptionSize::new(crate::OptionNum::some(10.), crate::OptionNum::some(20.));
999        let size = os.main_size(AxisDirection::Horizontal);
1000        // let size = main_size(target, dir)
1001        assert_eq!(size.val(), Some(10.));
1002        let size = os.main_size(AxisDirection::Vertical);
1003        assert_eq!(size.val(), Some(20.));
1004    }
1005
1006    #[test]
1007    fn option_size_get_cross_size() {
1008        let os = OptionSize::new(crate::OptionNum::some(10.), crate::OptionNum::some(20.));
1009        let size = os.cross_size(AxisDirection::Horizontal);
1010        assert_eq!(size.val(), Some(20.));
1011        let size = os.cross_size(AxisDirection::Vertical);
1012        assert_eq!(size.val(), Some(10.));
1013    }
1014
1015    #[test]
1016    fn normalized_option_size_get_size() {
1017        let os = OptionSize::new(crate::OptionNum::some(10.), crate::OptionNum::some(20.));
1018        let normalized = Normalized(os);
1019        let size = normalized.main_size(AxisDirection::Horizontal);
1020        assert_eq!(size.val(), Some(10.));
1021        let size = normalized.main_size(AxisDirection::Vertical);
1022        assert_eq!(size.val(), Some(20.));
1023    }
1024
1025    #[test]
1026    fn size_get_size() {
1027        let s = Size::new(10.0_f32, 20.0_f32);
1028        let size = s.main_size(AxisDirection::Horizontal);
1029        assert_eq!(size, 10.);
1030        let size = s.main_size(AxisDirection::Vertical);
1031        assert_eq!(size, 20.);
1032    }
1033
1034    #[test]
1035    fn size_set_size() {
1036        let mut s = Size::new(10.0_f32, 20.0_f32);
1037        s.set_main_size(AxisDirection::Horizontal, 20.);
1038        assert_eq!(s.main_size(AxisDirection::Horizontal), 20.);
1039        s.set_cross_size(AxisDirection::Horizontal, 30.);
1040        assert_eq!(s.cross_size(AxisDirection::Horizontal), 30.);
1041    }
1042}