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//! // Create new ecs instance and inserts new entity:
9//!
10//! let mut ecs = ecs_tiny::ECS::new();
11//! 
12//! let entity_key0 = ecs.insert_entity();
13//! let entity_key1 = ecs.insert_entity();
14//!
15//! // Register new component type:
16//!
17//! ecs.register::<i32>().unwrap();
18//! ecs.register::<()>().unwrap();
19//!
20//! // Inserts new component associated with specified entity:
21//! 
22//! let comp_key0 = ecs.insert_comp(entity_key0, 42).unwrap();
23//! let comp_key1 = ecs.insert_comp(entity_key0, 63).unwrap();
24//! let comp_key2 = ecs.insert_comp(entity_key1, 42).unwrap();
25//! let comp_key3 = ecs.insert_comp(entity_key1, ()).unwrap();
26//! 
27//! // Iterates over all components associated with specified entity:
28//! 
29//! for comp in ecs.iter_comp_mut_by_entity::<i32>(entity_key0).unwrap() {
30//!     *comp += 1;
31//! }
32//! 
33//! // Iterates over all components of specified type (single type only):
34//! 
35//! for comp in ecs.iter_comp_mut::<i32>().unwrap() {
36//!     *comp += 1;
37//! }
38//! 
39//! // Removes specified component:
40//! 
41//! ecs.remove_comp::<i32>(comp_key0).unwrap();
42//! 
43//! // Removes specified entity:
44//! 
45//! ecs.remove_entity(entity_key1).unwrap();
46//! ```
47
48type EntityKey = u32;
49
50type CompKey = (std::any::TypeId, u32);
51
52struct CompRow<T> {
53    comp: T,
54    entity_key: u32,
55    ref_0_row_key: u32,
56    ref_1_row_key: u32,
57}
58
59const ALLOC_SIZE: usize = std::mem::size_of::<slab::Slab<CompRow<()>>>();
60
61struct CompColumn {
62    comp_rows: stack_any::StackAny<ALLOC_SIZE>,
63    get_row_fn: fn(&Self, u32) -> Option<CompRow<()>>,
64    remove_row_fn: fn(&mut Self, u32) -> Option<CompRow<()>>,
65}
66
67/// A minimal ECS supporting entity and component insertion/removal, association, and single-type iteration.
68///
69/// # Examples
70///
71/// ```
72/// let mut ecs = ecs_tiny::ECS::new();
73///
74/// let entity_key = ecs.insert_entity();
75///
76/// ecs.register::<i32>().unwrap();
77///
78/// let comp_key0 = ecs.insert_comp(entity_key, 42).unwrap();
79/// let comp_key1 = ecs.insert_comp(entity_key, 63).unwrap();
80///
81/// for comp in ecs.iter_comp_mut::<i32>().unwrap() {
82///     *comp += 1;
83/// }
84/// ```
85#[derive(Default)]
86pub struct ECS {
87    entities: slab::Slab<()>,
88    comp_cols: ahash::AHashMap<std::any::TypeId, CompColumn>,
89    ref_0_cols: ahash::AHashMap<EntityKey, slab::Slab<(std::any::TypeId, u32)>>,
90    ref_1_cols: ahash::AHashMap<(EntityKey, std::any::TypeId), slab::Slab<u32>>,
91}
92
93impl ECS {
94    /// Create a new ECS instance.
95    ///
96    /// # Examples
97    ///
98    /// ```
99    /// let mut ecs = ecs_tiny::ECS::new();
100    /// ```
101    pub fn new() -> Self {
102        Default::default()
103    }
104
105    /// Insert a new entity and return the corresponding entity key.
106    ///
107    /// # Examples
108    ///
109    /// ```
110    /// let mut ecs = ecs_tiny::ECS::new();
111    /// let entity_key = ecs.insert_entity();
112    /// ```
113    pub fn insert_entity(&mut self) -> EntityKey {
114        self.entities.insert(()) as u32
115    }
116
117    /// Remove an entity with the corresponding entity key.
118    /// If the entity corresponding to the entity key is not found, return an `None`.
119    /// Otherwise, return an `Some(())`.
120    ///
121    /// # Examples
122    ///
123    /// ```
124    /// let mut ecs = ecs_tiny::ECS::new();
125    /// let entity_key = ecs.insert_entity();
126    /// ecs.remove_entity(entity_key).unwrap();
127    /// ```
128    pub fn remove_entity(&mut self, entity_key: EntityKey) -> Option<()> {
129        self.entities.try_remove(entity_key as usize)?;
130
131        if let Some(ref_0_col) = self.ref_0_cols.remove(&entity_key) {
132            for (_, (type_key, row_key)) in ref_0_col {
133                let comp_col = self.comp_cols.get_mut(&type_key).unwrap();
134                let comp_row = (comp_col.remove_row_fn)(comp_col, row_key).unwrap();
135
136                self.ref_1_cols
137                    .get_mut(&(entity_key, type_key))
138                    .unwrap()
139                    .try_remove(comp_row.ref_1_row_key as usize)
140                    .unwrap();
141            }
142        }
143
144        Some(())
145    }
146
147    /// Return entity with the corresponding entity key.
148    /// If the entity corresponding to the entity key is not found, return an `None`.
149    /// Otherwise, return an `Some(())`.
150    ///
151    /// # Examples
152    ///
153    /// ```
154    /// let mut ecs = ecs_tiny::ECS::new();
155    /// let entity_key = ecs.insert_entity();
156    /// ecs.get_entity(entity_key).unwrap();
157    /// ```
158    pub fn get_entity(&self, entity_key: EntityKey) -> Option<()> {
159        self.entities.get(entity_key as usize)?;
160        Some(())
161    }
162
163    /// Return an iterator over all entity keys.
164    ///
165    /// # Examples
166    ///
167    /// ```
168    /// let mut ecs = ecs_tiny::ECS::new();
169    /// let entity_key0 = ecs.insert_entity();
170    /// let entity_key1 = ecs.insert_entity();
171    /// let entity_key2 = ecs.insert_entity();
172    /// let mut iter = ecs.iter_entity();
173    ///
174    /// assert_eq!(iter.next(), Some(entity_key0));
175    /// assert_eq!(iter.next(), Some(entity_key1));
176    /// assert_eq!(iter.next(), Some(entity_key2));
177    /// assert_eq!(iter.next(), None);
178    /// ```
179    pub fn iter_entity(&self) -> impl Iterator<Item = EntityKey> + '_ {
180        self.entities.iter().map(|(key, _)| key as u32)
181    }
182
183    /// Register component type.
184    ///
185    /// # Examples
186    ///
187    /// ```
188    /// let mut ecs = ecs_tiny::ECS::new();
189    /// let entity_key = ecs.insert_entity();
190    /// ecs.register::<i32>().unwrap();
191    /// let comp_key = ecs.insert_comp(entity_key, 42).unwrap();
192    /// ```
193    pub fn register<T>(&mut self) -> Option<()>
194    where
195        T: std::any::Any,
196    {
197        let type_key = std::any::TypeId::of::<T>();
198
199        if self.comp_cols.contains_key(&type_key) {
200            return None;
201        }
202
203        let comp_col = CompColumn {
204            comp_rows: stack_any::StackAny::try_new(slab::Slab::<CompRow<T>>::new()).unwrap(),
205            get_row_fn: |comp_col, row_key| {
206                let comp_row = comp_col
207                    .comp_rows
208                    .downcast_ref::<slab::Slab<CompRow<T>>>()
209                    .unwrap()
210                    .get(row_key as usize)?;
211                Some(CompRow {
212                    comp: (),
213                    entity_key: comp_row.entity_key,
214                    ref_0_row_key: comp_row.ref_0_row_key,
215                    ref_1_row_key: comp_row.ref_1_row_key,
216                })
217            },
218            remove_row_fn: |comp_col, row_key| {
219                let comp_row = comp_col
220                    .comp_rows
221                    .downcast_mut::<slab::Slab<CompRow<T>>>()
222                    .unwrap()
223                    .try_remove(row_key as usize)?;
224                Some(CompRow {
225                    comp: (),
226                    entity_key: comp_row.entity_key,
227                    ref_0_row_key: comp_row.ref_0_row_key,
228                    ref_1_row_key: comp_row.ref_1_row_key,
229                })
230            },
231        };
232        self.comp_cols.insert(type_key, comp_col);
233
234        Some(())
235    }
236
237    /// Unregister component type.
238    ///
239    /// # Examples
240    ///
241    /// ```
242    /// let mut ecs = ecs_tiny::ECS::new();
243    /// let entity_key = ecs.insert_entity();
244    /// ecs.register::<i32>().unwrap();
245    /// let comp_key = ecs.insert_comp(entity_key, 42).unwrap();
246    /// ecs.unregister::<i32>().unwrap();
247    /// ```
248    pub fn unregister<T>(&mut self) -> Option<()>
249    where
250        T: std::any::Any,
251    {
252        let type_key = std::any::TypeId::of::<T>();
253
254        if !self.comp_cols.contains_key(&type_key) {
255            return None;
256        }
257
258        self.comp_cols.remove(&type_key);
259
260        Some(())
261    }
262
263    /// Insert a new component with the corresponding entity key and return the corresponding component key.
264    /// If the entity corresponding to the entity key is not found, return an `None`.
265    /// Otherwise, return an `Some(CompKey)`.
266    ///
267    /// # Examples
268    ///
269    /// ```
270    /// let mut ecs = ecs_tiny::ECS::new();
271    /// let entity_key = ecs.insert_entity();
272    /// ecs.register::<i32>().unwrap();
273    /// let comp_key = ecs.insert_comp(entity_key, 42).unwrap();
274    /// ```
275    pub fn insert_comp<T>(&mut self, entity_key: EntityKey, comp: T) -> Option<CompKey>
276    where
277        T: std::any::Any,
278    {
279        self.entities.get(entity_key as usize)?;
280
281        let type_key = std::any::TypeId::of::<T>();
282
283        let comp_rows = self
284            .comp_cols
285            .get_mut(&type_key)?
286            .comp_rows
287            .downcast_mut::<slab::Slab<CompRow<T>>>()
288            .unwrap();
289
290        let row_key = comp_rows.vacant_key() as u32;
291
292        let ref_0_row_key = self
293            .ref_0_cols
294            .entry(entity_key)
295            .or_default()
296            .insert((type_key, row_key)) as u32;
297
298        let ref_1_row_key = self
299            .ref_1_cols
300            .entry((entity_key, type_key))
301            .or_default()
302            .insert(row_key) as u32;
303
304        comp_rows.insert(CompRow {
305            comp,
306            entity_key,
307            ref_0_row_key,
308            ref_1_row_key,
309        });
310
311        Some((type_key, row_key))
312    }
313
314    /// Remove a component with the corresponding component key and type, and return the component.
315    /// If the component corresponding to the component key and type is not found, return an `None`.
316    /// Otherwise, return an `Some(T)`.
317    ///
318    /// # Examples
319    ///
320    /// ```
321    /// let mut ecs = ecs_tiny::ECS::new();
322    /// let entity_key = ecs.insert_entity();
323    /// ecs.register::<i32>().unwrap();
324    /// let comp_key = ecs.insert_comp(entity_key, 42).unwrap();
325    /// let comp = ecs.remove_comp::<i32>(comp_key).unwrap();
326    ///
327    /// assert_eq!(comp, 42);
328    /// ```
329    pub fn remove_comp<T>(&mut self, comp_key: CompKey) -> Option<T>
330    where
331        T: std::any::Any,
332    {
333        let (type_key, row_key) = comp_key;
334
335        if type_key != std::any::TypeId::of::<T>() {
336            return None;
337        }
338
339        let comp_rows = self
340            .comp_cols
341            .get_mut(&type_key)?
342            .comp_rows
343            .downcast_mut::<slab::Slab<CompRow<T>>>()
344            .unwrap();
345        let comp_row = comp_rows.try_remove(row_key as usize)?;
346
347        self.ref_0_cols
348            .get_mut(&comp_row.entity_key)
349            .unwrap()
350            .try_remove(comp_row.ref_0_row_key as usize)
351            .unwrap();
352
353        self.ref_1_cols
354            .get_mut(&(comp_row.entity_key, type_key))
355            .unwrap()
356            .try_remove(comp_row.ref_1_row_key as usize)
357            .unwrap();
358
359        Some(comp_row.comp)
360    }
361
362    /// Return a component with the corresponding component key and type.
363    /// If the component corresponding to the component key and type is not found, return an `None`.
364    /// Otherwise, return an `Some(&T)`.
365    ///
366    /// # Examples
367    ///
368    /// ```
369    /// let mut ecs = ecs_tiny::ECS::new();
370    /// let entity_key = ecs.insert_entity();
371    /// ecs.register::<i32>().unwrap();
372    /// let comp_key = ecs.insert_comp(entity_key, 42).unwrap();
373    /// let comp = ecs.get_comp::<i32>(comp_key).unwrap();
374    ///
375    /// assert_eq!(comp, &42);
376    /// ```
377    pub fn get_comp<T>(&self, comp_key: CompKey) -> Option<&T>
378    where
379        T: std::any::Any,
380    {
381        let (type_key, row_key) = comp_key;
382
383        if type_key != std::any::TypeId::of::<T>() {
384            return None;
385        }
386
387        let comp_rows = self
388            .comp_cols
389            .get(&type_key)?
390            .comp_rows
391            .downcast_ref::<slab::Slab<CompRow<T>>>()
392            .unwrap();
393        let comp_row = comp_rows.get(row_key as usize)?;
394
395        Some(&comp_row.comp)
396    }
397
398    /// Return a mutable component with the corresponding component key and type.
399    /// If the component corresponding to the component key and type is not found, return an `None`.
400    /// Otherwise, return an `Some(&mut T)`.
401    ///
402    /// # Examples
403    ///
404    /// ```
405    /// let mut ecs = ecs_tiny::ECS::new();
406    /// let entity_key = ecs.insert_entity();
407    /// ecs.register::<i32>().unwrap();
408    /// let comp_key = ecs.insert_comp(entity_key, 42).unwrap();
409    /// let comp = ecs.get_comp_mut::<i32>(comp_key).unwrap();
410    ///
411    /// assert_eq!(comp, &mut 42);
412    /// ```
413    pub fn get_comp_mut<T>(&mut self, comp_key: CompKey) -> Option<&mut T>
414    where
415        T: std::any::Any,
416    {
417        let (type_key, row_key) = comp_key;
418
419        if type_key != std::any::TypeId::of::<T>() {
420            return None;
421        }
422
423        let comp_rows = self
424            .comp_cols
425            .get_mut(&type_key)?
426            .comp_rows
427            .downcast_mut::<slab::Slab<CompRow<T>>>()
428            .unwrap();
429        let comp = comp_rows.get_mut(row_key as usize)?;
430
431        Some(&mut comp.comp)
432    }
433
434    /// Return an iterator over all components of the corresponding type.
435    /// If the component type is not found, return an `None`.
436    /// Otherwise, return an `Some(impl Iterator<Item = &T>)`.
437    ///
438    /// # Examples
439    ///
440    /// ```
441    /// let mut ecs = ecs_tiny::ECS::new();
442    /// let entity_key0 = ecs.insert_entity();
443    /// let entity_key1 = ecs.insert_entity();
444    /// ecs.register::<i32>().unwrap();
445    /// ecs.insert_comp(entity_key0, 42).unwrap();
446    /// ecs.insert_comp(entity_key0, 63).unwrap();
447    /// ecs.insert_comp(entity_key1, 42).unwrap();
448    /// let mut iter = ecs.iter_comp::<i32>().unwrap();
449    ///
450    /// assert_eq!(iter.next(), Some(&42));
451    /// assert_eq!(iter.next(), Some(&63));
452    /// assert_eq!(iter.next(), Some(&42));
453    /// assert_eq!(iter.next(), None);
454    /// ```
455    pub fn iter_comp<T>(&self) -> Option<impl Iterator<Item = &T>>
456    where
457        T: std::any::Any,
458    {
459        let type_key = std::any::TypeId::of::<T>();
460
461        let comp_rows = self
462            .comp_cols
463            .get(&type_key)?
464            .comp_rows
465            .downcast_ref::<slab::Slab<CompRow<T>>>()
466            .unwrap();
467        let iter = comp_rows.iter().map(|(_, comp_row)| &comp_row.comp);
468
469        Some(iter)
470    }
471
472    /// Return a mutable iterator over all components of the corresponding type.
473    /// If the component type is not found, return an `None`.
474    /// Otherwise, return an `Some(impl Iterator<Item = &mut T>)`.
475    ///
476    /// # Examples
477    ///
478    /// ```
479    /// let mut ecs = ecs_tiny::ECS::new();
480    /// let entity_key0 = ecs.insert_entity();
481    /// let entity_key1 = ecs.insert_entity();
482    /// ecs.register::<i32>().unwrap();
483    /// ecs.insert_comp(entity_key0, 42).unwrap();
484    /// ecs.insert_comp(entity_key0, 63).unwrap();
485    /// ecs.insert_comp(entity_key1, 42).unwrap();
486    /// let mut iter = ecs.iter_comp_mut::<i32>().unwrap();
487    ///
488    /// assert_eq!(iter.next(), Some(&mut 42));
489    /// assert_eq!(iter.next(), Some(&mut 63));
490    /// assert_eq!(iter.next(), Some(&mut 42));
491    /// assert_eq!(iter.next(), None);
492    /// ```
493    pub fn iter_comp_mut<T>(&mut self) -> Option<impl Iterator<Item = &mut T>>
494    where
495        T: std::any::Any,
496    {
497        let type_key = std::any::TypeId::of::<T>();
498
499        let comp_rows = self
500            .comp_cols
501            .get_mut(&type_key)?
502            .comp_rows
503            .downcast_mut::<slab::Slab<CompRow<T>>>()
504            .unwrap();
505        let iter = comp_rows.iter_mut().map(|(_, comp_row)| &mut comp_row.comp);
506
507        Some(iter)
508    }
509
510    /// Return an entity key with the corresponding component key.
511    /// If the component corresponding to the component key is not found, return an `None`.
512    /// Otherwise, return an `Some(EntityKey)`.
513    ///
514    /// # Examples
515    ///
516    /// ```
517    /// let mut ecs = ecs_tiny::ECS::new();
518    /// let entity_key0 = ecs.insert_entity();
519    /// let entity_key1 = ecs.insert_entity();
520    /// ecs.register::<i32>().unwrap();
521    /// let comp_key0 = ecs.insert_comp(entity_key0, 42).unwrap();
522    /// let comp_key1 = ecs.insert_comp(entity_key0, 63).unwrap();
523    /// let comp_key2 = ecs.insert_comp(entity_key1, 42).unwrap();
524    /// let entity_key = ecs.get_entity_by_comp(comp_key0).unwrap();
525    ///
526    /// assert_eq!(entity_key, entity_key0);
527    /// ```
528    pub fn get_entity_by_comp(&self, comp_key: CompKey) -> Option<EntityKey> {
529        let (type_key, row_key) = comp_key;
530
531        let comp_col = self.comp_cols.get(&type_key)?;
532        let comp_row = (comp_col.get_row_fn)(comp_col, row_key)?;
533
534        Some(comp_row.entity_key)
535    }
536
537    /// Return an iterator over all components with the corresponding entity key and type.
538    /// If the entity corresponding to the entity key and type is not found, return an `None`.
539    /// Otherwise, return an `Some(impl Iterator<Item = &T>)`.
540    ///
541    /// # Examples
542    ///
543    /// ```
544    /// let mut ecs = ecs_tiny::ECS::new();
545    /// let entity_key0 = ecs.insert_entity();
546    /// let entity_key1 = ecs.insert_entity();
547    /// ecs.register::<i32>().unwrap();
548    /// ecs.insert_comp(entity_key0, 42).unwrap();
549    /// ecs.insert_comp(entity_key0, 63).unwrap();
550    /// ecs.insert_comp(entity_key1, 42).unwrap();
551    /// let mut iter = ecs.iter_comp_by_entity::<i32>(entity_key0).unwrap();
552    ///
553    /// assert_eq!(iter.next(), Some(&42));
554    /// assert_eq!(iter.next(), Some(&63));
555    /// assert_eq!(iter.next(), None);
556    /// ```
557    pub fn iter_comp_by_entity<T>(&self, entity_key: EntityKey) -> Option<impl Iterator<Item = &T>>
558    where
559        T: std::any::Any,
560    {
561        let type_key = std::any::TypeId::of::<T>();
562
563        let comp_rows = self
564            .comp_cols
565            .get(&type_key)?
566            .comp_rows
567            .downcast_ref::<slab::Slab<CompRow<T>>>()
568            .unwrap();
569
570        let ref_1_col = self.ref_1_cols.get(&(entity_key, type_key))?;
571
572        let iter = ref_1_col
573            .iter()
574            .map(|(_, row_key)| &comp_rows.get(*row_key as usize).unwrap().comp);
575
576        Some(iter)
577    }
578
579    /// Return a mutable iterator over all components with the corresponding entity key and type.
580    /// If the entity corresponding to the entity key and type is not found, return an `None`.
581    /// Otherwise, return an `None(impl Iterator<Item = &mut T>)`.
582    ///
583    /// # Examples
584    ///
585    /// ```
586    /// let mut ecs = ecs_tiny::ECS::new();
587    /// let entity_key0 = ecs.insert_entity();
588    /// let entity_key1 = ecs.insert_entity();
589    /// ecs.register::<i32>().unwrap();
590    /// ecs.insert_comp(entity_key0, 42).unwrap();
591    /// ecs.insert_comp(entity_key0, 63).unwrap();
592    /// ecs.insert_comp(entity_key1, 42).unwrap();
593    /// let mut iter = ecs.iter_comp_mut_by_entity::<i32>(entity_key0).unwrap();
594    ///
595    /// assert_eq!(iter.next(), Some(&mut 42));
596    /// assert_eq!(iter.next(), Some(&mut 63));
597    /// assert_eq!(iter.next(), None);
598    /// ```
599    pub fn iter_comp_mut_by_entity<T>(
600        &mut self,
601        entity_key: EntityKey,
602    ) -> Option<impl Iterator<Item = &mut T>>
603    where
604        T: std::any::Any,
605    {
606        let type_key = std::any::TypeId::of::<T>();
607
608        let comp_rows = self
609            .comp_cols
610            .get_mut(&type_key)?
611            .comp_rows
612            .downcast_mut::<slab::Slab<CompRow<T>>>()
613            .unwrap();
614
615        let ref_1_col = self.ref_1_cols.get(&(entity_key, type_key))?;
616
617        // UNSAFE: allow double mutable borrow temporarily
618        let iter = ref_1_col
619            .iter()
620            .map(|(_, row_key)| &mut comp_rows.get_mut(*row_key as usize).unwrap().comp as *mut T)
621            .map(|ptr| unsafe { &mut *ptr });
622
623        Some(iter)
624    }
625
626    /// Clear all entities and components.
627    ///
628    /// # Examples
629    ///
630    /// ```
631    /// let mut ecs = ecs_tiny::ECS::new();
632    /// let entity_key = ecs.insert_entity();
633    /// ecs.register::<i32>().unwrap();
634    /// let comp_key = ecs.insert_comp(entity_key, 42).unwrap();
635    /// ecs.clear();
636    /// ```
637    pub fn clear(&mut self) {
638        self.entities.clear();
639        self.comp_cols.clear();
640        self.ref_0_cols.clear();
641        self.ref_1_cols.clear();
642    }
643}