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