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