1use crate::{Epoch, Index};
2use core::{
3 cmp::Ordering,
4 fmt::{self, Debug},
5 hash::Hash,
6 marker::PhantomData,
7 num::NonZeroU64,
8};
9use wgt::WasmNotSendSync;
10
11const _: () = {
12 if size_of::<Index>() != 4 {
13 panic!()
14 }
15};
16const _: () = {
17 if size_of::<Epoch>() != 4 {
18 panic!()
19 }
20};
21const _: () = {
22 if size_of::<RawId>() != 8 {
23 panic!()
24 }
25};
26
27#[repr(transparent)]
29#[cfg_attr(
30 any(feature = "serde", feature = "trace"),
31 derive(serde::Serialize),
32 serde(into = "SerialId")
33)]
34#[cfg_attr(
35 any(feature = "serde", feature = "replay"),
36 derive(serde::Deserialize),
37 serde(try_from = "SerialId")
38)]
39#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
40pub struct RawId(NonZeroU64);
41
42impl RawId {
43 pub fn zip(index: Index, epoch: Epoch) -> RawId {
49 let v = (index as u64) | ((epoch as u64) << 32);
50 Self(NonZeroU64::new(v).expect("IDs may not be zero"))
51 }
52
53 pub fn unzip(self) -> (Index, Epoch) {
55 (self.0.get() as Index, (self.0.get() >> 32) as Epoch)
56 }
57}
58
59#[repr(transparent)]
85#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
86#[cfg_attr(feature = "serde", serde(transparent))]
87pub struct Id<T: Marker>(RawId, PhantomData<T>);
88
89#[cfg(feature = "serde")]
91#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
92#[derive(Clone, Debug)]
93pub enum SerialId {
94 Id(Index, Epoch),
96}
97
98#[cfg(feature = "serde")]
99impl From<RawId> for SerialId {
100 fn from(id: RawId) -> Self {
101 let (index, epoch) = id.unzip();
102 Self::Id(index, epoch)
103 }
104}
105
106#[cfg(feature = "serde")]
107pub struct ZeroIdError;
108
109#[cfg(feature = "serde")]
110impl fmt::Display for ZeroIdError {
111 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112 write!(f, "IDs may not be zero")
113 }
114}
115
116#[cfg(feature = "serde")]
117impl TryFrom<SerialId> for RawId {
118 type Error = ZeroIdError;
119 fn try_from(id: SerialId) -> Result<Self, ZeroIdError> {
120 let SerialId::Id(index, epoch) = id;
121 if index == 0 && epoch == 0 {
122 Err(ZeroIdError)
123 } else {
124 Ok(RawId::zip(index, epoch))
125 }
126 }
127}
128
129#[allow(dead_code)]
133#[cfg(feature = "serde")]
134#[derive(Debug, serde::Serialize, serde::Deserialize)]
135pub enum PointerId<T: Marker> {
136 PointerId(core::num::NonZeroUsize, #[serde(skip)] PhantomData<T>),
138}
139
140#[cfg(feature = "serde")]
141impl<T: Marker> Copy for PointerId<T> {}
142
143#[cfg(feature = "serde")]
144impl<T: Marker> Clone for PointerId<T> {
145 fn clone(&self) -> Self {
146 *self
147 }
148}
149
150#[cfg(feature = "serde")]
151impl<T: Marker> PartialEq for PointerId<T> {
152 fn eq(&self, other: &Self) -> bool {
153 let PointerId::PointerId(this, _) = self;
154 let PointerId::PointerId(other, _) = other;
155 this == other
156 }
157}
158
159#[cfg(feature = "serde")]
160impl<T: Marker> Eq for PointerId<T> {}
161
162#[cfg(feature = "serde")]
163impl<T: Marker> Hash for PointerId<T> {
164 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
165 let PointerId::PointerId(this, _) = self;
166 this.hash(state);
167 }
168}
169
170#[cfg(feature = "serde")]
171impl<T: crate::storage::StorageItem> From<&alloc::sync::Arc<T>> for PointerId<T::Marker> {
172 fn from(arc: &alloc::sync::Arc<T>) -> Self {
173 PointerId::PointerId(
181 core::num::NonZeroUsize::new(alloc::sync::Arc::as_ptr(arc) as usize).unwrap(),
182 PhantomData,
183 )
184 }
185}
186
187impl<T> Id<T>
188where
189 T: Marker,
190{
191 pub unsafe fn from_raw(raw: RawId) -> Self {
195 Self(raw, PhantomData)
196 }
197
198 pub fn into_raw(self) -> RawId {
200 self.0
201 }
202
203 #[inline]
204 pub fn zip(index: Index, epoch: Epoch) -> Self {
205 Id(RawId::zip(index, epoch), PhantomData)
206 }
207
208 #[inline]
209 pub fn unzip(self) -> (Index, Epoch) {
210 self.0.unzip()
211 }
212}
213
214impl<T> Copy for Id<T> where T: Marker {}
215
216impl<T> Clone for Id<T>
217where
218 T: Marker,
219{
220 #[inline]
221 fn clone(&self) -> Self {
222 *self
223 }
224}
225
226impl<T> Debug for Id<T>
227where
228 T: Marker,
229{
230 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
231 let (index, epoch) = self.unzip();
232 write!(formatter, "Id({index},{epoch})")?;
233 Ok(())
234 }
235}
236
237impl<T> Hash for Id<T>
238where
239 T: Marker,
240{
241 #[inline]
242 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
243 self.0.hash(state);
244 }
245}
246
247impl<T> PartialEq for Id<T>
248where
249 T: Marker,
250{
251 #[inline]
252 fn eq(&self, other: &Self) -> bool {
253 self.0 == other.0
254 }
255}
256
257impl<T> Eq for Id<T> where T: Marker {}
258
259impl<T> PartialOrd for Id<T>
260where
261 T: Marker,
262{
263 #[inline]
264 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
265 Some(self.cmp(other))
266 }
267}
268
269impl<T> Ord for Id<T>
270where
271 T: Marker,
272{
273 #[inline]
274 fn cmp(&self, other: &Self) -> Ordering {
275 self.0.cmp(&other.0)
276 }
277}
278
279pub trait Marker: 'static + WasmNotSendSync {}
284
285#[cfg(test)]
290impl Marker for () {}
291
292macro_rules! ids {
294 ($(
295 $(#[$($meta:meta)*])*
296 pub type $name:ident $marker:ident;
297 )*) => {
298 pub mod markers {
300 $(
301 #[derive(Debug)]
302 pub enum $marker {}
303 impl super::Marker for $marker {}
304 )*
305 }
306
307 $(
308 $(#[$($meta)*])*
309 pub type $name = Id<self::markers::$marker>;
310 )*
311 }
312}
313
314ids! {
315 pub type AdapterId Adapter;
316 pub type SurfaceId Surface;
317 pub type DeviceId Device;
318 pub type QueueId Queue;
319 pub type BufferId Buffer;
320 pub type StagingBufferId StagingBuffer;
321 pub type TextureViewId TextureView;
322 pub type TextureId Texture;
323 pub type ExternalTextureId ExternalTexture;
324 pub type SamplerId Sampler;
325 pub type BindGroupLayoutId BindGroupLayout;
326 pub type PipelineLayoutId PipelineLayout;
327 pub type BindGroupId BindGroup;
328 pub type ShaderModuleId ShaderModule;
329 pub type RenderPipelineId RenderPipeline;
330 pub type ComputePipelineId ComputePipeline;
331 pub type PipelineCacheId PipelineCache;
332 pub type CommandEncoderId CommandEncoder;
333 pub type CommandBufferId CommandBuffer;
334 pub type RenderPassEncoderId RenderPassEncoder;
335 pub type ComputePassEncoderId ComputePassEncoder;
336 pub type RenderBundleEncoderId RenderBundleEncoder;
337 pub type RenderBundleId RenderBundle;
338 pub type QuerySetId QuerySet;
339 pub type BlasId Blas;
340 pub type TlasId Tlas;
341}
342
343#[test]
344fn test_id() {
345 let indexes = [0, Index::MAX / 2 - 1, Index::MAX / 2 + 1, Index::MAX];
346 let epochs = [1, Epoch::MAX / 2 - 1, Epoch::MAX / 2 + 1, Epoch::MAX];
347 for &i in &indexes {
348 for &e in &epochs {
349 let id = Id::<()>::zip(i, e);
350 let (index, epoch) = id.unzip();
351 assert_eq!(index, i);
352 assert_eq!(epoch, e);
353 }
354 }
355}