1use core::ops::{Add, AddAssign, Deref, DerefMut, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
2
3#[cfg(feature = "approx")]
4use approx::{AbsDiffEq, RelativeEq, UlpsEq};
5
6use crate::{
7 cast::ArrayCast,
8 clamp,
9 num::{self, Arithmetics, One, Real, Zero},
10 stimulus::Stimulus,
11 Alpha, ArrayExt, Mix, MixAssign, NextArray,
12};
13
14use super::Premultiply;
15
16#[derive(Clone, Copy, Debug)]
39#[repr(C)]
40pub struct PreAlpha<C: Premultiply> {
41 pub color: C,
43
44 pub alpha: C::Scalar,
47}
48
49impl<C> PreAlpha<C>
50where
51 C: Premultiply,
52{
53 pub fn new(color: C, alpha: C::Scalar) -> Self {
55 color.premultiply(alpha)
56 }
57
58 pub fn new_opaque(color: C) -> Self
60 where
61 C::Scalar: Stimulus,
62 {
63 Self {
64 color,
65 alpha: C::Scalar::max_intensity(),
66 }
67 }
68
69 pub fn unpremultiply(self) -> Alpha<C, C::Scalar> {
71 let (color, alpha) = C::unpremultiply(self);
72 Alpha { color, alpha }
73 }
74}
75
76impl<C> PartialEq for PreAlpha<C>
77where
78 C: PartialEq + Premultiply,
79 C::Scalar: PartialEq,
80{
81 fn eq(&self, other: &Self) -> bool {
82 self.color == other.color && self.alpha == other.alpha
83 }
84}
85
86impl<C> Eq for PreAlpha<C>
87where
88 C: Eq + Premultiply,
89 C::Scalar: Eq,
90{
91}
92
93impl<C> From<Alpha<C, C::Scalar>> for PreAlpha<C>
94where
95 C: Premultiply,
96{
97 #[inline]
98 fn from(color: Alpha<C, C::Scalar>) -> Self {
99 color.color.premultiply(color.alpha)
100 }
101}
102
103impl<C> From<PreAlpha<C>> for Alpha<C, C::Scalar>
104where
105 C: Premultiply,
106{
107 #[inline]
108 fn from(color: PreAlpha<C>) -> Self {
109 let (color, alpha) = C::unpremultiply(color);
110 Alpha { color, alpha }
111 }
112}
113
114impl<C> From<C> for PreAlpha<C>
115where
116 C: Premultiply,
117 C::Scalar: Stimulus,
118{
119 fn from(color: C) -> Self {
120 color.premultiply(C::Scalar::max_intensity())
121 }
122}
123
124impl<C, T> Mix for PreAlpha<C>
125where
126 C: Mix<Scalar = T> + Premultiply<Scalar = T>,
127 T: Real + Zero + One + num::Clamp + Arithmetics + Clone,
128{
129 type Scalar = T;
130
131 #[inline]
132 fn mix(mut self, other: Self, factor: T) -> Self {
133 let factor = clamp(factor, T::zero(), T::one());
134
135 self.color = self.color.mix(other.color, factor.clone());
136 self.alpha = self.alpha.clone() + factor * (other.alpha - self.alpha);
137
138 self
139 }
140}
141
142impl<C, T> MixAssign for PreAlpha<C>
143where
144 C: MixAssign<Scalar = T> + Premultiply<Scalar = T>,
145 T: Real + Zero + One + num::Clamp + Arithmetics + AddAssign + Clone,
146{
147 type Scalar = T;
148
149 #[inline]
150 fn mix_assign(&mut self, other: Self, factor: T) {
151 let factor = clamp(factor, T::zero(), T::one());
152
153 self.color.mix_assign(other.color, factor.clone());
154 self.alpha += factor * (other.alpha - self.alpha.clone());
155 }
156}
157
158unsafe impl<C, T> ArrayCast for PreAlpha<C>
159where
160 C: ArrayCast + Premultiply<Scalar = T>,
161 C::Array: NextArray + ArrayExt<Item = T>,
162{
163 type Array = <C::Array as NextArray>::Next;
164}
165
166impl<C> Default for PreAlpha<C>
167where
168 C: Default + Premultiply,
169 C::Scalar: Stimulus,
170{
171 fn default() -> PreAlpha<C> {
172 PreAlpha {
173 color: C::default(),
174 alpha: C::Scalar::max_intensity(),
175 }
176 }
177}
178
179#[cfg(feature = "approx")]
180impl<C, T> AbsDiffEq for PreAlpha<C>
181where
182 C: AbsDiffEq<Epsilon = T::Epsilon> + Premultiply<Scalar = T>,
183 T: AbsDiffEq,
184 T::Epsilon: Clone,
185{
186 type Epsilon = T::Epsilon;
187
188 fn default_epsilon() -> Self::Epsilon {
189 T::default_epsilon()
190 }
191
192 fn abs_diff_eq(&self, other: &PreAlpha<C>, epsilon: Self::Epsilon) -> bool {
193 self.color.abs_diff_eq(&other.color, epsilon.clone())
194 && self.alpha.abs_diff_eq(&other.alpha, epsilon)
195 }
196}
197
198#[cfg(feature = "approx")]
199impl<C, T> RelativeEq for PreAlpha<C>
200where
201 C: RelativeEq<Epsilon = T::Epsilon> + Premultiply<Scalar = T>,
202 T: RelativeEq,
203 T::Epsilon: Clone,
204{
205 fn default_max_relative() -> Self::Epsilon {
206 T::default_max_relative()
207 }
208
209 fn relative_eq(
210 &self,
211 other: &PreAlpha<C>,
212 epsilon: Self::Epsilon,
213 max_relative: Self::Epsilon,
214 ) -> bool {
215 self.color
216 .relative_eq(&other.color, epsilon.clone(), max_relative.clone())
217 && self.alpha.relative_eq(&other.alpha, epsilon, max_relative)
218 }
219}
220
221#[cfg(feature = "approx")]
222impl<C, T> UlpsEq for PreAlpha<C>
223where
224 C: UlpsEq<Epsilon = T::Epsilon> + Premultiply<Scalar = T>,
225 T: UlpsEq,
226 T::Epsilon: Clone,
227{
228 fn default_max_ulps() -> u32 {
229 T::default_max_ulps()
230 }
231
232 fn ulps_eq(&self, other: &PreAlpha<C>, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
233 self.color.ulps_eq(&other.color, epsilon.clone(), max_ulps)
234 && self.alpha.ulps_eq(&other.alpha, epsilon, max_ulps)
235 }
236}
237
238macro_rules! impl_binop {
239 (
240 $op_trait:ident::$op_trait_fn:ident,
241 $op_assign_trait:ident::$op_assign_trait_fn:ident
242 ) => {
243 impl<C> $op_trait for PreAlpha<C>
244 where
245 C: $op_trait<Output = C> + Premultiply,
246 C::Scalar: $op_trait<Output = C::Scalar>,
247 {
248 type Output = PreAlpha<C>;
249
250 fn $op_trait_fn(self, other: PreAlpha<C>) -> Self::Output {
251 PreAlpha {
252 color: self.color.$op_trait_fn(other.color),
253 alpha: self.alpha.$op_trait_fn(other.alpha),
254 }
255 }
256 }
257
258 impl<C> $op_assign_trait for PreAlpha<C>
259 where
260 C: $op_assign_trait + Premultiply,
261 C::Scalar: $op_assign_trait + Real,
262 {
263 fn $op_assign_trait_fn(&mut self, other: PreAlpha<C>) {
264 self.color.$op_assign_trait_fn(other.color);
265 self.alpha.$op_assign_trait_fn(other.alpha);
266 }
267 }
268 };
269}
270
271impl_binop!(Add::add, AddAssign::add_assign);
272impl_binop!(Sub::sub, SubAssign::sub_assign);
273impl_binop!(Mul::mul, MulAssign::mul_assign);
274impl_binop!(Div::div, DivAssign::div_assign);
275
276macro_rules! impl_scalar_binop {
277 (
278 $op_trait:ident::$op_trait_fn:ident,
279 $op_assign_trait:ident::$op_assign_trait_fn:ident,
280 [$($ty:ident),+]
281 ) => {
282 $(
283 impl<C> $op_trait<$ty> for PreAlpha<C>
284 where
285 C: $op_trait<$ty, Output = C> + Premultiply<Scalar = $ty>,
286 {
287 type Output = PreAlpha<C>;
288
289 fn $op_trait_fn(self, c: $ty) -> Self::Output {
290 PreAlpha {
291 color: self.color.$op_trait_fn(c),
292 alpha: self.alpha.$op_trait_fn(c),
293 }
294 }
295 }
296
297 impl<C> $op_assign_trait<$ty> for PreAlpha<C>
315 where
316 C: $op_assign_trait<$ty> + Premultiply<Scalar = $ty>,
317 {
318 fn $op_assign_trait_fn(&mut self, c: $ty) {
319 self.color.$op_assign_trait_fn(c);
320 self.alpha.$op_assign_trait_fn(c);
321 }
322 }
323 )+
324 };
325}
326
327impl_scalar_binop!(Add::add, AddAssign::add_assign, [f32, f64]);
328impl_scalar_binop!(Sub::sub, SubAssign::sub_assign, [f32, f64]);
329impl_scalar_binop!(Mul::mul, MulAssign::mul_assign, [f32, f64]);
330impl_scalar_binop!(Div::div, DivAssign::div_assign, [f32, f64]);
331
332impl_array_casts!([C: Premultiply, const N: usize] PreAlpha<C>, [C::Scalar; N], where PreAlpha<C>: ArrayCast<Array = [C::Scalar; N]>);
333
334impl<C: Premultiply> Deref for PreAlpha<C> {
335 type Target = C;
336
337 fn deref(&self) -> &C {
338 &self.color
339 }
340}
341
342impl<C: Premultiply> DerefMut for PreAlpha<C> {
343 fn deref_mut(&mut self) -> &mut C {
344 &mut self.color
345 }
346}
347
348#[cfg(feature = "serializing")]
349impl<C> serde::Serialize for PreAlpha<C>
350where
351 C: Premultiply + serde::Serialize,
352 C::Scalar: serde::Serialize,
353{
354 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
355 where
356 S: serde::Serializer,
357 {
358 self.color.serialize(crate::serde::AlphaSerializer {
359 inner: serializer,
360 alpha: &self.alpha,
361 })
362 }
363}
364
365#[cfg(feature = "serializing")]
366impl<'de, C> serde::Deserialize<'de> for PreAlpha<C>
367where
368 C: Premultiply + serde::Deserialize<'de>,
369 C::Scalar: serde::Deserialize<'de>,
370{
371 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
372 where
373 D: serde::Deserializer<'de>,
374 {
375 let mut alpha: Option<C::Scalar> = None;
376
377 let color = C::deserialize(crate::serde::AlphaDeserializer {
378 inner: deserializer,
379 alpha: &mut alpha,
380 })?;
381
382 if let Some(alpha) = alpha {
383 Ok(Self { color, alpha })
384 } else {
385 Err(serde::de::Error::missing_field("alpha"))
386 }
387 }
388}
389
390#[cfg(feature = "bytemuck")]
391unsafe impl<C> bytemuck::Zeroable for PreAlpha<C>
392where
393 C: bytemuck::Zeroable + Premultiply,
394 C::Scalar: bytemuck::Zeroable,
395{
396}
397
398#[cfg(feature = "bytemuck")]
402unsafe impl<C> bytemuck::Pod for PreAlpha<C>
403where
404 C: bytemuck::Pod + ArrayCast + Premultiply,
405 C::Scalar: bytemuck::Pod,
406{
407}
408
409#[cfg(test)]
410#[cfg(feature = "serializing")]
411mod test {
412 use super::PreAlpha;
413 use crate::LinSrgb;
414
415 #[cfg(feature = "serializing")]
416 #[test]
417 fn serialize() {
418 let color = PreAlpha {
419 color: LinSrgb::new(0.3, 0.8, 0.1),
420 alpha: 0.5,
421 };
422
423 assert_eq!(
424 serde_json::to_string(&color).unwrap(),
425 r#"{"red":0.3,"green":0.8,"blue":0.1,"alpha":0.5}"#
426 );
427
428 assert_eq!(
429 ron::to_string(&color).unwrap(),
430 r#"(red:0.3,green:0.8,blue:0.1,alpha:0.5)"#
431 );
432 }
433
434 #[cfg(feature = "serializing")]
435 #[test]
436 fn deserialize() {
437 let color = PreAlpha {
438 color: LinSrgb::new(0.3, 0.8, 0.1),
439 alpha: 0.5,
440 };
441
442 assert_eq!(
443 serde_json::from_str::<PreAlpha<LinSrgb>>(
444 r#"{"alpha":0.5,"red":0.3,"green":0.8,"blue":0.1}"#
445 )
446 .unwrap(),
447 color
448 );
449
450 assert_eq!(
451 ron::from_str::<PreAlpha<LinSrgb>>(r#"(alpha:0.5,red:0.3,green:0.8,blue:0.1)"#)
452 .unwrap(),
453 color
454 );
455
456 assert_eq!(
457 ron::from_str::<PreAlpha<LinSrgb>>(r#"Rgb(alpha:0.5,red:0.3,green:0.8,blue:0.1)"#)
458 .unwrap(),
459 color
460 );
461 }
462}