use crate::{BalancedColour, Colour, Component, DefinedGamut};
use crate::rgb::Rgb;
#[cfg(feature = "bytemuck")]
use bytemuck::{Pod, Zeroable};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "zerocopy")]
use zerocopy::{FromZeros, Immutable, IntoBytes};
#[repr(transparent)]
#[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "bytemuck", derive(Pod, Zeroable))]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[cfg_attr(feature = "zerocopy", derive(FromZeros, Immutable, IntoBytes))]
pub struct SRgb<T>(Rgb<T>);
impl<T: Component> SRgb<T> {
#[inline(always)]
#[must_use]
pub const fn new(red: T, green: T, blue: T) -> Self {
let colour = Rgb::new(red, green, blue);
Self(colour)
}
#[inline(always)]
#[must_use]
pub const fn from_rgb(colour: Rgb<T>) -> Self {
Self(colour)
}
#[inline]
#[must_use]
pub fn map<U, F>(self, mut op: F) -> SRgb<U>
where
U: Component,
F: FnMut(T) -> U,
{
let (red, green, blue) = self.get();
let red = op(red);
let green = op(green);
let blue = op(blue);
SRgb::new(red, green, blue)
}
#[inline(always)]
#[must_use]
pub const fn as_rgb(self) -> Rgb<T> {
self.0
}
#[inline(always)]
#[must_use]
pub const fn get(self) -> (T, T, T) {
self.as_rgb().get()
}
}
macro_rules! impl_conversions {
($($tys:ty),+$(,)?) => {
$(
impl ::hikari::rgb::SRgb<$tys> {
#[cfg(feature = "std")]
#[inline]
#[must_use]
pub fn transfer(colour: Rgb<$tys>) -> Self {
let colour = colour.map(|mut colour| {
let sign = colour;
colour = colour.abs();
colour = if colour > 0.003_130_800 {
colour.powf(const { 1.0 / 2.4 }) * 1.055 - 0.055
} else {
colour * 12.920
};
colour = colour.copysign(sign);
colour
});
Self::from_rgb(colour)
}
#[cfg(feature = "std")]
#[inline]
#[must_use]
pub fn untransfer(self) -> Rgb<$tys> {
self.as_rgb().map(|mut colour| {
let sign = colour;
colour = colour.abs();
colour = if colour > 0.040_450 {
((colour + 0.055) / 1.055).powf(2.4)
} else {
colour / 12.920
};
colour = colour.copysign(sign);
colour
})
}
}
)*
};
}
#[cfg(feature = "f16")]
impl_conversions!(f16);
impl_conversions!(f32, f64);
#[cfg(feature = "f128")]
impl_conversions!(f128);
unsafe impl<T: Component> BalancedColour for SRgb<T> {
type Component = T;
}
impl<T: Component> Colour for SRgb<T> { }
impl<T: Component> DefinedGamut for SRgb<T> { }