sdl2/
rect.rs

1//! Rectangles and points.
2
3use crate::sys;
4use std::convert::{AsMut, AsRef};
5use std::hash::{Hash, Hasher};
6use std::mem;
7use std::ops::{
8    Add, AddAssign, BitAnd, BitOr, Deref, DerefMut, Div, DivAssign, Mul, MulAssign, Neg, Sub,
9    SubAssign,
10};
11use std::ptr;
12
13/// The maximal integer value that can be used for rectangles.
14///
15/// This value is smaller than is strictly needed, but is useful in ensuring that
16/// rect sizes will never have to be truncated when clamping.
17pub fn max_int_value() -> u32 {
18    i32::MAX as u32 / 2
19}
20
21/// The minimal integer value that can be used for rectangle positions
22/// and points.
23///
24/// This value is needed, because otherwise the width of a rectangle created
25/// from a point would be able to exceed the maximum width.
26pub fn min_int_value() -> i32 {
27    i32::MIN / 2
28}
29
30fn clamp_size(val: u32) -> u32 {
31    if val == 0 {
32        1
33    } else if val > max_int_value() {
34        max_int_value()
35    } else {
36        val
37    }
38}
39
40fn clamp_position(val: i32) -> i32 {
41    if val > max_int_value() as i32 {
42        max_int_value() as i32
43    } else if val < min_int_value() {
44        min_int_value()
45    } else {
46        val
47    }
48}
49
50fn clamped_mul(a: i32, b: i32) -> i32 {
51    match a.checked_mul(b) {
52        Some(val) => val,
53        None => {
54            if (a < 0) ^ (b < 0) {
55                min_int_value()
56            } else {
57                max_int_value() as i32
58            }
59        }
60    }
61}
62
63fn clamp_f32_size(val: f32) -> f32 {
64    if val <= 0.0 {
65        1.0
66    } else {
67        val
68    }
69}
70
71/// A (non-empty) rectangle.
72///
73/// The width and height of a `Rect` must always be strictly positive (never
74/// zero).  In cases where empty rects may need to represented, it is
75/// recommended to use `Option<Rect>`, with `None` representing an empty
76/// rectangle (see, for example, the output of the
77/// [`intersection`](#method.intersection) method).
78// Uses repr(transparent) to allow pointer casting between Rect and SDL_Rect (see
79// `Rect::raw_slice`)
80#[repr(transparent)]
81#[derive(Clone, Copy)]
82pub struct Rect {
83    raw: sys::SDL_Rect,
84}
85
86impl ::std::fmt::Debug for Rect {
87    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
88        fmt.debug_struct("Rect")
89            .field("x", &self.raw.x)
90            .field("y", &self.raw.y)
91            .field("w", &self.raw.w)
92            .field("h", &self.raw.h)
93            .finish()
94    }
95}
96
97impl PartialEq for Rect {
98    fn eq(&self, other: &Rect) -> bool {
99        self.raw.x == other.raw.x
100            && self.raw.y == other.raw.y
101            && self.raw.w == other.raw.w
102            && self.raw.h == other.raw.h
103    }
104}
105
106impl Eq for Rect {}
107
108impl Hash for Rect {
109    fn hash<H: Hasher>(&self, state: &mut H) {
110        self.raw.x.hash(state);
111        self.raw.y.hash(state);
112        self.raw.w.hash(state);
113        self.raw.h.hash(state);
114    }
115}
116
117impl Rect {
118    /// Creates a new rectangle from the given values with an origin in the Upper Left.
119    ///
120    /// The width and height are clamped to ensure that the right and bottom
121    /// sides of the rectangle does not exceed i32::MAX (the value
122    /// 2147483647, the maximal positive size of an i32).  This means that the
123    /// rect size will behave oddly if you move it very far to the right or
124    /// downwards on the screen.
125    ///
126    /// `Rect`s must always be non-empty, so a `width` and/or `height` argument
127    /// of 0 will be replaced with 1.
128    pub fn new(x: i32, y: i32, width: u32, height: u32) -> Rect {
129        let raw = sys::SDL_Rect {
130            x: clamp_position(x),
131            y: clamp_position(y),
132            w: clamp_size(width) as i32,
133            h: clamp_size(height) as i32,
134        };
135        Rect { raw }
136    }
137
138    /// Creates a new rectangle centered on the given position.
139    ///
140    /// The width and height are clamped to ensure that the right and bottom
141    /// sides of the rectangle does not exceed i32::MAX (the value
142    /// 2147483647, the maximal positive size of an i32).  This means that the
143    /// rect size will behave oddly if you move it very far to the right or
144    /// downwards on the screen.
145    ///
146    /// `Rect`s must always be non-empty, so a `width` and/or `height` argument
147    /// of 0 will be replaced with 1.
148    pub fn from_center<P>(center: P, width: u32, height: u32) -> Rect
149    where
150        P: Into<Point>,
151    {
152        let raw = sys::SDL_Rect {
153            x: 0,
154            y: 0,
155            w: clamp_size(width) as i32,
156            h: clamp_size(height) as i32,
157        };
158        let mut rect = Rect { raw };
159        rect.center_on(center.into());
160        rect
161    }
162
163    /// The horizontal position of this rectangle.
164    #[inline]
165    pub fn x(&self) -> i32 {
166        self.raw.x
167    }
168
169    /// The vertical position of this rectangle.
170    #[inline]
171    pub fn y(&self) -> i32 {
172        self.raw.y
173    }
174
175    /// The width of this rectangle.
176    pub fn width(&self) -> u32 {
177        self.raw.w as u32
178    }
179
180    /// The height of this rectangle.
181    pub fn height(&self) -> u32 {
182        self.raw.h as u32
183    }
184
185    /// Returns the width and height of this rectangle.
186    pub fn size(&self) -> (u32, u32) {
187        (self.width(), self.height())
188    }
189
190    /// Sets the horizontal position of this rectangle to the given value,
191    /// clamped to be less than or equal to i32::MAX / 2.
192    pub fn set_x(&mut self, x: i32) {
193        self.raw.x = clamp_position(x);
194    }
195
196    /// Sets the vertical position of this rectangle to the given value,
197    /// clamped to be less than or equal to i32::MAX / 2.
198    pub fn set_y(&mut self, y: i32) {
199        self.raw.y = clamp_position(y);
200    }
201
202    /// Sets the width of this rectangle to the given value,
203    /// clamped to be less than or equal to i32::MAX / 2.
204    ///
205    /// `Rect`s must always be non-empty, so a `width` argument of 0 will be
206    /// replaced with 1.
207    pub fn set_width(&mut self, width: u32) {
208        self.raw.w = clamp_size(width) as i32;
209    }
210
211    /// Sets the height of this rectangle to the given value,
212    /// clamped to be less than or equal to i32::MAX / 2.
213    ///
214    /// `Rect`s must always be non-empty, so a `height` argument of 0 will be
215    /// replaced with 1.
216    pub fn set_height(&mut self, height: u32) {
217        self.raw.h = clamp_size(height) as i32;
218    }
219
220    /// Returns the x-position of the left side of this rectangle.
221    pub fn left(&self) -> i32 {
222        self.raw.x
223    }
224
225    /// Returns the x-position of the right side of this rectangle.
226    pub fn right(&self) -> i32 {
227        self.raw.x + self.raw.w
228    }
229
230    /// Returns the y-position of the top side of this rectangle.
231    pub fn top(&self) -> i32 {
232        self.raw.y
233    }
234
235    /// Returns the y-position of the bottom side of this rectangle.
236    pub fn bottom(&self) -> i32 {
237        self.raw.y + self.raw.h
238    }
239
240    /// Returns the origin of the rectangle (Top Left)
241    ///
242    /// ```
243    /// use sdl2::rect::Rect;
244    /// assert_eq!(Rect::new(5, 5, 10, 10).origin(), (5,5));
245    /// ```
246    pub fn origin(&self) -> (i32, i32) {
247        (self.left(), self.top())
248    }
249
250    /// Shifts this rectangle to the left by `offset`.
251    ///
252    /// # Example
253    ///
254    /// ```
255    /// use sdl2::rect::Rect;
256    /// assert_eq!(Rect::new(5, 5, 10, 10).left_shifted(5), Rect::new(0, 5, 10, 10));
257    /// ```
258    pub fn left_shifted(mut self, offset: i32) -> Rect {
259        self.offset(-offset, 0);
260        self
261    }
262
263    /// Shifts this rectangle to the right by `offset`.
264    ///
265    /// # Example
266    ///
267    /// ```
268    /// use sdl2::rect::Rect;
269    /// assert_eq!(Rect::new(5, 5, 10, 10).right_shifted(5), Rect::new(10, 5, 10, 10));
270    /// ```
271    pub fn right_shifted(mut self, offset: i32) -> Rect {
272        self.offset(offset, 0);
273        self
274    }
275
276    /// Shifts this rectangle to the top by `offset`.
277    ///
278    /// # Example
279    ///
280    /// ```
281    /// use sdl2::rect::Rect;
282    /// assert_eq!(Rect::new(5, 5, 10, 10).top_shifted(5), Rect::new(5, 0, 10, 10));
283    /// ```
284    pub fn top_shifted(mut self, offset: i32) -> Rect {
285        self.offset(0, -offset);
286        self
287    }
288
289    /// Shifts this rectangle to the bottom by `offset`.
290    ///
291    /// # Example
292    ///
293    /// ```
294    /// use sdl2::rect::Rect;
295    /// assert_eq!(Rect::new(5, 5, 10, 10).bottom_shifted(5), Rect::new(5, 10, 10, 10));
296    /// ```
297    pub fn bottom_shifted(mut self, offset: i32) -> Rect {
298        self.offset(0, offset);
299        self
300    }
301
302    /// Returns the center position of this rectangle.
303    ///
304    /// Note that if the width or height is not a multiple of two,
305    /// the center will be rounded down.
306    ///
307    /// # Example
308    ///
309    /// ```
310    /// use sdl2::rect::{Rect,Point};
311    /// let rect = Rect::new(1,0,2,3);
312    /// assert_eq!(Point::new(2,1),rect.center());
313    /// ```
314    pub fn center(&self) -> Point {
315        let x = self.raw.x + (self.raw.w / 2);
316        let y = self.raw.y + (self.raw.h / 2);
317        Point::new(x, y)
318    }
319
320    /// Returns the top-left corner of this rectangle.
321    ///
322    /// # Example
323    ///
324    /// ```
325    /// use sdl2::rect::{Rect, Point};
326    /// let rect = Rect::new(1, 0, 2, 3);
327    /// assert_eq!(Point::new(1, 0), rect.top_left());
328    /// ```
329    pub fn top_left(&self) -> Point {
330        Point::new(self.left(), self.top())
331    }
332
333    /// Returns the top-right corner of this rectangle.
334    ///
335    /// # Example
336    ///
337    /// ```
338    /// use sdl2::rect::{Rect, Point};
339    /// let rect = Rect::new(1, 0, 2, 3);
340    /// assert_eq!(Point::new(3, 0), rect.top_right());
341    /// ```
342    pub fn top_right(&self) -> Point {
343        Point::new(self.right(), self.top())
344    }
345
346    /// Returns the bottom-left corner of this rectangle.
347    ///
348    /// # Example
349    ///
350    /// ```
351    /// use sdl2::rect::{Rect, Point};
352    /// let rect = Rect::new(1, 0, 2, 3);
353    /// assert_eq!(Point::new(1, 3), rect.bottom_left());
354    /// ```
355    pub fn bottom_left(&self) -> Point {
356        Point::new(self.left(), self.bottom())
357    }
358
359    /// Returns the bottom-right corner of this rectangle.
360    ///
361    /// # Example
362    ///
363    /// ```
364    /// use sdl2::rect::{Rect, Point};
365    /// let rect = Rect::new(1, 0, 2, 3);
366    /// assert_eq!(Point::new(3, 3), rect.bottom_right());
367    /// ```
368    pub fn bottom_right(&self) -> Point {
369        Point::new(self.right(), self.bottom())
370    }
371
372    /// Sets the position of the right side of this rectangle to the given
373    /// value, clamped to be less than or equal to i32::MAX / 2.
374    pub fn set_right(&mut self, right: i32) {
375        self.raw.x = clamp_position(clamp_position(right) - self.raw.w);
376    }
377
378    /// Sets the position of the bottom side of this rectangle to the given
379    /// value, clamped to be less than or equal to i32::MAX / 2.
380    pub fn set_bottom(&mut self, bottom: i32) {
381        self.raw.y = clamp_position(clamp_position(bottom) - self.raw.h);
382    }
383
384    /// Centers the rectangle on the given point (in place).
385    #[inline]
386    pub fn center_on<P>(&mut self, point: P)
387    where
388        P: Into<(i32, i32)>,
389    {
390        let (x, y) = point.into();
391        self.raw.x = clamp_position(clamp_position(x) - self.raw.w / 2);
392        self.raw.y = clamp_position(clamp_position(y) - self.raw.h / 2);
393    }
394
395    /// Centers the rectangle on the given point.
396    #[inline]
397    pub fn centered_on<P>(mut self, point: P) -> Rect
398    where
399        P: Into<(i32, i32)>,
400    {
401        self.center_on(point);
402        self
403    }
404
405    /// Move this rect and clamp the positions to prevent over/underflow.
406    /// This also clamps the size to prevent overflow.
407    #[inline]
408    pub fn offset(&mut self, x: i32, y: i32) {
409        match self.raw.x.checked_add(x) {
410            Some(val) => self.raw.x = clamp_position(val),
411            None => {
412                if x >= 0 {
413                    self.raw.x = max_int_value() as i32;
414                } else {
415                    self.raw.x = i32::MIN;
416                }
417            }
418        }
419        match self.raw.y.checked_add(y) {
420            Some(val) => self.raw.y = clamp_position(val),
421            None => {
422                if y >= 0 {
423                    self.raw.y = max_int_value() as i32;
424                } else {
425                    self.raw.y = i32::MIN;
426                }
427            }
428        }
429    }
430
431    /// Moves this rect to the given position after clamping the values.
432    pub fn reposition<P>(&mut self, point: P)
433    where
434        P: Into<(i32, i32)>,
435    {
436        let (x, y) = point.into();
437        self.raw.x = clamp_position(x);
438        self.raw.y = clamp_position(y);
439    }
440
441    /// Resizes this rect to the given size after clamping the values.
442    pub fn resize(&mut self, width: u32, height: u32) {
443        self.raw.w = clamp_size(width) as i32;
444        self.raw.h = clamp_size(height) as i32;
445    }
446
447    /// Checks whether this rectangle contains a given point.
448    ///
449    /// Points along the right and bottom edges are not considered to be inside
450    /// the rectangle; this way, a 1-by-1 rectangle contains only a single
451    /// point.  Another way to look at it is that this method returns true if
452    /// and only if the given point would be painted by a call to
453    /// [`Renderer::fill_rect`](
454    /// ../render/struct.Renderer.html#method.fill_rect).
455    ///
456    /// # Examples
457    ///
458    /// ```
459    /// use sdl2::rect::{Rect, Point};
460    /// let rect = Rect::new(1, 2, 3, 4);
461    /// assert!(rect.contains_point(Point::new(1, 2)));
462    /// assert!(!rect.contains_point(Point::new(0, 1)));
463    /// assert!(rect.contains_point(Point::new(3, 5)));
464    /// assert!(!rect.contains_point(Point::new(4, 6)));
465    /// ```
466    pub fn contains_point<P>(&self, point: P) -> bool
467    where
468        P: Into<(i32, i32)>,
469    {
470        let (x, y) = point.into();
471        let inside_x = x >= self.left() && x < self.right();
472        inside_x && (y >= self.top() && y < self.bottom())
473    }
474
475    /// Checks whether this rectangle completely contains another rectangle.
476    ///
477    /// This method returns true if and only if every point contained by
478    /// `other` is also contained by `self`; in other words, if the
479    /// intersection of `self` and `other` is equal to `other`.
480    ///
481    /// # Examples
482    ///
483    /// ```
484    /// use sdl2::rect::Rect;
485    /// let rect = Rect::new(1, 2, 3, 4);
486    /// assert!(rect.contains_rect(rect));
487    /// assert!(rect.contains_rect(Rect::new(3, 3, 1, 1)));
488    /// assert!(!rect.contains_rect(Rect::new(2, 1, 1, 1)));
489    /// assert!(!rect.contains_rect(Rect::new(3, 3, 2, 1)));
490    /// ```
491    pub fn contains_rect(&self, other: Rect) -> bool {
492        other.left() >= self.left()
493            && other.right() <= self.right()
494            && other.top() >= self.top()
495            && other.bottom() <= self.bottom()
496    }
497
498    /// Returns the underlying C Rect.
499    // this can prevent introducing UB until
500    // https://github.com/rust-lang/rust-clippy/issues/5953 is fixed
501    #[allow(clippy::trivially_copy_pass_by_ref)]
502    pub fn raw(&self) -> *const sys::SDL_Rect {
503        &self.raw
504    }
505
506    pub fn raw_mut(&mut self) -> *mut sys::SDL_Rect {
507        &mut self.raw
508    }
509
510    #[doc(alias = "SDL_Rect")]
511    pub fn raw_slice(slice: &[Rect]) -> *const sys::SDL_Rect {
512        slice.as_ptr() as *const sys::SDL_Rect
513    }
514
515    pub fn from_ll(raw: sys::SDL_Rect) -> Rect {
516        Rect::new(raw.x, raw.y, raw.w as u32, raw.h as u32)
517    }
518
519    /// Calculate a minimal rectangle enclosing a set of points.
520    /// If a clipping rectangle is given, only points that are within it will be
521    /// considered.
522    #[doc(alias = "SDL_EnclosePoints")]
523    pub fn from_enclose_points<R>(points: &[Point], clipping_rect: R) -> Option<Rect>
524    where
525        R: Into<Option<Rect>>,
526    {
527        let clipping_rect = clipping_rect.into();
528
529        if points.is_empty() {
530            return None;
531        }
532
533        let mut out = mem::MaybeUninit::uninit();
534
535        let clip_ptr = match clipping_rect.as_ref() {
536            Some(r) => r.raw(),
537            None => ptr::null(),
538        };
539
540        let result = unsafe {
541            sys::SDL_EnclosePoints(
542                Point::raw_slice(points),
543                points.len() as i32,
544                clip_ptr,
545                out.as_mut_ptr(),
546            ) != sys::SDL_bool::SDL_FALSE
547        };
548
549        if result {
550            let out = unsafe { out.assume_init() };
551
552            // Return an error if the dimensions are too large.
553            Some(Rect::from_ll(out))
554        } else {
555            None
556        }
557    }
558
559    /// Determines whether two rectangles intersect.
560    ///
561    /// Rectangles that share an edge but don't actually overlap are not
562    /// considered to intersect.
563    ///
564    /// # Examples
565    ///
566    /// ```
567    /// use sdl2::rect::Rect;
568    /// let rect = Rect::new(0, 0, 5, 5);
569    /// assert!(rect.has_intersection(rect));
570    /// assert!(rect.has_intersection(Rect::new(2, 2, 5, 5)));
571    /// assert!(!rect.has_intersection(Rect::new(5, 0, 5, 5)));
572    /// ```
573    #[doc(alias = "SDL_HasIntersection")]
574    pub fn has_intersection(&self, other: Rect) -> bool {
575        unsafe { sys::SDL_HasIntersection(self.raw(), other.raw()) != sys::SDL_bool::SDL_FALSE }
576    }
577
578    /// Calculates the intersection of two rectangles.
579    ///
580    /// Returns `None` if the two rectangles don't intersect.  Rectangles that
581    /// share an edge but don't actually overlap are not considered to
582    /// intersect.
583    ///
584    /// The bitwise AND operator `&` can also be used.
585    ///
586    /// # Examples
587    ///
588    /// ```
589    /// use sdl2::rect::Rect;
590    /// let rect = Rect::new(0, 0, 5, 5);
591    /// assert_eq!(rect.intersection(rect), Some(rect));
592    /// assert_eq!(rect.intersection(Rect::new(2, 2, 5, 5)),
593    ///            Some(Rect::new(2, 2, 3, 3)));
594    /// assert_eq!(rect.intersection(Rect::new(5, 0, 5, 5)), None);
595    /// ```
596    #[doc(alias = "SDL_IntersectRect")]
597    pub fn intersection(&self, other: Rect) -> Option<Rect> {
598        let mut out = mem::MaybeUninit::uninit();
599
600        let success = unsafe {
601            sys::SDL_IntersectRect(self.raw(), other.raw(), out.as_mut_ptr())
602                != sys::SDL_bool::SDL_FALSE
603        };
604
605        if success {
606            let out = unsafe { out.assume_init() };
607            Some(Rect::from_ll(out))
608        } else {
609            None
610        }
611    }
612
613    /// Calculates the union of two rectangles (i.e. the smallest rectangle
614    /// that contains both).
615    ///
616    /// The bitwise OR operator `|` can also be used.
617    ///
618    /// # Examples
619    ///
620    /// ```
621    /// use sdl2::rect::Rect;
622    /// let rect = Rect::new(0, 0, 5, 5);
623    /// assert_eq!(rect.union(rect), rect);
624    /// assert_eq!(rect.union(Rect::new(2, 2, 5, 5)), Rect::new(0, 0, 7, 7));
625    /// assert_eq!(rect.union(Rect::new(5, 0, 5, 5)), Rect::new(0, 0, 10, 5));
626    /// ```
627    #[doc(alias = "SDL_UnionRect")]
628    pub fn union(&self, other: Rect) -> Rect {
629        let mut out = mem::MaybeUninit::uninit();
630
631        unsafe {
632            // If `self` and `other` are both empty, `out` remains uninitialized.
633            // Because empty rectangles aren't allowed in Rect, we don't need to worry about this.
634            sys::SDL_UnionRect(self.raw(), other.raw(), out.as_mut_ptr())
635        };
636
637        let out = unsafe { out.assume_init() };
638
639        Rect::from_ll(out)
640    }
641
642    /// Calculates the intersection of a rectangle and a line segment and
643    /// returns the points of their intersection.
644    #[doc(alias = "SDL_IntersectRectAndLine")]
645    pub fn intersect_line(&self, start: Point, end: Point) -> Option<(Point, Point)> {
646        let (mut start_x, mut start_y) = (start.x(), start.y());
647        let (mut end_x, mut end_y) = (end.x(), end.y());
648
649        let intersected = unsafe {
650            sys::SDL_IntersectRectAndLine(
651                self.raw(),
652                &mut start_x,
653                &mut start_y,
654                &mut end_x,
655                &mut end_y,
656            ) != sys::SDL_bool::SDL_FALSE
657        };
658
659        if intersected {
660            Some((Point::new(start_x, start_y), Point::new(end_x, end_y)))
661        } else {
662            None
663        }
664    }
665}
666
667impl Deref for Rect {
668    type Target = sys::SDL_Rect;
669
670    /// # Example
671    ///
672    /// ```rust
673    /// use sdl2::rect::Rect;
674    /// let rect = Rect::new(2, 3, 4, 5);
675    /// assert_eq!(2, rect.x);
676    /// ```
677    fn deref(&self) -> &sys::SDL_Rect {
678        &self.raw
679    }
680}
681
682impl DerefMut for Rect {
683    /// # Example
684    ///
685    /// ```rust
686    /// use sdl2::rect::Rect;
687    /// let mut rect = Rect::new(2, 3, 4, 5);
688    /// rect.x = 60;
689    /// assert_eq!(60, rect.x);
690    /// ```
691    fn deref_mut(&mut self) -> &mut sys::SDL_Rect {
692        &mut self.raw
693    }
694}
695
696impl From<Rect> for sys::SDL_Rect {
697    fn from(val: Rect) -> Self {
698        val.raw
699    }
700}
701
702impl From<Rect> for (i32, i32, u32, u32) {
703    fn from(val: Rect) -> Self {
704        (val.raw.x, val.raw.y, val.raw.w as u32, val.raw.h as u32)
705    }
706}
707
708impl From<sys::SDL_Rect> for Rect {
709    fn from(raw: sys::SDL_Rect) -> Rect {
710        Rect { raw }
711    }
712}
713
714impl From<(i32, i32, u32, u32)> for Rect {
715    fn from((x, y, width, height): (i32, i32, u32, u32)) -> Rect {
716        Rect::new(x, y, width, height)
717    }
718}
719
720impl AsRef<sys::SDL_Rect> for Rect {
721    fn as_ref(&self) -> &sys::SDL_Rect {
722        &self.raw
723    }
724}
725
726impl AsMut<sys::SDL_Rect> for Rect {
727    fn as_mut(&mut self) -> &mut sys::SDL_Rect {
728        &mut self.raw
729    }
730}
731
732// Intersection
733impl BitAnd<Rect> for Rect {
734    type Output = Option<Rect>;
735    #[doc(alias = "SDL_Point")]
736    fn bitand(self, rhs: Rect) -> Option<Rect> {
737        self.intersection(rhs)
738    }
739}
740
741// Union
742impl BitOr<Rect> for Rect {
743    type Output = Rect;
744    fn bitor(self, rhs: Rect) -> Rect {
745        self.union(rhs)
746    }
747}
748
749/// Immutable point type, consisting of x and y.
750// Uses repr(transparent) to allow pointer casting between Point and SDL_Point (see
751// `Point::raw_slice`)
752#[repr(transparent)]
753#[derive(Copy, Clone)]
754pub struct Point {
755    raw: sys::SDL_Point,
756}
757
758impl ::std::fmt::Debug for Point {
759    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
760        fmt.debug_struct("Point")
761            .field("x", &self.raw.x)
762            .field("y", &self.raw.y)
763            .finish()
764    }
765}
766
767impl PartialEq for Point {
768    fn eq(&self, other: &Point) -> bool {
769        self.raw.x == other.raw.x && self.raw.y == other.raw.y
770    }
771}
772
773impl Eq for Point {}
774
775impl Hash for Point {
776    fn hash<H: Hasher>(&self, state: &mut H) {
777        self.raw.x.hash(state);
778        self.raw.y.hash(state);
779    }
780}
781
782impl Deref for Point {
783    type Target = sys::SDL_Point;
784
785    /// # Example
786    ///
787    /// ```rust
788    /// use sdl2::rect::Point;
789    /// let point = Point::new(2, 3);
790    /// assert_eq!(2, point.x);
791    /// ```
792    fn deref(&self) -> &sys::SDL_Point {
793        &self.raw
794    }
795}
796
797impl DerefMut for Point {
798    /// # Example
799    ///
800    /// ```rust
801    /// use sdl2::rect::Point;
802    /// let mut point = Point::new(2, 3);
803    /// point.x = 4;
804    /// assert_eq!(4, point.x);
805    /// ```
806    fn deref_mut(&mut self) -> &mut sys::SDL_Point {
807        &mut self.raw
808    }
809}
810
811impl AsRef<sys::SDL_Point> for Point {
812    fn as_ref(&self) -> &sys::SDL_Point {
813        &self.raw
814    }
815}
816
817impl AsMut<sys::SDL_Point> for Point {
818    fn as_mut(&mut self) -> &mut sys::SDL_Point {
819        &mut self.raw
820    }
821}
822
823impl From<sys::SDL_Point> for Point {
824    fn from(prim: sys::SDL_Point) -> Point {
825        Point { raw: prim }
826    }
827}
828
829impl From<(i32, i32)> for Point {
830    fn from((x, y): (i32, i32)) -> Point {
831        Point::new(x, y)
832    }
833}
834
835impl From<Point> for sys::SDL_Point {
836    fn from(val: Point) -> Self {
837        val.raw
838    }
839}
840
841impl From<Point> for (i32, i32) {
842    fn from(val: Point) -> Self {
843        (val.x(), val.y())
844    }
845}
846
847impl Point {
848    /// Creates a new point from the given coordinates.
849    pub fn new(x: i32, y: i32) -> Point {
850        Point {
851            raw: sys::SDL_Point {
852                x: clamp_position(x),
853                y: clamp_position(y),
854            },
855        }
856    }
857
858    pub fn from_ll(raw: sys::SDL_Point) -> Point {
859        Point::new(raw.x, raw.y)
860    }
861
862    #[doc(alias = "SDL_Point")]
863    pub fn raw_slice(slice: &[Point]) -> *const sys::SDL_Point {
864        slice.as_ptr() as *const sys::SDL_Point
865    }
866    // this can prevent introducing UB until
867    // https://github.com/rust-lang/rust-clippy/issues/5953 is fixed
868    #[allow(clippy::trivially_copy_pass_by_ref)]
869    pub fn raw(&self) -> *const sys::SDL_Point {
870        &self.raw
871    }
872
873    /// Returns a new point by shifting this point's coordinates by the given
874    /// x and y values.
875    pub fn offset(self, x: i32, y: i32) -> Point {
876        let x = match self.raw.x.checked_add(x) {
877            Some(val) => val,
878            None => {
879                if x < 0 {
880                    min_int_value()
881                } else {
882                    max_int_value() as i32
883                }
884            }
885        };
886        let y = match self.raw.y.checked_add(y) {
887            Some(val) => val,
888            None => {
889                if y < 0 {
890                    min_int_value()
891                } else {
892                    max_int_value() as i32
893                }
894            }
895        };
896        Point::new(x, y)
897    }
898
899    /// Returns a new point by multiplying this point's coordinates by the
900    /// given scale factor.
901    pub fn scale(self, f: i32) -> Point {
902        Point::new(clamped_mul(self.raw.x, f), clamped_mul(self.raw.y, f))
903    }
904
905    /// Returns the x-coordinate of this point.
906    pub fn x(self) -> i32 {
907        self.raw.x
908    }
909
910    /// Returns the y-coordinate of this point.
911    pub fn y(self) -> i32 {
912        self.raw.y
913    }
914}
915
916impl Add for Point {
917    type Output = Point;
918
919    fn add(self, rhs: Point) -> Point {
920        self.offset(rhs.x(), rhs.y())
921    }
922}
923
924impl AddAssign for Point {
925    fn add_assign(&mut self, rhs: Point) {
926        self.raw.x = clamp_position(self.x() + rhs.x());
927        self.raw.y = clamp_position(self.y() + rhs.y());
928    }
929}
930
931impl Neg for Point {
932    type Output = Point;
933
934    fn neg(self) -> Point {
935        Point::new(-self.x(), -self.y())
936    }
937}
938
939impl Sub for Point {
940    type Output = Point;
941
942    fn sub(self, rhs: Point) -> Point {
943        self.offset(-rhs.x(), -rhs.y())
944    }
945}
946
947impl SubAssign for Point {
948    fn sub_assign(&mut self, rhs: Point) {
949        self.raw.x = clamp_position(self.x() - rhs.x());
950        self.raw.y = clamp_position(self.y() - rhs.y());
951    }
952}
953
954impl Mul<i32> for Point {
955    type Output = Point;
956
957    fn mul(self, rhs: i32) -> Point {
958        self.scale(rhs)
959    }
960}
961
962impl MulAssign<i32> for Point {
963    fn mul_assign(&mut self, rhs: i32) {
964        self.raw.x = clamped_mul(self.x(), rhs);
965        self.raw.y = clamped_mul(self.y(), rhs);
966    }
967}
968
969impl Div<i32> for Point {
970    type Output = Point;
971
972    fn div(self, rhs: i32) -> Point {
973        Point::new(self.x() / rhs, self.y() / rhs)
974    }
975}
976
977impl DivAssign<i32> for Point {
978    fn div_assign(&mut self, rhs: i32) {
979        self.raw.x /= rhs;
980        self.raw.y /= rhs;
981    }
982}
983
984impl std::iter::Sum for Point {
985    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
986        iter.fold(Point::new(0, 0), Point::add)
987    }
988}
989
990/// A (non-empty) rectangle with float precision.
991///
992/// The width and height of a `FRect` must always be strictly positive (never
993/// zero). In cases where empty rects may need to be represented, it is
994/// recommended to use `Option<FRect>`, with `None` representing an empty
995/// rectangle (see, for example, the output of the
996/// [`intersection`](#method.intersection) method).
997// Uses repr(transparent) to allow pointer casting between FRect and SDL_FRect (see
998// `FRect::raw_slice`)
999#[repr(transparent)]
1000#[derive(Clone, Copy)]
1001pub struct FRect {
1002    raw: sys::SDL_FRect,
1003}
1004
1005impl ::std::fmt::Debug for FRect {
1006    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
1007        fmt.debug_struct("FRect")
1008            .field("x", &self.raw.x)
1009            .field("y", &self.raw.y)
1010            .field("w", &self.raw.w)
1011            .field("h", &self.raw.h)
1012            .finish()
1013    }
1014}
1015
1016impl PartialEq for FRect {
1017    fn eq(&self, other: &FRect) -> bool {
1018        self.raw.x == other.raw.x
1019            && self.raw.y == other.raw.y
1020            && self.raw.w == other.raw.w
1021            && self.raw.h == other.raw.h
1022    }
1023}
1024
1025impl FRect {
1026    /// Creates a new rectangle with float precision from the given values.
1027    ///
1028    /// `FRect`s must always be non-empty, so a `width` and/or `height` argument
1029    /// of 0 or less will be replaced with 1.
1030    pub fn new(x: f32, y: f32, width: f32, height: f32) -> FRect {
1031        let raw = sys::SDL_FRect {
1032            x,
1033            y,
1034            w: clamp_f32_size(width),
1035            h: clamp_f32_size(height),
1036        };
1037        FRect { raw }
1038    }
1039
1040    /// Creates a new rectangle with float precision centered on the given position.
1041    ///
1042    /// `FRect`s must always be non-empty, so a `width` and/or `height` argument
1043    /// of 0 or less will be replaced with 1.
1044    pub fn from_center<P>(center: P, width: f32, height: f32) -> FRect
1045    where
1046        P: Into<FPoint>,
1047    {
1048        let raw = sys::SDL_FRect {
1049            x: 0.0,
1050            y: 0.0,
1051            w: clamp_f32_size(width),
1052            h: clamp_f32_size(height),
1053        };
1054        let mut rect = FRect { raw };
1055        rect.center_on(center.into());
1056        rect
1057    }
1058
1059    /// The horizontal position of this rectangle.
1060    #[inline]
1061    pub fn x(&self) -> f32 {
1062        self.raw.x
1063    }
1064
1065    /// The vertical position of this rectangle.
1066    #[inline]
1067    pub fn y(&self) -> f32 {
1068        self.raw.y
1069    }
1070
1071    /// The width of this rectangle.
1072    pub fn width(&self) -> f32 {
1073        self.raw.w
1074    }
1075
1076    /// The height of this rectangle.
1077    pub fn height(&self) -> f32 {
1078        self.raw.h
1079    }
1080
1081    /// Returns the width and height of this rectangle.
1082    pub fn size(&self) -> (f32, f32) {
1083        (self.width(), self.height())
1084    }
1085
1086    /// Sets the horizontal position of this rectangle to the given value,
1087    /// clamped to be less than or equal to i32::max_value() / 2.
1088    pub fn set_x(&mut self, x: f32) {
1089        self.raw.x = x;
1090    }
1091
1092    /// Sets the vertical position of this rectangle to the given value,
1093    /// clamped to be less than or equal to i32::max_value() / 2.
1094    pub fn set_y(&mut self, y: f32) {
1095        self.raw.y = y;
1096    }
1097
1098    /// Sets the width of this rectangle to the given value,
1099    /// clamped to be less than or equal to i32::max_value() / 2.
1100    ///
1101    /// `FRect`s must always be non-empty, so a `width` argument of 0 will be
1102    /// replaced with 1.
1103    pub fn set_width(&mut self, width: f32) {
1104        self.raw.w = clamp_f32_size(width);
1105    }
1106
1107    /// Sets the height of this rectangle to the given value,
1108    /// clamped to be less than or equal to i32::max_value() / 2.
1109    ///
1110    /// `FRect`s must always be non-empty, so a `height` argument of 0 will be
1111    /// replaced with 1.
1112    pub fn set_height(&mut self, height: f32) {
1113        self.raw.h = clamp_f32_size(height);
1114    }
1115
1116    /// Returns the x-position of the left side of this rectangle.
1117    pub fn left(&self) -> f32 {
1118        self.raw.x
1119    }
1120
1121    /// Returns the x-position of the right side of this rectangle.
1122    pub fn right(&self) -> f32 {
1123        self.raw.x + self.raw.w
1124    }
1125
1126    /// Returns the y-position of the top side of this rectangle.
1127    pub fn top(&self) -> f32 {
1128        self.raw.y
1129    }
1130
1131    /// Returns the y-position of the bottom side of this rectangle.
1132    pub fn bottom(&self) -> f32 {
1133        self.raw.y + self.raw.h
1134    }
1135
1136    /// Shifts this rectangle to the left by `offset`.
1137    ///
1138    /// # Example
1139    ///
1140    /// ```
1141    /// use sdl2::rect::FRect;
1142    /// assert_eq!(FRect::new(0.0, 0.0, 10.0, 10.0).left_shifted(5.0), FRect::new(-5.0, 0.0, 10.0, 10.0));
1143    /// ```
1144    pub fn left_shifted(mut self, offset: f32) -> FRect {
1145        self.offset(-offset, self.y());
1146        self
1147    }
1148
1149    /// Shifts this rectangle to the right by `offset`.
1150    ///
1151    /// # Example
1152    ///
1153    /// ```
1154    /// use sdl2::rect::FRect;
1155    /// assert_eq!(FRect::new(0.0, 0.0, 10.0, 10.0).right_shifted(5.0), FRect::new(5.0, 0.0, 10.0, 10.0));
1156    /// ```
1157    pub fn right_shifted(mut self, offset: f32) -> FRect {
1158        self.offset(offset, self.y());
1159        self
1160    }
1161
1162    /// Shifts this rectangle to the top by `offset`.
1163    ///
1164    /// # Example
1165    ///
1166    /// ```
1167    /// use sdl2::rect::FRect;
1168    /// assert_eq!(FRect::new(0.0, 0.0, 10.0, 10.0).top_shifted(5.00), FRect::new(0.0, -5.0, 10.0, 10.0));
1169    /// ```
1170    pub fn top_shifted(mut self, offset: f32) -> FRect {
1171        self.offset(self.x(), -offset);
1172        self
1173    }
1174
1175    /// Shifts this rectangle to the bottom by `offset`.
1176    ///
1177    /// # Example
1178    ///
1179    /// ```
1180    /// use sdl2::rect::FRect;
1181    /// assert_eq!(FRect::new(0.0, 0.0, 10.0, 10.0).bottom_shifted(5.0), FRect::new(0.0, 5.0, 10.0, 10.0));
1182    /// ```
1183    pub fn bottom_shifted(mut self, offset: f32) -> FRect {
1184        self.offset(self.x(), offset);
1185        self
1186    }
1187
1188    /// Returns the center position of this rectangle.
1189    ///
1190    /// Note that if the width or height is not a multiple of two,
1191    /// the center will be rounded down.
1192    ///
1193    /// # Example
1194    ///
1195    /// ```
1196    /// use sdl2::rect::{FRect, FPoint};
1197    /// let rect = FRect::new(1.0, 0.0, 2.0, 3.0);
1198    /// assert_eq!(FPoint::new(2.0, 1.5), rect.center());
1199    /// ```
1200    pub fn center(&self) -> FPoint {
1201        let x = self.raw.x + (self.raw.w / 2.0);
1202        let y = self.raw.y + (self.raw.h / 2.0);
1203        FPoint::new(x, y)
1204    }
1205
1206    /// Returns the top-left corner of this rectangle.
1207    ///
1208    /// # Example
1209    ///
1210    /// ```
1211    /// use sdl2::rect::{FRect, FPoint};
1212    /// let rect = FRect::new(1.0, 0.0, 2.0, 3.0);
1213    /// assert_eq!(FPoint::new(1.0, 0.0), rect.top_left());
1214    /// ```
1215    pub fn top_left(&self) -> FPoint {
1216        FPoint::new(self.left(), self.top())
1217    }
1218
1219    /// Returns the top-right corner of this rectangle.
1220    ///
1221    /// # Example
1222    ///
1223    /// ```
1224    /// use sdl2::rect::{FRect, FPoint};
1225    /// let rect = FRect::new(1.0, 0.0, 2.0, 3.0);
1226    /// assert_eq!(FPoint::new(3.0, 0.0), rect.top_right());
1227    /// ```
1228    pub fn top_right(&self) -> FPoint {
1229        FPoint::new(self.right(), self.top())
1230    }
1231
1232    /// Returns the bottom-left corner of this rectangle.
1233    ///
1234    /// # Example
1235    ///
1236    /// ```
1237    /// use sdl2::rect::{FRect, FPoint};
1238    /// let rect = FRect::new(1.0, 0.0, 2.0, 3.0);
1239    /// assert_eq!(FPoint::new(1.0, 3.0), rect.bottom_left());
1240    /// ```
1241    pub fn bottom_left(&self) -> FPoint {
1242        FPoint::new(self.left(), self.bottom())
1243    }
1244
1245    /// Returns the bottom-right corner of this rectangle.
1246    ///
1247    /// # Example
1248    ///
1249    /// ```
1250    /// use sdl2::rect::{FRect, FPoint};
1251    /// let rect = FRect::new(1.0, 0.0, 2.0, 3.0);
1252    /// assert_eq!(FPoint::new(3.0, 3.0), rect.bottom_right());
1253    /// ```
1254    pub fn bottom_right(&self) -> FPoint {
1255        FPoint::new(self.right(), self.bottom())
1256    }
1257
1258    /// Sets the position of the right side of this rectangle to the given
1259    /// value, clamped to be greater than 0.
1260    pub fn set_right(&mut self, right: f32) {
1261        self.raw.x = clamp_f32_size(clamp_f32_size(right) - self.raw.w);
1262    }
1263
1264    /// Sets the position of the bottom side of this rectangle to the given
1265    /// value, clamped to be greater than 0.
1266    pub fn set_bottom(&mut self, bottom: f32) {
1267        self.raw.y = clamp_f32_size(clamp_f32_size(bottom) - self.raw.h);
1268    }
1269
1270    /// Centers the rectangle on the given point (in place).
1271    #[inline]
1272    pub fn center_on<P>(&mut self, point: P)
1273    where
1274        P: Into<(f32, f32)>,
1275    {
1276        let (x, y) = point.into();
1277        self.raw.x = x - self.raw.w / 2.0;
1278        self.raw.y = y - self.raw.h / 2.0;
1279    }
1280
1281    /// Centers the rectangle on the given point.
1282    #[inline]
1283    pub fn centered_on<P>(mut self, point: P) -> FRect
1284    where
1285        P: Into<(f32, f32)>,
1286    {
1287        self.center_on(point);
1288        self
1289    }
1290
1291    /// Move this rect.
1292    #[inline]
1293    pub fn offset(&mut self, x: f32, y: f32) {
1294        self.raw.x += x;
1295        self.raw.y += y;
1296    }
1297
1298    /// Moves this rect to the given position.
1299    pub fn reposition<P>(&mut self, point: P)
1300    where
1301        P: Into<(f32, f32)>,
1302    {
1303        let (x, y) = point.into();
1304        self.raw.x = x;
1305        self.raw.y = y;
1306    }
1307
1308    /// Resizes this rect to the given size after clamping the values.
1309    pub fn resize(&mut self, width: f32, height: f32) {
1310        self.raw.w = clamp_f32_size(width);
1311        self.raw.h = clamp_f32_size(height);
1312    }
1313
1314    /// Checks whether this rectangle contains a given point.
1315    ///
1316    /// Points along the right and bottom edges are not considered to be inside
1317    /// the rectangle. Another way to look at it is that this method returns true if
1318    /// and only if the given point would be painted by a call to
1319    /// [`Renderer::fill_frect`](
1320    /// ../render/struct.Renderer.html#method.fill_frect).
1321    ///
1322    /// # Examples
1323    ///
1324    /// ```
1325    /// use sdl2::rect::{FRect, FPoint};
1326    /// let rect = FRect::new(1.0, 2.0, 3.0, 4.0);
1327    /// assert!(rect.contains_point(FPoint::new(1.0, 2.0)));
1328    /// assert!(!rect.contains_point(FPoint::new(0.0, 1.0)));
1329    /// assert!(rect.contains_point(FPoint::new(3.0, 5.0)));
1330    /// assert!(!rect.contains_point(FPoint::new(4.0, 6.0)));
1331    /// ```
1332    pub fn contains_point<P>(&self, point: P) -> bool
1333    where
1334        P: Into<(f32, f32)>,
1335    {
1336        let (x, y) = point.into();
1337        let inside_x = x >= self.left() && x < self.right();
1338        inside_x && (y >= self.top() && y < self.bottom())
1339    }
1340
1341    /// Checks whether this rectangle completely contains another rectangle.
1342    ///
1343    /// This method returns true if and only if every point contained by
1344    /// `other` is also contained by `self`; in other words, if the
1345    /// intersection of `self` and `other` is equal to `other`.
1346    ///
1347    /// # Examples
1348    ///
1349    /// ```
1350    /// use sdl2::rect::FRect;
1351    /// let rect = FRect::new(1.0, 2.0, 3.0, 4.0);
1352    /// assert!(rect.contains_rect(rect));
1353    /// assert!(rect.contains_rect(FRect::new(3.0, 3.0, 1.0, 1.0)));
1354    /// assert!(!rect.contains_rect(FRect::new(2.0, 1.0, 1.0, 1.0)));
1355    /// assert!(!rect.contains_rect(FRect::new(3.0, 3.0, 2.0, 1.0)));
1356    /// ```
1357    pub fn contains_rect(&self, other: FRect) -> bool {
1358        other.left() >= self.left()
1359            && other.right() <= self.right()
1360            && other.top() >= self.top()
1361            && other.bottom() <= self.bottom()
1362    }
1363
1364    /// Returns the underlying C FRect.
1365    // this can prevent introducing UB until
1366    // https://github.com/rust-lang/rust-clippy/issues/5953 is fixed
1367    #[allow(clippy::trivially_copy_pass_by_ref)]
1368    pub fn raw(&self) -> *const sys::SDL_FRect {
1369        &self.raw
1370    }
1371
1372    pub fn raw_mut(&mut self) -> *mut sys::SDL_FRect {
1373        &mut self.raw
1374    }
1375
1376    #[doc(alias = "SDL_FRect")]
1377    pub fn raw_slice(slice: &[FRect]) -> *const sys::SDL_FRect {
1378        slice.as_ptr() as *const sys::SDL_FRect
1379    }
1380
1381    pub fn from_ll(raw: sys::SDL_FRect) -> FRect {
1382        FRect::new(raw.x, raw.y, raw.w, raw.h)
1383    }
1384
1385    /// Calculate a minimal rectangle enclosing a set of points.
1386    /// If a clipping rectangle is given, only points that are within it will be
1387    /// considered.
1388    #[doc(alias = "SDL_EncloseFPoints")]
1389    pub fn from_enclose_points<R>(points: &[FPoint], clipping_rect: R) -> Option<FRect>
1390    where
1391        R: Into<Option<FRect>>,
1392    {
1393        let clipping_rect = clipping_rect.into();
1394
1395        if points.is_empty() {
1396            return None;
1397        }
1398
1399        let mut out = mem::MaybeUninit::uninit();
1400
1401        let clip_ptr = match clipping_rect.as_ref() {
1402            Some(r) => r.raw(),
1403            None => ptr::null(),
1404        };
1405
1406        let result = unsafe {
1407            sys::SDL_EncloseFPoints(
1408                FPoint::raw_slice(points),
1409                points.len() as i32,
1410                clip_ptr,
1411                out.as_mut_ptr(),
1412            ) != sys::SDL_bool::SDL_FALSE
1413        };
1414
1415        if result {
1416            let out = unsafe { out.assume_init() };
1417
1418            // Return an error if the dimensions are too large.
1419            Some(FRect::from_ll(out))
1420        } else {
1421            None
1422        }
1423    }
1424
1425    /// Determines whether two rectangles intersect.
1426    ///
1427    /// Rectangles that share an edge but don't actually overlap are not
1428    /// considered to intersect.
1429    ///
1430    /// # Examples
1431    ///
1432    /// ```
1433    /// use sdl2::rect::FRect;
1434    /// let rect = FRect::new(0.0, 0.0, 5.0, 5.0);
1435    /// assert!(rect.has_intersection(rect));
1436    /// assert!(rect.has_intersection(FRect::new(2.0, 2.0, 5.0, 5.0)));
1437    /// assert!(!rect.has_intersection(FRect::new(5.0, 0.0, 5.0, 5.0)));
1438    /// ```
1439    #[doc(alias = "SDL_HasIntersectionF")]
1440    pub fn has_intersection(&self, other: FRect) -> bool {
1441        unsafe { sys::SDL_HasIntersectionF(self.raw(), other.raw()) != sys::SDL_bool::SDL_FALSE }
1442    }
1443
1444    /// Calculates the intersection of two rectangles.
1445    ///
1446    /// Returns `None` if the two rectangles don't intersect.  Rectangles that
1447    /// share an edge but don't actually overlap are not considered to
1448    /// intersect.
1449    ///
1450    /// The bitwise AND operator `&` can also be used.
1451    ///
1452    /// # Examples
1453    ///
1454    /// ```
1455    /// use sdl2::rect::FRect;
1456    /// let rect = FRect::new(0.0, 0.0, 5.0, 5.0);
1457    /// assert_eq!(rect.intersection(rect), Some(rect));
1458    /// assert_eq!(rect.intersection(FRect::new(2.0, 2.0, 5.0, 5.0)),
1459    ///            Some(FRect::new(2.0, 2.0, 3.0, 3.0)));
1460    /// assert_eq!(rect.intersection(FRect::new(5.0, 0.0, 5.0, 5.0)), None);
1461    /// ```
1462    #[doc(alias = "SDL_IntersectFRect")]
1463    pub fn intersection(&self, other: FRect) -> Option<FRect> {
1464        let mut out = mem::MaybeUninit::uninit();
1465
1466        let success = unsafe {
1467            sys::SDL_IntersectFRect(self.raw(), other.raw(), out.as_mut_ptr())
1468                != sys::SDL_bool::SDL_FALSE
1469        };
1470
1471        if success {
1472            let out = unsafe { out.assume_init() };
1473            Some(FRect::from_ll(out))
1474        } else {
1475            None
1476        }
1477    }
1478
1479    /// Calculates the union of two rectangles (i.e. the smallest rectangle
1480    /// that contains both).
1481    ///
1482    /// The bitwise OR operator `|` can also be used.
1483    ///
1484    /// # Examples
1485    ///
1486    /// ```
1487    /// use sdl2::rect::FRect;
1488    /// let rect = FRect::new(0.0, 0.0, 5.0, 5.0);
1489    /// assert_eq!(rect.union(rect), rect);
1490    /// assert_eq!(rect.union(FRect::new(2.0, 2.0, 5.0, 5.0)), FRect::new(0.0, 0.0, 7.0, 7.0));
1491    /// assert_eq!(rect.union(FRect::new(5.0, 0.0, 5.0, 5.0)), FRect::new(0.0, 0.0, 10.0, 5.0));
1492    /// ```
1493    #[doc(alias = "SDL_UnionFRect")]
1494    pub fn union(&self, other: FRect) -> FRect {
1495        let mut out = mem::MaybeUninit::uninit();
1496
1497        unsafe {
1498            // If `self` and `other` are both empty, `out` remains uninitialized.
1499            // Because empty rectangles aren't allowed in Rect, we don't need to worry about this.
1500            sys::SDL_UnionFRect(self.raw(), other.raw(), out.as_mut_ptr())
1501        };
1502
1503        let out = unsafe { out.assume_init() };
1504
1505        FRect::from_ll(out)
1506    }
1507
1508    /// Calculates the intersection of a rectangle and a line segment and
1509    /// returns the points of their intersection.
1510    #[doc(alias = "SDL_IntersectFRectAndLine")]
1511    pub fn intersect_line(&self, start: FPoint, end: FPoint) -> Option<(FPoint, FPoint)> {
1512        let (mut start_x, mut start_y) = (start.x(), start.y());
1513        let (mut end_x, mut end_y) = (end.x(), end.y());
1514
1515        let intersected = unsafe {
1516            sys::SDL_IntersectFRectAndLine(
1517                self.raw(),
1518                &mut start_x,
1519                &mut start_y,
1520                &mut end_x,
1521                &mut end_y,
1522            ) != sys::SDL_bool::SDL_FALSE
1523        };
1524
1525        if intersected {
1526            Some((FPoint::new(start_x, start_y), FPoint::new(end_x, end_y)))
1527        } else {
1528            None
1529        }
1530    }
1531}
1532
1533impl Deref for FRect {
1534    type Target = sys::SDL_FRect;
1535
1536    /// # Example
1537    ///
1538    /// ```rust
1539    /// use sdl2::rect::FRect;
1540    /// let rect = FRect::new(2.0, 3.0, 4.0, 5.0);
1541    /// assert_eq!(2.0, rect.x);
1542    /// ```
1543    fn deref(&self) -> &sys::SDL_FRect {
1544        &self.raw
1545    }
1546}
1547
1548impl DerefMut for FRect {
1549    /// # Example
1550    ///
1551    /// ```rust
1552    /// use sdl2::rect::FRect;
1553    /// let mut rect = FRect::new(2.0, 3.0, 4.0, 5.0);
1554    /// rect.x = 60.0;
1555    /// assert_eq!(60.0, rect.x);
1556    /// ```
1557    fn deref_mut(&mut self) -> &mut sys::SDL_FRect {
1558        &mut self.raw
1559    }
1560}
1561
1562impl From<FRect> for sys::SDL_FRect {
1563    fn from(val: FRect) -> Self {
1564        val.raw
1565    }
1566}
1567
1568impl From<FRect> for (f32, f32, f32, f32) {
1569    fn from(val: FRect) -> Self {
1570        (val.raw.x, val.raw.y, val.raw.w, val.raw.h)
1571    }
1572}
1573
1574impl From<sys::SDL_FRect> for FRect {
1575    fn from(raw: sys::SDL_FRect) -> FRect {
1576        FRect { raw }
1577    }
1578}
1579
1580impl From<(f32, f32, f32, f32)> for FRect {
1581    fn from((x, y, width, height): (f32, f32, f32, f32)) -> FRect {
1582        FRect::new(x, y, width, height)
1583    }
1584}
1585
1586impl AsRef<sys::SDL_FRect> for FRect {
1587    fn as_ref(&self) -> &sys::SDL_FRect {
1588        &self.raw
1589    }
1590}
1591
1592impl AsMut<sys::SDL_FRect> for FRect {
1593    fn as_mut(&mut self) -> &mut sys::SDL_FRect {
1594        &mut self.raw
1595    }
1596}
1597
1598// Intersection
1599impl BitAnd<FRect> for FRect {
1600    type Output = Option<FRect>;
1601    #[doc(alias = "SDL_FPoint")]
1602    fn bitand(self, rhs: FRect) -> Option<FRect> {
1603        self.intersection(rhs)
1604    }
1605}
1606
1607// Union
1608impl BitOr<FRect> for FRect {
1609    type Output = FRect;
1610    fn bitor(self, rhs: FRect) -> FRect {
1611        self.union(rhs)
1612    }
1613}
1614
1615/// Immutable point type with float precision, consisting of x and y.
1616// Uses repr(transparent) to allow pointer casting between FPoint and SDL_FPoint (see
1617// `FPoint::raw_slice`)
1618#[repr(transparent)]
1619#[derive(Copy, Clone)]
1620pub struct FPoint {
1621    raw: sys::SDL_FPoint,
1622}
1623
1624impl ::std::fmt::Debug for FPoint {
1625    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
1626        fmt.debug_struct("FPoint")
1627            .field("x", &self.raw.x)
1628            .field("y", &self.raw.y)
1629            .finish()
1630    }
1631}
1632
1633impl PartialEq for FPoint {
1634    fn eq(&self, other: &FPoint) -> bool {
1635        self.raw.x == other.raw.x && self.raw.y == other.raw.y
1636    }
1637}
1638
1639impl Deref for FPoint {
1640    type Target = sys::SDL_FPoint;
1641
1642    /// # Example
1643    ///
1644    /// ```rust
1645    /// use sdl2::rect::FPoint;
1646    /// let point = FPoint::new(2.0, 3.0);
1647    /// assert_eq!(2.0, point.x);
1648    /// ```
1649    fn deref(&self) -> &sys::SDL_FPoint {
1650        &self.raw
1651    }
1652}
1653
1654impl DerefMut for FPoint {
1655    /// # Example
1656    ///
1657    /// ```rust
1658    /// use sdl2::rect::FPoint;
1659    /// let mut point = FPoint::new(2.0, 3.0);
1660    /// point.x = 4.0;
1661    /// assert_eq!(4.0, point.x);
1662    /// ```
1663    fn deref_mut(&mut self) -> &mut sys::SDL_FPoint {
1664        &mut self.raw
1665    }
1666}
1667
1668impl AsRef<sys::SDL_FPoint> for FPoint {
1669    fn as_ref(&self) -> &sys::SDL_FPoint {
1670        &self.raw
1671    }
1672}
1673
1674impl AsMut<sys::SDL_FPoint> for FPoint {
1675    fn as_mut(&mut self) -> &mut sys::SDL_FPoint {
1676        &mut self.raw
1677    }
1678}
1679
1680impl From<sys::SDL_FPoint> for FPoint {
1681    fn from(prim: sys::SDL_FPoint) -> FPoint {
1682        FPoint { raw: prim }
1683    }
1684}
1685
1686impl From<(f32, f32)> for FPoint {
1687    fn from((x, y): (f32, f32)) -> FPoint {
1688        FPoint::new(x, y)
1689    }
1690}
1691
1692impl From<FPoint> for sys::SDL_FPoint {
1693    fn from(val: FPoint) -> Self {
1694        val.raw
1695    }
1696}
1697
1698impl From<FPoint> for (f32, f32) {
1699    fn from(val: FPoint) -> Self {
1700        (val.x(), val.y())
1701    }
1702}
1703
1704impl FPoint {
1705    /// Creates a new point from the given coordinates.
1706    pub fn new(x: f32, y: f32) -> FPoint {
1707        FPoint {
1708            raw: sys::SDL_FPoint { x, y },
1709        }
1710    }
1711
1712    pub fn from_ll(raw: sys::SDL_FPoint) -> FPoint {
1713        FPoint::new(raw.x, raw.y)
1714    }
1715
1716    #[doc(alias = "SDL_FPoint")]
1717    pub fn raw_slice(slice: &[FPoint]) -> *const sys::SDL_FPoint {
1718        slice.as_ptr() as *const sys::SDL_FPoint
1719    }
1720
1721    // this can prevent introducing UB until
1722    // https://github.com/rust-lang/rust-clippy/issues/5953 is fixed
1723    #[allow(clippy::trivially_copy_pass_by_ref)]
1724    pub fn raw(&self) -> *const sys::SDL_FPoint {
1725        &self.raw
1726    }
1727
1728    /// Returns a new point by shifting this point's coordinates by the given
1729    /// x and y values.
1730    pub fn offset(self, x: f32, y: f32) -> FPoint {
1731        let x = self.raw.x + x;
1732        let y = self.raw.y + y;
1733        FPoint::new(x, y)
1734    }
1735
1736    /// Returns a new point by multiplying this point's coordinates by the
1737    /// given scale factor.
1738    pub fn scale(self, f: f32) -> FPoint {
1739        FPoint::new(self.raw.x * f, self.raw.y * f)
1740    }
1741
1742    /// Returns the x-coordinate of this point.
1743    pub fn x(self) -> f32 {
1744        self.raw.x
1745    }
1746
1747    /// Returns the y-coordinate of this point.
1748    pub fn y(self) -> f32 {
1749        self.raw.y
1750    }
1751}
1752
1753impl Add for FPoint {
1754    type Output = FPoint;
1755
1756    fn add(self, rhs: FPoint) -> FPoint {
1757        self.offset(rhs.x(), rhs.y())
1758    }
1759}
1760
1761impl AddAssign for FPoint {
1762    fn add_assign(&mut self, rhs: FPoint) {
1763        self.raw.x = self.x() + rhs.x();
1764        self.raw.y = self.y() + rhs.y();
1765    }
1766}
1767
1768impl Neg for FPoint {
1769    type Output = FPoint;
1770
1771    fn neg(self) -> FPoint {
1772        FPoint::new(-self.x(), -self.y())
1773    }
1774}
1775
1776impl Sub for FPoint {
1777    type Output = FPoint;
1778
1779    fn sub(self, rhs: FPoint) -> FPoint {
1780        self.offset(-rhs.x(), -rhs.y())
1781    }
1782}
1783
1784impl SubAssign for FPoint {
1785    fn sub_assign(&mut self, rhs: FPoint) {
1786        self.raw.x = self.x() - rhs.x();
1787        self.raw.y = self.y() - rhs.y();
1788    }
1789}
1790
1791impl Mul<f32> for FPoint {
1792    type Output = FPoint;
1793
1794    fn mul(self, rhs: f32) -> FPoint {
1795        self.scale(rhs)
1796    }
1797}
1798
1799impl MulAssign<f32> for FPoint {
1800    fn mul_assign(&mut self, rhs: f32) {
1801        self.raw.x = self.x() * rhs;
1802        self.raw.y = self.y() * rhs;
1803    }
1804}
1805
1806impl Div<f32> for FPoint {
1807    type Output = FPoint;
1808
1809    fn div(self, rhs: f32) -> FPoint {
1810        FPoint::new(self.x() / rhs, self.y() / rhs)
1811    }
1812}
1813
1814impl DivAssign<f32> for FPoint {
1815    fn div_assign(&mut self, rhs: f32) {
1816        self.raw.x /= rhs;
1817        self.raw.y /= rhs;
1818    }
1819}
1820
1821impl std::iter::Sum for FPoint {
1822    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
1823        iter.fold(FPoint::new(0.0, 0.0), FPoint::add)
1824    }
1825}
1826
1827#[cfg(test)]
1828mod test {
1829    use super::{max_int_value, min_int_value, FPoint, FRect, Point, Rect};
1830
1831    /// Used to compare "literal" (unclamped) rect values.
1832    fn tuple(x: i32, y: i32, w: u32, h: u32) -> (i32, i32, u32, u32) {
1833        (x, y, w, h)
1834    }
1835
1836    #[test]
1837    fn centered() {
1838        // Tests both center_on and centered_on
1839        assert_eq!(
1840            Rect::new(0, 0, 10, 10).centered_on((0, 0)),
1841            Rect::new(-5, -5, 10, 10)
1842        );
1843    }
1844
1845    #[test]
1846    fn enclose_points_valid() {
1847        assert_eq!(
1848            Some(tuple(2, 4, 4, 6)),
1849            Rect::from_enclose_points(&[Point::new(2, 4), Point::new(5, 9)], None)
1850                .map(|r| r.into())
1851        );
1852    }
1853
1854    #[test]
1855    fn enclose_points_outside_clip_rect() {
1856        assert_eq!(
1857            Rect::from_enclose_points(
1858                &[Point::new(0, 0), Point::new(10, 10)],
1859                Some(Rect::new(3, 3, 1, 1))
1860            ),
1861            None
1862        );
1863    }
1864
1865    #[test]
1866    fn enclose_points_max_values() {
1867        // Try to enclose the top-left-most and bottom-right-most points.
1868        assert_eq!(
1869            Some(tuple(
1870                min_int_value(),
1871                min_int_value(),
1872                max_int_value(),
1873                max_int_value()
1874            )),
1875            Rect::from_enclose_points(
1876                &[
1877                    Point::new(i32::MIN, i32::MIN),
1878                    Point::new(i32::MAX, i32::MAX)
1879                ],
1880                None
1881            )
1882            .map(|r| r.into())
1883        );
1884    }
1885
1886    #[test]
1887    fn has_intersection() {
1888        let rect = Rect::new(0, 0, 10, 10);
1889        assert!(rect.has_intersection(Rect::new(9, 9, 10, 10)));
1890        // edge
1891        assert!(!rect.has_intersection(Rect::new(10, 10, 10, 10)));
1892        // out
1893        assert!(!rect.has_intersection(Rect::new(11, 11, 10, 10)));
1894    }
1895
1896    #[test]
1897    fn intersection() {
1898        let rect = Rect::new(0, 0, 10, 10);
1899        assert_eq!(rect & Rect::new(9, 9, 10, 10), Some(Rect::new(9, 9, 1, 1)));
1900        assert_eq!(rect & Rect::new(11, 11, 10, 10), None);
1901    }
1902
1903    #[test]
1904    fn union() {
1905        assert_eq!(
1906            Rect::new(0, 0, 1, 1) | Rect::new(9, 9, 1, 1),
1907            Rect::new(0, 0, 10, 10)
1908        );
1909    }
1910
1911    #[test]
1912    fn intersect_line() {
1913        assert_eq!(
1914            Rect::new(1, 1, 5, 5).intersect_line(Point::new(0, 0), Point::new(10, 10)),
1915            Some((Point::new(1, 1), Point::new(5, 5)))
1916        );
1917    }
1918
1919    #[test]
1920    fn clamp_size_zero() {
1921        assert_eq!(tuple(0, 0, 1, 1), Rect::new(0, 0, 0, 0).into());
1922    }
1923
1924    #[test]
1925    fn clamp_position_min() {
1926        assert_eq!(
1927            tuple(min_int_value(), min_int_value(), 1, 1),
1928            Rect::new(i32::MIN, i32::MIN, 1, 1).into()
1929        );
1930    }
1931
1932    #[test]
1933    fn clamp_size_max() {
1934        assert_eq!(
1935            tuple(0, 0, max_int_value(), max_int_value()),
1936            Rect::new(0, 0, max_int_value() + 1, max_int_value() + 1).into()
1937        );
1938    }
1939
1940    #[test]
1941    fn clamp_i32_max() {
1942        assert_eq!(
1943            tuple(0, 0, max_int_value(), max_int_value()),
1944            Rect::new(0, 0, i32::MAX as u32, i32::MAX as u32).into()
1945        )
1946    }
1947
1948    #[test]
1949    fn clamp_position_max() {
1950        assert_eq!(
1951            tuple(max_int_value() as i32, max_int_value() as i32, 1, 1),
1952            Rect::new(max_int_value() as i32 + 1, max_int_value() as i32 + 1, 1, 1).into()
1953        );
1954    }
1955
1956    #[test]
1957    fn shifted() {
1958        // Groups all functions into a single assertion
1959        let rect = Rect::new(5, 5, 10, 10)
1960            .left_shifted(5)
1961            .right_shifted(5)
1962            .top_shifted(5)
1963            .bottom_shifted(5);
1964        assert_eq!(rect, Rect::new(5, 5, 10, 10));
1965    }
1966
1967    #[test]
1968    fn rect_into() {
1969        let test: (i32, i32, u32, u32) = (-11, 5, 50, 20);
1970        assert_eq!(test, Rect::new(-11, 5, 50, 20).into());
1971    }
1972
1973    #[test]
1974    fn rect_from() {
1975        assert_eq!(Rect::from((-11, 5, 50, 20)), Rect::new(-11, 5, 50, 20));
1976    }
1977
1978    #[test]
1979    fn point_into() {
1980        let test: (i32, i32) = (-11, 5);
1981        assert_eq!(test, Point::new(-11, 5).into());
1982    }
1983
1984    #[test]
1985    fn point_from() {
1986        let test: (i32, i32) = (-11, 5);
1987        assert_eq!(test, Point::new(-11, 5).into());
1988    }
1989
1990    #[test]
1991    fn point_add() {
1992        assert_eq!(Point::new(-5, 7), Point::new(-11, 5) + Point::new(6, 2));
1993    }
1994
1995    #[test]
1996    fn point_add_assign() {
1997        let mut point = Point::new(-11, 5);
1998        point += Point::new(6, 2);
1999        assert_eq!(point, Point::new(-11, 5) + Point::new(6, 2));
2000    }
2001
2002    #[test]
2003    fn point_sub() {
2004        assert_eq!(Point::new(-17, 3), Point::new(-11, 5) - Point::new(6, 2));
2005    }
2006
2007    #[test]
2008    fn point_sub_assign() {
2009        let mut point = Point::new(-11, 5);
2010        point -= Point::new(6, 2);
2011        assert_eq!(point, Point::new(-11, 5) - Point::new(6, 2));
2012    }
2013
2014    #[test]
2015    fn point_mul() {
2016        assert_eq!(Point::new(-33, 15), Point::new(-11, 5) * 3);
2017    }
2018
2019    #[test]
2020    fn point_mul_assign() {
2021        let mut point = Point::new(-11, 5);
2022        point *= 3;
2023        assert_eq!(point, Point::new(-11, 5) * 3);
2024    }
2025
2026    #[test]
2027    fn point_mul_clamp() {
2028        assert_eq!(
2029            Point::new(0x7fffffff, -0x7fffffff),
2030            Point::new(-1000000, 5000000) * -3000000
2031        );
2032    }
2033
2034    #[test]
2035    fn point_mul_assign_clamp() {
2036        let mut point = Point::new(-1000000, 5000000);
2037        point *= -3000000;
2038        assert_eq!(point, Point::new(-1000000, 5000000) * -3000000);
2039    }
2040
2041    #[test]
2042    fn point_div() {
2043        assert_eq!(Point::new(-3, 1), Point::new(-11, 5) / 3);
2044    }
2045
2046    #[test]
2047    fn point_div_assign() {
2048        let mut point = Point::new(-11, 5);
2049        point /= 3;
2050        assert_eq!(point, Point::new(-11, 5) / 3);
2051    }
2052
2053    #[test]
2054    fn point_sum() {
2055        let points_sum: Point = vec![Point::new(-11, 5), Point::new(6, 2)].into_iter().sum();
2056        assert_eq!(Point::new(-5, 7), points_sum);
2057    }
2058
2059    #[test]
2060    fn frect_centered() {
2061        // Tests both center_on and centered_on
2062        assert_eq!(
2063            FRect::new(0.0, 0.0, 10.0, 10.0).centered_on((0.0, 0.0)),
2064            FRect::new(-5.0, -5.0, 10.0, 10.0)
2065        );
2066    }
2067
2068    #[test]
2069    fn frect_enclose_points_valid() {
2070        assert_eq!(
2071            Some((2.0, 4.0, 4.0, 6.0)),
2072            FRect::from_enclose_points(&[FPoint::new(2.0, 4.0), FPoint::new(5.0, 9.0)], None)
2073                .map(|r| r.into())
2074        );
2075    }
2076
2077    #[test]
2078    fn frect_enclose_points_outside_clip_rect() {
2079        assert_eq!(
2080            FRect::from_enclose_points(
2081                &[FPoint::new(0.0, 0.0), FPoint::new(10.0, 10.0)],
2082                Some(FRect::new(3.0, 3.0, 1.0, 1.0))
2083            ),
2084            None
2085        );
2086    }
2087
2088    #[test]
2089    fn frect_has_intersection() {
2090        let rect = FRect::new(0.0, 0.0, 10.0, 10.0);
2091        assert!(rect.has_intersection(FRect::new(9.0, 9.0, 10.0, 10.0)));
2092        // edge
2093        assert!(!rect.has_intersection(FRect::new(10.0, 10.0, 10.0, 10.0)));
2094        // out
2095        assert!(!rect.has_intersection(FRect::new(11.0, 11.0, 10.0, 10.0)));
2096    }
2097
2098    #[test]
2099    fn frect_intersection() {
2100        let rect = FRect::new(0.0, 0.0, 10.0, 10.0);
2101        assert_eq!(
2102            rect & FRect::new(9.0, 9.0, 10.0, 10.0),
2103            Some(FRect::new(9.0, 9.0, 1.0, 1.0))
2104        );
2105        assert_eq!(rect & FRect::new(11.0, 11.0, 10.0, 10.0), None);
2106    }
2107
2108    #[test]
2109    fn frect_union() {
2110        assert_eq!(
2111            FRect::new(0.0, 0.0, 1.0, 1.0) | FRect::new(9.0, 9.0, 1.0, 1.0),
2112            FRect::new(0.0, 0.0, 10.0, 10.0)
2113        );
2114    }
2115
2116    #[test]
2117    fn frect_intersect_line() {
2118        assert_eq!(
2119            FRect::new(1.0, 1.0, 5.0, 5.0)
2120                .intersect_line(FPoint::new(0.0, 0.0), FPoint::new(10.0, 10.0)),
2121            Some((FPoint::new(1.0, 1.0), FPoint::new(5.0, 5.0)))
2122        );
2123    }
2124
2125    #[test]
2126    fn frect_shifted() {
2127        // Groups all functions into a single assertion
2128        let rect = FRect::new(0.0, 0.0, 10.0, 10.0)
2129            .left_shifted(5.0)
2130            .right_shifted(5.0)
2131            .top_shifted(5.0)
2132            .bottom_shifted(5.0);
2133        assert_eq!(rect, FRect::new(0.0, 0.0, 10.0, 10.0));
2134    }
2135
2136    #[test]
2137    fn frect_into() {
2138        let test: (f32, f32, f32, f32) = (-11.0, 5.0, 50.0, 20.0);
2139        assert_eq!(test, FRect::new(-11.0, 5.0, 50.0, 20.0).into());
2140    }
2141
2142    #[test]
2143    fn frect_from() {
2144        assert_eq!(
2145            FRect::from((-11.0, 5.0, 50.0, 20.0)),
2146            FRect::new(-11.0, 5.0, 50.0, 20.0)
2147        );
2148    }
2149
2150    #[test]
2151    fn fpoint_into() {
2152        let test: (f32, f32) = (-11.0, 5.0);
2153        assert_eq!(test, FPoint::new(-11.0, 5.0).into());
2154    }
2155
2156    #[test]
2157    fn fpoint_from() {
2158        let test: (f32, f32) = (-11.0, 5.0);
2159        assert_eq!(test, FPoint::new(-11.0, 5.0).into());
2160    }
2161
2162    #[test]
2163    fn fpoint_add() {
2164        assert_eq!(
2165            FPoint::new(-5.0, 7.0),
2166            FPoint::new(-11.0, 5.0) + FPoint::new(6.0, 2.0)
2167        );
2168    }
2169
2170    #[test]
2171    fn fpoint_add_assign() {
2172        let mut point = FPoint::new(-11.0, 5.0);
2173        point += FPoint::new(6.0, 2.0);
2174        assert_eq!(point, FPoint::new(-11.0, 5.0) + FPoint::new(6.0, 2.0));
2175    }
2176
2177    #[test]
2178    fn fpoint_sub() {
2179        assert_eq!(
2180            FPoint::new(-17.0, 3.0),
2181            FPoint::new(-11.0, 5.0) - FPoint::new(6.0, 2.0)
2182        );
2183    }
2184
2185    #[test]
2186    fn fpoint_sub_assign() {
2187        let mut point = FPoint::new(-11.0, 5.0);
2188        point -= FPoint::new(6.0, 2.0);
2189        assert_eq!(point, FPoint::new(-11.0, 5.0) - FPoint::new(6.0, 2.0));
2190    }
2191
2192    #[test]
2193    fn fpoint_mul() {
2194        assert_eq!(FPoint::new(-33.0, 15.0), FPoint::new(-11.0, 5.0) * 3.0);
2195    }
2196
2197    #[test]
2198    fn fpoint_mul_assign() {
2199        let mut point = FPoint::new(-11.0, 5.0);
2200        point *= 3.0;
2201        assert_eq!(point, FPoint::new(-11.0, 5.0) * 3.0);
2202    }
2203
2204    #[test]
2205    fn fpoint_div() {
2206        assert_eq!(FPoint::new(-3.0, 1.0), FPoint::new(-9.0, 3.0) / 3.0);
2207    }
2208
2209    #[test]
2210    fn fpoint_div_assign() {
2211        let mut point = FPoint::new(-11.0, 5.0);
2212        point /= 3.0;
2213        assert_eq!(point, FPoint::new(-11.0, 5.0) / 3.0);
2214    }
2215
2216    #[test]
2217    fn fpoint_sum() {
2218        let points_sum: FPoint = vec![FPoint::new(-11.0, 5.0), FPoint::new(6.0, 2.0)]
2219            .into_iter()
2220            .sum();
2221        assert_eq!(FPoint::new(-5.0, 7.0), points_sum);
2222    }
2223}