#![no_std]
#![allow(unsafe_code)]
#[cfg(feature = "bytemuck")]
use bytemuck::{Pod, Zeroable};
pub trait ColorType {
type ComponentTy: Copy;
const SPACE: Spaces;
const NUM_COMPONENTS: usize;
}
pub trait ColorInterop
where
Self: Into<<Self as ColorInterop>::CintTy>,
{
type CintTy: Into<Self>;
fn from_cint(col: Self::CintTy) -> Self {
col.into()
}
fn into_cint(self) -> Self::CintTy {
self.into()
}
}
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
#[repr(C)]
pub struct Alpha<ColorTy: ColorType> {
pub color: ColorTy,
pub alpha: ColorTy::ComponentTy,
}
impl<BaseColorTy: ColorType> ColorType for Alpha<BaseColorTy> {
type ComponentTy = BaseColorTy::ComponentTy;
const SPACE: Spaces = BaseColorTy::SPACE;
const NUM_COMPONENTS: usize = BaseColorTy::NUM_COMPONENTS + 1;
}
#[cfg(feature = "bytemuck")]
unsafe impl<ColorTy: ColorType + Zeroable> Zeroable for Alpha<ColorTy> {}
#[cfg(feature = "bytemuck")]
unsafe impl<ColorTy: ColorType + Pod> Pod for Alpha<ColorTy> {}
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
pub struct PremultipliedAlpha<ColorTy: ColorType> {
pub color: ColorTy,
pub alpha: ColorTy::ComponentTy,
}
impl<BaseColorTy: ColorType> ColorType for PremultipliedAlpha<BaseColorTy> {
type ComponentTy = BaseColorTy::ComponentTy;
const SPACE: Spaces = BaseColorTy::SPACE;
const NUM_COMPONENTS: usize = BaseColorTy::NUM_COMPONENTS + 1;
}
#[cfg(feature = "bytemuck")]
unsafe impl<ColorTy: ColorType + Zeroable> Zeroable for PremultipliedAlpha<ColorTy> {}
#[cfg(feature = "bytemuck")]
unsafe impl<ColorTy: ColorType + Pod> Pod for PremultipliedAlpha<ColorTy> {}
macro_rules! color_struct {
{
$(#[$doc:meta])*
$name:ident<$default_component_ty:ty, $num_components:literal> {
$($(#[$compdoc:meta])+
$compname:ident,)+
}
} => {
$(#[$doc])*
#[repr(C)]
#[derive(Clone, Copy, Debug, Hash, PartialEq, PartialOrd, Eq, Ord)]
pub struct $name<ComponentTy=$default_component_ty> {
$($(#[$compdoc])+
pub $compname: ComponentTy,)+
}
impl<CTy: Clone + Copy> ColorType for $name<CTy> {
type ComponentTy = CTy;
const SPACE: Spaces = Spaces::$name;
const NUM_COMPONENTS: usize = $num_components;
}
#[cfg(feature = "bytemuck")]
unsafe impl<ComponentTy: Zeroable> Zeroable for $name<ComponentTy> {}
#[cfg(feature = "bytemuck")]
unsafe impl<ComponentTy: Pod> Pod for $name<ComponentTy> {}
impl<ComponentTy> From<[ComponentTy; $num_components]> for $name<ComponentTy> {
fn from([$($compname),+]: [ComponentTy; $num_components]) -> $name<ComponentTy> {
$name {
$($compname,)+
}
}
}
#[allow(clippy::from_over_into)]
impl<ComponentTy> Into<[ComponentTy; $num_components]> for $name<ComponentTy> {
fn into(self) -> [ComponentTy; $num_components] {
let $name {
$($compname,)+
} = self;
[$($compname),+]
}
}
impl<ComponentTy> AsRef<[ComponentTy; $num_components]> for $name<ComponentTy> {
fn as_ref(&self) -> &[ComponentTy; $num_components] {
unsafe { &*(self as *const $name<ComponentTy> as *const [ComponentTy; $num_components]) }
}
}
impl<ComponentTy> AsMut<[ComponentTy; $num_components]> for $name<ComponentTy> {
fn as_mut(&mut self) -> &mut [ComponentTy; $num_components] {
unsafe { &mut *(self as *mut $name<ComponentTy> as *mut [ComponentTy; $num_components]) }
}
}
macro_rules! impl_alpha_traits {
($alphaty:ident) => {
impl<ComponentTy: Copy> From<$alphaty<$name<ComponentTy>>> for $name<ComponentTy> {
fn from(col_alpha: $alphaty<$name<ComponentTy>>) -> $name<ComponentTy> {
col_alpha.color
}
}
impl<ComponentTy: Copy> From<[ComponentTy; $num_components + 1]> for $alphaty<$name<ComponentTy>> {
fn from([$($compname,)+ alpha]: [ComponentTy; $num_components + 1]) -> $alphaty<$name<ComponentTy>> {
$alphaty {
color: $name::from([$($compname,)+]),
alpha,
}
}
}
#[allow(clippy::from_over_into)]
impl<ComponentTy: Copy> Into<[ComponentTy; $num_components + 1]> for $alphaty<$name<ComponentTy>> {
fn into(self) -> [ComponentTy; $num_components + 1] {
let $alphaty {
color,
alpha
} = self;
let $name {
$($compname,)+
} = color;
[$($compname,)+ alpha]
}
}
impl<ComponentTy: Copy> AsRef<[ComponentTy; $num_components + 1]> for $alphaty<$name<ComponentTy>> {
fn as_ref(&self) -> &[ComponentTy; $num_components + 1] {
unsafe { &*(self as *const $alphaty<$name<ComponentTy>> as *const [ComponentTy; $num_components + 1]) }
}
}
impl<ComponentTy: Copy> AsMut<[ComponentTy; $num_components + 1]> for $alphaty<$name<ComponentTy>> {
fn as_mut(&mut self) -> &mut [ComponentTy; $num_components + 1] {
unsafe { &mut *(self as *mut $alphaty<$name<ComponentTy>> as *mut [ComponentTy; $num_components + 1]) }
}
}
}
}
impl_alpha_traits!(Alpha);
impl_alpha_traits!(PremultipliedAlpha);
};
}
macro_rules! color_spaces {
{
$($(#[$space_doc:meta])*
$space_name:ident<$default_component_ty:ty, $num_components:literal> {
$($(#[$comp_doc:meta])+
$comp_name:ident,)+
})*
} => {
#[repr(u32)]
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
pub enum Spaces {
$(
$(#[$space_doc])*
$space_name,
)*
}
impl Spaces {
pub fn num_components(&self) -> usize {
match *self {
$(
Self::$space_name => $num_components,
)*
}
}
}
$(
color_struct! {
$(#[$space_doc])*
$space_name<$default_component_ty, $num_components> {
$( $(#[$comp_doc])+
$comp_name,)+
}
}
)*
}
}
color_spaces! {
EncodedSrgb<u8, 3> {
r,
g,
b,
}
LinearSrgb<f32, 3> {
r,
g,
b,
}
EncodedRec709<u8, 3> {
r,
g,
b,
}
Rec709<f32, 3> {
r,
g,
b,
}
GenericColor3<f32, 3> {
x,
y,
z,
}
GenericColor1<f32, 1> {
x,
}
Luminance<f32, 1> {
l,
}
Luma<f32, 1> {
l,
}
AcesCg<f32, 3> {
r,
g,
b,
}
Aces2065<f32, 3> {
r,
g,
b,
}
AcesCc<f32, 3> {
r,
g,
b,
}
AcesCct<f32, 3> {
r,
g,
b,
}
DisplayP3<f32, 3> {
r,
g,
b,
}
EncodedDisplayP3<u8, 3> {
r,
g,
b,
}
DciP3<f32, 3> {
r,
g,
b,
}
DciXYZPrime<f32, 3> {
x,
y,
z,
}
Bt2020<f32, 3> {
r,
g,
b,
}
EncodedBt2020<f32, 3> {
r,
g,
b,
}
Bt2100<f32, 3> {
r,
g,
b,
}
EncodedBt2100PQ<f32, 3> {
r,
g,
b,
}
EncodedBt2100HLG<f32, 3> {
r,
g,
b,
}
ICtCpPQ<f32, 3> {
i,
ct,
cp,
}
ICtCpHLG<f32, 3> {
i,
ct,
cp,
}
CieXYZ<f32, 3> {
x,
y,
z,
}
CieLab<f32, 3> {
l,
a,
b,
}
CieLCh<f32, 3> {
l,
c,
h,
}
Oklab<f32, 3> {
l,
a,
b,
}
Oklch<f32, 3> {
l,
c,
h,
}
Hsl<f32, 3> {
h,
s,
l,
}
Hsv<f32, 3> {
h,
s,
v,
}
YCbCr<u8, 3> {
y,
cb,
cr,
}
YPrimeCbCr<u8, 3> {
y,
cb,
cr,
}
YPbPr<f32, 3> {
y,
pb,
pr,
}
YPrimePbPr<f32, 3> {
y,
pb,
pr,
}
Yuv<f32, 3> {
y,
u,
v,
}
YCxCz<f32, 3> {
y,
cx,
cz,
}
}