use core::marker::PhantomData;
use crate::cast::UintCast;
use super::ArrayCast;
#[derive(Debug, PartialEq, Eq)]
#[repr(transparent)]
pub struct Packed<O, P> {
pub color: P,
pub channel_order: PhantomData<O>,
}
impl<O, P> Packed<O, P> {
#[inline]
pub fn pack<C>(color: C) -> Self
where
O: ComponentOrder<C, P>,
{
Packed {
color: O::pack(color),
channel_order: PhantomData,
}
}
#[inline]
pub fn unpack<C>(self) -> C
where
O: ComponentOrder<C, P>,
{
O::unpack(self.color)
}
}
impl<O, P> Copy for Packed<O, P> where P: Copy {}
impl<O, P> Clone for Packed<O, P>
where
P: Clone,
{
#[inline]
fn clone(&self) -> Self {
Self {
color: self.color.clone(),
channel_order: PhantomData,
}
}
}
unsafe impl<O, T, const N: usize> ArrayCast for Packed<O, [T; N]> {
type Array = [T; N];
}
unsafe impl<O> UintCast for Packed<O, u8> {
type Uint = u8;
}
unsafe impl<O> UintCast for Packed<O, u16> {
type Uint = u16;
}
unsafe impl<O> UintCast for Packed<O, u32> {
type Uint = u32;
}
unsafe impl<O> UintCast for Packed<O, u64> {
type Uint = u64;
}
unsafe impl<O> UintCast for Packed<O, u128> {
type Uint = u128;
}
impl_array_casts!([O, T, const N: usize] Packed<O, [T; N]>, [T; N]);
impl_uint_casts_self!(Packed<O, P>, P, where Packed<O, P>: UintCast<Uint = P>);
impl_uint_casts_other!([O] Packed<O, u8>, u8);
impl_uint_casts_other!([O] Packed<O, u16>, u16);
impl_uint_casts_other!([O] Packed<O, u32>, u32);
impl_uint_casts_other!([O] Packed<O, u64>, u64);
impl_uint_casts_other!([O] Packed<O, u128>, u128);
#[cfg(feature = "bytemuck")]
unsafe impl<O, P> bytemuck::Zeroable for Packed<O, P> where P: bytemuck::Zeroable {}
#[cfg(feature = "bytemuck")]
unsafe impl<O: 'static, P> bytemuck::Pod for Packed<O, P> where P: bytemuck::Pod {}
pub trait ComponentOrder<C, P> {
fn pack(color: C) -> P;
fn unpack(packed: P) -> C;
}
impl<C, T> ComponentOrder<C, u8> for T
where
T: ComponentOrder<C, [u8; 1]>,
{
#[inline]
fn pack(color: C) -> u8 {
let [packed] = T::pack(color);
packed
}
#[inline]
fn unpack(packed: u8) -> C {
T::unpack([packed])
}
}
impl<C, T> ComponentOrder<C, u16> for T
where
T: ComponentOrder<C, [u8; 2]>,
{
#[inline]
fn pack(color: C) -> u16 {
u16::from_be_bytes(T::pack(color))
}
#[inline]
fn unpack(packed: u16) -> C {
T::unpack(packed.to_be_bytes())
}
}
impl<C, T> ComponentOrder<C, u32> for T
where
T: ComponentOrder<C, [u8; 4]>,
{
#[inline]
fn pack(color: C) -> u32 {
u32::from_be_bytes(T::pack(color))
}
#[inline]
fn unpack(packed: u32) -> C {
T::unpack(packed.to_be_bytes())
}
}
impl<C, T> ComponentOrder<C, u64> for T
where
T: ComponentOrder<C, [u8; 8]>,
{
#[inline]
fn pack(color: C) -> u64 {
u64::from_be_bytes(T::pack(color))
}
#[inline]
fn unpack(packed: u64) -> C {
T::unpack(packed.to_be_bytes())
}
}
impl<C, T> ComponentOrder<C, u128> for T
where
T: ComponentOrder<C, [u8; 16]>,
{
#[inline]
fn pack(color: C) -> u128 {
u128::from_be_bytes(T::pack(color))
}
#[inline]
fn unpack(packed: u128) -> C {
T::unpack(packed.to_be_bytes())
}
}