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}