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