font_types/
point.rs

1use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
2
3/// Two dimensional point with a generic coordinate type.
4#[derive(Copy, Clone, PartialEq, Eq, Default, Debug)]
5#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
6#[cfg_attr(feature = "bytemuck", derive(bytemuck::AnyBitPattern))]
7#[repr(C)]
8pub struct Point<T> {
9    /// X coordinate.
10    pub x: T,
11    /// Y coordinate.
12    pub y: T,
13}
14
15/// SAFETY:
16/// This trait has four preconditions:
17///
18/// 1. All fields in the struct must implement `NoUninit`
19/// 2. The struct must be `#[repr(C)]` or `#[repr(transparent)]`
20/// 3. The struct must not contain any padding bytes
21/// 4. The struct must contain no generic parameters
22///
23/// We satisfy the first and second preconditions trivially. The third
24/// condition is satisfied because the struct is repr(C) and contains
25/// two fields of the same type which guarantees no padding.
26///
27/// The fourth condition is obviously not satisfied which is what
28/// requires implementing this trait manually rather than deriving
29/// it. This condition only exists because the bytemuck derive
30/// macro cannot guarantee the first three conditions in a type
31/// with generic parameters.
32#[cfg(feature = "bytemuck")]
33unsafe impl<T> bytemuck::NoUninit for Point<T> where T: bytemuck::NoUninit {}
34
35impl<T> Point<T> {
36    /// Creates a new point with the given x and y coordinates.
37    #[inline(always)]
38    pub const fn new(x: T, y: T) -> Self {
39        Self { x, y }
40    }
41
42    /// Creates a new point from a single value assigned to both coordinates.
43    pub const fn broadcast(xy: T) -> Self
44    where
45        T: Copy,
46    {
47        Self { x: xy, y: xy }
48    }
49
50    /// Maps `Point<T>` to `Point<U>` by applying a function to each coordinate.
51    #[inline(always)]
52    pub fn map<U>(self, mut f: impl FnMut(T) -> U) -> Point<U> {
53        Point {
54            x: f(self.x),
55            y: f(self.y),
56        }
57    }
58}
59
60impl<T> Add for Point<T>
61where
62    T: Add<Output = T>,
63{
64    type Output = Self;
65
66    #[inline(always)]
67    fn add(self, rhs: Self) -> Self::Output {
68        Self {
69            x: self.x + rhs.x,
70            y: self.y + rhs.y,
71        }
72    }
73}
74
75impl<T> AddAssign for Point<T>
76where
77    T: AddAssign,
78{
79    #[inline(always)]
80    fn add_assign(&mut self, rhs: Self) {
81        self.x += rhs.x;
82        self.y += rhs.y;
83    }
84}
85
86impl<T> Sub for Point<T>
87where
88    T: Sub<Output = T>,
89{
90    type Output = Self;
91
92    #[inline(always)]
93    fn sub(self, rhs: Self) -> Self::Output {
94        Self {
95            x: self.x - rhs.x,
96            y: self.y - rhs.y,
97        }
98    }
99}
100
101impl<T> SubAssign for Point<T>
102where
103    T: SubAssign,
104{
105    #[inline(always)]
106    fn sub_assign(&mut self, rhs: Self) {
107        self.x -= rhs.x;
108        self.y -= rhs.y;
109    }
110}
111
112impl<T> Mul for Point<T>
113where
114    T: Mul<Output = T>,
115{
116    type Output = Self;
117
118    #[inline(always)]
119    fn mul(self, rhs: Self) -> Self::Output {
120        Self {
121            x: self.x * rhs.x,
122            y: self.y * rhs.y,
123        }
124    }
125}
126
127impl<T> Mul<T> for Point<T>
128where
129    T: Mul<Output = T> + Copy,
130{
131    type Output = Self;
132
133    #[inline(always)]
134    fn mul(self, rhs: T) -> Self::Output {
135        Self {
136            x: self.x * rhs,
137            y: self.y * rhs,
138        }
139    }
140}
141
142impl<T> MulAssign for Point<T>
143where
144    T: MulAssign,
145{
146    #[inline(always)]
147    fn mul_assign(&mut self, rhs: Self) {
148        self.x *= rhs.x;
149        self.y *= rhs.y;
150    }
151}
152
153impl<T> MulAssign<T> for Point<T>
154where
155    T: MulAssign + Copy,
156{
157    #[inline(always)]
158    fn mul_assign(&mut self, rhs: T) {
159        self.x *= rhs;
160        self.y *= rhs;
161    }
162}
163
164impl<T> Div for Point<T>
165where
166    T: Div<Output = T>,
167{
168    type Output = Self;
169
170    #[inline(always)]
171    fn div(self, rhs: Self) -> Self::Output {
172        Self {
173            x: self.x / rhs.x,
174            y: self.y / rhs.y,
175        }
176    }
177}
178
179impl<T> Div<T> for Point<T>
180where
181    T: Div<Output = T> + Copy,
182{
183    type Output = Self;
184
185    #[inline(always)]
186    fn div(self, rhs: T) -> Self::Output {
187        Self {
188            x: self.x / rhs,
189            y: self.y / rhs,
190        }
191    }
192}
193
194impl<T> DivAssign for Point<T>
195where
196    T: DivAssign,
197{
198    #[inline(always)]
199    fn div_assign(&mut self, rhs: Self) {
200        self.x /= rhs.x;
201        self.y /= rhs.y;
202    }
203}
204
205impl<T> DivAssign<T> for Point<T>
206where
207    T: DivAssign + Copy,
208{
209    #[inline(always)]
210    fn div_assign(&mut self, rhs: T) {
211        self.x /= rhs;
212        self.y /= rhs;
213    }
214}
215
216impl<T> Neg for Point<T>
217where
218    T: Neg<Output = T>,
219{
220    type Output = Self;
221
222    #[inline(always)]
223    fn neg(self) -> Self::Output {
224        Self {
225            x: -self.x,
226            y: -self.y,
227        }
228    }
229}
230
231#[cfg(test)]
232mod tests {
233    use super::Point;
234    use crate::F26Dot6;
235
236    #[test]
237    fn map() {
238        assert_eq!(
239            Point::new(42.5, 20.1).map(F26Dot6::from_f64),
240            Point::new(F26Dot6::from_f64(42.5), F26Dot6::from_f64(20.1))
241        );
242    }
243
244    #[test]
245    fn add() {
246        assert_eq!(Point::new(1, 2) + Point::new(3, 4), Point::new(4, 6));
247        let mut point = Point::new(1, 2);
248        point += Point::new(3, 4);
249        assert_eq!(point, Point::new(4, 6));
250    }
251
252    #[test]
253    fn sub() {
254        assert_eq!(Point::new(1, 2) - Point::new(3, 4), Point::new(-2, -2));
255        let mut point = Point::new(1, 2);
256        point -= Point::new(3, 4);
257        assert_eq!(point, Point::new(-2, -2));
258    }
259
260    #[test]
261    fn mul() {
262        assert_eq!(Point::new(1, 2) * Point::new(3, 4), Point::new(3, 8));
263        let mut point = Point::new(1, 2);
264        point *= Point::new(3, 4);
265        assert_eq!(point, Point::new(3, 8));
266        assert_eq!(Point::new(1, 2) * 8, Point::new(8, 16));
267    }
268
269    #[test]
270    fn div() {
271        assert_eq!(Point::new(10, 16) / Point::new(2, 3), Point::new(5, 5));
272        let mut point = Point::new(10, 16);
273        point /= Point::new(2, 3);
274        assert_eq!(point, Point::new(5, 5));
275        assert_eq!(Point::new(10, 16) / 2, Point::new(5, 8));
276    }
277
278    #[test]
279    fn neg() {
280        assert_eq!(-Point::new(1, -2), Point::new(-1, 2));
281    }
282}