use crate::prelude::*;
use crate::{
create,
element::Classes,
storage::{Storage, StorageGuard, StorageGuardMut},
style_storage::{StyleStorage, STYLE_STORAGE},
StorageRef, StorageRefMut,
};
use once_cell::sync::Lazy;
use owning_ref::{OwningRef, OwningRefMut};
use std::{
any::TypeId,
cell::RefCell,
collections::{BTreeSet, HashMap},
sync::atomic::{AtomicU64, Ordering},
};
use sugars::hash;
pub(crate) static WORLD: Lazy<World> = Lazy::new(|| {
let world = World { next_entity: AtomicU64::new(1), ..Default::default() };
world.component_ownership.borrow_mut().insert(Entity::root(), BTreeSet::default());
{
fn update_classes(storage: &mut Storage<Classes>, entity: Entity) {
use std::fmt::Write;
let mut res = String::new();
{
let classes = storage.get(entity).unwrap();
for id in &classes.marks {
write!(&mut res, "t-{:x} ", hash!(id)).unwrap();
}
let style_storage = unsafe { &mut *STYLE_STORAGE.get() as &mut StyleStorage };
for (style, ordinal) in classes.styles.values() {
write!(&mut res, "{} ", style_storage.fetch(style.clone(), *ordinal)).unwrap();
}
}
let elements = WORLD.storage::<web_sys::Element>();
let element = elements.get(entity).unwrap();
let res = res.trim();
if res.is_empty() {
element.remove_attribute(web_str::class()).expect("can't remove class attribute");
} else {
element.set_attribute(web_str::class(), res).expect("can't set class attribute");
}
}
let mut classes = world.storage_mut::<Classes>();
classes.on_added = Some(update_classes);
classes.on_modified = Some(update_classes);
}
create::register_handlers(&world);
world
});
#[derive(Default)]
pub struct World {
pub(crate) storages: elsa::FrozenMap<TypeId, &'static RefCell<Box<dyn DynStorage>>>,
pub(crate) component_ownership: RefCell<HashMap<Entity, BTreeSet<TypeId>>>,
next_entity: AtomicU64,
}
unsafe impl Send for World {}
unsafe impl Sync for World {}
impl World {
#[cfg(debug_assertions)]
#[track_caller]
pub(crate) fn dyn_storage<Component: 'static>(&self) -> std::cell::Ref<'static, Box<dyn DynStorage>> {
let caller = std::panic::Location::caller();
if let Some(storage) = self.storages.map_get(&TypeId::of::<Component>(), |x| x.try_borrow()) {
storage.unwrap_or_else(|e| panic!("'{e}': Trying to immutably borrow `{}` storage at `{caller}` while a mutable borrow to it already exists:\n\n{}\n",
std::any::type_name::<Component>(),
crate::backtrace::STORAGE_MAP.0.borrow()[&TypeId::of::<Component>()]
))
} else {
let storage: RefCell<Box<dyn DynStorage>> = RefCell::new(Box::new(Storage::<Component>::default()));
let storage: &'static _ = Box::leak(Box::new(storage));
self.storages.insert(TypeId::of::<Component>(), storage);
storage.borrow()
}
}
#[cfg(not(debug_assertions))]
#[track_caller]
pub(crate) fn dyn_storage<Component: 'static>(&self) -> std::cell::Ref<'static, Box<dyn DynStorage>> {
if let Some(storage) = self.storages.map_get(&TypeId::of::<Component>(), |x| x.borrow()) {
storage
} else {
let storage: RefCell<Box<dyn DynStorage>> = RefCell::new(Box::new(Storage::<Component>::default()));
let storage: &'static _ = Box::leak(Box::new(storage));
self.storages.insert(TypeId::of::<Component>(), storage);
storage.borrow()
}
}
#[cfg(debug_assertions)]
#[track_caller]
pub(crate) fn dyn_storage_mut<Component: 'static>(&self) -> std::cell::RefMut<'static, Box<dyn DynStorage>> {
let caller = std::panic::Location::caller();
if let Some(storage) = self.storages.map_get(&TypeId::of::<Component>(), |x| x.try_borrow_mut()) {
storage.unwrap_or_else(|e| panic!("'{e}': Trying to mutably borrow `{}` storage at `{caller}` while other borrows to it already exist:\n\n{}\n",
std::any::type_name::<Component>(),
crate::backtrace::STORAGE_MAP.0.borrow()[&TypeId::of::<Component>()]
))
} else {
let storage: RefCell<Box<dyn DynStorage>> = RefCell::new(Box::new(Storage::<Component>::default()));
let storage: &'static _ = Box::leak(Box::new(storage));
self.storages.insert(TypeId::of::<Component>(), storage);
storage.borrow_mut()
}
}
#[cfg(not(debug_assertions))]
#[track_caller]
pub(crate) fn dyn_storage_mut<Component: 'static>(&self) -> std::cell::RefMut<'static, Box<dyn DynStorage>> {
if let Some(storage) = self.storages.map_get(&TypeId::of::<Component>(), |x| x.borrow_mut()) {
storage
} else {
let storage: RefCell<Box<dyn DynStorage>> = RefCell::new(Box::new(Storage::<Component>::default()));
let storage: &'static _ = Box::leak(Box::new(storage));
self.storages.insert(TypeId::of::<Component>(), storage);
storage.borrow_mut()
}
}
#[track_caller]
pub fn storage<Component: 'static>(&self) -> StorageGuard<Component, StorageRef<Component>> {
#[cfg(debug_assertions)]
crate::backtrace::STORAGE_MAP.0.borrow_mut()
.entry(TypeId::of::<Component>())
.or_default()
.insert(*std::panic::Location::caller(), false);
let storage = OwningRef::new(self.dyn_storage::<Component>())
.map(|x| x.as_any().downcast_ref().unwrap());
StorageGuard {
inner: storage,
#[cfg(debug_assertions)]
location: *std::panic::Location::caller()
}
}
#[track_caller]
pub fn storage_mut<Component: 'static>(&self) -> StorageGuardMut<Component, StorageRefMut<Component>> {
#[cfg(debug_assertions)]
crate::backtrace::STORAGE_MAP.0.borrow_mut()
.entry(TypeId::of::<Component>())
.or_default()
.insert(*std::panic::Location::caller(), true);
let storage = OwningRefMut::new(self.dyn_storage_mut::<Component>())
.map_mut(|x| x.as_any_mut().downcast_mut().unwrap());
StorageGuardMut {
inner: Some(storage),
#[cfg(debug_assertions)]
location: *std::panic::Location::caller()
}
}
#[track_caller]
pub fn register_resource<T: 'static>(&self, resource: T) { self.storage_mut().add(Entity::root(), resource); }
#[track_caller]
pub fn resource<T: 'static>(&self) -> OwningRef<StorageGuard<T, StorageRef<T>>, T> {
OwningRef::new(self.storage()).map(|x| x.get(Entity::root()).unwrap())
}
#[track_caller]
pub fn resource_mut<T: 'static>(&self) -> OwningRefMut<StorageGuardMut<T, StorageRefMut<T>>, T> {
OwningRefMut::new(self.storage_mut()).map_mut(|x| x.get_mut(Entity::root()).unwrap())
}
#[track_caller]
pub fn resource_exists<T: 'static>(&self) -> bool {
self.storage::<T>().has(Entity::root())
}
#[track_caller]
pub fn try_resource<T: 'static>(&self) -> Option<OwningRef<StorageGuard<T, StorageRef<T>>, T>> {
if !self.storage::<T>().has(Entity::root()) { return None; }
Some(OwningRef::new(self.storage()).map(|x| x.get(Entity::root()).unwrap()))
}
#[track_caller]
pub fn try_resource_mut<T: 'static>(&self) -> Option<OwningRefMut<StorageGuardMut<T, StorageRefMut<T>>, T>> {
if !self.storage::<T>().has(Entity::root()) { return None; }
Some(OwningRefMut::new(self.storage_mut()).map_mut(|x| x.get_mut(Entity::root()).unwrap()))
}
#[track_caller]
pub fn remove_resource<T: 'static>(&self) {
self.storage_mut::<T>().remove(Entity::root());
}
pub fn new_entity(&self) -> Entity {
let entity = Entity(self.next_entity.fetch_add(1, Ordering::Relaxed));
self.component_ownership.borrow_mut().insert(entity, BTreeSet::default());
entity
}
#[track_caller]
pub fn remove_entity(&self, entity: impl AsEntity) {
let entity = entity.as_entity();
if self.is_dead(entity) {
log::warn!("remove entity already dead {:?}", entity);
return;
}
let children = self.storage::<Children>().get(entity).map(|x| x.0.clone());
if let Some(children) = children {
for child in children { self.remove_entity(child); }
}
let parent = self.storage::<Parent>().get(entity).copied();
if let Some(parent) = parent {
let mut children_store = self.storage_mut::<Children>();
let children = children_store.get_mut(parent).unwrap();
if let Some(child_pos) = children.0.iter().position(|&x| x == entity) {
children.0.remove(child_pos);
}
}
let components = self.component_ownership.borrow_mut().remove(&entity).unwrap();
for component_id in components {
let mut storage = self.storages.map_get(&component_id, |x| x.try_borrow_mut().expect("remove_entity storages -> storage.try_borrow_mut .. remove")).unwrap();
storage.dyn_remove(entity);
storage.flush();
}
}
pub fn is_dead(&self, entity: impl AsEntity) -> bool {
let entity = entity.as_entity();
!self.component_ownership.borrow().contains_key(&entity)
}
}