use core::fmt::Debug;
use core::marker::PhantomData;
use core::ops::Deref;
use derive_where::derive_where;
use sealed::sealed;
#[sealed(pub(crate))]
pub trait Signature: Default + Debug {
const NAME: &'static str;
type Params: ArrayU32;
type Result;
fn descriptor() -> Descriptor {
Descriptor { name: Self::NAME, params: Self::Params::LENGTH }
}
}
#[derive(Debug, Copy, Clone)]
pub struct Descriptor {
pub name: &'static str,
pub params: usize,
}
#[derive_where(Debug, Copy, Clone)]
#[derive(bytemuck::Zeroable)]
#[zeroable(bound = "")]
#[repr(transparent)]
pub struct U32<T> {
value: u32,
phantom: PhantomData<T>,
}
unsafe impl<T: 'static> bytemuck::Pod for U32<T> {}
unsafe impl<T> Send for U32<T> {}
impl<T> Default for U32<T> {
fn default() -> Self {
U32 { value: 0, phantom: PhantomData }
}
}
impl<T> Deref for U32<T> {
type Target = u32;
fn deref(&self) -> &Self::Target {
&self.value
}
}
impl<T> From<u32> for U32<T> {
fn from(value: u32) -> Self {
U32 { value, phantom: PhantomData }
}
}
impl From<bool> for U32<bool> {
fn from(x: bool) -> Self {
(x as u32).into()
}
}
impl From<()> for U32<()> {
fn from(_: ()) -> Self {
0u32.into()
}
}
impl From<!> for U32<!> {
fn from(x: !) -> Self {
match x {}
}
}
#[sealed(pub(crate))]
pub trait ArrayU32: bytemuck::Pod {
const LENGTH: usize = core::mem::size_of::<Self>() / core::mem::size_of::<u32>();
fn from(values: &[u32]) -> &Self {
bytemuck::from_bytes(bytemuck::cast_slice(values))
}
fn into(&self) -> &[u32] {
bytemuck::cast_slice(bytemuck::bytes_of(self))
}
}
pub trait Dispatch {
type Erased: Debug;
type Merged<T: Signature>: Debug;
fn merge<T: Signature>(erased: Self::Erased) -> Self::Merged<T>;
fn erase<T: Signature>(merged: Self::Merged<T>) -> Self::Erased;
}
#[derive(Debug, Copy, Clone)]
pub struct Id;
impl Dispatch for Id {
type Erased = ();
type Merged<T: Signature> = T;
fn merge<T: Signature>((): Self::Erased) -> Self::Merged<T> {
Default::default()
}
fn erase<T: Signature>(_: Self::Merged<T>) -> Self::Erased {}
}