1use 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#[derive(Copy, Clone, Debug, PartialEq, Eq)]
13pub enum AbsoluteAxis {
14 Horizontal,
16 Vertical,
18}
19
20impl AbsoluteAxis {
21 #[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 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 #[inline(always)]
43 pub fn transpose(self) -> Size<T> {
44 Size { width: self.height, height: self.width }
45 }
46}
47
48impl<T: Add> Rect<T> {
49 #[inline(always)]
50 pub fn grid_axis_sum(self, axis: AbsoluteAxis) -> <T as Add>::Output {
52 match axis {
53 AbsoluteAxis::Horizontal => self.left + self.right,
54 AbsoluteAxis::Vertical => self.top + self.bottom,
55 }
56 }
57}
58
59#[derive(Copy, Clone, Debug, PartialEq, Eq)]
62pub enum AbstractAxis {
63 Inline,
65 Block,
67}
68
69impl AbstractAxis {
70 #[inline]
72 pub const fn other(&self) -> AbstractAxis {
73 match *self {
74 AbstractAxis::Inline => AbstractAxis::Block,
75 AbstractAxis::Block => AbstractAxis::Inline,
76 }
77 }
78
79 #[inline]
82 pub const fn as_abs_naive(&self) -> AbsoluteAxis {
83 match self {
84 AbstractAxis::Inline => AbsoluteAxis::Horizontal,
85 AbstractAxis::Block => AbsoluteAxis::Vertical,
86 }
87 }
88}
89
90#[derive(Clone, Copy, Debug, PartialEq, Eq)]
93pub(crate) struct InBothAbsAxis<T> {
94 pub horizontal: T,
96 pub vertical: T,
98}
99
100impl<T: Copy> InBothAbsAxis<T> {
101 #[cfg(feature = "grid")]
102 pub const fn get(&self, axis: AbsoluteAxis) -> T {
104 match axis {
105 AbsoluteAxis::Horizontal => self.horizontal,
106 AbsoluteAxis::Vertical => self.vertical,
107 }
108 }
109}
110
111#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
113#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
114pub struct Rect<T> {
115 pub left: T,
121 pub right: T,
127 pub top: T,
130 pub bottom: T,
133}
134
135impl<U, T: Add<U>> Add<Rect<U>> for Rect<T> {
136 type Output = Rect<T::Output>;
137
138 fn add(self, rhs: Rect<U>) -> Self::Output {
139 Rect {
140 left: self.left + rhs.left,
141 right: self.right + rhs.right,
142 top: self.top + rhs.top,
143 bottom: self.bottom + rhs.bottom,
144 }
145 }
146}
147
148impl<T> Rect<T> {
149 #[inline(always)]
151 pub fn transpose(self) -> Rect<T> {
152 Rect { left: self.top, right: self.bottom, top: self.left, bottom: self.right }
153 }
154
155 #[cfg(any(feature = "flexbox", feature = "block_layout"))]
161 #[inline(always)]
162 pub(crate) fn zip_size<R, F, U>(self, size: Size<U>, f: F) -> Rect<R>
163 where
164 F: Fn(T, U) -> R,
165 U: Copy,
166 {
167 Rect {
168 left: f(self.left, size.width),
169 right: f(self.right, size.width),
170 top: f(self.top, size.height),
171 bottom: f(self.bottom, size.height),
172 }
173 }
174
175 #[inline(always)]
179 pub fn map<R, F>(self, f: F) -> Rect<R>
180 where
181 F: Fn(T) -> R,
182 {
183 Rect { left: f(self.left), right: f(self.right), top: f(self.top), bottom: f(self.bottom) }
184 }
185
186 pub fn horizontal_components(self) -> Line<T> {
188 Line { start: self.left, end: self.right }
189 }
190
191 pub fn vertical_components(self) -> Line<T> {
193 Line { start: self.top, end: self.bottom }
194 }
195}
196
197impl<T, U> Rect<T>
198where
199 T: Add<Output = U> + Copy + Clone,
200{
201 #[inline(always)]
207 pub fn horizontal_axis_sum(&self) -> U {
208 self.left + self.right
209 }
210
211 #[inline(always)]
217 pub fn vertical_axis_sum(&self) -> U {
218 self.top + self.bottom
219 }
220
221 #[inline(always)]
225 #[allow(dead_code)] pub fn sum_axes(&self) -> Size<U> {
227 Size { width: self.horizontal_axis_sum(), height: self.vertical_axis_sum() }
228 }
229
230 #[cfg(feature = "flexbox")]
237 pub(crate) fn main_axis_sum(&self, direction: FlexDirection) -> U {
238 if direction.is_row() {
239 self.horizontal_axis_sum()
240 } else {
241 self.vertical_axis_sum()
242 }
243 }
244
245 #[cfg(feature = "flexbox")]
250 pub(crate) fn cross_axis_sum(&self, direction: FlexDirection) -> U {
251 if direction.is_row() {
252 self.vertical_axis_sum()
253 } else {
254 self.horizontal_axis_sum()
255 }
256 }
257}
258
259impl<T> Rect<T>
260where
261 T: Copy + Clone,
262{
263 #[cfg(feature = "flexbox")]
265 pub(crate) const fn main_start(&self, direction: FlexDirection) -> T {
266 if direction.is_row() {
267 self.left
268 } else {
269 self.top
270 }
271 }
272
273 #[cfg(feature = "flexbox")]
275 pub(crate) const fn main_end(&self, direction: FlexDirection) -> T {
276 if direction.is_row() {
277 self.right
278 } else {
279 self.bottom
280 }
281 }
282
283 #[cfg(feature = "flexbox")]
285 pub(crate) const fn cross_start(&self, direction: FlexDirection) -> T {
286 if direction.is_row() {
287 self.top
288 } else {
289 self.left
290 }
291 }
292
293 #[cfg(feature = "flexbox")]
295 pub(crate) const fn cross_end(&self, direction: FlexDirection) -> T {
296 if direction.is_row() {
297 self.bottom
298 } else {
299 self.right
300 }
301 }
302}
303
304impl Rect<Option<f32>> {
305 pub const NONE: Rect<Option<f32>> = Self { left: None, right: None, top: None, bottom: None };
307}
308
309impl Rect<f32> {
310 pub const ZERO: Rect<f32> = Self { left: 0.0, right: 0.0, top: 0.0, bottom: 0.0 };
312
313 #[must_use]
315 pub const fn new(start: f32, end: f32, top: f32, bottom: f32) -> Self {
316 Self { left: start, right: end, top, bottom }
317 }
318
319 #[must_use]
323 pub fn union(self, other: Self) -> Self {
324 Self {
325 left: self.left.min(other.left),
326 right: self.right.max(other.right),
327 top: self.top.min(other.top),
328 bottom: self.bottom.max(other.bottom),
329 }
330 }
331}
332
333#[derive(Debug, Copy, Clone, PartialEq, Eq)]
335#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
336#[cfg_attr(feature = "serde", serde(default))]
337pub struct Line<T> {
338 pub start: T,
340 pub end: T,
342}
343
344impl<T> Line<T> {
345 pub fn map<R, F>(self, f: F) -> Line<R>
349 where
350 F: Fn(T) -> R,
351 {
352 Line { start: f(self.start), end: f(self.end) }
353 }
354}
355
356impl Line<bool> {
357 pub const TRUE: Self = Line { start: true, end: true };
359 pub const FALSE: Self = Line { start: false, end: false };
361}
362
363impl<T: Add + Copy> Line<T> {
364 pub fn sum(&self) -> <T as Add>::Output {
366 self.start + self.end
367 }
368}
369
370#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
372#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
373pub struct Size<T> {
374 pub width: T,
376 pub height: T,
378}
379
380impl<U, T: Add<U>> Add<Size<U>> for Size<T> {
382 type Output = Size<<T as Add<U>>::Output>;
383
384 fn add(self, rhs: Size<U>) -> Self::Output {
385 Size { width: self.width + rhs.width, height: self.height + rhs.height }
386 }
387}
388
389impl<U, T: Sub<U>> Sub<Size<U>> for Size<T> {
391 type Output = Size<<T as Sub<U>>::Output>;
392
393 fn sub(self, rhs: Size<U>) -> Self::Output {
394 Size { width: self.width - rhs.width, height: self.height - rhs.height }
395 }
396}
397
398#[allow(dead_code)]
401impl<T> Size<T> {
402 pub fn map<R, F>(self, f: F) -> Size<R>
406 where
407 F: Fn(T) -> R,
408 {
409 Size { width: f(self.width), height: f(self.height) }
410 }
411
412 pub fn map_width<F>(self, f: F) -> Size<T>
414 where
415 F: Fn(T) -> T,
416 {
417 Size { width: f(self.width), height: self.height }
418 }
419
420 pub fn map_height<F>(self, f: F) -> Size<T>
422 where
423 F: Fn(T) -> T,
424 {
425 Size { width: self.width, height: f(self.height) }
426 }
427
428 pub fn zip_map<Other, Ret, Func>(self, other: Size<Other>, f: Func) -> Size<Ret>
431 where
432 Func: Fn(T, Other) -> Ret,
433 {
434 Size { width: f(self.width, other.width), height: f(self.height, other.height) }
435 }
436
437 #[cfg(feature = "flexbox")]
441 pub(crate) fn set_main(&mut self, direction: FlexDirection, value: T) {
442 if direction.is_row() {
443 self.width = value
444 } else {
445 self.height = value
446 }
447 }
448
449 #[cfg(feature = "flexbox")]
453 pub(crate) fn set_cross(&mut self, direction: FlexDirection, value: T) {
454 if direction.is_row() {
455 self.height = value
456 } else {
457 self.width = value
458 }
459 }
460
461 #[cfg(feature = "flexbox")]
465 pub(crate) fn with_main(self, direction: FlexDirection, value: T) -> Self {
466 let mut new = self;
467 if direction.is_row() {
468 new.width = value
469 } else {
470 new.height = value
471 }
472 new
473 }
474
475 #[cfg(feature = "flexbox")]
479 pub(crate) fn with_cross(self, direction: FlexDirection, value: T) -> Self {
480 let mut new = self;
481 if direction.is_row() {
482 new.height = value
483 } else {
484 new.width = value
485 }
486 new
487 }
488
489 #[cfg(feature = "flexbox")]
493 pub(crate) fn map_main(self, direction: FlexDirection, mapper: impl FnOnce(T) -> T) -> Self {
494 let mut new = self;
495 if direction.is_row() {
496 new.width = mapper(new.width);
497 } else {
498 new.height = mapper(new.height);
499 }
500 new
501 }
502
503 #[cfg(feature = "flexbox")]
507 pub(crate) fn map_cross(self, direction: FlexDirection, mapper: impl FnOnce(T) -> T) -> Self {
508 let mut new = self;
509 if direction.is_row() {
510 new.height = mapper(new.height);
511 } else {
512 new.width = mapper(new.width);
513 }
514 new
515 }
516
517 #[cfg(feature = "flexbox")]
521 pub(crate) fn main(self, direction: FlexDirection) -> T {
522 if direction.is_row() {
523 self.width
524 } else {
525 self.height
526 }
527 }
528
529 #[cfg(feature = "flexbox")]
533 pub(crate) fn cross(self, direction: FlexDirection) -> T {
534 if direction.is_row() {
535 self.height
536 } else {
537 self.width
538 }
539 }
540
541 #[cfg(feature = "grid")]
544 pub(crate) fn get(self, axis: AbstractAxis) -> T {
545 match axis {
546 AbstractAxis::Inline => self.width,
547 AbstractAxis::Block => self.height,
548 }
549 }
550
551 #[cfg(feature = "grid")]
554 pub(crate) fn set(&mut self, axis: AbstractAxis, value: T) {
555 match axis {
556 AbstractAxis::Inline => self.width = value,
557 AbstractAxis::Block => self.height = value,
558 }
559 }
560
561 #[cfg(feature = "grid")]
564 pub(crate) fn with(mut self, axis: AbstractAxis, value: T) -> Self {
565 match axis {
566 AbstractAxis::Inline => self.width = value,
567 AbstractAxis::Block => self.height = value,
568 }
569 self
570 }
571}
572
573impl Size<f32> {
574 pub const ZERO: Size<f32> = Self { width: 0.0, height: 0.0 };
576
577 #[inline(always)]
579 pub fn f32_max(self, rhs: Size<f32>) -> Size<f32> {
580 Size { width: f32_max(self.width, rhs.width), height: f32_max(self.height, rhs.height) }
581 }
582
583 #[inline(always)]
585 pub fn f32_min(self, rhs: Size<f32>) -> Size<f32> {
586 Size { width: f32_min(self.width, rhs.width), height: f32_min(self.height, rhs.height) }
587 }
588
589 #[inline(always)]
591 pub fn has_non_zero_area(self) -> bool {
592 self.width > 0.0 && self.height > 0.0
593 }
594}
595
596impl Size<Option<f32>> {
597 pub const NONE: Size<Option<f32>> = Self { width: None, height: None };
599
600 #[must_use]
602 pub const fn new(width: f32, height: f32) -> Self {
603 Size { width: Some(width), height: Some(height) }
604 }
605
606 #[cfg(feature = "flexbox")]
608 pub const fn from_cross(direction: FlexDirection, value: Option<f32>) -> Self {
609 let mut new = Self::NONE;
610 if direction.is_row() {
611 new.height = value
612 } else {
613 new.width = value
614 }
615 new
616 }
617
618 pub fn maybe_apply_aspect_ratio(self, aspect_ratio: Option<f32>) -> Size<Option<f32>> {
624 match aspect_ratio {
625 Some(ratio) => match (self.width, self.height) {
626 (Some(width), None) => Size { width: Some(width), height: Some(width / ratio) },
627 (None, Some(height)) => Size { width: Some(height * ratio), height: Some(height) },
628 _ => self,
629 },
630 None => self,
631 }
632 }
633}
634
635impl<T> Size<Option<T>> {
636 pub fn unwrap_or(self, alt: Size<T>) -> Size<T> {
638 Size { width: self.width.unwrap_or(alt.width), height: self.height.unwrap_or(alt.height) }
639 }
640
641 pub fn or(self, alt: Size<Option<T>>) -> Size<Option<T>> {
643 Size { width: self.width.or(alt.width), height: self.height.or(alt.height) }
644 }
645
646 #[inline(always)]
648 pub fn both_axis_defined(&self) -> bool {
649 self.width.is_some() && self.height.is_some()
650 }
651}
652
653impl Size<Dimension> {
654 #[must_use]
656 pub const fn from_lengths(width: f32, height: f32) -> Self {
657 Size { width: Dimension(CompactLength::length(width)), height: Dimension(CompactLength::length(height)) }
658 }
659
660 #[must_use]
662 pub const fn from_percent(width: f32, height: f32) -> Self {
663 Size { width: Dimension(CompactLength::percent(width)), height: Dimension(CompactLength::percent(height)) }
664 }
665}
666
667#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
671#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
672pub struct Point<T> {
673 pub x: T,
675 pub y: T,
677}
678
679impl Point<f32> {
680 pub const ZERO: Self = Self { x: 0.0, y: 0.0 };
682}
683
684impl Point<Option<f32>> {
685 pub const NONE: Self = Self { x: None, y: None };
687}
688
689impl<U, T: Add<U>> Add<Point<U>> for Point<T> {
691 type Output = Point<<T as Add<U>>::Output>;
692
693 fn add(self, rhs: Point<U>) -> Self::Output {
694 Point { x: self.x + rhs.x, y: self.y + rhs.y }
695 }
696}
697
698impl<T> Point<T> {
699 pub fn map<R, F>(self, f: F) -> Point<R>
703 where
704 F: Fn(T) -> R,
705 {
706 Point { x: f(self.x), y: f(self.y) }
707 }
708
709 #[cfg(feature = "grid")]
712 pub fn get(self, axis: AbstractAxis) -> T {
713 match axis {
714 AbstractAxis::Inline => self.x,
715 AbstractAxis::Block => self.y,
716 }
717 }
718
719 pub fn transpose(self) -> Point<T> {
721 Point { x: self.y, y: self.x }
722 }
723
724 #[cfg(feature = "grid")]
727 pub fn set(&mut self, axis: AbstractAxis, value: T) {
728 match axis {
729 AbstractAxis::Inline => self.x = value,
730 AbstractAxis::Block => self.y = value,
731 }
732 }
733
734 #[cfg(feature = "flexbox")]
738 pub(crate) fn main(self, direction: FlexDirection) -> T {
739 if direction.is_row() {
740 self.x
741 } else {
742 self.y
743 }
744 }
745
746 #[cfg(feature = "flexbox")]
750 pub(crate) fn cross(self, direction: FlexDirection) -> T {
751 if direction.is_row() {
752 self.y
753 } else {
754 self.x
755 }
756 }
757}
758
759impl<T> From<Point<T>> for Size<T> {
760 fn from(value: Point<T>) -> Self {
761 Size { width: value.x, height: value.y }
762 }
763}
764
765#[derive(Debug, Copy, Clone, PartialEq, Eq)]
767#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
768pub struct MinMax<Min, Max> {
769 pub min: Min,
771 pub max: Max,
773}