use once_map::OnceMap;
use std::sync::Arc;
use crate::prelude::*;
mod iterator;
mod typed;
mod untyped;
pub use iterator::*;
pub use typed::*;
pub use untyped::*;
pub type AtomicComponentStore<T> = Arc<AtomicCell<ComponentStore<T>>>;
pub type UntypedAtomicComponentStore = Arc<AtomicCell<UntypedComponentStore>>;
#[derive(Default)]
pub struct ComponentStores {
pub(crate) components: OnceMap<SchemaId, UntypedAtomicComponentStore>,
}
unsafe impl Sync for ComponentStores {}
unsafe impl Send for ComponentStores {}
impl Clone for ComponentStores {
fn clone(&self) -> Self {
Self {
components: self
.components
.read_only_view()
.iter()
.map(|(&k, v)| (k, Arc::new((**v).clone())))
.collect(),
}
}
}
impl ComponentStores {
pub fn get_cell<T: HasSchema>(&self) -> AtomicComponentStore<T> {
let untyped = self.get_cell_by_schema(T::schema());
unsafe {
std::mem::transmute::<
Arc<AtomicCell<UntypedComponentStore>>,
Arc<AtomicCell<ComponentStore<T>>>,
>(untyped)
}
}
pub fn get<T: HasSchema>(&self) -> &AtomicCell<ComponentStore<T>> {
let schema = T::schema();
let atomiccell = self.get_by_schema(schema);
unsafe {
std::mem::transmute::<&AtomicCell<UntypedComponentStore>, &AtomicCell<ComponentStore<T>>>(
atomiccell,
)
}
}
pub fn get_by_schema(&self, schema: &'static Schema) -> &AtomicCell<UntypedComponentStore> {
self.components.insert(schema.id(), |_| {
Arc::new(AtomicCell::new(UntypedComponentStore::new(schema)))
})
}
pub fn get_cell_by_schema(
&self,
schema: &'static Schema,
) -> Arc<AtomicCell<UntypedComponentStore>> {
self.components.map_insert(
schema.id(),
|_| Arc::new(AtomicCell::new(UntypedComponentStore::new(schema))),
|_key, value| value.clone(),
)
}
}
#[cfg(test)]
mod test {
use crate::prelude::*;
#[derive(Clone, Copy, HasSchema, Default)]
#[repr(C)]
struct MyData(pub i32);
#[test]
fn borrow_many_mut() {
World::new().run_system(
|mut entities: ResMut<Entities>, mut my_datas: CompMut<MyData>| {
let ent1 = entities.create();
let ent2 = entities.create();
my_datas.insert(ent1, MyData(7));
my_datas.insert(ent2, MyData(8));
{
let [data2, data1] = my_datas.get_many_mut([ent2, ent1]).unwrap_many();
data1.0 = 0;
data2.0 = 1;
}
assert_eq!(my_datas.get(ent1).unwrap().0, 0);
assert_eq!(my_datas.get(ent2).unwrap().0, 1);
},
(),
);
}
#[test]
#[should_panic = "must be unique"]
fn borrow_many_overlapping_mut() {
World::new().run_system(
|mut entities: ResMut<Entities>, mut my_datas: CompMut<MyData>| {
let ent1 = entities.create();
let ent2 = entities.create();
my_datas.insert(ent1, MyData(1));
my_datas.insert(ent2, MyData(2));
my_datas.get_many_mut([ent1, ent2, ent1]).unwrap_many();
},
(),
)
}
}