1use core::fmt;
2
3#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
9#[repr(C)]
10pub struct EntityId {
11 owner: u32,
12 packed: u64,
13}
14
15impl EntityId {
16 pub(crate) const fn from_parts(slot: u32, generation: u32) -> Self {
17 Self::from_owned_parts(0, slot, generation)
18 }
19
20 pub(crate) const fn from_owned_parts(owner: u32, slot: u32, generation: u32) -> Self {
21 Self {
22 owner,
23 packed: ((generation as u64) << 32) | slot as u64,
24 }
25 }
26
27 pub(crate) const fn owner(self) -> u32 {
28 self.owner
29 }
30
31 pub(crate) const fn slot(self) -> u32 {
32 (self.packed & 0xFFFF_FFFF) as u32
33 }
34
35 pub(crate) const fn generation(self) -> u32 {
36 (self.packed >> 32) as u32
37 }
38
39 #[cfg(test)]
40 pub(crate) const fn with_generation(self, generation: u32) -> Self {
41 Self::from_owned_parts(self.owner, self.slot(), generation)
42 }
43}
44
45impl fmt::Debug for EntityId {
46 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47 f.debug_tuple("EntityId")
48 .field(&self.slot())
49 .field(&self.generation())
50 .finish()
51 }
52}
53
54#[cfg(test)]
55mod tests {
56 use super::*;
57 use core::mem::{align_of, size_of};
58
59 #[test]
60 fn entity_id_carries_private_owner_and_packed_position() {
61 assert_eq!(size_of::<EntityId>(), 16);
62 assert_eq!(align_of::<EntityId>(), 8);
63 }
64
65 #[test]
66 fn owner_participates_in_identity_but_not_debug_output() {
67 let a = EntityId::from_owned_parts(1, 2, 3);
68 let b = EntityId::from_owned_parts(2, 2, 3);
69 assert_ne!(a, b);
70 assert_eq!(alloc::format!("{a:?}"), "EntityId(2, 3)");
71 }
72}