hayro_syntax/object/
rect.rs

1//! Rectangles.
2
3use crate::object::Array;
4use crate::object::{Object, ObjectLike};
5use crate::reader::{Readable, ReaderContext, ReaderExt};
6
7use crate::reader::Reader;
8
9/// A rectangle.
10#[derive(Copy, Clone, Debug)]
11pub struct Rect {
12    /// The minimum x coordinate.
13    pub x0: f64,
14    /// The minimum y coordinate.
15    pub y0: f64,
16    /// The maximum x coordinate.
17    pub x1: f64,
18    /// The maximum y coordinate.
19    pub y1: f64,
20}
21
22impl Rect {
23    /// The empty rectangle at the origin.
24    pub const ZERO: Self = Self::new(0., 0., 0., 0.);
25
26    /// A new rectangle from minimum and maximum coordinates.
27    #[inline(always)]
28    pub const fn new(x0: f64, y0: f64, x1: f64, y1: f64) -> Self {
29        Self { x0, y0, x1, y1 }
30    }
31
32    /// The intersection of two rectangles.
33    #[inline]
34    pub fn intersect(&self, other: Self) -> Self {
35        let x0 = self.x0.max(other.x0);
36        let y0 = self.y0.max(other.y0);
37        let x1 = self.x1.min(other.x1);
38        let y1 = self.y1.min(other.y1);
39        Self::new(x0, y0, x1.max(x0), y1.max(y0))
40    }
41
42    /// The width of the rectangle.
43    #[inline]
44    pub const fn width(&self) -> f64 {
45        self.x1 - self.x0
46    }
47
48    /// The height of the rectangle.
49    #[inline]
50    pub const fn height(&self) -> f64 {
51        self.y1 - self.y0
52    }
53}
54
55impl<'a> Readable<'a> for Rect {
56    fn read(r: &mut Reader<'a>, ctx: &ReaderContext<'a>) -> Option<Self> {
57        let arr = r.read::<Array<'_>>(ctx)?;
58        from_arr(&arr)
59    }
60}
61
62fn from_arr(array: &Array<'_>) -> Option<Rect> {
63    let mut iter = array.iter::<f32>();
64    let x0 = iter.next()? as f64;
65    let y0 = iter.next()? as f64;
66    let x1 = iter.next()? as f64;
67    let y1 = iter.next()? as f64;
68
69    Some(Rect::new(x0.min(x1), y0.min(y1), x1.max(x0), y1.max(y0)))
70}
71
72impl TryFrom<Object<'_>> for Rect {
73    type Error = ();
74
75    fn try_from(value: Object<'_>) -> Result<Self, Self::Error> {
76        match value {
77            Object::Array(arr) => from_arr(&arr).ok_or(()),
78            _ => Err(()),
79        }
80    }
81}
82
83impl ObjectLike<'_> for Rect {}