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