use crate::error::SpirvCrossError;
use crate::{error, Compiler, PhantomCompiler};
use spirv_cross_sys::spvc_compiler_s;
use std::fmt::{Debug, Formatter};
use std::ptr::NonNull;
use crate::sealed::Sealed;
pub use spirv_cross_sys::ConstantId;
pub use spirv_cross_sys::TypeId;
pub use spirv_cross_sys::VariableId;
#[derive(Copy, Clone)]
#[repr(transparent)]
struct PointerOnlyForComparison<T>(NonNull<T>);
unsafe impl<T> Send for PointerOnlyForComparison<T> {}
unsafe impl<T> Sync for PointerOnlyForComparison<T> {}
impl<T> PartialEq for PointerOnlyForComparison<T> {
fn eq(&self, other: &Self) -> bool {
other.0.as_ptr() == self.0.as_ptr()
}
}
impl<T> Eq for PointerOnlyForComparison<T> {}
impl<T> Debug for PointerOnlyForComparison<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"Tag({:x})",
(((self.0.as_ptr() as usize) << 16) >> 18) as u32
)
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct Handle<T> {
id: T,
tag: PointerOnlyForComparison<spvc_compiler_s>,
}
impl<T: Id> Handle<T> {
pub fn id(&self) -> u32 {
self.id.id()
}
}
pub trait Id: Sealed + Debug + Send + Sync + 'static {
fn id(&self) -> u32;
}
impl Sealed for TypeId {}
impl Id for TypeId {
#[inline(always)]
fn id(&self) -> u32 {
self.0 .0
}
}
impl Sealed for VariableId {}
impl Id for VariableId {
#[inline(always)]
fn id(&self) -> u32 {
self.0 .0
}
}
impl Sealed for ConstantId {}
impl Id for ConstantId {
#[inline(always)]
fn id(&self) -> u32 {
self.0 .0
}
}
impl<T: Id> Handle<T> {
#[cold]
fn erase_type(self) -> Handle<Box<dyn Id>> {
Handle {
id: Box::new(self.id) as Box<dyn Id>,
tag: self.tag,
}
}
}
impl<T> Compiler<T> {
#[inline(always)]
pub unsafe fn create_handle<I>(&self, id: I) -> Handle<I> {
Handle {
id,
tag: PointerOnlyForComparison(self.ptr),
}
}
#[inline(always)]
pub unsafe fn create_handle_if_not_zero<I: Id>(&self, id: I) -> Option<Handle<I>> {
let raw = id.id();
if raw == 0 {
return None;
}
Some(Handle {
id,
tag: PointerOnlyForComparison(self.ptr),
})
}
pub fn handle_is_valid<I>(&self, handle: &Handle<I>) -> bool {
handle.tag == PointerOnlyForComparison(self.ptr)
}
pub fn yield_id<I: Id>(&self, handle: Handle<I>) -> error::Result<I> {
if self.handle_is_valid(&handle) {
Ok(handle.id)
} else {
Err(SpirvCrossError::InvalidHandle(handle.erase_type()))
}
}
}
impl PhantomCompiler {
#[inline(always)]
pub(crate) fn create_handle<I>(&self, id: I) -> Handle<I> {
Handle {
id,
tag: PointerOnlyForComparison(self.ptr),
}
}
}