1use crate::formats::gray::Gray_v08 as Gray;
2use super::pixel::ComponentMap;
3use crate::alt::GrayAlpha;
4use crate::alt::ARGB;
5use crate::alt::GRB;
6use crate::{RGB, RGBA};
7use core::iter::Sum;
8use core::ops::{Sub, SubAssign, Add, AddAssign, Mul, MulAssign, Div, DivAssign};
9
10#[cfg(feature = "checked_fns")]
11macro_rules! impl_struct_checked {
12 ($ty:ident, $field_ty:ident, => $($field:tt)+) => {
13 impl $ty<$field_ty>
14 {
15 #[inline(always)]
17 #[allow(deprecated)]
18 pub fn checked_add(self, rhs: $ty<$field_ty>) -> Option<Self> {
19 Some($ty {
20 $(
21 $field: self.$field.checked_add(rhs.$field)?,
22 )+
23 })
24 }
25
26 #[inline(always)]
28 #[allow(deprecated)]
29 pub fn checked_sub(self, rhs: $ty<$field_ty>) -> Option<Self> {
30 Some($ty {
31 $(
32 $field: self.$field.checked_sub(rhs.$field)?,
33 )+
34 })
35 }
36 }
37 }
38}
39
40#[cfg(not(feature = "checked_fns"))]
41macro_rules! impl_struct_checked {
42 ($ty:ident, $field_ty:ident, => $($field:tt)+) => {};
43}
44
45macro_rules! impl_struct_ops_opaque {
46 ($ty:ident => $($field:tt)+) => {
47 impl<T: Add> Add for $ty<T> {
49 type Output = $ty<<T as Add>::Output>;
50
51 #[inline(always)]
52 #[allow(deprecated)]
53 fn add(self, other: $ty<T>) -> Self::Output {
54 $ty {
55 $(
56 $field: self.$field + other.$field,
57 )+
58 }
59 }
60 }
61
62 impl<T> AddAssign for $ty<T> where
64 T: Add<Output = T> + Copy
65 {
66 #[inline(always)]
67 #[allow(deprecated)]
68 fn add_assign(&mut self, other: $ty<T>) {
69 *self = Self {
70 $(
71 $field: self.$field + other.$field,
72 )+
73 };
74 }
75 }
76
77 impl<T: Mul> Mul for $ty<T> {
79 type Output = $ty<<T as Mul>::Output>;
80
81 #[inline(always)]
82 #[allow(deprecated)]
83 fn mul(self, other: $ty<T>) -> Self::Output {
84 $ty {
85 $(
86 $field: self.$field * other.$field,
87 )+
88 }
89 }
90 }
91
92 impl<T> MulAssign for $ty<T> where
94 T: Mul<Output = T> + Copy
95 {
96 #[inline(always)]
97 #[allow(deprecated)]
98 fn mul_assign(&mut self, other: $ty<T>) {
99 *self = Self {
100 $(
101 $field: self.$field * other.$field,
102 )+
103 };
104 }
105 }
106
107 impl<T: Sub> Sub for $ty<T> {
109 type Output = $ty<<T as Sub>::Output>;
110
111 #[inline(always)]
112 #[allow(deprecated)]
113 fn sub(self, other: $ty<T>) -> Self::Output {
114 $ty {
115 $(
116 $field: self.$field - other.$field,
117 )+
118 }
119 }
120 }
121
122 impl<T> SubAssign for $ty<T> where
124 T: Sub<Output = T> + Copy
125 {
126 #[inline(always)]
127 #[allow(deprecated)]
128 fn sub_assign(&mut self, other: $ty<T>) {
129 *self = Self {
130 $(
131 $field: self.$field - other.$field,
132 )+
133 };
134 }
135 }
136
137 impl<T> Sum<$ty<T>> for $ty<T> where T: Default + Add<Output=T> {
138 #[inline(always)]
139 fn sum<I: Iterator<Item=Self>>(iter: I) -> Self {
140 iter.fold($ty::default(), Add::add)
141 }
142 }
143
144 impl_struct_checked!($ty, u8, => $($field)+);
145 impl_struct_checked!($ty, u16, => $($field)+);
146 impl_struct_checked!($ty, u32, => $($field)+);
147 impl_struct_checked!($ty, u64, => $($field)+);
148 impl_struct_checked!($ty, i8, => $($field)+);
149 impl_struct_checked!($ty, i16, => $($field)+);
150 impl_struct_checked!($ty, i32, => $($field)+);
151 impl_struct_checked!($ty, i64, => $($field)+);
152 };
153}
154
155macro_rules! impl_struct_ops_alpha {
156 ($ty:ident => $($field:tt)+) => {
157 impl<T: Add, A: Add> Add for $ty<T, A> {
159 type Output = $ty<<T as Add>::Output, <A as Add>::Output>;
160
161 #[inline(always)]
162 #[allow(deprecated)]
163 fn add(self, other: $ty<T, A>) -> Self::Output {
164 $ty {
165 $(
166 $field: self.$field + other.$field,
167 )+
168 }
169 }
170 }
171
172 impl<T, A> AddAssign for $ty<T, A> where
174 T: Add<Output = T> + Copy,
175 A: Add<Output = A> + Copy
176 {
177 #[inline(always)]
178 #[allow(deprecated)]
179 fn add_assign(&mut self, other: $ty<T, A>) {
180 *self = Self {
181 $(
182 $field: self.$field + other.$field,
183 )+
184 };
185 }
186 }
187
188 impl<T: Sub, A: Sub> Sub for $ty<T, A> {
190 type Output = $ty<<T as Sub>::Output, <A as Sub>::Output>;
191
192 #[inline(always)]
193 #[allow(deprecated)]
194 fn sub(self, other: $ty<T, A>) -> Self::Output {
195 $ty {
196 $(
197 $field: self.$field - other.$field,
198 )+
199 }
200 }
201 }
202
203 impl<T, A> SubAssign for $ty<T, A> where
205 T: Sub<Output = T> + Copy,
206 A: Sub<Output = A> + Copy
207 {
208 #[inline(always)]
209 #[allow(deprecated)]
210 fn sub_assign(&mut self, other: $ty<T, A>) {
211 *self = Self {
212 $(
213 $field: self.$field - other.$field,
214 )+
215 };
216 }
217 }
218
219 impl<T, A> Sum<$ty<T, A>> for $ty<T, A> where T: Default + Add<Output=T>, A: Default + Add<Output=A> {
220 #[inline(always)]
221 fn sum<I: Iterator<Item=Self>>(iter: I) -> Self {
222 iter.fold($ty::default(), Add::add)
223 }
224 }
225
226 impl_struct_checked!($ty, u8, => $($field)+);
227 impl_struct_checked!($ty, u16, => $($field)+);
228 impl_struct_checked!($ty, u32, => $($field)+);
229 impl_struct_checked!($ty, u64, => $($field)+);
230 impl_struct_checked!($ty, i8, => $($field)+);
231 impl_struct_checked!($ty, i16, => $($field)+);
232 impl_struct_checked!($ty, i32, => $($field)+);
233 impl_struct_checked!($ty, i64, => $($field)+);
234 };
235}
236
237macro_rules! impl_scalar {
238 ($ty:ident) => {
239 impl<T> Sub<T> for $ty<T>
241 where T: Copy + Sub<Output = T>
242 {
243 type Output = $ty<<T as Sub>::Output>;
244
245 #[inline(always)]
246 fn sub(self, r: T) -> Self::Output {
247 self.map(|l| l - r)
248 }
249 }
250
251 impl<T> SubAssign<T> for $ty<T>
253 where T: Copy + Sub<Output = T>
254 {
255 #[inline(always)]
256 fn sub_assign(&mut self, r: T) {
257 *self = self.map(|l| l - r);
258 }
259 }
260
261 impl<T> Add<T> for $ty<T>
263 where T: Copy + Add<Output = T>
264 {
265 type Output = $ty<T>;
266
267 #[inline(always)]
268 fn add(self, r: T) -> Self::Output {
269 self.map(|l| l + r)
270 }
271 }
272
273 impl<T> AddAssign<T> for $ty<T>
275 where T: Copy + Add<Output = T>
276 {
277 #[inline(always)]
278 fn add_assign(&mut self, r: T) {
279 *self = self.map(|l| l + r);
280 }
281 }
282
283 impl<T> Mul<T> for $ty<T>
285 where T: Copy + Mul<Output = T>
286 {
287 type Output = $ty<T>;
288
289 #[inline(always)]
290 fn mul(self, r: T) -> Self::Output {
291 self.map(|l| l * r)
292 }
293 }
294
295 impl<T> MulAssign<T> for $ty<T>
297 where T: Copy + Mul<Output = T>
298 {
299 #[inline(always)]
300 fn mul_assign(&mut self, r: T) {
301 *self = self.map(|l| l * r);
302 }
303 }
304
305 impl<T> Div<T> for $ty<T>
307 where T: Copy + Div<Output = T>
308 {
309 type Output = $ty<T>;
310
311 #[inline(always)]
312 fn div(self, r: T) -> Self::Output {
313 self.map(|l| l / r)
314 }
315 }
316
317 impl<T> DivAssign<T> for $ty<T>
319 where T: Copy + Div<Output = T>
320 {
321 #[inline(always)]
322 fn div_assign(&mut self, r: T) {
323 *self = self.map(|l| l / r);
324 }
325 }
326 };
327}
328
329impl_scalar! {RGB}
330impl_scalar! {RGBA}
331impl_scalar! {ARGB}
332impl_scalar! {GRB}
333impl_scalar! {Gray}
334impl_scalar! {GrayAlpha}
335
336impl_struct_ops_opaque! {RGB => r g b}
337impl_struct_ops_opaque! {GRB => g r b}
338impl_struct_ops_opaque! {Gray => 0}
339
340impl_struct_ops_alpha! {RGBA => r g b a}
341impl_struct_ops_alpha! {ARGB => a r g b}
342impl_struct_ops_alpha! {GrayAlpha => 0 1}
343
344#[cfg(test)]
345mod test {
346 use super::*;
347 use core::num::Wrapping;
348 const WHITE_RGB: RGB<u8> = RGB::new(255, 255, 255);
349 const BLACK_RGB: RGB<u8> = RGB::new(0, 0, 0);
350 const RED_RGB: RGB<u8> = RGB::new(255, 0, 0);
351 const GREEN_RGB: RGB<u8> = RGB::new(0, 255, 0);
352 const BLUE_RGB: RGB<u8> = RGB::new(0, 0, 255);
353
354 const WHITE_RGBA: RGBA<u8> = RGBA::new(255, 255, 255, 255);
355 const BLACK_RGBA: RGBA<u8> = RGBA::new(0, 0, 0, 0);
356 const RED_RGBA: RGBA<u8> = RGBA::new(255, 0, 0, 255);
357 const GREEN_RGBA: RGBA<u8> = RGBA::new(0, 255, 0, 0);
358 const BLUE_RGBA: RGBA<u8> = RGBA::new(0, 0, 255, 255);
359
360 #[test]
361 fn test_add() {
362 assert_eq!(RGB::new(2,4,6), RGB::new(1,2,3) + RGB{r:1,g:2,b:3});
363 assert_eq!(RGB::new(2.,4.,6.), RGB::new(1.,3.,5.) + 1.);
364
365 assert_eq!(RGBA::new_alpha(2f32,4.,6.,8u32), RGBA::new_alpha(1f32,2.,3.,4u32) + RGBA{r:1f32,g:2.0,b:3.0,a:4u32});
366 assert_eq!(RGBA::new(2i16,4,6,8), RGBA::new(1,3,5,7) + 1);
367
368 assert_eq!(RGB::new(255, 255, 0), RED_RGB+GREEN_RGB);
369 assert_eq!(RGB::new(255, 0, 0), RED_RGB+RGB::new(0, 0, 0));
370 assert_eq!(WHITE_RGB, BLACK_RGB + 255);
371
372 assert_eq!(RGBA::new(255, 255, 0, 255), RED_RGBA+GREEN_RGBA);
373 assert_eq!(RGBA::new(255, 0, 0, 255), RED_RGBA+RGBA::new(0, 0, 0, 0));
374 assert_eq!(WHITE_RGBA, BLACK_RGBA + 255);
375 }
376
377 #[test]
378 #[cfg(feature = "checked_fns")]
379 fn test_checked_add() {
380 assert_eq!(WHITE_RGB.checked_add(WHITE_RGB), None);
381 assert_eq!(RGB::<u8>::new(255, 255, 255).checked_add(RGB::<u8>::new(255, 0, 0)), None);
382 assert_eq!(RGB::<u8>::new(255, 255, 255).checked_add(RGB::<u8>::new(0, 255, 0)), None);
383 assert_eq!(RGB::<u8>::new(255, 255, 255).checked_add(RGB::<u8>::new(0, 0, 255)), None);
384 assert_eq!(WHITE_RGBA.checked_add(BLACK_RGBA), Some(WHITE_RGBA));
385
386 assert_eq!(RGB::<i8>::new(-128, 2, 3).checked_add(RGB::<i8>::new(-1, 0, 0)), None);
387 assert_eq!(RGB::<i8>::new(2, -128, 3).checked_add(RGB::<i8>::new(0, -1, 0)), None);
388 assert_eq!(RGB::<i8>::new(2, 2, -128).checked_add(RGB::<i8>::new(0, 0, -1)), None);
389 assert_eq!(RGB::<i8>::new(2, 2, -128).checked_add(RGB::<i8>::new(0, 0, 1)), Some(RGB::<i8>::new(2, 2, -127)));
390 }
391
392 #[test]
393 #[should_panic]
394 #[cfg(debug_assertions)]
395 fn test_add_overflow() {
396 assert_ne!(RGBA::new(255u8, 255, 0, 0), RED_RGBA + BLUE_RGBA);
397 }
398
399 #[test]
400 fn test_sub() {
401 assert_eq!(RED_RGB, (WHITE_RGB - GREEN_RGB) - BLUE_RGB);
402 assert_eq!(BLACK_RGB, WHITE_RGB - 255);
403
404 assert_eq!(RGBA::new(255, 255, 0, 0), WHITE_RGBA - BLUE_RGBA);
405 assert_eq!(BLACK_RGBA, WHITE_RGBA - 255);
406 }
407
408 #[test]
409 #[cfg(feature = "checked_fns")]
410 fn test_checked_sub() {
411 assert_eq!(RGBA::<u8>::new(2,4,6,111).checked_sub(RGBA::<u8>::new(3,4,6,0)), None);
412 assert_eq!(RGB::<u8>::new(2,4,6).checked_sub(RGB::<u8>::new(2,5,6)), None);
413 assert_eq!(RGB::<u8>::new(2,4,6).checked_sub(RGB::<u8>::new(2,4,7)), None);
414 assert_eq!(RGB::<u8>::new(2,4,6).checked_sub(RGB::<u8>::new(2,4,6)), Some(BLACK_RGB));
415
416 assert_eq!(RGB::<i8>::new(-128,4,6).checked_sub(RGB::<i8>::new(1,4,7)), None);
417 assert_eq!(RGB::<i8>::new(2,-128,6).checked_sub(RGB::<i8>::new(2,1,7)), None);
418 assert_eq!(RGB::<i8>::new(2,4,-128).checked_sub(RGB::<i8>::new(2,4,1)), None);
419 assert_eq!(RGB::<i8>::new(2,4,6).checked_sub(RGB::<i8>::new(-2,4,6)), Some(RGB::<i8>::new(4,0,0)));
420 }
421
422 #[test]
423 fn test_add_assign() {
424 let mut green_rgb = RGB::new(0, 255, 0);
425 green_rgb += RGB::new(255, 0, 255);
426 assert_eq!(WHITE_RGB, green_rgb);
427
428 let mut black_rgb = RGB::new(0, 0, 0);
429 black_rgb += 255;
430 assert_eq!(WHITE_RGB, black_rgb);
431
432 let mut green_rgba = RGBA::new(0, 255, 0, 0);
433 green_rgba += RGBA::new(255, 0, 255, 255);
434 assert_eq!(WHITE_RGBA, green_rgba);
435
436 let mut black_rgba = RGBA::new(0, 0, 0, 0);
437 black_rgba += 255;
438 assert_eq!(WHITE_RGBA, black_rgba);
439 }
440
441 #[test]
442 fn test_sub_assign() {
443 let mut green_rgb = RGB::new(0, 255, 0);
444 green_rgb -= RGB::new(0, 255, 0);
445 assert_eq!(BLACK_RGB, green_rgb);
446
447 let mut white_rgb = RGB::new(255, 255, 255);
448 white_rgb -= 255;
449 assert_eq!(BLACK_RGB, white_rgb);
450
451 let mut green_rgba = RGBA::new(0, 255, 0, 0);
452 green_rgba -= RGBA::new(0, 255, 0, 0);
453 assert_eq!(BLACK_RGBA, green_rgba);
454
455 let mut white_rgba = RGBA::new(255, 255, 255, 255);
456 white_rgba -= 255;
457 assert_eq!(BLACK_RGBA, white_rgba);
458 }
459
460 #[test]
461 fn test_mult() {
462 assert_eq!(RGB::new(0.5,1.5,2.5), RGB::new(1.,3.,5.) * 0.5);
463 assert_eq!(RGBA::new(2,4,6,8), RGBA::new(1,2,3,4) * 2);
464 assert_eq!(RGB::new(0.5,1.5,2.5) * RGB::new(1.,3.,5.),
465 RGB::new(0.5,4.5,12.5));
466 }
467
468 #[test]
469 fn test_mult_assign() {
470 let mut green_rgb = RGB::new(0u16, 255, 0);
471 green_rgb *= 1;
472 assert_eq!(RGB::new(0, 255, 0), green_rgb);
473 green_rgb *= 2;
474 assert_eq!(RGB::new(0, 255*2, 0), green_rgb);
475
476 let mut rgb = RGB::new(0.5,1.5,2.5);
477 rgb *= RGB::new(1.,3.,5.);
478 assert_eq!(rgb, RGB::new(0.5,4.5,12.5));
479
480 let mut green_rgba = RGBA::new(0u16, 255, 0, 0);
481 green_rgba *= 1;
482 assert_eq!(RGBA::new(0, 255, 0, 0), green_rgba);
483 green_rgba *= 2;
484 assert_eq!(RGBA::new(0, 255*2, 0, 0), green_rgba);
485 }
486
487 #[test]
488 fn sum() {
489 let s1 = [RGB::new(1u8,1,1), RGB::new(2,3,4)].iter().copied().sum::<RGB<u8>>();
490 let s2 = [RGB::new(1u16,1,1), RGB::new(2,3,4)].iter().copied().sum::<RGB<u16>>();
491 let s3 = [RGBA::new_alpha(1u16,1,1,Wrapping(1u16)), RGBA::new_alpha(2,3,4,Wrapping(5))].iter().copied().sum::<RGBA<u16, Wrapping<u16>>>();
492 let s4 = [RGBA::new_alpha(1u16,1,1,1u16), RGBA::new_alpha(2,3,4,5)].iter().copied().sum::<RGBA<u16, u16>>();
493 assert_eq!(s1, RGB::new(3, 4, 5));
494 assert_eq!(s2, RGB::new(3, 4, 5));
495 assert_eq!(s3, RGBA::new_alpha(3, 4, 5, Wrapping(6)));
496 assert_eq!(s4, RGBA::new_alpha(3, 4, 5, 6));
497 }
498}