Skip to main content

ecs_tiny/
lib.rs

1//! # ecs-tiny
2//! 
3//! A minimal ECS supporting entity and component insertion/removal, association, and single-type iteration.
4//!
5//! # Usages
6//! 
7//! ```
8//! // Define an component:
9//!
10//! #[repr(C)]
11//! #[derive(Debug, Clone, Copy, PartialEq, Eq, bytemuck::Pod, bytemuck::Zeroable)]
12//! pub struct ComponentA(i32);
13//! impl ecs_tiny::Component for ComponentA {}
14//!
15//! // Create new ecs instance and inserts new entity:
16//!
17//! let mut world = ecs_tiny::World::new();
18//! 
19//! let entity_key0 = world.insert_entity();
20//! let entity_key1 = world.insert_entity();
21//!
22//! // Inserts new component associated with specified entity:
23//! 
24//! assert_eq!(world.insert_component(entity_key0, ComponentA(42)), Some(()));
25//! assert_eq!(world.insert_component(entity_key1, ComponentA(63)), Some(()));
26//! 
27//! // Iterates over all components of specified type (single type only):
28//! 
29//! for ComponentA(value) in world.iter_component_mut::<ComponentA>() {
30//!     *value += 1;
31//! }
32//! 
33//! // Removes specified component:
34//! 
35//! world.remove_component::<ComponentA>(entity_key0).unwrap();
36//! 
37//! // Removes specified entity:
38//! 
39//! world.remove_entity(entity_key1).unwrap();
40//! ```
41
42mod util;
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq)]
45pub struct EntityKey(usize);
46
47pub trait Component: bytemuck::Pod {}
48
49#[derive(Debug)]
50struct ComponentColumn {
51    sparse: util::SparseIndex<256>,
52    dense: util::BlobStorage,
53    rev: Vec<usize>,
54}
55
56impl ComponentColumn {
57    #[inline]
58    fn new<T>() -> Self where T: Component {
59        Self {
60            sparse: Default::default(),
61            dense: util::BlobStorage::new::<T>(),
62            rev: Default::default(),
63        }
64    }
65
66    fn insert<T>(&mut self, entity_key: usize, comp: T) -> Option<T> where T: Component {
67        if let Some(index) = self.sparse.get(entity_key) {
68            let target = self.dense.get_mut::<T>(*index).unwrap();
69            let old = std::mem::replace(target, comp);
70            return Some(old);
71        }
72
73        let index = self.dense.len();
74        self.dense.push(comp);
75        self.rev.push(entity_key);
76        self.sparse.insert(entity_key, index);
77        None
78    }
79
80    fn remove(&mut self, entity_key: usize) -> Option<()> {
81        let index = self.sparse.remove(entity_key)?;
82        self.dense.swap_remove(index);
83        self.rev.swap_remove(index);
84
85        if let Some(entity_key) = self.rev.get(index) {
86            let target = self.sparse.get_mut(*entity_key).unwrap();
87            *target = index;
88        }
89        Some(())
90    }
91
92    #[inline]
93    fn get<T>(&self, entity_key: usize) -> Option<&T> where T: Component {
94        let index = *self.sparse.get(entity_key)?;
95        let component = self.dense.get(index).unwrap();
96        Some(component)
97    }
98
99    #[inline]
100    fn get_mut<T>(&mut self, entity_key: usize) -> Option<&mut T> where T: Component {
101        let index = *self.sparse.get(entity_key)?;
102        let component = self.dense.get_mut(index).unwrap();
103        Some(component)
104    }
105
106    #[inline]
107    fn iter<T>(&self) -> impl Iterator<Item = &T> where T: Component {
108        self.dense.iter()
109    }
110
111    #[inline]
112    fn iter_mut<T>(&mut self) -> impl Iterator<Item = &mut T> where T: Component {
113        self.dense.iter_mut()
114    }
115}
116
117/// A minimal ECS supporting entity and component insertion/removal, association, and single-type iteration.
118#[derive(Debug, Default)]
119pub struct World {
120    entities: slab::Slab<()>,
121    component_table: util::IndexMap<std::any::TypeId, ComponentColumn>,
122}
123
124impl World {
125    /// Create a new ECS instance.
126    #[inline]
127    pub fn new() -> Self {
128        Default::default()
129    }
130
131    /// Insert a new entity and return the corresponding entity key.
132    pub fn insert_entity(&mut self) -> EntityKey {
133        let entity_key = self.entities.insert(());
134        EntityKey(entity_key)
135    }
136
137    /// Remove an entity with the corresponding entity key.
138    /// If the entity corresponding to the entity key is not found, return an `None`.
139    /// Otherwise, return an `Some(())`.
140    pub fn remove_entity(&mut self, entity_key: EntityKey) -> Option<()> {
141        let EntityKey(entity_key) = entity_key;
142        self.entities.try_remove(entity_key)?;
143
144        for component_column in self.component_table.iter_mut() {
145            component_column.remove(entity_key);
146        }
147
148        Some(())
149    }
150
151    /// Return entity with the corresponding entity key.
152    /// If the entity corresponding to the entity key is not found, return an `None`.
153    /// Otherwise, return an `Some(())`.
154    #[inline]
155    pub fn contains_entity(&self, entity_key: EntityKey) -> bool {
156        let EntityKey(entity_key) = entity_key;
157        self.entities.get(entity_key).is_some()
158    }
159
160    /// Return an iterator over all entity keys.
161    #[inline]
162    pub fn iter_entity(&self) -> impl Iterator<Item = EntityKey> + '_ {
163        self.entities.iter().map(|(entity_key, _)| EntityKey(entity_key))
164    }
165
166    /// Insert a new component with the corresponding entity key and return the corresponding component key.
167    /// If the entity corresponding to the entity key is not found, return an `None`.
168    /// Otherwise, return an `Some(CompKey)`.
169    pub fn insert_component<T>(&mut self, entity_key: EntityKey, component: T) -> Option<()> where T: Component {
170        let EntityKey(entity_key) = entity_key;
171        self.entities.get(entity_key)?;
172
173        let type_key = std::any::TypeId::of::<T>();
174        if !self.component_table.contains_key(&type_key) {
175            self.component_table.insert(type_key, ComponentColumn::new::<T>());
176        }
177        let component_column = self.component_table.get_mut(&type_key).unwrap();
178        component_column.insert(entity_key, component);
179        Some(())
180    }
181
182    /// Remove a component with the corresponding component key and type, and return the component.
183    /// If the component corresponding to the component key and type is not found, return an `None`.
184    /// Otherwise, return an `Some(())`.
185    pub fn remove_component<T>(&mut self, entity_key: EntityKey) -> Option<()> where T: Component {
186        let EntityKey(entity_key) = entity_key;
187        self.entities.get(entity_key)?;
188
189        let type_key = std::any::TypeId::of::<T>();
190        let component_column = self.component_table.get_mut(&type_key)?;
191        component_column.remove(entity_key)?;
192        Some(())
193    }
194
195    /// Return a component with the corresponding component key and type.
196    /// If the component corresponding to the component key and type is not found, return an `None`.
197    /// Otherwise, return an `Some(&T)`.
198    #[inline]
199    pub fn get_component<T>(&self, entity_key: EntityKey) -> Option<&T> where T: Component {
200        let EntityKey(entity_key) = entity_key;
201        self.entities.get(entity_key)?;
202
203        let type_key = std::any::TypeId::of::<T>();
204        let component_column = self.component_table.get(&type_key)?;
205        let component = component_column.get(entity_key)?;
206        Some(component)
207    }
208
209    /// Return a mutable component with the corresponding component key and type.
210    /// If the component corresponding to the component key and type is not found, return an `None`.
211    /// Otherwise, return an `Some(&mut T)`.
212    #[inline]
213    pub fn get_component_mut<T>(&mut self, entity_key: EntityKey) -> Option<&mut T> where T: Component {
214        let EntityKey(entity_key) = entity_key;
215        self.entities.get(entity_key)?;
216
217        let type_key = std::any::TypeId::of::<T>();
218        let component_column = self.component_table.get_mut(&type_key)?;
219        let component = component_column.get_mut(entity_key)?;
220        Some(component)
221    }
222
223    /// Return an iterator over all components of the corresponding type.
224    /// If the component type is not found, return an `None`.
225    /// Otherwise, return an `Some(impl Iterator<Item = &T>)`.
226    #[inline]
227    pub fn iter_component<T>(&self) -> impl Iterator<Item = &T> where T: Component {
228        let type_key = std::any::TypeId::of::<T>();
229        if let Some(component_column) = self.component_table.get(&type_key) {
230            return either::Left(component_column.iter());
231        }
232        either::Right(std::iter::empty())
233    }
234
235    /// Return a mutable iterator over all components of the corresponding type.
236    /// If the component type is not found, return an `None`.
237    /// Otherwise, return an `Some(impl Iterator<Item = &mut T>)`.
238    #[inline]
239    pub fn iter_component_mut<T>(&mut self) -> impl Iterator<Item = &mut T> where T: Component {
240        let type_key = std::any::TypeId::of::<T>();
241        if let Some(component_column) = self.component_table.get_mut(&type_key) {
242            return either::Left(component_column.iter_mut());
243        }
244        either::Right(std::iter::empty())
245    }
246}