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
42impl<T: Add> Rect<T> {
43 #[inline(always)]
44 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#[derive(Copy, Clone, Debug, PartialEq, Eq)]
56pub enum AbstractAxis {
57 Inline,
59 Block,
61}
62
63impl AbstractAxis {
64 #[inline]
66 pub const fn other(&self) -> AbstractAxis {
67 match *self {
68 AbstractAxis::Inline => AbstractAxis::Block,
69 AbstractAxis::Block => AbstractAxis::Inline,
70 }
71 }
72
73 #[inline]
76 pub const fn as_abs_naive(&self) -> AbsoluteAxis {
77 match self {
78 AbstractAxis::Inline => AbsoluteAxis::Horizontal,
79 AbstractAxis::Block => AbsoluteAxis::Vertical,
80 }
81 }
82}
83
84#[derive(Clone, Copy, Debug, PartialEq, Eq)]
87pub(crate) struct InBothAbsAxis<T> {
88 pub horizontal: T,
90 pub vertical: T,
92}
93
94impl<T: Copy> InBothAbsAxis<T> {
95 #[cfg(feature = "grid")]
96 pub const fn get(&self, axis: AbsoluteAxis) -> T {
98 match axis {
99 AbsoluteAxis::Horizontal => self.horizontal,
100 AbsoluteAxis::Vertical => self.vertical,
101 }
102 }
103}
104
105#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
107#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
108pub struct Rect<T> {
109 pub left: T,
115 pub right: T,
121 pub top: T,
124 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 #[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 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 pub fn horizontal_components(self) -> Line<T> {
174 Line { start: self.left, end: self.right }
175 }
176
177 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 #[inline(always)]
193 pub fn horizontal_axis_sum(&self) -> U {
194 self.left + self.right
195 }
196
197 #[inline(always)]
203 pub fn vertical_axis_sum(&self) -> U {
204 self.top + self.bottom
205 }
206
207 #[inline(always)]
211 #[allow(dead_code)] pub fn sum_axes(&self) -> Size<U> {
213 Size { width: self.horizontal_axis_sum(), height: self.vertical_axis_sum() }
214 }
215
216 #[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 #[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 #[cfg(feature = "flexbox")]
251 pub(crate) const fn main_start(&self, direction: FlexDirection) -> T {
252 if direction.is_row() {
253 self.left
254 } else {
255 self.top
256 }
257 }
258
259 #[cfg(feature = "flexbox")]
261 pub(crate) const fn main_end(&self, direction: FlexDirection) -> T {
262 if direction.is_row() {
263 self.right
264 } else {
265 self.bottom
266 }
267 }
268
269 #[cfg(feature = "flexbox")]
271 pub(crate) const fn cross_start(&self, direction: FlexDirection) -> T {
272 if direction.is_row() {
273 self.top
274 } else {
275 self.left
276 }
277 }
278
279 #[cfg(feature = "flexbox")]
281 pub(crate) const 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 pub const ZERO: Rect<f32> = Self { left: 0.0, right: 0.0, top: 0.0, bottom: 0.0 };
293
294 #[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 #[must_use]
304 pub fn union(self, other: Self) -> Self {
305 Self {
306 left: self.left.min(other.left),
307 right: self.right.max(other.right),
308 top: self.top.min(other.top),
309 bottom: self.bottom.max(other.bottom),
310 }
311 }
312}
313
314#[derive(Debug, Copy, Clone, PartialEq, Eq)]
316#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
317#[cfg_attr(feature = "serde", serde(default))]
318pub struct Line<T> {
319 pub start: T,
321 pub end: T,
323}
324
325impl<T> Line<T> {
326 pub fn map<R, F>(self, f: F) -> Line<R>
330 where
331 F: Fn(T) -> R,
332 {
333 Line { start: f(self.start), end: f(self.end) }
334 }
335}
336
337impl Line<bool> {
338 pub const TRUE: Self = Line { start: true, end: true };
340 pub const FALSE: Self = Line { start: false, end: false };
342}
343
344impl<T: Add + Copy> Line<T> {
345 pub fn sum(&self) -> <T as Add>::Output {
347 self.start + self.end
348 }
349}
350
351#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
353#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
354pub struct Size<T> {
355 pub width: T,
357 pub height: T,
359}
360
361impl<U, T: Add<U>> Add<Size<U>> for Size<T> {
363 type Output = Size<<T as Add<U>>::Output>;
364
365 fn add(self, rhs: Size<U>) -> Self::Output {
366 Size { width: self.width + rhs.width, height: self.height + rhs.height }
367 }
368}
369
370impl<U, T: Sub<U>> Sub<Size<U>> for Size<T> {
372 type Output = Size<<T as Sub<U>>::Output>;
373
374 fn sub(self, rhs: Size<U>) -> Self::Output {
375 Size { width: self.width - rhs.width, height: self.height - rhs.height }
376 }
377}
378
379#[allow(dead_code)]
382impl<T> Size<T> {
383 pub fn map<R, F>(self, f: F) -> Size<R>
387 where
388 F: Fn(T) -> R,
389 {
390 Size { width: f(self.width), height: f(self.height) }
391 }
392
393 pub fn map_width<F>(self, f: F) -> Size<T>
395 where
396 F: Fn(T) -> T,
397 {
398 Size { width: f(self.width), height: self.height }
399 }
400
401 pub fn map_height<F>(self, f: F) -> Size<T>
403 where
404 F: Fn(T) -> T,
405 {
406 Size { width: self.width, height: f(self.height) }
407 }
408
409 pub fn zip_map<Other, Ret, Func>(self, other: Size<Other>, f: Func) -> Size<Ret>
412 where
413 Func: Fn(T, Other) -> Ret,
414 {
415 Size { width: f(self.width, other.width), height: f(self.height, other.height) }
416 }
417
418 #[cfg(feature = "flexbox")]
422 pub(crate) fn set_main(&mut self, direction: FlexDirection, value: T) {
423 if direction.is_row() {
424 self.width = value
425 } else {
426 self.height = value
427 }
428 }
429
430 #[cfg(feature = "flexbox")]
434 pub(crate) fn set_cross(&mut self, direction: FlexDirection, value: T) {
435 if direction.is_row() {
436 self.height = value
437 } else {
438 self.width = value
439 }
440 }
441
442 #[cfg(feature = "flexbox")]
446 pub(crate) fn with_main(self, direction: FlexDirection, value: T) -> Self {
447 let mut new = self;
448 if direction.is_row() {
449 new.width = value
450 } else {
451 new.height = value
452 }
453 new
454 }
455
456 #[cfg(feature = "flexbox")]
460 pub(crate) fn with_cross(self, direction: FlexDirection, value: T) -> Self {
461 let mut new = self;
462 if direction.is_row() {
463 new.height = value
464 } else {
465 new.width = value
466 }
467 new
468 }
469
470 #[cfg(feature = "flexbox")]
474 pub(crate) fn map_main(self, direction: FlexDirection, mapper: impl FnOnce(T) -> T) -> Self {
475 let mut new = self;
476 if direction.is_row() {
477 new.width = mapper(new.width);
478 } else {
479 new.height = mapper(new.height);
480 }
481 new
482 }
483
484 #[cfg(feature = "flexbox")]
488 pub(crate) fn map_cross(self, direction: FlexDirection, mapper: impl FnOnce(T) -> T) -> Self {
489 let mut new = self;
490 if direction.is_row() {
491 new.height = mapper(new.height);
492 } else {
493 new.width = mapper(new.width);
494 }
495 new
496 }
497
498 #[cfg(feature = "flexbox")]
502 pub(crate) fn main(self, direction: FlexDirection) -> T {
503 if direction.is_row() {
504 self.width
505 } else {
506 self.height
507 }
508 }
509
510 #[cfg(feature = "flexbox")]
514 pub(crate) fn cross(self, direction: FlexDirection) -> T {
515 if direction.is_row() {
516 self.height
517 } else {
518 self.width
519 }
520 }
521
522 #[cfg(feature = "grid")]
525 pub(crate) fn get(self, axis: AbstractAxis) -> T {
526 match axis {
527 AbstractAxis::Inline => self.width,
528 AbstractAxis::Block => self.height,
529 }
530 }
531
532 #[cfg(feature = "grid")]
535 pub(crate) fn set(&mut self, axis: AbstractAxis, value: T) {
536 match axis {
537 AbstractAxis::Inline => self.width = value,
538 AbstractAxis::Block => self.height = value,
539 }
540 }
541
542 #[cfg(feature = "grid")]
545 pub(crate) fn with(mut self, axis: AbstractAxis, value: T) -> Self {
546 match axis {
547 AbstractAxis::Inline => self.width = value,
548 AbstractAxis::Block => self.height = value,
549 }
550 self
551 }
552}
553
554impl Size<f32> {
555 pub const ZERO: Size<f32> = Self { width: 0.0, height: 0.0 };
557
558 #[inline(always)]
560 pub fn f32_max(self, rhs: Size<f32>) -> Size<f32> {
561 Size { width: f32_max(self.width, rhs.width), height: f32_max(self.height, rhs.height) }
562 }
563
564 #[inline(always)]
566 pub fn f32_min(self, rhs: Size<f32>) -> Size<f32> {
567 Size { width: f32_min(self.width, rhs.width), height: f32_min(self.height, rhs.height) }
568 }
569
570 #[inline(always)]
572 pub fn has_non_zero_area(self) -> bool {
573 self.width > 0.0 && self.height > 0.0
574 }
575}
576
577impl Size<Option<f32>> {
578 pub const NONE: Size<Option<f32>> = Self { width: None, height: None };
580
581 #[must_use]
583 pub const fn new(width: f32, height: f32) -> Self {
584 Size { width: Some(width), height: Some(height) }
585 }
586
587 #[cfg(feature = "flexbox")]
589 pub const fn from_cross(direction: FlexDirection, value: Option<f32>) -> Self {
590 let mut new = Self::NONE;
591 if direction.is_row() {
592 new.height = value
593 } else {
594 new.width = value
595 }
596 new
597 }
598
599 pub fn maybe_apply_aspect_ratio(self, aspect_ratio: Option<f32>) -> Size<Option<f32>> {
605 match aspect_ratio {
606 Some(ratio) => match (self.width, self.height) {
607 (Some(width), None) => Size { width: Some(width), height: Some(width / ratio) },
608 (None, Some(height)) => Size { width: Some(height * ratio), height: Some(height) },
609 _ => self,
610 },
611 None => self,
612 }
613 }
614}
615
616impl<T> Size<Option<T>> {
617 pub fn unwrap_or(self, alt: Size<T>) -> Size<T> {
619 Size { width: self.width.unwrap_or(alt.width), height: self.height.unwrap_or(alt.height) }
620 }
621
622 pub fn or(self, alt: Size<Option<T>>) -> Size<Option<T>> {
624 Size { width: self.width.or(alt.width), height: self.height.or(alt.height) }
625 }
626
627 #[inline(always)]
629 pub fn both_axis_defined(&self) -> bool {
630 self.width.is_some() && self.height.is_some()
631 }
632}
633
634impl Size<Dimension> {
635 #[must_use]
637 pub const fn from_lengths(width: f32, height: f32) -> Self {
638 Size { width: Dimension(CompactLength::length(width)), height: Dimension(CompactLength::length(height)) }
639 }
640
641 #[must_use]
643 pub const fn from_percent(width: f32, height: f32) -> Self {
644 Size { width: Dimension(CompactLength::percent(width)), height: Dimension(CompactLength::percent(height)) }
645 }
646}
647
648#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
652#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
653pub struct Point<T> {
654 pub x: T,
656 pub y: T,
658}
659
660impl Point<f32> {
661 pub const ZERO: Self = Self { x: 0.0, y: 0.0 };
663}
664
665impl Point<Option<f32>> {
666 pub const NONE: Self = Self { x: None, y: None };
668}
669
670impl<U, T: Add<U>> Add<Point<U>> for Point<T> {
672 type Output = Point<<T as Add<U>>::Output>;
673
674 fn add(self, rhs: Point<U>) -> Self::Output {
675 Point { x: self.x + rhs.x, y: self.y + rhs.y }
676 }
677}
678
679impl<T> Point<T> {
680 pub fn map<R, F>(self, f: F) -> Point<R>
684 where
685 F: Fn(T) -> R,
686 {
687 Point { x: f(self.x), y: f(self.y) }
688 }
689
690 #[cfg(feature = "grid")]
693 pub fn get(self, axis: AbstractAxis) -> T {
694 match axis {
695 AbstractAxis::Inline => self.x,
696 AbstractAxis::Block => self.y,
697 }
698 }
699
700 pub fn transpose(self) -> Point<T> {
702 Point { x: self.y, y: self.x }
703 }
704
705 #[cfg(feature = "grid")]
708 pub fn set(&mut self, axis: AbstractAxis, value: T) {
709 match axis {
710 AbstractAxis::Inline => self.x = value,
711 AbstractAxis::Block => self.y = value,
712 }
713 }
714
715 #[cfg(feature = "flexbox")]
719 pub(crate) fn main(self, direction: FlexDirection) -> T {
720 if direction.is_row() {
721 self.x
722 } else {
723 self.y
724 }
725 }
726
727 #[cfg(feature = "flexbox")]
731 pub(crate) fn cross(self, direction: FlexDirection) -> T {
732 if direction.is_row() {
733 self.y
734 } else {
735 self.x
736 }
737 }
738}
739
740impl<T> From<Point<T>> for Size<T> {
741 fn from(value: Point<T>) -> Self {
742 Size { width: value.x, height: value.y }
743 }
744}
745
746#[derive(Debug, Copy, Clone, PartialEq, Eq)]
748#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
749pub struct MinMax<Min, Max> {
750 pub min: Min,
752 pub max: Max,
754}