1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
use crate::*;

#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[repr(C)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Rect<T> {
    pub origin: Point<T>,
    pub size: Size<T>,
}

impl<T> Rect<T> {
    #[inline]
    pub fn new(origin: impl Into<Point<T>>, size: impl Into<Size<T>>) -> Self {
        Self {
            origin: origin.into(),
            size: size.into(),
        }
    }
}

impl<T> Rect<T>
where
    T: std::ops::Add<T, Output = T> + Copy,
{
    pub fn endpoint(&self) -> Point<T> {
        self.origin + self.size
    }
}

impl<T> Rect<T>
where
    T: std::ops::Sub<T, Output = T> + Copy + PartialOrd,
{
    #[inline]
    pub fn from_points(a: impl Into<Point<T>>, b: impl Into<Point<T>>) -> Self {
        let a = a.into();
        let b = b.into();
        let (t, u) = {
            let (tx, ux) = (a.x < b.x).then(|| (a.x, b.x)).unwrap_or((b.x, a.x));
            let (ty, uy) = (a.y < b.y).then(|| (a.y, b.y)).unwrap_or((b.y, a.y));
            (point(tx, ty), point(ux, uy))
        };
        Self::new(t, u - t)
    }
}

impl<T> Rect<T>
where
    T: std::ops::Add<T, Output = T> + Copy,
{
    #[inline]
    pub fn translate(&self, d: impl Into<Vector<T>>) -> Self {
        let d = d.into();
        Self::new(self.origin + d, self.size)
    }
}

impl<T> Rect<T>
where
    T: std::ops::Mul<T, Output = T> + Copy,
{
    #[inline]
    pub fn scale(&self, x: T, y: T) -> Self {
        Self::new(self.origin, (self.size.width * x, self.size.height * y))
    }
}

impl<T: ToPrimitive> Rect<T> {
    #[inline]
    pub fn cast<U: NumCast>(self) -> Option<Rect<U>> {
        Some(Rect::new(self.origin.cast::<U>()?, self.size.cast::<U>()?))
    }
}

#[inline]
pub fn rect<T>(point: impl Into<Point<T>>, size: impl Into<Size<T>>) -> Rect<T> {
    Rect::new(point, size)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn eq_test() {
        assert!(rect((10, 20), (30, 40)) == rect((10, 20), (30, 40)));
    }

    #[test]
    fn from_points_test() {
        let rc = Rect::from_points((10, 20), (30, 40));
        assert!(rc == rect((10, 20), (20, 20)));
        assert!(rc.endpoint() == (30, 40));
    }

    #[test]
    fn translate_test() {
        assert!(rect((10, 20), (30, 40)).translate((1, 2)) == rect((11, 22), (30, 40)));
    }

    #[test]
    fn scale_test() {
        assert!(rect((10, 20), (30, 40)).scale(2, 3) == rect((10, 20), (60, 120)));
    }
}