beach_map/id/
mod.rs

1#[cfg(feature = "serde")]
2mod serde;
3
4use core::{cmp::Ordering, marker::PhantomData, num::NonZeroU32};
5
6/// Handle to a value inside the BeachMap.
7pub struct Id<T> {
8    data: NonZeroU32,
9    phantom: PhantomData<fn() -> T>,
10}
11
12impl<T> core::hash::Hash for Id<T> {
13    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
14        self.data.hash(state);
15    }
16}
17
18impl<T> Eq for Id<T> {}
19
20impl<T> PartialEq for Id<T> {
21    fn eq(&self, other: &Self) -> bool {
22        self.data == other.data
23    }
24}
25
26impl<T> PartialOrd for Id<T> {
27    fn partial_cmp(&self, other: &Id<T>) -> Option<Ordering> {
28        Some(self.cmp(other))
29    }
30}
31
32impl<T> Ord for Id<T> {
33    fn cmp(&self, other: &Id<T>) -> Ordering {
34        match self.index().cmp(&other.index()) {
35            ord @ Ordering::Less | ord @ Ordering::Greater => ord,
36            Ordering::Equal => self.gen().cmp(&other.gen()),
37        }
38    }
39}
40
41impl<T> core::fmt::Debug for Id<T> {
42    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
43        write!(f, "Id({}.{})", self.index(), self.gen())
44    }
45}
46
47impl<T> Clone for Id<T> {
48    fn clone(&self) -> Self {
49        *self
50    }
51}
52
53impl<T> Copy for Id<T> {}
54
55impl<T> Id<T> {
56    pub(crate) fn new(index: u32) -> Id<T> {
57        Id {
58            data: unsafe { NonZeroU32::new_unchecked(index + 1) },
59            phantom: PhantomData,
60        }
61    }
62
63    #[cfg(test)]
64    pub(crate) fn with_gen(index: u32, gen: u32) -> Id<T> {
65        Id {
66            data: unsafe { NonZeroU32::new_unchecked(index + 1 | (gen << 24)) },
67            phantom: PhantomData,
68        }
69    }
70
71    /// Returns an [`Id`] that can be used as a dummy value.
72    /// This [`Id`] can't access any value.
73    pub fn invalid() -> Self {
74        Id {
75            data: unsafe { NonZeroU32::new_unchecked(u32::MAX) },
76            phantom: PhantomData,
77        }
78    }
79
80    pub(crate) fn index(self) -> u32 {
81        // 24 first bits
82        (self.data.get() & !(255 << 24)) - 1
83    }
84
85    pub(crate) fn uindex(self) -> usize {
86        self.index() as usize
87    }
88
89    pub(crate) fn set_index(&mut self, new_index: u32) {
90        self.data = unsafe { NonZeroU32::new_unchecked(new_index + 1 | (self.gen() << 24)) };
91    }
92
93    pub(crate) fn gen(self) -> u32 {
94        // 8 last bits
95        self.data.get() >> 24
96    }
97
98    pub(crate) fn increment_gen(&mut self) {
99        self.data =
100            unsafe { NonZeroU32::new_unchecked(self.index() + 1 | ((self.gen() + 1) << 24)) };
101    }
102
103    /// Returns a handle without the generic type.
104    pub fn untype(self) -> UntypedId {
105        UntypedId(Id {
106            data: self.data,
107            phantom: PhantomData,
108        })
109    }
110}
111
112/// Same as [`Id`] but without type.
113#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
114pub struct UntypedId(Id<()>);
115
116impl core::fmt::Debug for UntypedId {
117    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
118        write!(f, "UntypedId({}.{})", self.0.index(), self.0.gen())
119    }
120}
121
122impl UntypedId {
123    /// Adds back a type to the handle.
124    pub fn as_type<T>(self) -> Id<T> {
125        Id {
126            data: self.0.data,
127            phantom: PhantomData,
128        }
129    }
130}