bones_ecs/
components.rs

1//! ECS component storage.
2
3use once_map::OnceMap;
4use std::sync::Arc;
5
6use crate::prelude::*;
7
8mod iterator;
9mod typed;
10mod untyped;
11
12pub use iterator::*;
13pub use typed::*;
14pub use untyped::*;
15
16/// An atomic component store.
17pub type AtomicComponentStore<T> = Arc<AtomicCell<ComponentStore<T>>>;
18/// An untyped atomic component store.
19pub type UntypedAtomicComponentStore = Arc<AtomicCell<UntypedComponentStore>>;
20
21/// A collection of [`ComponentStore<T>`].
22///
23/// [`ComponentStores`] is used to in [`World`] to store all component types that have been
24/// initialized for that world.
25#[derive(Default)]
26pub struct ComponentStores {
27    pub(crate) components: OnceMap<SchemaId, UntypedAtomicComponentStore>,
28}
29
30// SOUND: all of the functions for ComponentStores requires that the types stored implement Sync +
31// Send.
32unsafe impl Sync for ComponentStores {}
33unsafe impl Send for ComponentStores {}
34
35impl Clone for ComponentStores {
36    fn clone(&self) -> Self {
37        Self {
38            components: self
39                .components
40                .read_only_view()
41                .iter()
42                // Be sure to clone the inner data of the components, so we don't just end up with
43                // new `Arc`s pointing to the same data.
44                .map(|(&k, v)| (k, Arc::new((**v).clone())))
45                .collect(),
46        }
47    }
48}
49
50impl ComponentStores {
51    /// Get the components of a certain type
52    pub fn get_cell<T: HasSchema>(&self) -> AtomicComponentStore<T> {
53        let untyped = self.get_cell_by_schema(T::schema());
54
55        // Safe: We know the schema matches, and `ComponentStore<T>` is repr(transparent) over
56        // `UntypedComponentStore`.
57        unsafe {
58            std::mem::transmute::<
59                Arc<AtomicCell<UntypedComponentStore>>,
60                Arc<AtomicCell<ComponentStore<T>>>,
61            >(untyped)
62        }
63    }
64
65    /// Borrow a component store.
66    /// # Errors
67    /// Errors if the component store has not been initialized yet.
68    pub fn get<T: HasSchema>(&self) -> &AtomicCell<ComponentStore<T>> {
69        let schema = T::schema();
70        let atomiccell = self.get_by_schema(schema);
71
72        // SOUND: ComponentStore<T> is repr(transparent) over UntypedComponent store.
73        unsafe {
74            std::mem::transmute::<&AtomicCell<UntypedComponentStore>, &AtomicCell<ComponentStore<T>>>(
75                atomiccell,
76            )
77        }
78    }
79
80    /// Get the untyped component storage by the component's [`SchemaId`].
81    pub fn get_by_schema(&self, schema: &'static Schema) -> &AtomicCell<UntypedComponentStore> {
82        self.components.insert(schema.id(), |_| {
83            Arc::new(AtomicCell::new(UntypedComponentStore::new(schema)))
84        })
85    }
86
87    /// Get the untyped component storage by the component's [`SchemaId`].
88    pub fn get_cell_by_schema(
89        &self,
90        schema: &'static Schema,
91    ) -> Arc<AtomicCell<UntypedComponentStore>> {
92        self.components.map_insert(
93            schema.id(),
94            |_| Arc::new(AtomicCell::new(UntypedComponentStore::new(schema))),
95            |_key, value| value.clone(),
96        )
97    }
98}
99
100#[cfg(test)]
101mod test {
102    use crate::prelude::*;
103
104    #[derive(Clone, Copy, HasSchema, Default)]
105    #[repr(C)]
106    struct MyData(pub i32);
107
108    #[test]
109    fn borrow_many_mut() {
110        World::new().run_system(
111            |mut entities: ResMut<Entities>, mut my_datas: CompMut<MyData>| {
112                let ent1 = entities.create();
113                let ent2 = entities.create();
114
115                my_datas.insert(ent1, MyData(7));
116                my_datas.insert(ent2, MyData(8));
117
118                {
119                    let [data2, data1] = my_datas.get_many_mut([ent2, ent1]).unwrap_many();
120
121                    data1.0 = 0;
122                    data2.0 = 1;
123                }
124
125                assert_eq!(my_datas.get(ent1).unwrap().0, 0);
126                assert_eq!(my_datas.get(ent2).unwrap().0, 1);
127            },
128            (),
129        );
130    }
131
132    #[test]
133    #[should_panic = "must be unique"]
134    fn borrow_many_overlapping_mut() {
135        World::new().run_system(
136            |mut entities: ResMut<Entities>, mut my_datas: CompMut<MyData>| {
137                let ent1 = entities.create();
138                let ent2 = entities.create();
139
140                my_datas.insert(ent1, MyData(1));
141                my_datas.insert(ent2, MyData(2));
142
143                my_datas.get_many_mut([ent1, ent2, ent1]).unwrap_many();
144            },
145            (),
146        )
147    }
148}