tuix_core/state/
entity.rs1use std::cmp::{Eq, PartialEq};
2use std::collections::VecDeque;
3use std::hash::Hash;
4
5const ENTITY_INDEX_BITS: u32 = 24;
6const ENTITY_INDEX_MASK: u32 = (1<<ENTITY_INDEX_BITS)-1;
7
8const ENTITY_GENERATION_BITS: u32 = 8;
9const ENTITY_GENERATION_MASK: u32 = (1<<ENTITY_GENERATION_BITS)-1;
10
11const ENTITY_MAX: u32 = std::u32::MAX>>8;
12
13const MINIMUM_FREE_INDICES: usize = 1024;
14
15
16#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
20pub struct Entity(u32);
21
22impl Default for Entity {
23 fn default() -> Self {
24 Entity::null()
25 }
26}
27
28impl std::fmt::Display for Entity {
29 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
30 write!(f, "{}", self.index_unchecked())
31 }
32}
33
34impl Entity {
35 pub fn null() -> Entity {
39 Entity(std::u32::MAX)
40 }
41
42 pub fn root() -> Entity {
48 Entity(0)
49 }
50
51 pub(crate) fn new(index: u32, generation: u32) -> Entity {
53 Entity(index | generation << ENTITY_INDEX_BITS)
54 }
55
56 pub fn is_null(&self) -> bool {
58 self.0 == std::u32::MAX
59 }
60
61 pub fn index(&self) -> Option<usize> {
63 if self.0 < std::u32::MAX {
64 Some((self.0 & ENTITY_INDEX_MASK) as usize)
65 } else {
66 None
67 }
68 }
69
70 pub fn generation(&self) -> Option<u8> {
72 if self.0 < std::u32::MAX {
73 Some(((self.0 >> ENTITY_INDEX_BITS) & ENTITY_GENERATION_MASK) as u8)
74 } else {
75 None
76 }
77 }
78
79 pub(crate) fn index_unchecked(&self) -> usize {
80 (self.0 & ENTITY_INDEX_MASK) as usize
81 }
82
83
84}
85
86pub(crate) struct EntityManager {
88 count: u32,
89 generation: Vec<u8>,
90 free_list: VecDeque<u32>,
91}
92
93impl EntityManager {
94 pub fn new() -> EntityManager {
95 EntityManager {
96 count: 0,
97 generation: Vec::new(),
98 free_list: VecDeque::with_capacity(MINIMUM_FREE_INDICES),
99 }
100 }
101
102 pub(crate) fn create_entity(&mut self) -> Option<Entity> {
104 let index = if self.free_list.len() > MINIMUM_FREE_INDICES {
105 self.free_list.pop_front()
106 } else {
107 self.generation.push(0);
108 let idx = (self.generation.len() - 1) as u32;
109 assert!((idx as u32) < ENTITY_MAX, "Entity index exceeds maximum allowed value");
110 Some(idx)
111 };
112
113 index.map(|idx| Entity::new(idx, self.generation[idx as usize] as u32))
115 }
116
117 pub fn is_alive(&self, entity: Entity) -> bool {
119 self.generation[entity.index_unchecked()] == entity.generation().unwrap()
120 }
121
122 pub fn destroy_entity(&mut self, entity: Entity) {
124 let index = entity.index_unchecked() as u32;
125 assert!(self.generation[index as usize] <= std::u8::MAX, "Entity generation exceeds maximum allowed value");
126 self.generation[index as usize] += 1;
127 self.free_list.push_back(index);
128 }
129}
130
131pub trait AsEntity {
132 fn entity(&self) -> Entity;
133}
134
135impl AsEntity for Entity {
136 fn entity(&self) -> Entity {
137 *self
138 }
139}
140
141impl AsEntity for (Entity, Entity) {
142 fn entity(&self) -> Entity {
143 self.0
144 }
145}
146
147impl AsEntity for (Entity, Entity, Entity) {
148 fn entity(&self) -> Entity {
149 self.0
150 }
151}
152
153impl AsEntity for (Entity, Entity, Entity, Entity) {
154 fn entity(&self) -> Entity {
155 self.0
156 }
157}
158
159impl AsEntity for (Entity, Entity, Entity, Entity, Entity) {
160 fn entity(&self) -> Entity {
161 self.0
162 }
163}
164
165#[cfg(test)]
166mod tests {
167 use super::*;
168 #[test]
169 fn create() {
170 let entity = Entity::new(42, 69);
171 assert_eq!(entity.index(), Some(42));
172 assert_eq!(entity.generation(), Some(69));
173 }
174}