Skip to main content

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}