shipyard/entity_id/
mod.rs1#[cfg(feature = "serde1")]
2mod serde;
3
4use core::num::NonZeroU64;
5
6#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
14#[repr(transparent)]
15pub struct EntityId(pub(super) NonZeroU64);
16
17impl Default for EntityId {
19 fn default() -> Self {
20 Self::dead()
21 }
22}
23
24impl EntityId {
25 const GEN_LEN: u64 = 16;
27 const INDEX_LEN: u64 = 64 - Self::GEN_LEN;
28 const INDEX_MASK: u64 = !(!0 << Self::INDEX_LEN);
29 const GEN_MASK: u64 = !(!0 >> Self::GEN_LEN);
30 const MAX_GEN: u16 = u16::MAX - 1;
31
32 #[inline]
35 pub fn index(self) -> u64 {
36 (self.0.get() & Self::INDEX_MASK) - 1
37 }
38 #[inline]
41 pub fn uindex(self) -> usize {
42 self.index() as usize
43 }
44 #[inline]
46 pub(crate) fn set_index(&mut self, index: u64) {
47 assert!(index < Self::INDEX_MASK);
48 self.0 =
50 unsafe { NonZeroU64::new_unchecked((index + 1) | (self.0.get() & !Self::INDEX_MASK)) }
51 }
52 #[inline]
54 pub fn gen(self) -> u16 {
55 ((self.0.get() & Self::GEN_MASK) >> Self::INDEX_LEN) as u16
56 }
57 #[inline]
59 pub(super) fn bump_gen(&mut self) -> Result<(), ()> {
60 if self.gen() < Self::MAX_GEN - 1 {
61 self.0 = unsafe {
63 NonZeroU64::new_unchecked(
64 (self.0.get() & !Self::GEN_MASK)
65 | (((self.gen() + 1) as u64) << Self::INDEX_LEN),
66 )
67 };
68 Ok(())
69 } else {
70 Err(())
71 }
72 }
73 #[inline]
75 pub(crate) fn new(index: u64) -> Self {
76 assert!(index < Self::INDEX_MASK);
77 EntityId(unsafe { NonZeroU64::new_unchecked(index + 1) })
79 }
80 #[inline]
81 pub(crate) const fn new_from_parts(index: u64, gen: u16) -> Self {
82 assert!(index < Self::INDEX_MASK);
83
84 EntityId(unsafe {
85 NonZeroU64::new_unchecked((index + 1) | ((gen as u64) << Self::INDEX_LEN))
86 })
87 }
88 #[inline]
90 pub const fn new_from_index_and_gen(index: u64, gen: u16) -> Self {
91 EntityId::new_from_parts(index, gen)
92 }
93 #[cfg(test)]
94 pub(crate) fn zero() -> Self {
95 EntityId(NonZeroU64::new(1).unwrap())
96 }
97 #[inline]
99 pub fn dead() -> Self {
100 EntityId(unsafe { NonZeroU64::new_unchecked(!0) })
102 }
103 #[inline]
104 pub(crate) fn bucket(self) -> usize {
105 self.uindex() / crate::sparse_set::BUCKET_SIZE
106 }
107 #[inline]
108 pub(crate) fn bucket_index(self) -> usize {
109 self.uindex() % crate::sparse_set::BUCKET_SIZE
110 }
111 #[inline]
112 pub(crate) fn max_index() -> u64 {
113 Self::INDEX_MASK - 1
114 }
115 #[inline]
118 pub(crate) const fn max_gen() -> u16 {
119 Self::MAX_GEN
120 }
121 #[inline]
122 pub(crate) fn is_dead(&self) -> bool {
123 (self.0.get() & Self::GEN_MASK) == Self::GEN_MASK
124 }
125 #[inline]
126 pub(crate) fn copy_index(&mut self, other: EntityId) {
127 unsafe {
128 self.0 = NonZeroU64::new_unchecked(
129 (self.0.get() & !Self::INDEX_MASK) | (other.0.get() & Self::INDEX_MASK),
130 );
131 }
132 }
133 #[inline]
134 pub(crate) fn copy_gen(&mut self, other: EntityId) {
135 unsafe {
136 self.0 = NonZeroU64::new_unchecked(
137 (self.0.get() & !Self::GEN_MASK) | (other.0.get() & Self::GEN_MASK),
138 );
139 }
140 }
141 #[inline]
142 pub(crate) fn copy_index_gen(&mut self, other: EntityId) {
143 unsafe {
144 self.0 = NonZeroU64::new_unchecked(self.0.get() | other.0.get());
145 }
146 }
147 #[inline]
149 pub fn inner(self) -> u64 {
150 self.0.get()
151 }
152 #[inline]
154 pub fn from_inner(inner: u64) -> Option<EntityId> {
155 Some(EntityId(NonZeroU64::new(inner)?))
156 }
157}
158
159impl core::fmt::Debug for EntityId {
160 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
161 if *self == EntityId::dead() {
162 f.write_str("EId(dead)")
163 } else {
164 write!(f, "EId({}.{})", self.index(), self.gen())
165 }
166 }
167}
168
169#[test]
170fn entity_id() {
171 let mut entity_id = EntityId::new(0);
172 assert_eq!(entity_id.index(), 0);
173 assert_eq!(entity_id.gen(), 0);
174 entity_id.set_index(701);
175 assert_eq!(entity_id.index(), 701);
176 assert_eq!(entity_id.gen(), 0);
177 entity_id.bump_gen().unwrap();
178 entity_id.bump_gen().unwrap();
179 entity_id.bump_gen().unwrap();
180 assert_eq!(entity_id.index(), 701);
181 assert_eq!(entity_id.gen(), 3);
182 entity_id.set_index(554);
183 assert_eq!(entity_id.index(), 554);
184 assert_eq!(entity_id.gen(), 3);
185}