1 use crate::alt::Gray;
2 use crate::alt::GrayAlpha;
3 use super::pixel::*;
4 use crate::RGB;
5 use crate::RGBA;
6 use core::ops::*;
7 use core::iter::Sum;
8 #[cfg(feature = "argb")]
9 use crate::alt::ARGB;
10 
11 macro_rules! impl_struct_ops_opaque {
12     ($ty:ident => $($field:tt)+) => {
13         /// `px + px`
14         impl<T: Add> Add for $ty<T> {
15             type Output = $ty<<T as Add>::Output>;
16 
17             #[inline(always)]
18             fn add(self, other: $ty<T>) -> Self::Output {
19                 $ty {
20                     $(
21                         $field: self.$field + other.$field,
22                     )+
23                 }
24             }
25         }
26 
27         /// `px + px`
28         impl<T> AddAssign for $ty<T> where
29             T: Add<Output = T> + Copy
30         {
31             #[inline(always)]
32             fn add_assign(&mut self, other: $ty<T>) {
33                 *self = Self {
34                     $(
35                         $field: self.$field + other.$field,
36                     )+
37                 };
38             }
39         }
40 
41         /// `px * px`
42         impl<T: Mul> Mul for $ty<T> {
43             type Output = $ty<<T as Mul>::Output>;
44 
45             #[inline(always)]
46             fn mul(self, other: $ty<T>) -> Self::Output {
47                 $ty {
48                     $(
49                         $field: self.$field * other.$field,
50                     )+
51                 }
52             }
53         }
54 
55         /// `px * px`
56         impl<T> MulAssign for $ty<T> where
57             T: Mul<Output = T> + Copy
58         {
59             #[inline(always)]
60             fn mul_assign(&mut self, other: $ty<T>) {
61                 *self = Self {
62                     $(
63                         $field: self.$field * other.$field,
64                     )+
65                 };
66             }
67         }
68 
69         /// `px - px`
70         impl<T: Sub> Sub for $ty<T> {
71             type Output = $ty<<T as Sub>::Output>;
72 
73             #[inline(always)]
74             fn sub(self, other: $ty<T>) -> Self::Output {
75                 $ty {
76                     $(
77                         $field: self.$field - other.$field,
78                     )+
79                 }
80             }
81         }
82 
83         /// `px - px`
84         impl<T> SubAssign for $ty<T> where
85             T: Sub<Output = T> + Copy
86         {
87             #[inline(always)]
88             fn sub_assign(&mut self, other: $ty<T>) {
89                 *self = Self {
90                     $(
91                         $field: self.$field - other.$field,
92                     )+
93                 };
94             }
95         }
96 
97         impl<T> Sum<$ty<T>> for $ty<T> where T: Default + Add<Output=T> {
98             #[inline(always)]
99             fn sum<I: Iterator<Item=Self>>(iter: I) -> Self {
100                 iter.fold($ty::default(), Add::add)
101             }
102         }
103     };
104 }
105 
106 macro_rules! impl_struct_ops_alpha {
107     ($ty:ident => $($field:tt)+) => {
108         /// `px + px`
109         impl<T: Add, A: Add> Add for $ty<T, A> {
110             type Output = $ty<<T as Add>::Output, <A as Add>::Output>;
111 
112             #[inline(always)]
113             fn add(self, other: $ty<T, A>) -> Self::Output {
114                 $ty {
115                     $(
116                         $field: self.$field + other.$field,
117                     )+
118                 }
119             }
120         }
121 
122         /// `px + px`
123         impl<T, A> AddAssign for $ty<T, A> where
124             T: Add<Output = T> + Copy,
125             A: Add<Output = A> + Copy
126         {
127             #[inline(always)]
128             fn add_assign(&mut self, other: $ty<T, A>) {
129                 *self = Self {
130                     $(
131                         $field: self.$field + other.$field,
132                     )+
133                 };
134             }
135         }
136 
137         /// `px - px`
138         impl<T: Sub, A: Sub> Sub for $ty<T, A> {
139             type Output = $ty<<T as Sub>::Output, <A as Sub>::Output>;
140 
141             #[inline(always)]
142             fn sub(self, other: $ty<T, A>) -> Self::Output {
143                 $ty {
144                     $(
145                         $field: self.$field - other.$field,
146                     )+
147                 }
148             }
149         }
150 
151         /// `px - px`
152         impl<T, A> SubAssign for $ty<T, A> where
153             T: Sub<Output = T> + Copy,
154             A: Sub<Output = A> + Copy
155         {
156             #[inline(always)]
157             fn sub_assign(&mut self, other: $ty<T, A>) {
158                 *self = Self {
159                     $(
160                         $field: self.$field - other.$field,
161                     )+
162                 };
163             }
164         }
165 
166         impl<T, A> Sum<$ty<T, A>> for $ty<T, A> where T: Default + Add<Output=T>, A: Default + Add<Output=A> {
167             #[inline(always)]
168             fn sum<I: Iterator<Item=Self>>(iter: I) -> Self {
169                 iter.fold($ty::default(), Add::add)
170             }
171         }
172     };
173 }
174 
175 macro_rules! impl_scalar {
176     ($ty:ident) => {
177         /// `px - 1`
178         impl<T> Sub<T> for $ty<T> where
179             T: Copy + Sub<Output=T>
180         {
181             type Output = $ty<<T as Sub>::Output>;
182 
183             #[inline(always)]
184             fn sub(self, r: T) -> Self::Output {
185                 self.map(|l| l-r)
186             }
187         }
188 
189         /// `px - 1`
190         impl<T> SubAssign<T> for $ty<T> where
191             T: Copy + Sub<Output=T>
192         {
193             #[inline(always)]
194             fn sub_assign(&mut self, r: T) {
195                 *self = self.map(|l| l-r);
196             }
197         }
198 
199         /// `px + 1`
200         impl<T> Add<T> for $ty<T> where
201             T: Copy + Add<Output=T>
202         {
203             type Output = $ty<T>;
204 
205             #[inline(always)]
206             fn add(self, r: T) -> Self::Output {
207                 self.map(|l|l+r)
208             }
209         }
210 
211         /// `px + 1`
212         impl<T> AddAssign<T> for $ty<T> where
213             T: Copy + Add<Output=T>
214         {
215             #[inline(always)]
216             fn add_assign(&mut self, r: T) {
217                 *self = self.map(|l| l+r);
218             }
219         }
220 
221         /// `px * 1`
222         impl<T> Mul<T> for $ty<T> where
223             T: Copy + Mul<Output=T>
224         {
225             type Output = $ty<T>;
226 
227             #[inline(always)]
228             fn mul(self, r: T) -> Self::Output {
229                 self.map(|l|l*r)
230             }
231         }
232 
233         /// `px * 1`
234         impl<T> MulAssign<T> for $ty<T> where
235             T: Copy + Mul<Output=T>
236         {
237             #[inline(always)]
238             fn mul_assign(&mut self, r: T) {
239                 *self = self.map(|l| l*r);
240             }
241         }
242 
243         /// `px / 1`
244         impl<T> Div<T> for $ty<T> where
245             T: Copy + Div<Output=T>
246         {
247             type Output = $ty<T>;
248 
249             #[inline(always)]
250             fn div(self, r: T) -> Self::Output {
251                 self.map(|l| l / r)
252             }
253         }
254 
255         /// `px * 1`
256         impl<T> DivAssign<T> for $ty<T> where
257             T: Copy + Div<Output=T>
258         {
259             #[inline(always)]
260             fn div_assign(&mut self, r: T) {
261                 *self = self.map(|l| l / r);
262             }
263         }
264     }
265 }
266 
267 impl_scalar!{RGB}
268 impl_scalar!{RGBA}
269 #[cfg(feature = "argb")]
270 impl_scalar!{ARGB}
271 impl_scalar!{Gray}
272 impl_scalar!{GrayAlpha}
273 
274 impl_struct_ops_opaque! {RGB => r g b}
275 impl_struct_ops_opaque! {Gray => 0}
276 
277 impl_struct_ops_alpha! {RGBA => r g b a}
278 #[cfg(feature = "argb")]
279 impl_struct_ops_alpha! {ARGB => a r g b}
280 impl_struct_ops_alpha! {GrayAlpha => 0 1}
281 
282 #[cfg(test)]
283 mod test {
284     use super::*;
285     const WHITE_RGB: RGB<u8> = RGB::new(255, 255, 255);
286     const BLACK_RGB: RGB<u8> = RGB::new(0, 0, 0);
287     const RED_RGB: RGB<u8> = RGB::new(255, 0, 0);
288     const GREEN_RGB: RGB<u8> = RGB::new(0, 255, 0);
289     const BLUE_RGB: RGB<u8> = RGB::new(0, 0, 255);
290 
291     const WHITE_RGBA: RGBA<u8> = RGBA::new(255, 255, 255, 255);
292     const BLACK_RGBA: RGBA<u8> = RGBA::new(0, 0, 0, 0);
293     const RED_RGBA: RGBA<u8> = RGBA::new(255, 0, 0, 255);
294     const GREEN_RGBA: RGBA<u8> = RGBA::new(0, 255, 0, 0);
295     const BLUE_RGBA: RGBA<u8> = RGBA::new(0, 0, 255, 255);
296 
297     #[test]
test_add()298     fn test_add() {
299         assert_eq!(RGB::new(2,4,6), RGB::new(1,2,3) + RGB{r:1,g:2,b:3});
300         assert_eq!(RGB::new(2.,4.,6.), RGB::new(1.,3.,5.) + 1.);
301 
302         assert_eq!(RGBA::new_alpha(2u8,4,6,8u16), RGBA::new_alpha(1u8,2,3,4u16) + RGBA{r:1u8,g:2,b:3,a:4u16});
303         assert_eq!(RGBA::new(2i16,4,6,8), RGBA::new(1,3,5,7) + 1);
304 
305         assert_eq!(RGB::new(255, 255, 0), RED_RGB+GREEN_RGB);
306         assert_eq!(RGB::new(255, 0, 0), RED_RGB+RGB::new(0, 0, 0));
307         assert_eq!(WHITE_RGB, BLACK_RGB + 255);
308 
309         assert_eq!(RGBA::new(255, 255, 0, 255), RED_RGBA+GREEN_RGBA);
310         assert_eq!(RGBA::new(255, 0, 0, 255), RED_RGBA+RGBA::new(0, 0, 0, 0));
311         assert_eq!(WHITE_RGBA, BLACK_RGBA + 255);
312     }
313 
314     #[test]
315     #[should_panic]
316     #[cfg(debug_assertions)]
test_add_overflow()317     fn test_add_overflow() {
318         assert_ne!(RGBA::new(255u8, 255, 0, 0), RED_RGBA+BLUE_RGBA);
319     }
320 
321     #[test]
test_sub()322     fn test_sub() {
323         assert_eq!(RED_RGB, (WHITE_RGB - GREEN_RGB) - BLUE_RGB);
324         assert_eq!(BLACK_RGB, WHITE_RGB - 255);
325 
326         assert_eq!(RGBA::new(255, 255, 0, 0), WHITE_RGBA - BLUE_RGBA);
327         assert_eq!(BLACK_RGBA, WHITE_RGBA - 255);
328     }
329 
330     #[test]
test_add_assign()331     fn test_add_assign() {
332         let mut green_rgb = RGB::new(0, 255, 0);
333         green_rgb += RGB::new(255, 0, 255);
334         assert_eq!(WHITE_RGB, green_rgb);
335 
336         let mut black_rgb = RGB::new(0, 0, 0);
337         black_rgb += 255;
338         assert_eq!(WHITE_RGB, black_rgb);
339 
340         let mut green_rgba = RGBA::new(0, 255, 0, 0);
341         green_rgba += RGBA::new(255, 0, 255, 255);
342         assert_eq!(WHITE_RGBA, green_rgba);
343 
344         let mut black_rgba = RGBA::new(0, 0, 0, 0);
345         black_rgba += 255;
346         assert_eq!(WHITE_RGBA, black_rgba);
347     }
348 
349     #[test]
test_sub_assign()350     fn test_sub_assign() {
351         let mut green_rgb = RGB::new(0, 255, 0);
352         green_rgb -= RGB::new(0, 255, 0);
353         assert_eq!(BLACK_RGB, green_rgb);
354 
355         let mut white_rgb = RGB::new(255, 255, 255);
356         white_rgb -= 255;
357         assert_eq!(BLACK_RGB, white_rgb);
358 
359         let mut green_rgba = RGBA::new(0, 255, 0, 0);
360         green_rgba -= RGBA::new(0, 255, 0, 0);
361         assert_eq!(BLACK_RGBA, green_rgba);
362 
363         let mut white_rgba = RGBA::new(255, 255, 255, 255);
364         white_rgba -= 255;
365         assert_eq!(BLACK_RGBA, white_rgba);
366     }
367 
368     #[test]
test_mult()369     fn test_mult() {
370         assert_eq!(RGB::new(0.5,1.5,2.5), RGB::new(1.,3.,5.) * 0.5);
371         assert_eq!(RGBA::new(2,4,6,8), RGBA::new(1,2,3,4) * 2);
372         assert_eq!(RGB::new(0.5,1.5,2.5) * RGB::new(1.,3.,5.),
373         RGB::new(0.5,4.5,12.5));
374     }
375 
376     #[test]
test_mult_assign()377     fn test_mult_assign() {
378         let mut green_rgb = RGB::new(0u16, 255, 0);
379         green_rgb *= 1;
380         assert_eq!(RGB::new(0, 255, 0), green_rgb);
381         green_rgb *= 2;
382         assert_eq!(RGB::new(0, 255*2, 0), green_rgb);
383 
384         let mut rgb = RGB::new(0.5,1.5,2.5);
385         rgb *= RGB::new(1.,3.,5.);
386         assert_eq!(rgb, RGB::new(0.5,4.5,12.5));
387 
388         let mut green_rgba = RGBA::new(0u16, 255, 0, 0);
389         green_rgba *= 1;
390         assert_eq!(RGBA::new(0, 255, 0, 0), green_rgba);
391         green_rgba *= 2;
392         assert_eq!(RGBA::new(0, 255*2, 0, 0), green_rgba);
393     }
394 
395     #[test]
sum()396     fn sum() {
397         let s1 = [RGB::new(1u8,1,1), RGB::new(2,3,4)].iter().copied().sum::<RGB<u8>>();
398         let s2 = [RGB::new(1u16,1,1), RGB::new(2,3,4)].iter().copied().sum::<RGB<u16>>();
399         let s3 = [RGBA::new_alpha(1u8,1,1,1u16), RGBA::new_alpha(2,3,4,5)].iter().copied().sum::<RGBA<u8, u16>>();
400         let s4 = [RGBA::new_alpha(1u16,1,1,1u8), RGBA::new_alpha(2,3,4,5)].iter().copied().sum::<RGBA<u16, u8>>();
401         assert_eq!(s1, RGB::new(3, 4, 5));
402         assert_eq!(s2, RGB::new(3, 4, 5));
403         assert_eq!(s3, RGBA::new_alpha(3, 4, 5, 6));
404         assert_eq!(s4, RGBA::new_alpha(3, 4, 5, 6));
405     }
406 }
407