fyrox_core/pool/
handle.rs

1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21use 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/// Handle is some sort of non-owning reference to content in a pool. It stores
36/// index of object and additional information that allows to ensure that handle
37/// is still valid (points to the same object as when handle was created).
38#[derive(Reflect, Serialize, Deserialize)]
39pub struct Handle<T> {
40    /// Index of object in pool.
41    #[reflect(read_only, description = "Index of an object in a pool.")]
42    pub(super) index: u32,
43    /// Generation number, if it is same as generation of pool record at
44    /// index of handle then this is valid handle.
45    #[reflect(read_only, description = "Generation of an object in a pool.")]
46    pub(super) generation: u32,
47    /// Type holder.
48    #[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
172/// Atomic handle.
173pub 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/// Type-erased handle.
252#[derive(
253    Copy, Clone, Debug, Ord, PartialOrd, PartialEq, Eq, Hash, Reflect, Visit, Serialize, Deserialize,
254)]
255pub struct ErasedHandle {
256    /// Index of object in pool.
257    #[reflect(read_only)]
258    index: u32,
259    /// Generation number, if it is same as generation of pool record at
260    /// index of handle then this is valid handle.
261    #[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}