1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
15pub struct Entity(u64);
16
17impl Entity {
18 pub const INVALID: Self = Self(u64::MAX);
21
22 #[inline]
32 pub fn new(id: u32, generation: u32) -> Self {
33 Self(((generation as u64) << 32) | id as u64)
34 }
35
36 #[inline]
38 pub fn id(self) -> u32 {
39 self.0 as u32
40 }
41
42 #[inline]
44 pub fn generation(self) -> u32 {
45 (self.0 >> 32) as u32
46 }
47
48 #[inline]
50 pub fn is_valid(self) -> bool {
51 self != Self::INVALID
52 }
53
54 #[inline]
57 pub fn to_bits(self) -> u64 {
58 self.0
59 }
60
61 #[inline]
63 pub fn from_bits(bits: u64) -> Self {
64 Self(bits)
65 }
66}
67
68impl std::fmt::Display for Entity {
69 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
70 if *self == Self::INVALID {
71 write!(f, "Entity(INVALID)")
72 } else {
73 write!(f, "Entity({}:{})", self.id(), self.generation())
74 }
75 }
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81
82 #[test]
83 fn test_new_and_accessors() {
84 let e = Entity::new(42, 7);
85 assert_eq!(e.id(), 42);
86 assert_eq!(e.generation(), 7);
87 }
88
89 #[test]
90 fn test_zero_generation() {
91 let e = Entity::new(0, 0);
92 assert_eq!(e.id(), 0);
93 assert_eq!(e.generation(), 0);
94 assert!(e.is_valid());
95 }
96
97 #[test]
98 fn test_max_values() {
99 let e = Entity::new(u32::MAX - 1, u32::MAX - 1);
100 assert_eq!(e.id(), u32::MAX - 1);
101 assert_eq!(e.generation(), u32::MAX - 1);
102 assert!(e.is_valid());
103 }
104
105 #[test]
106 fn test_invalid_sentinel() {
107 assert!(!Entity::INVALID.is_valid());
108 assert_eq!(Entity::INVALID.id(), u32::MAX);
109 assert_eq!(Entity::INVALID.generation(), u32::MAX);
110 }
111
112 #[test]
113 fn test_to_bits_from_bits_roundtrip() {
114 let e = Entity::new(123, 456);
115 let bits = e.to_bits();
116 let e2 = Entity::from_bits(bits);
117 assert_eq!(e, e2);
118 assert_eq!(e2.id(), 123);
119 assert_eq!(e2.generation(), 456);
120 }
121
122 #[test]
123 fn test_display() {
124 let e = Entity::new(5, 2);
125 assert_eq!(format!("{}", e), "Entity(5:2)");
126 }
127
128 #[test]
129 fn test_display_invalid() {
130 assert_eq!(format!("{}", Entity::INVALID), "Entity(INVALID)");
131 }
132
133 #[test]
134 fn test_equality_and_hash() {
135 use std::collections::HashSet;
136 let e1 = Entity::new(1, 0);
137 let e2 = Entity::new(1, 0);
138 let e3 = Entity::new(1, 1); assert_eq!(e1, e2);
141 assert_ne!(e1, e3);
142
143 let mut set = HashSet::new();
144 set.insert(e1);
145 assert!(set.contains(&e2));
146 assert!(!set.contains(&e3));
147 }
148
149 #[test]
150 fn test_copy_semantics() {
151 let e1 = Entity::new(10, 3);
152 let e2 = e1; assert_eq!(e1, e2);
154 assert_eq!(e1.id(), e2.id());
155 }
156
157 #[test]
158 fn test_serde_roundtrip() {
159 let e = Entity::new(999, 42);
160 let serialized = ron::to_string(&e).expect("serialize failed");
161 let deserialized: Entity = ron::from_str(&serialized).expect("deserialize failed");
162 assert_eq!(e, deserialized);
163 }
164}
165pub mod allocator;