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