1use crate::alt::Gray;
2use crate::alt::GrayAlpha;
3use super::pixel::*;
4use crate::RGB;
5use crate::RGBA;
6use core::ops::*;
7use core::iter::Sum;
8#[cfg(feature = "argb")]
9use crate::alt::ARGB;
10#[cfg(feature = "grb")]
11use crate::alt::GRB;
12
13macro_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
108macro_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
177macro_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
269impl_scalar!{RGB}
270impl_scalar!{RGBA}
271#[cfg(feature = "argb")]
272impl_scalar!{ARGB}
273#[cfg(feature = "grb")]
274impl_scalar!{GRB}
275impl_scalar!{Gray}
276impl_scalar!{GrayAlpha}
277
278impl_struct_ops_opaque! {RGB => r g b}
279#[cfg(feature = "grb")]
280impl_struct_ops_opaque! {GRB => g r b}
281impl_struct_ops_opaque! {Gray => 0}
282
283impl_struct_ops_alpha! {RGBA => r g b a}
284#[cfg(feature = "argb")]
285impl_struct_ops_alpha! {ARGB => a r g b}
286impl_struct_ops_alpha! {GrayAlpha => 0 1}
287
288#[cfg(test)]
289mod 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