unlit_ecs/column.rs
1//! Component storage.
2//!
3//! Every component value lives in its own [`UnsafeCell`], so a component can be
4//! read or written through a shared `&World`. Aliasing is policed by the borrow
5//! ledger instead of by the compiler: an access path claims what it is about to
6//! reach before it hands out a reference, and the claim is released when it goes
7//! away. See [`crate::borrow`].
8//!
9//! The world is therefore `!Send` and stays on the thread that created it, which
10//! is where a renderer and its other thread-bound state live.
11//!
12//! Structural changes (spawning and despawning) still need `&mut World`, so a
13//! claimed row can never be moved around while it is borrowed.
14
15use core::any::Any;
16use core::cell::UnsafeCell;
17
18/// A type-erased component column: one component type's values in one
19/// archetype.
20///
21/// A value that moves between archetypes travels in a `Box<dyn Any>` holding
22/// the component value itself, so moving a row never needs to know the
23/// component type. Reads and writes do not go through this interface; they use
24/// the concrete [`Column`].
25pub trait AnyColumn: 'static {
26 /// Downcast support.
27 fn as_any(&self) -> &dyn Any;
28 /// Downcast support for a column reached exclusively.
29 fn as_any_mut(&mut self) -> &mut dyn Any;
30 /// Move the value at `row` out, filling the hole with the last value.
31 fn swap_remove(&mut self, row: usize) -> Box<dyn Any>;
32 /// Append an already erased value of this column's component type.
33 fn push_boxed(&mut self, value: Box<dyn Any>);
34}
35
36/// One component type's values inside one archetype.
37///
38/// Each value sits in its own cell, so a query may hold the components of two
39/// entities at once. A row's cell index is the row number and never changes
40/// while the row exists.
41pub struct Column<T: 'static> {
42 cells: Vec<UnsafeCell<T>>,
43}
44
45impl<T: 'static> Column<T> {
46 /// An empty column.
47 pub(crate) fn new() -> Self {
48 Self { cells: Vec::new() }
49 }
50
51 /// A function that builds an empty column of this component type.
52 pub(crate) fn eraser() -> fn() -> Box<dyn AnyColumn> {
53 fn make<T: 'static>() -> Box<dyn AnyColumn> {
54 Column::<T>::new().erase()
55 }
56 make::<T>
57 }
58
59 /// Every cell of the column, one per row.
60 ///
61 /// Handing out the slice is safe; taking the value out of a cell needs the
62 /// claim the caller took on the column. See [`crate::borrow`].
63 #[inline]
64 pub(crate) fn cells(&self) -> &[UnsafeCell<T>] {
65 &self.cells
66 }
67
68 /// Every cell of the column, reached exclusively.
69 #[inline]
70 pub(crate) fn cells_mut(&mut self) -> &mut [UnsafeCell<T>] {
71 &mut self.cells
72 }
73
74 /// Erase the column.
75 pub(crate) fn erase(self) -> Box<dyn AnyColumn> {
76 Box::new(self)
77 }
78}
79
80impl<T: 'static> AnyColumn for Column<T> {
81 fn as_any(&self) -> &dyn Any {
82 self
83 }
84
85 fn as_any_mut(&mut self) -> &mut dyn Any {
86 self
87 }
88
89 fn swap_remove(&mut self, row: usize) -> Box<dyn Any> {
90 Box::new(self.cells.swap_remove(row).into_inner())
91 }
92
93 fn push_boxed(&mut self, value: Box<dyn Any>) {
94 let value = *value
95 .downcast::<T>()
96 .expect("only a value of this column's component type can be pushed");
97 self.cells.push(UnsafeCell::new(value));
98 }
99}