Skip to main content

moirai/entity/
id.rs

1use core::fmt;
2
3/// Opaque entity handle relative to one [`crate::world::World`].
4///
5/// Copyable, orderable, and hashable for deterministic diagnostics. Stale handles
6/// are rejected after despawn, including before the slot is reused. There is no
7/// public raw constructor or bit conversion.
8#[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}