Skip to main content

gizmo_core/entity/
mod.rs

1/// ECS Entity tanımlayıcısı — Packed u64 temsili.
2///
3/// Alt 32 bit = entity ID (slot index), üst 32 bit = generation (yeniden kullanım sayacı).
4/// Generation, aynı slot'a (ID'ye) yeni bir entity atandığında artırılır ve eski referansların
5/// (dangling entity) güvenli şekilde tespit edilmesini sağlar.
6///
7/// # Layout
8/// ```text
9/// ┌──────────────────────────────────────────────────────────────────┐
10/// │  63 ───────────── 32 │ 31 ───────────── 0 │
11/// │     generation (u32) │       id (u32)     │
12/// └──────────────────────────────────────────────────────────────────┘
13/// ```
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
15pub struct Entity(u64);
16
17impl Entity {
18    /// Geçersiz / null entity sentinel değeri.
19    /// `Option<Entity>` yerine kullanılabilir (ergonomi ve cache dostu).
20    pub const INVALID: Self = Self(u64::MAX);
21
22    /// Yeni bir Entity oluşturur.
23    #[inline]
24    pub fn new(id: u32, generation: u32) -> Self {
25        Self(((generation as u64) << 32) | id as u64)
26    }
27
28    /// Entity'nin slot indeksini (ID) döndürür.
29    #[inline]
30    pub fn id(self) -> u32 {
31        self.0 as u32
32    }
33
34    /// Entity'nin generation (nesil) sayacını döndürür.
35    #[inline]
36    pub fn generation(self) -> u32 {
37        (self.0 >> 32) as u32
38    }
39
40    /// Bu entity'nin geçerli (INVALID olmayan) olup olmadığını kontrol eder.
41    #[inline]
42    pub fn is_valid(self) -> bool {
43        self != Self::INVALID
44    }
45
46    /// Entity'yi ham u64 bit temsiline dönüştürür.
47    /// Serializasyon, network sync ve hash key olarak kullanılabilir.
48    #[inline]
49    pub fn to_bits(self) -> u64 {
50        self.0
51    }
52
53    /// Ham u64 bit temsilinden Entity oluşturur.
54    #[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); // Aynı ID, farklı generation
131
132        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; // Copy
145        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;