use core::marker::PhantomData;
use crate::encoding::{Encoded, Encoding, Linear};
use crate::fixed::Q0_16;
use crate::space::{ColorSpace, Perceptual};
#[cfg(feature = "f32")]
pub use crate::color_f32::ColorF32;
pub struct Color<S: ColorSpace, E: Encoding> {
pub ch: [Q0_16; 3],
_pd: PhantomData<fn() -> (S, E)>,
}
impl<S: ColorSpace, E: Encoding> Copy for Color<S, E> {}
impl<S: ColorSpace, E: Encoding> Clone for Color<S, E> {
fn clone(&self) -> Self {
*self
}
}
impl<S: ColorSpace, E: Encoding> PartialEq for Color<S, E> {
fn eq(&self, other: &Self) -> bool {
self.ch == other.ch
}
}
impl<S: ColorSpace, E: Encoding> Eq for Color<S, E> {}
impl<S: ColorSpace, E: Encoding> core::fmt::Debug for Color<S, E> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Color").field("ch", &self.ch).finish()
}
}
impl<S: ColorSpace, E: Encoding> Color<S, E> {
#[must_use]
pub const fn new(ch: [Q0_16; 3]) -> Self {
Self {
ch,
_pd: PhantomData,
}
}
#[cfg(feature = "f32")]
#[must_use]
pub const fn to_f32(self) -> crate::ColorF32<S, E> {
let [c0, c1, c2] = self.ch;
crate::ColorF32::new([c0.to_f32(), c1.to_f32(), c2.to_f32()])
}
}
impl<S: ColorSpace> Color<S, Linear> {
#[must_use]
pub const fn encode(self) -> Color<S, Encoded> {
Color::new(self.ch)
}
#[must_use]
pub const fn lerp(self, other: Self, t: Q0_16) -> Self {
let [a0, a1, a2] = self.ch;
let [b0, b1, b2] = other.ch;
Color::new([
crate::arith::lerp_q0_16(a0, b0, t),
crate::arith::lerp_q0_16(a1, b1, t),
crate::arith::lerp_q0_16(a2, b2, t),
])
}
}
impl<S: ColorSpace> Color<S, Encoded> {
#[must_use]
pub const fn decode(self) -> Color<S, Linear> {
Color::new(self.ch)
}
}
impl<S: ColorSpace + Perceptual> Color<S, Encoded> {
#[must_use]
pub const fn lerp(self, other: Self, t: Q0_16) -> Self {
let [a0, a1, a2] = self.ch;
let [b0, b1, b2] = other.ch;
Color::new([
crate::arith::lerp_q0_16(a0, b0, t),
crate::arith::lerp_q0_16(a1, b1, t),
crate::arith::lerp_q0_16(a2, b2, t),
])
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::space::Srgb;
#[test]
fn constructs_linear_and_encoded_srgb() {
let lin = Color::<Srgb, Linear>::new(Q0_16::array_from_raw([1, 2, 3]));
let enc = Color::<Srgb, Encoded>::new(Q0_16::array_from_raw([4, 5, 6]));
assert_eq!(lin.ch, Q0_16::array_from_raw([1, 2, 3]));
assert_eq!(enc.ch, Q0_16::array_from_raw([4, 5, 6]));
let _ = lin.encode();
let _ = enc.decode();
}
fn assert_send_sync<T: Send + Sync>() {}
#[test]
fn color_matrix_gain_are_send_sync() {
assert_send_sync::<Color<Srgb, Linear>>();
assert_send_sync::<Color<Srgb, Encoded>>();
assert_send_sync::<crate::matrix::Matrix3<Srgb, Srgb>>();
assert_send_sync::<crate::gain::Gain<Srgb>>();
}
}