wgpu/
cmp.rs

1//! We need to impl `PartialEq`, `Eq`, `PartialOrd`, `Ord`, and `Hash` for all handle types in wgpu.
2//!
3//! For types that have some already-unique property, we can use that property to implement these traits.
4//!
5//! For types (like WebGPU) that don't have such a property, we generate an identifier and use that.
6
7pub use wgpu_sync::atomic::{AtomicU64, Ordering};
8
9use core::num::NonZeroU64;
10
11static NEXT_ID: AtomicU64 = AtomicU64::new(1);
12
13#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
14pub struct Identifier {
15    inner: NonZeroU64,
16}
17
18impl Identifier {
19    pub fn create() -> Self {
20        let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
21        // Safety: Will take 7000+ years of constant incrementing to overflow. It's fine.
22        let inner = unsafe { NonZeroU64::new_unchecked(id) };
23        Self { inner }
24    }
25}
26
27/// Implements `PartialEq`, `Eq`, `PartialOrd`, `Ord`, and `Hash` for a type by proxying the operations to a single field.
28///
29/// ```ignore
30/// impl_eq_ord_hash_proxy!(MyType => .field);
31/// ```
32macro_rules! impl_eq_ord_hash_proxy {
33    ($type:ty => $($access:tt)*) => {
34        impl PartialEq for $type {
35            fn eq(&self, other: &Self) -> bool {
36                self $($access)* == other $($access)*
37            }
38        }
39
40        impl Eq for $type {}
41
42        impl PartialOrd for $type {
43            fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
44                Some(self.cmp(other))
45            }
46        }
47
48        impl Ord for $type {
49            fn cmp(&self, other: &Self) -> core::cmp::Ordering {
50                self $($access)*.cmp(&other $($access)*)
51            }
52        }
53
54        impl core::hash::Hash for $type {
55            fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
56                self $($access)*.hash(state)
57            }
58        }
59    };
60}
61
62/// Implements `PartialEq`, `Eq`, `PartialOrd`, `Ord`, and `Hash` for a type by comparing the addresses of the `Arc`s.
63///
64/// ```ignore
65/// impl_eq_ord_hash_arc_address!(MyType => .field);
66/// ```
67#[cfg_attr(not(any(wgpu_core, custom)), expect(unused_macros))]
68macro_rules! impl_eq_ord_hash_arc_address {
69    ($type:ty => $($access:tt)*) => {
70        impl PartialEq for $type {
71            fn eq(&self, other: &Self) -> bool {
72                let address_left = alloc::sync::Arc::as_ptr(&self $($access)*);
73                let address_right = alloc::sync::Arc::as_ptr(&other $($access)*);
74
75                address_left == address_right
76            }
77        }
78
79        impl Eq for $type {}
80
81        impl PartialOrd for $type {
82            fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
83                Some(self.cmp(other))
84            }
85        }
86
87        impl Ord for $type {
88            fn cmp(&self, other: &Self) -> core::cmp::Ordering {
89                let address_left = alloc::sync::Arc::as_ptr(&self $($access)*);
90                let address_right = alloc::sync::Arc::as_ptr(&other $($access)*);
91
92                address_left.cmp(&address_right)
93            }
94        }
95
96        impl core::hash::Hash for $type {
97            fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
98                let address = alloc::sync::Arc::as_ptr(&self $($access)*);
99                address.hash(state)
100            }
101        }
102    };
103}
104
105/// Implements `PartialEq`, `Eq`, `PartialOrd`, `Ord`, and `Hash` for a type by comparing the addresses of the `Arc`s.
106///
107/// ```ignore
108/// impl_eq_ord_hash_arc_address!(MyType => .field);
109/// ```
110#[cfg_attr(not(any(wgpu_core, custom)), expect(unused_macros))]
111macro_rules! impl_eq_ord_hash_box_address {
112    ($type:ty => $($access:tt)*) => {
113        impl PartialEq for $type {
114            fn eq(&self, other: &Self) -> bool {
115                let address_left: *const _ = &self $($access)*;
116                let address_right: *const _ = &other $($access)*;
117
118                address_left == address_right
119            }
120        }
121
122        impl Eq for $type {}
123
124        impl PartialOrd for $type {
125            fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
126                Some(self.cmp(other))
127            }
128        }
129
130        impl Ord for $type {
131            fn cmp(&self, other: &Self) -> core::cmp::Ordering {
132                let address_left: *const _ = &self $($access)*;
133                let address_right: *const _ = &other $($access)*;
134
135                address_left.cmp(&address_right)
136            }
137        }
138
139        impl core::hash::Hash for $type {
140            fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
141                let address: *const _ = &self $($access)*;
142                address.hash(state)
143            }
144        }
145    };
146}
147
148#[cfg_attr(not(any(wgpu_core, custom)), expect(unused_imports))]
149pub(crate) use {
150    impl_eq_ord_hash_arc_address, impl_eq_ord_hash_box_address, impl_eq_ord_hash_proxy,
151};