fey_math/
rect.rs

1use crate::{
2    Circle, Float, Line, Num, Polygonal, Projection, Ray, RayHit, Shape, Signed, Vec2, extract_on,
3    impl_approx, impl_bytemuck, impl_casts, impl_interp, impl_serde, impl_tuple_arr, line,
4    overlaps_on, vec2,
5};
6use std::fmt::{Display, Formatter};
7use std::ops::{Add, AddAssign, Sub, SubAssign};
8
9use super::Quad;
10
11pub type RectF = Rect<f32>;
12pub type RectI = Rect<i32>;
13pub type RectU = Rect<u32>;
14
15/// A 2D axis-aligned rectangle.
16///
17/// Most of the methods for this struct assume that the rectangle
18/// has a positive width and height, so rectangles where `T` is
19/// signed may yield incorrect values for negative-sized instances.
20#[repr(C)]
21#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
22pub struct Rect<T> {
23    pub x: T,
24    pub y: T,
25    pub w: T,
26    pub h: T,
27}
28
29impl_tuple_arr!(
30    NAME = Rect
31    LEN = 4
32    FIELDS = (x, y, w, h)
33    TUPLE = (T, T, T, T)
34);
35
36impl_approx!(
37    NAME = Rect
38    FIELDS = (x, y, w, h)
39);
40
41impl_serde!(
42    NAME = Rect
43    FIELDS = (x, y, w, h)
44);
45
46impl_bytemuck!(Rect);
47
48impl_casts!(
49    NAME = Rect
50    FIELDS = (x, y, w, h)
51);
52
53impl_interp!(
54    NAME = Rect
55    FIELDS = (x, y, w, h)
56);
57
58/// Create a [`Rect`].
59#[inline]
60pub const fn rect<T>(x: T, y: T, w: T, h: T) -> Rect<T> {
61    Rect { x, y, w, h }
62}
63
64impl<T> Rect<T> {
65    /// Create a new rectangle.
66    #[inline]
67    pub const fn new(x: T, y: T, w: T, h: T) -> Self {
68        Self { x, y, w, h }
69    }
70
71    /// Map the rectangle from one type to another.
72    #[inline]
73    pub fn map<U, F: FnMut(T) -> U>(self, mut f: F) -> Rect<U> {
74        rect(f(self.x), f(self.y), f(self.w), f(self.h))
75    }
76}
77
78impl<T: Copy> Rect<T> {
79    /// The width and height of the rectangle.
80    #[inline]
81    pub fn size(&self) -> Vec2<T> {
82        vec2(self.w, self.h)
83    }
84
85    /// The left edge of the rectangle. Equivalent to `x`.
86    #[inline]
87    pub fn left(&self) -> T {
88        self.x
89    }
90
91    /// The top edge of the rectangle. Equivalent to `y`.
92    #[inline]
93    pub fn top(&self) -> T {
94        self.y
95    }
96
97    /// The top-left point of the rectangle.
98    #[inline]
99    pub fn top_left(&self) -> Vec2<T> {
100        vec2(self.left(), self.top())
101    }
102}
103
104impl<T: Num> Rect<T> {
105    /// A zero-sized rectangle.
106    pub const ZERO: Self = rect(T::ZERO, T::ZERO, T::ZERO, T::ZERO);
107
108    /// A rectangle at `(0, 0)` with the provided width and height.
109    #[inline]
110    pub const fn sized(size: Vec2<T>) -> Self {
111        rect(T::ZERO, T::ZERO, size.x, size.y)
112    }
113
114    /// A rectangle at `pos` with the `size`.
115    #[inline]
116    pub const fn pos_size(pos: Vec2<T>, size: Vec2<T>) -> Self {
117        rect(pos.x, pos.y, size.x, size.y)
118    }
119
120    /// Right edge of the rectangle. Equivalent to `x + w`.
121    #[inline]
122    pub fn right(&self) -> T {
123        self.x + self.w
124    }
125
126    /// Bottom edge of the rectangle. Equivalent to `y + h`.
127    #[inline]
128    pub fn bottom(&self) -> T {
129        self.y + self.h
130    }
131
132    /// Top-right point of the rectangle.
133    #[inline]
134    pub fn top_right(&self) -> Vec2<T> {
135        vec2(self.right(), self.top())
136    }
137
138    /// Bottom-right point of the rectangle.
139    #[inline]
140    pub fn bottom_right(&self) -> Vec2<T> {
141        vec2(self.right(), self.bottom())
142    }
143
144    /// Bottom-left point of the rectangle.
145    #[inline]
146    pub fn bottom_left(&self) -> Vec2<T> {
147        vec2(self.left(), self.bottom())
148    }
149
150    /// Center x-position of the rectangle.
151    #[inline]
152    pub fn center_x(&self) -> T {
153        self.x + self.w / T::TWO
154    }
155
156    /// Cente y-position of the rectangle.
157    #[inline]
158    pub fn center_y(&self) -> T {
159        self.y + self.h / T::TWO
160    }
161
162    /// Center point of the rectangle.
163    #[inline]
164    pub fn center(&self) -> Vec2<T> {
165        vec2(self.center_x(), self.center_y())
166    }
167
168    /// Center point along the rectangle's top edge.
169    #[inline]
170    pub fn top_center(&self) -> Vec2<T> {
171        vec2(self.center_x(), self.top())
172    }
173
174    /// Center point along the rectangle's bottom edge.
175    #[inline]
176    pub fn bottom_center(&self) -> Vec2<T> {
177        vec2(self.center_x(), self.bottom())
178    }
179
180    /// Center point along the rectangle's right edge.
181    #[inline]
182    pub fn right_center(&self) -> Vec2<T> {
183        vec2(self.right(), self.center_y())
184    }
185
186    /// Center point along the rectangle's left edge.
187    #[inline]
188    pub fn left_center(&self) -> Vec2<T> {
189        vec2(self.left(), self.center_y())
190    }
191
192    /// Area of the rectangle.
193    #[inline]
194    pub fn area(&self) -> T {
195        self.w * self.h
196    }
197
198    /// Length of the rectangle's perimeter.
199    #[inline]
200    pub fn perimeter(&self) -> T {
201        self.w + self.w + self.h + self.h
202    }
203
204    /// Returns true if this rectangle contains the point.
205    #[inline]
206    pub fn contains(&self, p: Vec2<T>) -> bool {
207        p.x >= self.x && p.y >= self.y && p.x < self.right() && p.y < self.bottom()
208    }
209
210    /// Translate the rectangle.
211    #[inline]
212    pub fn translate(&self, amount: &Vec2<T>) -> Self {
213        rect(self.x + amount.x, self.y + amount.y, self.w, self.h)
214    }
215
216    /// Top edge segment of the rectangle.
217    #[inline]
218    pub fn top_edge(&self) -> Line<T> {
219        line(self.top_left(), self.top_right())
220    }
221
222    /// Right edge segment of the rectangle.
223    #[inline]
224    pub fn right_edge(&self) -> Line<T> {
225        line(self.top_right(), self.bottom_right())
226    }
227
228    /// Bottom edge segment of the rectangle.
229    #[inline]
230    pub fn bottom_edge(&self) -> Line<T> {
231        line(self.bottom_right(), self.bottom_left())
232    }
233
234    /// Left edge segment of the rectangle.
235    #[inline]
236    pub fn left_edge(&self) -> Line<T> {
237        line(self.bottom_left(), self.top_left())
238    }
239
240    /// The rectangle's 4 corner points.
241    #[inline]
242    pub fn corners(&self) -> [Vec2<T>; 4] {
243        let r = self.right();
244        let b = self.bottom();
245        [
246            vec2(self.x, self.y),
247            vec2(r, self.y),
248            vec2(r, b),
249            vec2(self.x, b),
250        ]
251    }
252
253    /// The rectangle's 4 edges.
254    #[inline]
255    pub fn edges(&self) -> [Line<T>; 4] {
256        let [a, b, c, d] = self.corners();
257        [line(a, b), line(b, c), line(c, d), line(d, a)]
258    }
259
260    /// Inflate the rectangle by the amount.
261    #[inline]
262    pub fn inflate(self, amount: impl Into<Vec2<T>>) -> Self {
263        let amount = amount.into();
264        rect(
265            self.x - amount.x,
266            self.y - amount.y,
267            self.w + amount.x + amount.x,
268            self.h + amount.y + amount.y,
269        )
270    }
271
272    /// Absolute left bounds of the rectangle.
273    #[inline]
274    pub fn min_x(&self) -> T {
275        T::min(self.x, self.right())
276    }
277
278    /// Absolute top bounds of the rectangle.
279    #[inline]
280    pub fn min_y(&self) -> T {
281        T::min(self.y, self.bottom())
282    }
283
284    /// Absolute right bounds of the rectangle.
285    #[inline]
286    pub fn max_x(&self) -> T {
287        T::max(self.x, self.right())
288    }
289
290    /// Absolute bottom bounds of the rectangle.
291    #[inline]
292    pub fn max_y(&self) -> T {
293        T::max(self.y, self.bottom())
294    }
295
296    /// Absolute top-left point of the rectangle.
297    #[inline]
298    pub fn min_pos(&self) -> Vec2<T> {
299        vec2(self.min_x(), self.min_y())
300    }
301
302    /// Absolute bottom-right point of the rectangle.
303    #[inline]
304    pub fn max_pos(&self) -> Vec2<T> {
305        vec2(self.max_x(), self.max_y())
306    }
307
308    /// If this rectangle contains the other.
309    #[inline]
310    pub fn contains_rect(&self, r: &Self) -> bool {
311        r.x >= self.x && r.y >= self.y && r.right() <= self.right() && r.bottom() <= self.bottom()
312    }
313
314    /// If this rectangle overlaps the other.
315    #[inline]
316    pub fn overlaps(&self, r: &Self) -> bool {
317        self.x < r.right() && self.y < r.bottom() && self.right() > r.x && self.bottom() > r.y
318    }
319
320    /// If this rectangle overlaps the other, returns a rectangle
321    /// representing the overlapping region.
322    #[inline]
323    pub fn overlap(&self, r: &Self) -> Option<Self> {
324        let min = self.top_left().max(r.top_left());
325        let max = self.bottom_right().min(r.bottom_right());
326        if max.x > min.x && max.y > min.y {
327            Some(rect(min.x, min.y, max.x - min.x, max.y - min.y))
328        } else {
329            None
330        }
331    }
332
333    /// Return a rectangle that minimally encapsulates this rectangle and the other.
334    /// This is useful if you have a lot of rectangles (or bounds) and want to find
335    /// the minimal sum boundary that contains them all.
336    #[inline]
337    pub fn conflate(&self, r: &Self) -> Self {
338        let min = self.min_pos().min(r.min_pos());
339        let max = self.max_pos().max(r.max_pos());
340        rect(min.x, min.y, max.x - min.x, max.y - min.y)
341    }
342
343    /// Return a rectangle that is this rectangle clamped inside of the provided
344    /// outer rectangle. If this rectangle is larger than the outer by either
345    /// dimension, it will be shrunk to fit.
346    pub fn clamp_inside(&self, outer: &Self) -> Self {
347        let mut rect = *self;
348        if rect.right() > outer.right() {
349            rect.x -= rect.right() - outer.right();
350        }
351        if rect.bottom() > outer.bottom() {
352            rect.y -= rect.bottom() - outer.bottom();
353        }
354        if rect.x < outer.x {
355            rect.w -= outer.x - rect.x;
356            rect.x = outer.x;
357        }
358        if rect.y < outer.y {
359            rect.h -= outer.y - rect.y;
360            rect.y = outer.y;
361        }
362        rect
363    }
364}
365
366impl<T: Signed> Rect<T> {
367    /// If the rectangle has a non-negative size.
368    #[inline]
369    pub fn is_positive(&self) -> bool {
370        self.w >= T::ZERO && self.h >= T::ZERO
371    }
372
373    /// If the rectangle has a negative width or height, invert it on those
374    /// axes and return a corrected version with non-negative dimensions
375    #[inline]
376    pub fn non_neg(mut self) -> Self {
377        if self.w < T::ZERO {
378            self.x += self.w;
379            self.w = -self.w;
380        }
381        if self.h < T::ZERO {
382            self.y += self.h;
383            self.h = -self.h;
384        }
385        self
386    }
387}
388
389impl<T: Float> Rect<T> {
390    /// Transform the rectangle, producing a quad.
391    #[inline]
392    pub fn transform_by(&self, f: impl FnMut(Vec2<T>) -> Vec2<T>) -> Quad<T> {
393        Quad(self.corners().map(f))
394    }
395
396    /// Transform the rectangle, but retain the type.
397    #[inline]
398    pub fn transform_by_retain(&self, mut f: impl FnMut(Vec2<T>) -> Vec2<T>) -> Rect<T> {
399        //let center = self.transform_by(f).centroid();
400        //self.transform_by(f).bounds()
401        //let orig = f(Vec2::ZERO);
402        self + f(Vec2::ZERO)
403    }
404}
405
406impl<T: Display> Display for Rect<T> {
407    #[inline]
408    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
409        self.x.fmt(f)?;
410        f.write_str(", ")?;
411        self.y.fmt(f)?;
412        f.write_str(", ")?;
413        self.w.fmt(f)?;
414        f.write_str(", ")?;
415        self.h.fmt(f)
416    }
417}
418
419impl<T: Float> Shape<T> for Rect<T> {
420    #[inline]
421    fn centroid(&self) -> Vec2<T> {
422        self.center()
423    }
424
425    #[inline]
426    fn contains(&self, p: Vec2<T>) -> bool {
427        p.x >= self.x && p.y >= self.y && p.x < self.right() && p.y < self.bottom()
428    }
429
430    #[inline]
431    fn bounds(&self) -> Rect<T> {
432        *self
433    }
434
435    #[inline]
436    fn project_onto_axis(&self, axis: Vec2<T>) -> Projection<T> {
437        let dot1 = self.top_left().dot(axis);
438        let dot2 = self.top_right().dot(axis);
439        let dot3 = self.bottom_right().dot(axis);
440        let dot4 = self.bottom_left().dot(axis);
441        let min = T::min(dot1, T::min(dot2, T::min(dot3, dot4)));
442        let max = T::max(dot1, T::max(dot2, T::max(dot3, dot4)));
443        Projection { min, max }
444    }
445
446    #[inline]
447    fn project_point(&self, p: Vec2<T>) -> Vec2<T> {
448        let projections = [
449            self.top_edge().project_point(p),
450            self.right_edge().project_point(p),
451            self.bottom_edge().project_point(p),
452            self.left_edge().project_point(p),
453        ];
454        // Find which edge projected point is nearest to the origin.
455        let (i, _) = projections
456            .iter()
457            .enumerate()
458            .map(|(i, proj)| (i, proj.sqr_dist(p)))
459            .min_by(|(_, a), (_, b)| a.partial_cmp(b).unwrap())
460            .unwrap();
461        projections[i]
462    }
463
464    #[inline]
465    fn rayhit(&self, ray: &Ray<T>) -> bool {
466        self.edges().iter().any(|edge| edge.raycast(ray).is_some())
467    }
468
469    fn raycast(&self, ray: &Ray<T>) -> Option<RayHit<T>> {
470        // Raycast against each of our edges.
471        let edges = self.edges();
472        let hit_dists = [
473            edges[0].raycast(ray).map(|d| (0, d)),
474            edges[1].raycast(ray).map(|d| (1, d)),
475            edges[2].raycast(ray).map(|d| (2, d)),
476            edges[3].raycast(ray).map(|d| (3, d)),
477        ];
478
479        // TODO: come back to this, need to find out if edge raycasts are 2-sided?? this seems weird
480        let crossings = hit_dists.iter().flatten().count();
481        if crossings > 0 && (crossings % 2) == 0 {
482            hit_dists
483                .iter()
484                .flatten()
485                .min_by(|(_, a), (_, b)| a.partial_cmp(b).unwrap())
486                .map(|&(i, d)| RayHit::new(edges[i].norm().turn_left(), d))
487        } else {
488            None
489        }
490    }
491
492    #[inline]
493    fn overlaps_rect(&self, rect: &Rect<T>) -> bool {
494        self.x < rect.right()
495            && self.y < rect.bottom()
496            && self.right() > rect.x
497            && self.bottom() > rect.y
498    }
499
500    #[inline]
501    fn overlaps_circ(&self, circ: &Circle<T>) -> bool {
502        circ.overlaps_poly(self)
503    }
504
505    #[inline]
506    fn overlaps_poly<P: Polygonal<T>>(&self, poly: &P) -> bool {
507        self.all_normals(|axis| overlaps_on(self, poly, axis))
508            && poly.all_normals(|axis| overlaps_on(self, poly, axis))
509    }
510
511    #[inline]
512    fn extract_from_circ(&self, circ: &Circle<T>) -> Option<Vec2<T>> {
513        circ.extract_from_poly(self).map(|p| -p)
514    }
515
516    #[inline]
517    fn extract_from_poly<P: Polygonal<T>>(&self, poly: &P) -> Option<Vec2<T>> {
518        let mut dist = T::MAX;
519        let mut dir = Vec2::ZERO;
520        (self.all_normals(|axis| extract_on(self, poly, axis, &mut dist, &mut dir))
521            && poly.all_normals(|axis| extract_on(self, poly, axis, &mut dist, &mut dir)))
522        .then(|| dir * dist)
523    }
524
525    #[inline]
526    fn is_convex(&self) -> bool {
527        self.w > T::ZERO && self.h > T::ZERO
528    }
529}
530
531impl<T: Float> Polygonal<T> for Rect<T> {
532    #[inline]
533    fn nearest_vertex(&self, source: Vec2<T>) -> Vec2<T> {
534        self.corners().nearest_vertex(source)
535    }
536
537    #[inline]
538    fn all_edges<F: FnMut(Line<T>) -> bool>(&self, mut cond: F) -> bool {
539        cond(self.right_edge())
540            && cond(self.bottom_edge())
541            && cond(self.left_edge())
542            && cond(self.top_edge())
543    }
544
545    #[inline]
546    fn all_normals<F: FnMut(Vec2<T>) -> bool>(&self, mut cond: F) -> bool {
547        cond(Vec2::RIGHT) && cond(Vec2::DOWN) && cond(Vec2::LEFT) && cond(Vec2::UP)
548    }
549
550    #[inline]
551    fn visit_normals<F: FnMut(Vec2<T>)>(&self, mut plot: F) {
552        plot(Vec2::RIGHT);
553        plot(Vec2::DOWN);
554        plot(Vec2::LEFT);
555        plot(Vec2::UP);
556    }
557}
558
559impl<T: Float> Rect<T> {
560    pub fn fitted(&self, size: Vec2<T>, fractional: bool) -> (Self, T) {
561        let scale = self.size() / size;
562        let mut scale = T::min(scale.x, scale.y);
563        if !fractional && scale > T::ONE {
564            scale = T::floor(scale);
565        }
566        let new_size = size * scale;
567        let pos = self.top_left() + ((self.size() - new_size) * T::HALF).floor();
568        let rect = Rect::pos_size(pos, new_size);
569        (rect, scale)
570    }
571
572    pub fn map_pos(&self, pos: Vec2<T>, target: &Rect<T>) -> Vec2<T> {
573        target.min_pos() + target.size() * ((pos - self.min_pos()) / self.size().abs())
574    }
575}
576
577// ---------- ADD ----------
578
579impl<T: Add<T, Output = T>> Add<Vec2<T>> for Rect<T> {
580    type Output = Rect<T>;
581
582    #[inline]
583    fn add(self, rhs: Vec2<T>) -> Self::Output {
584        rect(self.x + rhs.x, self.y + rhs.y, self.w, self.h)
585    }
586}
587
588impl<T: Copy + Add<T, Output = T>> Add<Vec2<T>> for &Rect<T> {
589    type Output = Rect<T>;
590
591    #[inline]
592    fn add(self, rhs: Vec2<T>) -> Self::Output {
593        rect(self.x + rhs.x, self.y + rhs.y, self.w, self.h)
594    }
595}
596
597impl<T: Copy + Add<T, Output = T>> Add<&Vec2<T>> for Rect<T> {
598    type Output = Rect<T>;
599
600    #[inline]
601    fn add(self, rhs: &Vec2<T>) -> Self::Output {
602        rect(self.x + rhs.x, self.y + rhs.y, self.w, self.h)
603    }
604}
605
606impl<T: Copy + Add<T, Output = T>> Add<&Vec2<T>> for &Rect<T> {
607    type Output = Rect<T>;
608
609    #[inline]
610    fn add(self, rhs: &Vec2<T>) -> Self::Output {
611        rect(self.x + rhs.x, self.y + rhs.y, self.w, self.h)
612    }
613}
614
615// ---------- ADD ASSIGN ----------
616
617impl<T: AddAssign<T>> AddAssign<Vec2<T>> for Rect<T> {
618    #[inline]
619    fn add_assign(&mut self, rhs: Vec2<T>) {
620        self.x += rhs.x;
621        self.y += rhs.y;
622    }
623}
624
625impl<T: Copy + AddAssign<T>> AddAssign<&Vec2<T>> for Rect<T> {
626    #[inline]
627    fn add_assign(&mut self, rhs: &Vec2<T>) {
628        self.x += rhs.x;
629        self.y += rhs.y;
630    }
631}
632
633// ---------- SUB ----------
634
635impl<T: Sub<T, Output = T>> Sub<Vec2<T>> for Rect<T> {
636    type Output = Rect<T>;
637
638    #[inline]
639    fn sub(self, rhs: Vec2<T>) -> Self::Output {
640        rect(self.x - rhs.x, self.y - rhs.y, self.w, self.h)
641    }
642}
643
644impl<T: Copy + Sub<T, Output = T>> Sub<Vec2<T>> for &Rect<T> {
645    type Output = Rect<T>;
646
647    #[inline]
648    fn sub(self, rhs: Vec2<T>) -> Self::Output {
649        rect(self.x - rhs.x, self.y - rhs.y, self.w, self.h)
650    }
651}
652
653impl<T: Copy + Sub<T, Output = T>> Sub<&Vec2<T>> for Rect<T> {
654    type Output = Rect<T>;
655
656    #[inline]
657    fn sub(self, rhs: &Vec2<T>) -> Self::Output {
658        rect(self.x - rhs.x, self.y - rhs.y, self.w, self.h)
659    }
660}
661
662impl<T: Copy + Sub<T, Output = T>> Sub<&Vec2<T>> for &Rect<T> {
663    type Output = Rect<T>;
664
665    #[inline]
666    fn sub(self, rhs: &Vec2<T>) -> Self::Output {
667        rect(self.x - rhs.x, self.y - rhs.y, self.w, self.h)
668    }
669}
670
671// ---------- SUB ASSIGN ----------
672
673impl<T: SubAssign<T>> SubAssign<Vec2<T>> for Rect<T> {
674    #[inline]
675    fn sub_assign(&mut self, rhs: Vec2<T>) {
676        self.x -= rhs.x;
677        self.y -= rhs.y;
678    }
679}
680
681impl<T: Copy + SubAssign<T>> SubAssign<&Vec2<T>> for Rect<T> {
682    #[inline]
683    fn sub_assign(&mut self, rhs: &Vec2<T>) {
684        self.x -= rhs.x;
685        self.y -= rhs.y;
686    }
687}
688
689// ---------- SCALAR/VEC2 OPS ----------
690
691macro_rules! impl_ops {
692    ($op:ident $op_fn:ident $assign:ident $assign_fn:ident) => {
693        impl<T: Num> std::ops::$op<T> for Rect<T> {
694            type Output = Rect<T>;
695
696            #[inline]
697            fn $op_fn(self, rhs: T) -> Self::Output {
698                rect(
699                    self.x.$op_fn(rhs),
700                    self.y.$op_fn(rhs),
701                    self.w.$op_fn(rhs),
702                    self.h.$op_fn(rhs),
703                )
704            }
705        }
706
707        impl<T: Num> std::ops::$op<T> for &Rect<T> {
708            type Output = Rect<T>;
709
710            #[inline]
711            fn $op_fn(self, rhs: T) -> Self::Output {
712                rect(
713                    self.x.$op_fn(rhs),
714                    self.y.$op_fn(rhs),
715                    self.w.$op_fn(rhs),
716                    self.h.$op_fn(rhs),
717                )
718            }
719        }
720
721        impl<T: Num> std::ops::$op<Vec2<T>> for Rect<T> {
722            type Output = Rect<T>;
723
724            #[inline]
725            fn $op_fn(self, rhs: Vec2<T>) -> Self::Output {
726                rect(
727                    self.x.$op_fn(rhs.x),
728                    self.y.$op_fn(rhs.x),
729                    self.w.$op_fn(rhs.y),
730                    self.h.$op_fn(rhs.y),
731                )
732            }
733        }
734
735        impl<T: Num> std::ops::$op<Vec2<T>> for &Rect<T> {
736            type Output = Rect<T>;
737
738            #[inline]
739            fn $op_fn(self, rhs: Vec2<T>) -> Self::Output {
740                rect(
741                    self.x.$op_fn(rhs.x),
742                    self.y.$op_fn(rhs.x),
743                    self.w.$op_fn(rhs.y),
744                    self.h.$op_fn(rhs.y),
745                )
746            }
747        }
748
749        impl<T: Num> std::ops::$assign<T> for Rect<T> {
750            #[inline]
751            fn $assign_fn(&mut self, rhs: T) {
752                self.x.$assign_fn(rhs);
753                self.y.$assign_fn(rhs);
754                self.w.$assign_fn(rhs);
755                self.h.$assign_fn(rhs);
756            }
757        }
758    };
759}
760
761impl_ops!(Mul mul MulAssign mul_assign);
762impl_ops!(Div div DivAssign div_assign);
763impl_ops!(Rem rem RemAssign rem_assign);