1use crate::error::SpirvCrossError;
2use crate::{error, Compiler, PhantomCompiler};
3use spirv_cross_sys::spvc_compiler_s;
4use std::fmt::{Debug, Formatter};
5use std::ptr::NonNull;
6
7use crate::sealed::Sealed;
8
9pub use spirv_cross_sys::ConstantId;
11
12pub use spirv_cross_sys::TypeId;
14
15pub use spirv_cross_sys::VariableId;
17
18#[derive(Copy, Clone)]
19#[repr(transparent)]
20struct PointerOnlyForComparison<T>(NonNull<T>);
21
22unsafe impl<T> Send for PointerOnlyForComparison<T> {}
24unsafe impl<T> Sync for PointerOnlyForComparison<T> {}
25
26impl<T> PartialEq for PointerOnlyForComparison<T> {
27 fn eq(&self, other: &Self) -> bool {
28 other.0.as_ptr() == self.0.as_ptr()
29 }
30}
31
32impl<T> Eq for PointerOnlyForComparison<T> {}
33
34impl<T> Debug for PointerOnlyForComparison<T> {
35 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
36 write!(
41 f,
42 "Tag({:x})",
43 (((self.0.as_ptr() as usize) << 16) >> 18) as u32
44 )
45 }
46}
47
48#[derive(Debug, Copy, Clone, Eq, PartialEq)]
53pub struct Handle<T> {
54 id: T,
55 tag: PointerOnlyForComparison<spvc_compiler_s>,
56}
57
58impl<T: Id> Handle<T> {
59 pub fn id(&self) -> u32 {
65 self.id.id()
66 }
67}
68
69pub trait Id: Sealed + Debug + Send + Sync + 'static {
71 fn id(&self) -> u32;
73}
74
75impl Sealed for TypeId {}
76impl Id for TypeId {
77 #[inline(always)]
78 fn id(&self) -> u32 {
79 self.0 .0
80 }
81}
82
83impl Sealed for VariableId {}
84impl Id for VariableId {
85 #[inline(always)]
86 fn id(&self) -> u32 {
87 self.0 .0
88 }
89}
90
91impl Sealed for ConstantId {}
92impl Id for ConstantId {
93 #[inline(always)]
94 fn id(&self) -> u32 {
95 self.0 .0
96 }
97}
98
99impl<T: Id> Handle<T> {
100 #[cold]
103 fn erase_type(self) -> Handle<Box<dyn Id>> {
104 Handle {
105 id: Box::new(self.id) as Box<dyn Id>,
106 tag: self.tag,
107 }
108 }
109}
110
111impl<T> Compiler<T> {
113 #[inline(always)]
114 pub unsafe fn create_handle<I>(&self, id: I) -> Handle<I> {
119 Handle {
120 id,
121 tag: PointerOnlyForComparison(self.ptr),
122 }
123 }
124
125 #[inline(always)]
126 pub unsafe fn create_handle_if_not_zero<I: Id>(&self, id: I) -> Option<Handle<I>> {
132 let raw = id.id();
133 if raw == 0 {
134 return None;
135 }
136 Some(Handle {
137 id,
138 tag: PointerOnlyForComparison(self.ptr),
139 })
140 }
141
142 pub fn handle_is_valid<I>(&self, handle: &Handle<I>) -> bool {
144 handle.tag == PointerOnlyForComparison(self.ptr)
145 }
146
147 pub fn yield_id<I: Id>(&self, handle: Handle<I>) -> error::Result<I> {
150 if self.handle_is_valid(&handle) {
151 Ok(handle.id)
152 } else {
153 Err(SpirvCrossError::InvalidHandle(handle.erase_type()))
154 }
155 }
156}
157
158impl PhantomCompiler {
159 #[inline(always)]
168 pub(crate) fn create_handle<I>(&self, id: I) -> Handle<I> {
169 Handle {
170 id,
171 tag: PointerOnlyForComparison(self.ptr),
172 }
173 }
174}