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]
24 pub fn new(id: u32, generation: u32) -> Self {
25 Self(((generation as u64) << 32) | id as u64)
26 }
27
28 #[inline]
30 pub fn id(self) -> u32 {
31 self.0 as u32
32 }
33
34 #[inline]
36 pub fn generation(self) -> u32 {
37 (self.0 >> 32) as u32
38 }
39
40 #[inline]
42 pub fn is_valid(self) -> bool {
43 self != Self::INVALID
44 }
45
46 #[inline]
49 pub fn to_bits(self) -> u64 {
50 self.0
51 }
52
53 #[inline]
55 pub fn from_bits(bits: u64) -> Self {
56 Self(bits)
57 }
58}
59
60impl std::fmt::Display for Entity {
61 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62 if *self == Self::INVALID {
63 write!(f, "Entity(INVALID)")
64 } else {
65 write!(f, "Entity({}:{})", self.id(), self.generation())
66 }
67 }
68}
69
70#[cfg(test)]
71mod tests {
72 use super::*;
73
74 #[test]
75 fn test_new_and_accessors() {
76 let e = Entity::new(42, 7);
77 assert_eq!(e.id(), 42);
78 assert_eq!(e.generation(), 7);
79 }
80
81 #[test]
82 fn test_zero_generation() {
83 let e = Entity::new(0, 0);
84 assert_eq!(e.id(), 0);
85 assert_eq!(e.generation(), 0);
86 assert!(e.is_valid());
87 }
88
89 #[test]
90 fn test_max_values() {
91 let e = Entity::new(u32::MAX - 1, u32::MAX - 1);
92 assert_eq!(e.id(), u32::MAX - 1);
93 assert_eq!(e.generation(), u32::MAX - 1);
94 assert!(e.is_valid());
95 }
96
97 #[test]
98 fn test_invalid_sentinel() {
99 assert!(!Entity::INVALID.is_valid());
100 assert_eq!(Entity::INVALID.id(), u32::MAX);
101 assert_eq!(Entity::INVALID.generation(), u32::MAX);
102 }
103
104 #[test]
105 fn test_to_bits_from_bits_roundtrip() {
106 let e = Entity::new(123, 456);
107 let bits = e.to_bits();
108 let e2 = Entity::from_bits(bits);
109 assert_eq!(e, e2);
110 assert_eq!(e2.id(), 123);
111 assert_eq!(e2.generation(), 456);
112 }
113
114 #[test]
115 fn test_display() {
116 let e = Entity::new(5, 2);
117 assert_eq!(format!("{}", e), "Entity(5:2)");
118 }
119
120 #[test]
121 fn test_display_invalid() {
122 assert_eq!(format!("{}", Entity::INVALID), "Entity(INVALID)");
123 }
124
125 #[test]
126 fn test_equality_and_hash() {
127 use std::collections::HashSet;
128 let e1 = Entity::new(1, 0);
129 let e2 = Entity::new(1, 0);
130 let e3 = Entity::new(1, 1); assert_eq!(e1, e2);
133 assert_ne!(e1, e3);
134
135 let mut set = HashSet::new();
136 set.insert(e1);
137 assert!(set.contains(&e2));
138 assert!(!set.contains(&e3));
139 }
140
141 #[test]
142 fn test_copy_semantics() {
143 let e1 = Entity::new(10, 3);
144 let e2 = e1; assert_eq!(e1, e2);
146 assert_eq!(e1.id(), e2.id());
147 }
148
149 #[test]
150 fn test_serde_roundtrip() {
151 let e = Entity::new(999, 42);
152 let serialized = ron::to_string(&e).expect("serialize failed");
153 let deserialized: Entity = ron::from_str(&serialized).expect("deserialize failed");
154 assert_eq!(e, deserialized);
155 }
156}
157pub mod allocator;