colr 0.3.1

A general purpose, extensible color type unifying color models and their operations at the type level.
Documentation
//! Channel-wise multiplication of two colors in the same color space.

use core::ops::{Mul, MulAssign};

use crate::BackingStore;
use crate::ChannelMap;
use crate::Color;
use crate::illuminant::Illuminant;
use crate::model::{Lab, Oklab, Rgb, Spectral, SpectralKind, WavelengthGrid};
use crate::primaries::Primaries;
use crate::transfer::Linear;

// Scalar multiply: scale color channels by a float. Alpha passes through.

macro_rules! impl_scalar_mul_perceptual {
    ($name:ident, $bound:tt) => {
        impl<$bound> Mul<f32> for Color<[f32; 3], $name<$bound>>
        where
            $bound: Illuminant,
        {
            type Output = Self;
            #[inline(always)]
            fn mul(self, s: f32) -> Self {
                Color::new(self.inner().map(|v| v * s))
            }
        }
        impl<$bound, const O: usize> Mul<f32> for Color<[f32; 4], $name<$bound, O>>
        where
            $bound: Illuminant,
        {
            type Output = Self;
            #[inline(always)]
            fn mul(self, s: f32) -> Self {
                let ch = self.inner();
                let mut out = ch;
                out[O] = ch[O] * s;
                out[O + 1] = ch[O + 1] * s;
                out[O + 2] = ch[O + 2] * s;
                Color::new(out)
            }
        }
    };
    ($name:ident) => {
        impl Mul<f32> for Color<[f32; 3], $name> {
            type Output = Self;
            #[inline(always)]
            fn mul(self, s: f32) -> Self {
                Color::new(self.inner().map(|v| v * s))
            }
        }
        impl<const O: usize> Mul<f32> for Color<[f32; 4], $name<O>> {
            type Output = Self;
            #[inline(always)]
            fn mul(self, s: f32) -> Self {
                let ch = self.inner();
                let mut out = ch;
                out[O] = ch[O] * s;
                out[O + 1] = ch[O + 1] * s;
                out[O + 2] = ch[O + 2] * s;
                Color::new(out)
            }
        }
    };
}

impl_scalar_mul_perceptual!(Lab, W);
impl_scalar_mul_perceptual!(Oklab);

impl<P, L> Mul<f32> for Color<[f32; 3], Rgb<P, Linear, L>>
where
    P: Primaries,
    L: BackingStore<[f32; 3]>,
{
    type Output = Self;
    #[inline(always)]
    fn mul(self, s: f32) -> Self {
        Color::new(self.inner().map(|v| v * s))
    }
}

impl<P, L> Mul<f32> for Color<[f32; 4], Rgb<P, Linear, L>>
where
    P: Primaries,
    L: BackingStore<[f32; 4]> + ChannelMap<4>,
{
    type Output = Self;
    /// Scales color channels. Alpha passes through.
    #[inline(always)]
    fn mul(self, s: f32) -> Self {
        let ch = self.inner();
        let [ri, gi, bi, _] = L::INDICES;
        let mut out = ch;
        out[ri] = ch[ri] * s;
        out[gi] = ch[gi] * s;
        out[bi] = ch[bi] * s;
        Color::new(out)
    }
}

impl<P, L> Mul for Color<[f32; 3], Rgb<P, Linear, L>>
where
    P: Primaries,
    L: BackingStore<[f32; 3]>,
{
    type Output = Self;
    #[inline(always)]
    fn mul(self, rhs: Self) -> Self {
        let [a0, a1, a2] = self.inner();
        let [b0, b1, b2] = rhs.inner();
        Color::new([a0 * b0, a1 * b1, a2 * b2])
    }
}

impl<const BANDS: usize, G, K> Mul for Color<[f32; BANDS], Spectral<BANDS, G, K>>
where
    G: WavelengthGrid<BANDS>,
    K: SpectralKind,
    Spectral<BANDS, G, K>: BackingStore<[f32; BANDS]>,
{
    type Output = Self;
    #[inline(always)]
    fn mul(self, rhs: Self) -> Self {
        let a = self.inner();
        let b = rhs.inner();
        let mut out = a;
        for i in 0..BANDS {
            out[i] = a[i] * b[i];
        }
        Color::new(out)
    }
}

impl<const BANDS: usize, G, K> Mul<f32> for Color<[f32; BANDS], Spectral<BANDS, G, K>>
where
    G: WavelengthGrid<BANDS>,
    K: SpectralKind,
    Spectral<BANDS, G, K>: BackingStore<[f32; BANDS]>,
{
    type Output = Self;
    #[inline(always)]
    fn mul(self, s: f32) -> Self {
        let mut out = self.inner();
        for v in &mut out {
            *v *= s;
        }

        Color::new(out)
    }
}

impl<P, L> Mul for Color<[f32; 4], Rgb<P, Linear, L>>
where
    P: Primaries,
    L: BackingStore<[f32; 4]> + ChannelMap<4>,
{
    type Output = Self;
    /// Multiplies color channels. Alpha passes through from `self`.
    #[inline(always)]
    fn mul(self, rhs: Self) -> Self {
        let s = self.inner();
        let r = rhs.inner();
        let [ri, gi, bi, _] = L::INDICES;
        let mut out = s;
        out[ri] = s[ri] * r[ri];
        out[gi] = s[gi] * r[gi];
        out[bi] = s[bi] * r[bi];
        Color::new(out)
    }
}

impl<const BANDS: usize, G, K> MulAssign<f32> for Color<[f32; BANDS], Spectral<BANDS, G, K>>
where
    G: WavelengthGrid<BANDS>,
    K: SpectralKind,
    Spectral<BANDS, G, K>: BackingStore<[f32; BANDS]>,
{
    #[inline(always)]
    fn mul_assign(&mut self, s: f32) {
        let mut out = self.inner();
        for v in &mut out {
            *v *= s;
        }

        *self = Color::new(out);
    }
}

impl<P, L> MulAssign<f32> for Color<[f32; 3], Rgb<P, Linear, L>>
where
    P: Primaries,
    L: BackingStore<[f32; 3]>,
{
    #[inline(always)]
    fn mul_assign(&mut self, s: f32) {
        let [a0, a1, a2] = self.inner();
        *self = Color::new([a0 * s, a1 * s, a2 * s]);
    }
}