1use approx::AbsDiffEq;
4use num_traits::ConstZero;
5
6use crate::{
7 Box2, IntUnit, Point2, Size2, Unit, Vector2,
8 traits::{Contains, Intersection, Union},
9 unit::FloatUnit,
10};
11
12#[cfg_attr(
14 all(not(target_arch = "wasm32"), feature = "wasmtime"),
15 derive(
16 wasmtime::component::ComponentType,
17 wasmtime::component::Lower,
18 wasmtime::component::Lift
19 )
20)]
21#[cfg_attr(
22 all(not(target_arch = "wasm32"), feature = "wasmtime"),
23 component(record)
24)]
25#[cfg_attr(feature = "facet", derive(facet_derive::Facet))]
26#[repr(C)]
27pub struct Rect<U: Unit = f32> {
28 pub origin: Point2<U>,
30 pub size: Size2<U>,
32}
33
34unsafe impl<T: Unit> bytemuck::Pod for Rect<T> {}
36unsafe impl<T: Unit> bytemuck::Zeroable for Rect<T> {}
38
39impl<T: Unit> Clone for Rect<T> {
40 fn clone(&self) -> Self {
41 *self
42 }
43}
44impl<T: Unit> Copy for Rect<T> {}
45
46impl<T: Unit> Default for Rect<T> {
47 fn default() -> Self {
48 Self::ZERO
49 }
50}
51
52impl<T: Unit> Rect<T> {
53 pub const ZERO: Self = Rect {
55 origin: Point2::ZERO,
56 size: Size2::ZERO,
57 };
58
59 pub fn new(origin: Point2<T>, size: Size2<T>) -> Rect<T> {
61 Rect { origin, size }
62 }
63
64 pub fn from_origin_and_size(
68 origin: impl Into<Point2<T>>,
69 size: impl Into<Size2<T>>,
70 ) -> Rect<T> {
71 Self::new(origin.into(), size.into())
72 }
73
74 #[inline]
76 #[must_use]
77 pub const fn from_size(size: Size2<T>) -> Self {
78 Rect {
79 origin: Point2::ZERO,
80 size,
81 }
82 }
83
84 #[inline]
88 #[must_use]
89 pub fn from_box(b: Box2<T>) -> Self {
90 Self::from_min_max(b.min, b.max)
91 }
92
93 #[inline]
95 #[must_use]
96 pub fn from_min_max(min: Point2<T>, max: Point2<T>) -> Self {
97 let size = Size2::from_vector(max - min);
98 let origin = min;
99 Rect { origin, size }
100 }
101
102 #[must_use]
104 pub fn from_points<I>(points: I) -> Self
105 where
106 I: IntoIterator<Item = Point2<T>>,
107 {
108 Box2::from_points(points).into()
109 }
110
111 #[inline]
113 #[must_use]
114 pub const fn min(&self) -> Point2<T> {
115 self.origin
116 }
117
118 #[inline]
120 #[must_use]
121 pub fn max(&self) -> Point2<T> {
122 self.origin + self.size.to_vector()
123 }
124
125 #[inline]
127 #[must_use]
128 pub const fn width(&self) -> T::Scalar {
129 self.size.width
130 }
131
132 #[inline]
134 #[must_use]
135 pub const fn height(&self) -> T::Scalar {
136 self.size.height
137 }
138
139 #[inline]
141 #[must_use]
142 pub fn x_range(&self) -> core::ops::Range<T::Scalar> {
143 let (min, max) = (self.min(), self.max());
144 min.x..max.x
145 }
146
147 #[inline]
149 #[must_use]
150 pub fn y_range(&self) -> core::ops::Range<T::Scalar> {
151 let (min, max) = (self.min(), self.max());
152 min.y..max.y
153 }
154
155 #[must_use]
157 pub fn corners(&self) -> [Point2<T>; 4] {
158 let (min, max) = (self.origin, self.max());
159 let top_left = min;
160 let top_right = (max.x, min.y).into();
161 let bottom_right = max;
162 let bottom_left = (min.x, max.y).into();
163 [top_left, top_right, bottom_right, bottom_left]
164 }
165
166 #[inline]
168 #[must_use]
169 pub fn center(&self) -> Point2<T> {
170 self.origin + self.size.to_vector() / (Vector2::ONE + Vector2::ONE)
171 }
172
173 #[must_use]
175 pub fn translate(self, by: Vector2<T>) -> Self {
176 Rect {
177 origin: self.origin.translate(by),
178 size: self.size,
179 }
180 }
181
182 #[must_use]
195 pub fn inflate(&self, by: Size2<T>) -> Self {
196 Rect {
197 origin: self.origin - by.to_vector(),
198 size: self.size + by + by,
199 }
200 }
201
202 #[inline]
204 #[must_use]
205 pub fn to_box2(&self) -> Box2<T> {
206 (*self).into()
207 }
208
209 #[inline]
211 #[must_use]
212 pub fn area(&self) -> T::Scalar {
213 self.size.area()
214 }
215
216 #[inline]
218 #[must_use]
219 pub fn is_empty(&self) -> bool {
220 self.size.is_empty()
221 }
222
223 #[inline]
225 #[must_use]
226 pub fn is_negative(&self) -> bool {
227 !(self.size.width >= T::Scalar::ZERO && self.size.height >= T::Scalar::ZERO)
228 }
229
230 #[inline]
232 #[must_use]
233 pub fn to_tuple(self) -> (Point2<T>, Size2<T>) {
234 (self.origin, self.size)
235 }
236
237 #[inline]
239 #[must_use]
240 pub fn from_tuple((origin, size): (Point2<T>, Size2<T>)) -> Self {
241 Self::new(origin, size)
242 }
243
244 #[inline]
246 #[must_use]
247 pub fn from_untyped(untyped: Rect<T::Scalar>) -> Self {
248 Rect {
249 origin: Point2::from_untyped(untyped.origin),
250 size: Size2::from_untyped(untyped.size),
251 }
252 }
253
254 #[inline]
256 #[must_use]
257 pub fn to_untyped(self) -> Rect<T::Scalar> {
258 Rect {
259 origin: self.origin.to_untyped(),
260 size: self.size.to_untyped(),
261 }
262 }
263
264 #[inline]
267 #[must_use]
268 pub fn try_cast<T2>(self) -> Option<Rect<T2>>
269 where
270 T2: Unit,
271 {
272 Some(Rect {
273 origin: self.origin.try_cast()?,
274 size: self.size.try_cast()?,
275 })
276 }
277
278 #[must_use]
281 pub fn as_<T2>(self) -> Rect<T2>
282 where
283 T: Unit<Scalar: num_traits::AsPrimitive<T2::Scalar>>,
284 T2: Unit,
285 {
286 Rect {
287 origin: self.origin.as_(),
288 size: self.size.as_(),
289 }
290 }
291}
292
293impl<T: FloatUnit> Rect<T> {
294 #[inline]
296 #[must_use]
297 pub fn is_finite(&self) -> bool {
298 self.origin.is_finite() && self.size.is_finite()
299 }
300
301 #[inline]
314 #[must_use]
315 pub fn round(self) -> Self {
316 Rect {
317 origin: self.origin.round(),
318 size: self.size.round(),
319 }
320 }
321
322 #[inline]
339 #[must_use]
340 pub fn round_in(self) -> Self {
341 self.to_box2().round_in().to_rect()
342 }
343
344 #[inline]
361 #[must_use]
362 pub fn round_out(self) -> Self {
363 self.to_box2().round_out().to_rect()
364 }
365
366 #[inline]
368 #[must_use]
369 pub fn lerp(self, other: Self, t: T::Scalar) -> Self {
370 Rect {
371 origin: self.origin.lerp(other.origin, t),
372 size: self.size.lerp(other.size, t),
373 }
374 }
375}
376
377impl<T: Unit> PartialEq for Rect<T> {
378 #[inline]
379 fn eq(&self, other: &Self) -> bool {
380 self.origin == other.origin && self.size == other.size
381 }
382}
383impl<T: IntUnit> Eq for Rect<T> {}
384
385impl<T: FloatUnit> AbsDiffEq for Rect<T> {
386 type Epsilon = <T::Scalar as approx::AbsDiffEq>::Epsilon;
387
388 #[must_use]
389 fn default_epsilon() -> Self::Epsilon {
390 T::Scalar::default_epsilon()
391 }
392
393 #[must_use]
394 fn abs_diff_eq(&self, other: &Rect<T>, epsilon: Self::Epsilon) -> bool {
395 self.origin.abs_diff_eq(&other.origin, epsilon)
396 && self.size.abs_diff_eq(&other.size, epsilon)
397 }
398
399 #[must_use]
400 fn abs_diff_ne(&self, other: &Rect<T>, epsilon: Self::Epsilon) -> bool {
401 self.origin.abs_diff_ne(&other.origin, epsilon)
402 || self.size.abs_diff_ne(&other.size, epsilon)
403 }
404}
405
406impl<T: FloatUnit> approx::RelativeEq for Rect<T> {
407 #[must_use]
408 fn default_max_relative() -> Self::Epsilon {
409 T::Scalar::default_max_relative()
410 }
411
412 #[must_use]
413 fn relative_eq(
414 &self,
415 other: &Rect<T>,
416 epsilon: Self::Epsilon,
417 max_relative: Self::Epsilon,
418 ) -> bool {
419 self.origin
420 .relative_eq(&other.origin, epsilon, max_relative)
421 && self.size.relative_eq(&other.size, epsilon, max_relative)
422 }
423
424 #[must_use]
425 fn relative_ne(
426 &self,
427 other: &Rect<T>,
428 epsilon: Self::Epsilon,
429 max_relative: Self::Epsilon,
430 ) -> bool {
431 self.origin
432 .relative_ne(&other.origin, epsilon, max_relative)
433 || self.size.relative_ne(&other.size, epsilon, max_relative)
434 }
435}
436
437impl<T: FloatUnit> approx::UlpsEq for Rect<T> {
438 #[must_use]
439 fn default_max_ulps() -> u32 {
440 T::Scalar::default_max_ulps()
441 }
442
443 #[must_use]
444 fn ulps_eq(&self, other: &Rect<T>, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
445 self.origin.ulps_eq(&other.origin, epsilon, max_ulps)
446 && self.size.ulps_eq(&other.size, epsilon, max_ulps)
447 }
448
449 #[must_use]
450 fn ulps_ne(&self, other: &Rect<T>, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
451 self.origin.ulps_ne(&other.origin, epsilon, max_ulps)
452 || self.size.ulps_ne(&other.size, epsilon, max_ulps)
453 }
454}
455
456impl<T: Unit> Contains<Point2<T>> for Rect<T> {
457 #[inline]
458 #[must_use]
459 fn contains(&self, point: &Point2<T>) -> bool {
460 let p2 = *point - self.origin;
462 point.x >= self.origin.x
463 && point.y >= self.origin.y
464 && p2.x <= self.size.width
465 && p2.y <= self.size.height
466 }
467}
468
469impl<T: Unit> Intersection<Point2<T>> for Rect<T> {
470 type Intersection = Point2<T>;
471
472 fn intersects(&self, thing: &Point2<T>) -> bool {
473 let diff = *thing - self.origin;
474 diff.x >= T::Scalar::ZERO
475 && diff.y >= T::Scalar::ZERO
476 && diff.x < self.size.width
477 && diff.y < self.size.height
478 }
479
480 fn intersection(&self, thing: &Point2<T>) -> Option<Self::Intersection> {
481 if self.intersects(thing) {
482 Some(*thing)
483 } else {
484 None
485 }
486 }
487}
488
489impl<T: Unit> Intersection<Rect<T>> for Rect<T> {
490 type Intersection = Rect<T>;
491
492 #[inline]
493 #[must_use]
494 fn intersects(&self, thing: &Rect<T>) -> bool {
495 self.intersects(&thing.to_box2())
496 }
497
498 #[inline]
499 #[must_use]
500 fn intersection(&self, thing: &Rect<T>) -> Option<Self::Intersection> {
501 self.intersection(&thing.to_box2())
502 }
503}
504
505impl<T: Unit> Intersection<Box2<T>> for Rect<T> {
506 type Intersection = Rect<T>;
507
508 #[inline]
509 #[must_use]
510 fn intersects(&self, thing: &Box2<T>) -> bool {
511 self.to_box2().intersects(thing)
512 }
513
514 #[inline]
515 #[must_use]
516 fn intersection(&self, thing: &Box2<T>) -> Option<Self::Intersection> {
517 self.to_box2().intersection(thing).map(Into::into)
518 }
519}
520
521impl<T> Union<Rect<T>> for Rect<T>
522where
523 T: Unit,
524{
525 type Union = Rect<T>;
526
527 #[inline]
528 #[must_use]
529 fn union(self, other: Self) -> Self {
530 if self.is_empty() {
531 return other;
532 }
533 if other.is_empty() {
534 return self;
535 }
536
537 let origin = self.origin.min(other.origin);
538 let max = self.max().max(other.max());
539 let size = (max - origin).to_size();
540
541 Rect { origin, size }
542 }
543}
544
545impl<T: Unit> core::fmt::Debug for Rect<T> {
546 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
547 f.debug_struct("Rect")
548 .field("origin", &self.origin)
549 .field("size", &self.size)
550 .finish()
551 }
552}
553
554#[cfg(test)]
555mod tests {
556 use approx::{
557 assert_abs_diff_eq, assert_abs_diff_ne, assert_relative_eq, assert_relative_ne,
558 assert_ulps_eq, assert_ulps_ne,
559 };
560
561 type Rect = super::Rect<i32>;
562 type RectF = super::Rect<f32>;
563 type Size = super::Size2<i32>;
564 type Box2 = super::Box2<i32>;
565 type Point = super::Point2<i32>;
566 type PointF = super::Point2<f32>;
567
568 #[test]
569 fn basics() {
570 let zero = Rect::ZERO;
571 assert_eq!(zero.origin, (0, 0));
572 assert_eq!(zero.size, (0, 0));
573
574 let from_size = Rect::from_size(Size {
575 width: 100,
576 height: 200,
577 });
578 assert_eq!(from_size.origin, (0, 0));
579 assert_eq!(from_size.size, (100, 200));
580 assert_eq!(from_size.min(), from_size.origin);
581 assert_eq!(from_size.max(), (100, 200));
582 assert_eq!(from_size.width(), 100);
583 assert_eq!(from_size.height(), 200);
584
585 let (_origin, _size) = from_size.to_tuple();
586 }
587
588 #[test]
589 fn equality() {
590 use crate::{Point2, Size2};
591 let a = RectF::new(Point2::new(0.0, 0.0), Size2::new(1.0, 1.0));
592 let b = a.translate((0.0, 1.0).into());
593
594 assert_abs_diff_eq!(a, a);
595 assert_relative_eq!(a, a);
596 assert_ulps_eq!(a, a);
597 assert_abs_diff_ne!(a, b);
598 assert_relative_ne!(a, b);
599 assert_ulps_ne!(a, b);
600 }
601
602 #[test]
603 fn from_box() {
604 let b = Box2::new((100, 200).into(), (300, 400).into());
605 let r = Rect::from_box(b);
606 assert_eq!(r.origin, (100, 200));
607 assert_eq!(r.size, (200, 200));
608
609 let r2 = Rect::from_min_max((100, 200).into(), (300, 400).into());
610 assert_eq!(r2, r);
611 }
612
613 #[test]
614 fn from_points() {
615 let points: [Point; 1] = [(100, 100)].map(Point::from);
616
617 let r = Rect::from_points(points);
618 assert_eq!(r, Rect::from_origin_and_size((100, 100), (0, 0)));
619
620 let points: [Point; 10] = [
621 (-10, 10),
622 (10, -10),
623 (200, -2),
624 (1, 1),
625 (2, 2),
626 (3, 4),
627 (5, 6),
628 (250, -11),
629 (1, 1),
630 (1, 1),
631 ]
632 .map(Point::from);
633
634 let r = Rect::from_points(points);
635 assert_eq!(r.origin, (-10, -11));
636 assert_eq!(r.size, (260, 21));
637 }
638
639 #[test]
640 fn xy_range() {
641 let rect = Rect::from_origin_and_size((10, 10), (10, 10));
642
643 let x_range = rect.x_range();
644 assert!(x_range.eq([10, 11, 12, 13, 14, 15, 16, 17, 18, 19]));
645 let y_range = rect.y_range();
646 assert!(y_range.eq([10, 11, 12, 13, 14, 15, 16, 17, 18, 19]));
647 }
648
649 #[test]
650 fn corners() {
651 let r = Rect::from_origin_and_size((10, 11), (12, 13));
652 let [nw, ne, se, sw] = r.corners();
653 assert_eq!(nw, (10, 11));
654 assert_eq!(ne, (22, 11));
655 assert_eq!(se, (22, 24));
656 assert_eq!(sw, (10, 24));
657 }
658
659 #[test]
660 fn center() {
661 let r = Rect::from_origin_and_size((10, 19), (100, 200));
662 assert_eq!(r.center(), (60, 119));
663
664 let r = Rect::from_origin_and_size((-10, -10), (20, 20));
665 assert_eq!(r.center(), (0, 0));
666
667 let r = Rect::from_origin_and_size((0, 0), (-1, -1));
668 assert_eq!(r.center(), (0, 0));
669
670 let r = Rect::from_origin_and_size((0, 0), (-2, -2));
671 assert_eq!(r.center(), (-1, -1));
672 }
673
674 #[test]
675 fn translate() {
676 let r = Rect::from_origin_and_size((10, 20), (11, 12));
677 let r = r.translate(crate::Vector2::new(2, 3));
678 assert_eq!(r.origin, (12, 23));
679 assert_eq!(r.size, (11, 12));
680 }
681
682 #[test]
683 fn negative_empty() {
684 let r = Rect::from_size((-1, -1).into());
685 assert!(r.is_empty());
686 assert!(r.is_negative());
687
688 let r = Rect::from_size((0, 0).into());
689 assert!(r.is_empty());
690 assert!(!r.is_negative());
691
692 let r = Rect::from_size((1, 1).into());
693 assert!(!r.is_empty());
694 assert!(!r.is_negative());
695
696 let r = RectF::from_size((-0.0, 0.0).into());
699 assert!(r.is_empty());
700 assert!(!r.is_negative());
701
702 let r = RectF::from_origin_and_size((1.0, 1.0), (-0.0, -0.0));
703 assert!(r.is_empty());
704 assert!(!r.is_negative());
705
706 let r = RectF::from_size((f32::NAN, f32::NAN).into());
709 assert!(r.is_empty());
710 assert!(r.is_negative());
711
712 let r = RectF::from_origin_and_size((f32::NAN, 1.0), (1.0, 1.0));
713 assert!(!r.is_empty());
714 assert!(!r.is_negative());
715 }
716
717 #[test]
718 fn contains() {
719 use super::Contains;
720
721 let r: RectF = RectF::from_origin_and_size((10.0, 10.0), (10.0, 10.0));
722 assert!(r.contains(&PointF::new(10.0, 10.0)));
723 assert!(r.contains(&PointF::new(20.0, 20.0)));
724 assert!(!r.contains(&PointF::new(10.0, 9.999_999)));
725 assert!(!r.contains(&PointF::new(9.999_999, 10.0)));
726 }
727
728 #[test]
729 fn intersection() {
730 use super::Intersection;
731
732 let r = RectF::from_origin_and_size((10.0, 10.0), (10.0, 10.0));
733 assert!(r.intersects(&PointF::new(10.0, 10.0)));
734 assert!(!r.intersects(&PointF::new(20.0, 20.0)));
735 assert!(!r.intersects(&PointF::new(10.0, 9.999_999)));
736 assert!(!r.intersects(&PointF::new(9.999_999, 10.0)));
737
738 assert_eq!(
739 r.intersection(&PointF::new(10.0, 10.0)),
740 Some(PointF::new(10.0, 10.0))
741 );
742 assert_eq!(r.intersection(&PointF::new(20.0, 20.0)), None);
743 assert_eq!(r.intersection(&PointF::new(10.0, 9.999_999)), None);
744 assert_eq!(r.intersection(&PointF::new(9.999_999, 10.0)), None);
745
746 let r2 = RectF::from_origin_and_size((5.0, 5.0), (15.0, 15.0));
748 assert!(r2.intersects(&r));
749 assert_eq!(
750 r2.intersection(&r),
751 Some(RectF {
752 origin: (10.0, 10.0).into(),
753 size: (10.0, 10.0).into(),
754 })
755 );
756
757 let r2 = RectF::from_origin_and_size((5.0, 5.0), (10.0, 10.0));
759 assert!(r2.intersects(&r));
760 assert_eq!(
761 r2.intersection(&r),
762 Some(RectF {
763 origin: (10.0, 10.0).into(),
764 size: (5.0, 5.0).into(),
765 })
766 );
767 }
768
769 #[test]
770 fn union() {
771 use super::Union;
772
773 let r = RectF::from_origin_and_size((10.0, 10.0), (10.0, 10.0));
774
775 assert_eq!(r.union(RectF::ZERO), r);
776 assert_eq!(RectF::ZERO.union(r), r);
777
778 assert_eq!(r.union(r), r);
779 assert_eq!(
780 r.union(RectF {
781 origin: (0.0, 0.0).into(),
782 size: (30.0, 30.0).into(),
783 }),
784 RectF {
785 origin: (0.0, 0.0).into(),
786 size: (30.0, 30.0).into(),
787 }
788 );
789 assert_eq!(
790 r.union(RectF {
791 origin: (-1.0, -1.0).into(),
792 size: (2.0, 2.0).into(),
793 }),
794 RectF {
795 origin: (-1.0, -1.0).into(),
796 size: (21.0, 21.0).into(),
797 }
798 );
799 }
800
801 #[test]
802 fn lerp() {
803 let src = RectF::from_origin_and_size((0.0, 0.0), (1.0, 1.0));
804 let dst = RectF::from_origin_and_size((1.0, 1.0), (2.0, 2.0));
805 assert_eq!(
806 src.lerp(dst, 0.5),
807 RectF {
808 origin: (0.5, 0.5).into(),
809 size: (1.5, 1.5).into(),
810 }
811 );
812 }
813
814 #[test]
815 fn area() {
816 let r = RectF::from_origin_and_size((-1.0, -1.0), (10.0, 10.0));
817 assert_eq!(r.area(), 100.0);
818 assert_eq!(r.size.area(), r.area());
819 }
820
821 #[test]
822 fn is_finite() {
823 assert!(RectF::ZERO.is_finite());
824 assert!(RectF::new(super::Point2::ZERO, super::Size2::ONE).is_finite());
825
826 let r = RectF::from_origin_and_size((-1.0, -1.0), (10.0, f32::NAN));
827 assert!(!r.is_finite());
828
829 let r = RectF::from_origin_and_size((-1.0, f32::NAN), (10.0, 10.0));
830 assert!(!r.is_finite());
831 }
832
833 #[test]
834 fn to_tuple() {
835 let r = Rect::from_tuple((Point::new(10, 10), Size::new(20, 20)));
836 assert_eq!(r.origin, (10, 10));
837 assert_eq!(r.size, (20, 20));
838
839 let r = Rect::new(
840 crate::Point2 { x: 10, y: 10 },
841 crate::Size2 {
842 width: 20,
843 height: 20,
844 },
845 );
846 let (origin, size) = r.to_tuple();
847 assert_eq!(origin, (10, 10));
848 assert_eq!(size, (20, 20));
849 }
850
851 #[test]
852 fn round_out() {
853 let rect = RectF::from_origin_and_size((0.8, 0.8), (0.1, 0.1)).round_out();
854 assert_eq!(rect.origin, (0.0, 0.0));
855 assert_eq!(rect.size, (1.0, 1.0));
856
857 let rect = RectF::from_origin_and_size((0.8, 0.8), (0.3, 0.3)).round_out();
858 assert_eq!(rect.origin, (0.0, 0.0));
859 assert_eq!(rect.size, (2.0, 2.0));
860
861 let rect = RectF::from_origin_and_size((0.1, 0.1), (0.3, 0.3)).round_out();
862 assert_eq!(rect.origin, (0.0, 0.0));
863 assert_eq!(rect.size, (1.0, 1.0));
864 }
865
866 #[test]
867 fn casting() {
868 let r = RectF::from_origin_and_size((0.1, 0.2), (0.3, 0.4));
869 let r2 = r.try_cast::<i32>().unwrap();
870 assert_eq!(r2.origin, (0, 0));
871 assert_eq!(r2.size, (0, 0));
872
873 let r2 = r.as_::<i32>();
874 assert_eq!(r2.origin, (0, 0));
875 assert_eq!(r2.size, (0, 0));
876
877 assert_eq!(r.to_untyped(), r);
878 assert_eq!(RectF::from_untyped(r), r);
879 }
880
881 #[test]
882 fn gaslight_coverage() {
883 extern crate alloc;
884
885 fn clone_me<T: Clone>(v: &T) -> T {
886 v.clone()
887 }
888 _ = clone_me(&Rect::ZERO);
889
890 _ = alloc::format!("{:?}", Rect::default());
891 }
892}