gfx_hal/pso/
specialization.rsuse std::{borrow::Cow, ops::Range, slice};
#[derive(Debug, Clone, Hash, PartialEq)]
pub struct SpecializationConstant {
pub id: u32,
pub range: Range<u16>,
}
#[derive(Debug, Clone)]
pub struct Specialization<'a> {
pub constants: Cow<'a, [SpecializationConstant]>,
pub data: Cow<'a, [u8]>,
}
impl Specialization<'_> {
pub const EMPTY: Self = Specialization {
constants: Cow::Borrowed(&[]),
data: Cow::Borrowed(&[]),
};
}
impl Default for Specialization<'_> {
fn default() -> Self {
Specialization::EMPTY
}
}
#[doc(hidden)]
#[derive(Debug, Default)]
pub struct SpecializationStorage {
constants: Vec<SpecializationConstant>,
data: Vec<u8>,
}
#[doc(hidden)]
pub trait SpecConstList: Sized {
fn fold(self, storage: &mut SpecializationStorage);
}
impl<T> From<T> for Specialization<'_>
where
T: SpecConstList,
{
fn from(list: T) -> Self {
let mut storage = SpecializationStorage::default();
list.fold(&mut storage);
Specialization {
data: Cow::Owned(storage.data),
constants: Cow::Owned(storage.constants),
}
}
}
#[doc(hidden)]
#[derive(Debug)]
pub struct SpecConstListNil;
#[doc(hidden)]
#[derive(Debug)]
pub struct SpecConstListCons<H, T> {
pub head: (u32, H),
pub tail: T,
}
impl SpecConstList for SpecConstListNil {
fn fold(self, _storage: &mut SpecializationStorage) {}
}
impl<H, T> SpecConstList for SpecConstListCons<H, T>
where
T: SpecConstList,
{
fn fold(self, storage: &mut SpecializationStorage) {
let size = std::mem::size_of::<H>();
assert!(storage.data.len() + size <= u16::MAX as usize);
let offset = storage.data.len() as u16;
storage.data.extend_from_slice(unsafe {
let head_ptr: *const H = &self.head.1;
slice::from_raw_parts(head_ptr as *const u8, size)
});
storage.constants.push(SpecializationConstant {
id: self.head.0,
range: offset..offset + size as u16,
});
self.tail.fold(storage)
}
}
#[macro_export]
macro_rules! spec_const_list {
(@ $(,)?) => {
$crate::pso::SpecConstListNil
};
(@ $head_id:expr => $head_constant:expr $(,$tail_id:expr => $tail_constant:expr)* $(,)?) => {
$crate::pso::SpecConstListCons {
head: ($head_id, $head_constant),
tail: $crate::spec_const_list!(@ $($tail_id => $tail_constant),*),
}
};
($($id:expr => $constant:expr),* $(,)?) => {
$crate::spec_const_list!(@ $($id => $constant),*).into()
};
($($constant:expr),* $(,)?) => {
{
let mut counter = 0;
$crate::spec_const_list!(@ $({ counter += 1; counter - 1 } => $constant),*).into()
}
};
}