1use num::One;
12
13use num_traits::NumCast;
14#[cfg(feature = "serde")]
15use serde::{Deserialize, Deserializer, Serialize, Serializer};
16use core::fmt;
17use core::ops::{Add, Div, Mul, Neg, Sub};
18use core::marker::PhantomData;
19use {TypedPoint2D, TypedRect, TypedSize2D, TypedVector2D};
20
21#[repr(C)]
41pub struct TypedScale<T, Src, Dst>(pub T, #[doc(hidden)] pub PhantomData<(Src, Dst)>);
42
43#[cfg(feature = "serde")]
44impl<'de, T, Src, Dst> Deserialize<'de> for TypedScale<T, Src, Dst>
45where
46 T: Deserialize<'de>,
47{
48 fn deserialize<D>(deserializer: D) -> Result<TypedScale<T, Src, Dst>, D::Error>
49 where
50 D: Deserializer<'de>,
51 {
52 Ok(TypedScale(
53 try!(Deserialize::deserialize(deserializer)),
54 PhantomData,
55 ))
56 }
57}
58
59#[cfg(feature = "serde")]
60impl<T, Src, Dst> Serialize for TypedScale<T, Src, Dst>
61where
62 T: Serialize,
63{
64 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
65 where
66 S: Serializer,
67 {
68 self.0.serialize(serializer)
69 }
70}
71
72impl<T, Src, Dst> TypedScale<T, Src, Dst> {
73 pub fn new(x: T) -> Self {
74 TypedScale(x, PhantomData)
75 }
76}
77
78impl<T: Clone, Src, Dst> TypedScale<T, Src, Dst> {
79 pub fn get(&self) -> T {
80 self.0.clone()
81 }
82}
83
84impl<Src, Dst> TypedScale<f32, Src, Dst> {
85 pub const ONE: Self = TypedScale(1.0, PhantomData);
87}
88
89impl<T: Clone + One + Div<T, Output = T>, Src, Dst> TypedScale<T, Src, Dst> {
90 pub fn inv(&self) -> TypedScale<T, Dst, Src> {
92 let one: T = One::one();
93 TypedScale::new(one / self.get())
94 }
95}
96
97impl<T: Clone + Mul<T, Output = T>, A, B, C> Mul<TypedScale<T, B, C>> for TypedScale<T, A, B> {
99 type Output = TypedScale<T, A, C>;
100 #[inline]
101 fn mul(self, other: TypedScale<T, B, C>) -> TypedScale<T, A, C> {
102 TypedScale::new(self.get() * other.get())
103 }
104}
105
106impl<T: Clone + Add<T, Output = T>, Src, Dst> Add for TypedScale<T, Src, Dst> {
108 type Output = TypedScale<T, Src, Dst>;
109 #[inline]
110 fn add(self, other: TypedScale<T, Src, Dst>) -> TypedScale<T, Src, Dst> {
111 TypedScale::new(self.get() + other.get())
112 }
113}
114
115impl<T: Clone + Sub<T, Output = T>, Src, Dst> Sub for TypedScale<T, Src, Dst> {
117 type Output = TypedScale<T, Src, Dst>;
118 #[inline]
119 fn sub(self, other: TypedScale<T, Src, Dst>) -> TypedScale<T, Src, Dst> {
120 TypedScale::new(self.get() - other.get())
121 }
122}
123
124impl<T: NumCast + Clone, Src, Dst0> TypedScale<T, Src, Dst0> {
125 pub fn cast<T1: NumCast + Clone>(&self) -> TypedScale<T1, Src, Dst0> {
127 self.try_cast().unwrap()
128 }
129
130 pub fn try_cast<T1: NumCast + Clone>(&self) -> Option<TypedScale<T1, Src, Dst0>> {
132 NumCast::from(self.get()).map(TypedScale::new)
133 }
134}
135
136impl<T, Src, Dst> TypedScale<T, Src, Dst>
137where
138 T: Copy + Clone + Mul<T, Output = T> + Neg<Output = T> + PartialEq + One,
139{
140 #[inline]
142 pub fn transform_point(&self, point: &TypedPoint2D<T, Src>) -> TypedPoint2D<T, Dst> {
143 TypedPoint2D::new(point.x * self.get(), point.y * self.get())
144 }
145
146 #[inline]
148 pub fn transform_vector(&self, vec: &TypedVector2D<T, Src>) -> TypedVector2D<T, Dst> {
149 TypedVector2D::new(vec.x * self.get(), vec.y * self.get())
150 }
151
152 #[inline]
154 pub fn transform_size(&self, size: &TypedSize2D<T, Src>) -> TypedSize2D<T, Dst> {
155 TypedSize2D::new(size.width * self.get(), size.height * self.get())
156 }
157
158 #[inline]
160 pub fn transform_rect(&self, rect: &TypedRect<T, Src>) -> TypedRect<T, Dst> {
161 TypedRect::new(
162 self.transform_point(&rect.origin),
163 self.transform_size(&rect.size),
164 )
165 }
166
167 #[inline]
169 pub fn inverse(&self) -> TypedScale<T, Dst, Src> {
170 TypedScale::new(-self.get())
171 }
172
173 #[inline]
175 pub fn is_identity(&self) -> bool {
176 self.get() == T::one()
177 }
178}
179
180impl<T: PartialEq, Src, Dst> PartialEq for TypedScale<T, Src, Dst> {
184 fn eq(&self, other: &TypedScale<T, Src, Dst>) -> bool {
185 self.0 == other.0
186 }
187}
188
189impl<T: Clone, Src, Dst> Clone for TypedScale<T, Src, Dst> {
190 fn clone(&self) -> TypedScale<T, Src, Dst> {
191 TypedScale::new(self.get())
192 }
193}
194
195impl<T: Copy, Src, Dst> Copy for TypedScale<T, Src, Dst> {}
196
197impl<T: fmt::Debug, Src, Dst> fmt::Debug for TypedScale<T, Src, Dst> {
198 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
199 self.0.fmt(f)
200 }
201}
202
203impl<T: fmt::Display, Src, Dst> fmt::Display for TypedScale<T, Src, Dst> {
204 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
205 self.0.fmt(f)
206 }
207}
208
209#[cfg(test)]
210mod tests {
211 use super::TypedScale;
212
213 enum Inch {}
214 enum Cm {}
215 enum Mm {}
216
217 #[test]
218 fn test_scale() {
219 let mm_per_inch: TypedScale<f32, Inch, Mm> = TypedScale::new(25.4);
220 let cm_per_mm: TypedScale<f32, Mm, Cm> = TypedScale::new(0.1);
221
222 let mm_per_cm: TypedScale<f32, Cm, Mm> = cm_per_mm.inv();
223 assert_eq!(mm_per_cm.get(), 10.0);
224
225 let cm_per_inch: TypedScale<f32, Inch, Cm> = mm_per_inch * cm_per_mm;
226 assert_eq!(cm_per_inch, TypedScale::new(2.54));
227
228 let a: TypedScale<isize, Inch, Inch> = TypedScale::new(2);
229 let b: TypedScale<isize, Inch, Inch> = TypedScale::new(3);
230 assert!(a != b);
231 assert_eq!(a, a.clone());
232 assert_eq!(a.clone() + b.clone(), TypedScale::new(5));
233 assert_eq!(a - b, TypedScale::new(-1));
234 }
235}