1use crate::{
22 combine_uuids, pool::INVALID_GENERATION, reflect::prelude::*, uuid_provider,
23 visitor::prelude::*, TypeUuidProvider,
24};
25use serde::{Deserialize, Serialize};
26use std::{
27 cmp::Ordering,
28 fmt::{Debug, Display, Formatter},
29 hash::{Hash, Hasher},
30 marker::PhantomData,
31 sync::atomic::{self, AtomicUsize},
32};
33use uuid::Uuid;
34
35#[derive(Reflect, Serialize, Deserialize)]
39pub struct Handle<T> {
40 #[reflect(read_only, description = "Index of an object in a pool.")]
42 pub(super) index: u32,
43 #[reflect(read_only, description = "Generation of an object in a pool.")]
46 pub(super) generation: u32,
47 #[reflect(hidden)]
49 #[serde(skip)]
50 pub(super) type_marker: PhantomData<T>,
51}
52
53impl<T> Copy for Handle<T> {}
54
55impl<T> Eq for Handle<T> {}
56
57impl<T> PartialEq for Handle<T> {
58 #[inline]
59 fn eq(&self, other: &Handle<T>) -> bool {
60 self.generation == other.generation && self.index == other.index
61 }
62}
63
64impl<T> Hash for Handle<T> {
65 #[inline]
66 fn hash<H>(&self, state: &mut H)
67 where
68 H: Hasher,
69 {
70 self.index.hash(state);
71 self.generation.hash(state);
72 }
73}
74
75impl<T> Handle<T> {
76 pub const NONE: Handle<T> = Handle {
77 index: 0,
78 generation: INVALID_GENERATION,
79 type_marker: PhantomData,
80 };
81
82 #[inline(always)]
83 pub fn is_none(self) -> bool {
84 self.index == 0 && self.generation == INVALID_GENERATION
85 }
86
87 #[inline(always)]
88 pub fn is_some(self) -> bool {
89 !self.is_none()
90 }
91
92 #[inline(always)]
93 pub fn index(self) -> u32 {
94 self.index
95 }
96
97 #[inline(always)]
98 pub fn generation(self) -> u32 {
99 self.generation
100 }
101
102 #[inline(always)]
103 pub fn new(index: u32, generation: u32) -> Self {
104 Handle {
105 index,
106 generation,
107 type_marker: PhantomData,
108 }
109 }
110
111 #[inline(always)]
112 pub fn transmute<U>(&self) -> Handle<U> {
113 Handle {
114 index: self.index,
115 generation: self.generation,
116 type_marker: Default::default(),
117 }
118 }
119
120 #[inline(always)]
121 pub fn decode_from_u128(num: u128) -> Self {
122 Self {
123 index: num as u32,
124 generation: (num >> 32) as u32,
125 type_marker: Default::default(),
126 }
127 }
128
129 #[inline(always)]
130 pub fn encode_to_u128(&self) -> u128 {
131 (self.index as u128) | ((self.generation as u128) << 32)
132 }
133}
134
135impl<T> TypeUuidProvider for Handle<T>
136where
137 T: TypeUuidProvider,
138{
139 #[inline]
140 fn type_uuid() -> Uuid {
141 combine_uuids(
142 uuid::uuid!("30c0668d-7a2c-47e6-8c7b-208fdcc905a1"),
143 T::type_uuid(),
144 )
145 }
146}
147
148impl<T> PartialOrd for Handle<T> {
149 #[inline]
150 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
151 Some(self.cmp(other))
152 }
153}
154
155impl<T> Ord for Handle<T> {
156 #[inline]
157 fn cmp(&self, other: &Self) -> Ordering {
158 self.index.cmp(&other.index)
159 }
160}
161
162unsafe impl<T> Send for Handle<T> {}
163unsafe impl<T> Sync for Handle<T> {}
164
165impl<T> Display for Handle<T> {
166 #[inline]
167 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
168 write!(f, "{}:{}", self.index, self.generation)
169 }
170}
171
172pub struct AtomicHandle(AtomicUsize);
174
175impl Clone for AtomicHandle {
176 #[inline]
177 fn clone(&self) -> Self {
178 Self(AtomicUsize::new(self.0.load(atomic::Ordering::Relaxed)))
179 }
180}
181
182impl Default for AtomicHandle {
183 #[inline]
184 fn default() -> Self {
185 Self::none()
186 }
187}
188
189impl AtomicHandle {
190 #[inline]
191 pub fn none() -> Self {
192 Self(AtomicUsize::new(0))
193 }
194
195 #[inline]
196 pub fn new(index: u32, generation: u32) -> Self {
197 let handle = Self(AtomicUsize::new(0));
198 handle.set(index, generation);
199 handle
200 }
201
202 #[inline]
203 pub fn set(&self, index: u32, generation: u32) {
204 let index = (index as usize) << (usize::BITS / 2) >> (usize::BITS / 2);
205 let generation = (generation as usize) << (usize::BITS / 2);
206 self.0.store(index | generation, atomic::Ordering::Relaxed);
207 }
208
209 #[inline]
210 pub fn set_from_handle<T>(&self, handle: Handle<T>) {
211 self.set(handle.index, handle.generation)
212 }
213
214 #[inline(always)]
215 pub fn is_some(&self) -> bool {
216 self.generation() != INVALID_GENERATION
217 }
218
219 #[inline(always)]
220 pub fn is_none(&self) -> bool {
221 !self.is_some()
222 }
223
224 #[inline]
225 pub fn index(&self) -> u32 {
226 let bytes = self.0.load(atomic::Ordering::Relaxed);
227 ((bytes << (usize::BITS / 2)) >> (usize::BITS / 2)) as u32
228 }
229
230 #[inline]
231 pub fn generation(&self) -> u32 {
232 let bytes = self.0.load(atomic::Ordering::Relaxed);
233 (bytes >> (usize::BITS / 2)) as u32
234 }
235}
236
237impl Display for AtomicHandle {
238 #[inline]
239 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
240 write!(f, "{}:{}", self.index(), self.generation())
241 }
242}
243
244impl Debug for AtomicHandle {
245 #[inline]
246 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
247 write!(f, "[Idx: {}; Gen: {}]", self.index(), self.generation())
248 }
249}
250
251#[derive(
253 Copy, Clone, Debug, Ord, PartialOrd, PartialEq, Eq, Hash, Reflect, Visit, Serialize, Deserialize,
254)]
255pub struct ErasedHandle {
256 #[reflect(read_only)]
258 index: u32,
259 #[reflect(read_only)]
262 generation: u32,
263}
264
265uuid_provider!(ErasedHandle = "50131acc-8b3b-40b5-b495-e2c552c94db3");
266
267impl Display for ErasedHandle {
268 #[inline]
269 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
270 write!(f, "{}:{}", self.index, self.generation)
271 }
272}
273
274impl Default for ErasedHandle {
275 #[inline]
276 fn default() -> Self {
277 Self::none()
278 }
279}
280
281impl<T> From<ErasedHandle> for Handle<T> {
282 #[inline]
283 fn from(erased_handle: ErasedHandle) -> Self {
284 Handle {
285 index: erased_handle.index,
286 generation: erased_handle.generation,
287 type_marker: PhantomData,
288 }
289 }
290}
291
292impl<T> From<AtomicHandle> for Handle<T> {
293 #[inline]
294 fn from(atomic_handle: AtomicHandle) -> Self {
295 Handle {
296 index: atomic_handle.index(),
297 generation: atomic_handle.generation(),
298 type_marker: PhantomData,
299 }
300 }
301}
302
303impl<T> From<Handle<T>> for ErasedHandle {
304 #[inline]
305 fn from(h: Handle<T>) -> Self {
306 Self {
307 index: h.index,
308 generation: h.generation,
309 }
310 }
311}
312
313impl ErasedHandle {
314 #[inline]
315 pub fn none() -> Self {
316 Self {
317 index: 0,
318 generation: INVALID_GENERATION,
319 }
320 }
321
322 #[inline]
323 pub fn new(index: u32, generation: u32) -> Self {
324 Self { index, generation }
325 }
326
327 #[inline(always)]
328 pub fn is_some(&self) -> bool {
329 self.generation != INVALID_GENERATION
330 }
331
332 #[inline(always)]
333 pub fn is_none(&self) -> bool {
334 !self.is_some()
335 }
336
337 #[inline(always)]
338 pub fn index(self) -> u32 {
339 self.index
340 }
341
342 #[inline(always)]
343 pub fn generation(self) -> u32 {
344 self.generation
345 }
346}
347
348impl<T> Visit for Handle<T> {
349 #[inline]
350 fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
351 let mut region = visitor.enter_region(name)?;
352
353 self.index.visit("Index", &mut region)?;
354 self.generation.visit("Generation", &mut region)?;
355
356 Ok(())
357 }
358}
359
360impl<T> Default for Handle<T> {
361 #[inline]
362 fn default() -> Self {
363 Self::NONE
364 }
365}
366
367impl<T> Debug for Handle<T> {
368 #[inline]
369 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
370 write!(f, "[Idx: {}; Gen: {}]", self.index, self.generation)
371 }
372}
373
374#[cfg(test)]
375mod test {
376 use crate::{
377 pool::{AtomicHandle, ErasedHandle, Handle, INVALID_GENERATION},
378 visitor::{Visit, Visitor},
379 };
380
381 #[test]
382 fn test_handle_u128_encode_decode() {
383 let a = Handle::<()>::new(123, 321);
384 let encoded = a.encode_to_u128();
385 let decoded = Handle::<()>::decode_from_u128(encoded);
386 assert_eq!(decoded, a);
387 }
388
389 #[test]
390 fn erased_handle_none() {
391 assert_eq!(
392 ErasedHandle::none(),
393 ErasedHandle {
394 index: 0,
395 generation: INVALID_GENERATION,
396 }
397 );
398 }
399
400 #[test]
401 fn erased_handle_new() {
402 assert_eq!(
403 ErasedHandle::new(0, 1),
404 ErasedHandle {
405 index: 0,
406 generation: 1,
407 }
408 );
409 }
410
411 #[test]
412 fn erased_handle_is_some() {
413 assert!(ErasedHandle::new(0, 1).is_some());
414 assert!(!ErasedHandle::none().is_some());
415 }
416
417 #[test]
418 fn erased_handle_is_none() {
419 assert!(!ErasedHandle::new(0, 1).is_none());
420 assert!(ErasedHandle::none().is_none());
421 }
422
423 #[test]
424 fn erased_handle_index() {
425 assert_eq!(
426 ErasedHandle {
427 index: 42,
428 generation: 15
429 }
430 .index(),
431 42
432 );
433 }
434
435 #[test]
436 fn erased_handle_generation() {
437 assert_eq!(
438 ErasedHandle {
439 index: 42,
440 generation: 15
441 }
442 .generation(),
443 15
444 );
445 }
446
447 #[test]
448 fn default_for_erased_handle() {
449 assert_eq!(ErasedHandle::default(), ErasedHandle::none());
450 }
451
452 #[test]
453 fn erased_handle_from_handle() {
454 let handle = Handle::<u32> {
455 index: 0,
456 generation: 1,
457 type_marker: std::marker::PhantomData,
458 };
459
460 assert_eq!(
461 ErasedHandle::from(handle),
462 ErasedHandle {
463 index: 0,
464 generation: 1
465 }
466 );
467 }
468
469 #[test]
470 fn handle_from_erased_handle() {
471 let er = ErasedHandle {
472 index: 0,
473 generation: 1,
474 };
475
476 assert_eq!(
477 Handle::from(er),
478 Handle::<u32> {
479 index: 0,
480 generation: 1,
481 type_marker: std::marker::PhantomData,
482 }
483 );
484 }
485
486 #[test]
487 fn default_for_handle() {
488 assert_eq!(Handle::default(), Handle::<u32>::NONE);
489 }
490
491 #[test]
492 fn visit_for_handle() {
493 let mut h = Handle::<u32>::default();
494 let mut visitor = Visitor::default();
495
496 assert!(h.visit("name", &mut visitor).is_ok());
497 }
498
499 #[test]
500 fn test_debug_for_handle() {
501 let h = Handle::<u32> {
502 index: 0,
503 generation: 1,
504 type_marker: std::marker::PhantomData,
505 };
506
507 assert_eq!(format!("{h:?}"), "[Idx: 0; Gen: 1]");
508 }
509
510 #[test]
511 fn handle_getters() {
512 let h = Handle::<u32> {
513 index: 0,
514 generation: 1,
515 type_marker: std::marker::PhantomData,
516 };
517
518 assert_eq!(h.index(), 0);
519 assert_eq!(h.generation(), 1);
520 }
521
522 #[test]
523 fn handle_transmute() {
524 assert_eq!(
525 Handle::<u32>::default().transmute::<f32>(),
526 Handle::<f32>::default()
527 );
528 }
529
530 #[test]
531 fn test_atomic_handle() {
532 let handle = AtomicHandle::new(123, 321);
533 assert!(handle.is_some());
534 assert_eq!(handle.index(), 123);
535 assert_eq!(handle.generation(), 321);
536
537 let handle = AtomicHandle::default();
538 assert!(handle.is_none());
539 }
540}