use atomic_refcell::AtomicRef;
use std::{any::type_name, marker::PhantomData, ops::Deref};
use crate::{access::*, borrow::ComponentBorrow, Error, Result};
use crate::{GenericWorld, QueryOne};
use hecs::{Component, Entity, Query, QueryBorrow, World};
pub type SubWorld<'a, T> = SubWorldRaw<AtomicRef<'a, World>, T>;
pub type SubWorldRefCell<'a, T> = SubWorldRaw<std::cell::Ref<'a, World>, T>;
pub type SubWorldRef<'a, T> = SubWorldRaw<&'a World, T>;
pub type EmptyWorld<'a> = SubWorldRef<'a, ()>;
pub struct SubWorldRaw<A, T> {
pub(crate) world: A,
marker: PhantomData<T>,
}
impl<A, T> SubWorldRaw<A, T> {
pub fn new(world: A) -> Self {
Self {
world,
marker: PhantomData,
}
}
}
impl<A, T: ComponentBorrow> SubWorldRaw<A, T> {
pub fn has<U: IntoAccess>(&self) -> bool {
T::has::<U>()
}
pub fn has_all<U: Subset>(&self) -> bool {
U::is_subset::<T>()
}
}
impl<'w, A: 'w + Deref<Target = World>, T: ComponentBorrow> SubWorldRaw<A, T> {
pub fn query<Q: Query + Subset>(&self) -> QueryBorrow<'_, Q> {
self.try_query()
.expect("Failed to execute query on subworld")
}
pub fn query_one<Q: Query + Subset>(&'w self, entity: Entity) -> Result<QueryOne<'w, Q>> {
if !self.has_all::<Q>() {
return Err(Error::IncompatibleSubworld {
subworld: type_name::<T>(),
query: type_name::<Q>(),
});
}
let query = self
.world
.query_one(entity)
.map_err(|_| Error::NoSuchEntity(entity))?;
Ok(QueryOne::new(entity, query))
}
pub fn get<C: Component>(&self, entity: Entity) -> Result<hecs::Ref<C>> {
if !self.has::<&C>() {
return Err(Error::IncompatibleSubworld {
subworld: type_name::<T>(),
query: type_name::<&C>(),
});
}
match self.world.get(entity) {
Ok(val) => Ok(val),
Err(hecs::ComponentError::NoSuchEntity) => Err(Error::NoSuchEntity(entity)),
Err(hecs::ComponentError::MissingComponent(name)) => {
Err(Error::MissingComponent(entity, name))
}
}
}
pub fn get_mut<C: Component>(&self, entity: Entity) -> Result<hecs::RefMut<C>> {
if !self.has::<&C>() {
return Err(Error::IncompatibleSubworld {
subworld: type_name::<T>(),
query: type_name::<&C>(),
});
}
match self.world.get_mut(entity) {
Ok(val) => Ok(val),
Err(hecs::ComponentError::NoSuchEntity) => Err(Error::NoSuchEntity(entity)),
Err(hecs::ComponentError::MissingComponent(name)) => {
Err(Error::MissingComponent(entity, name))
}
}
}
pub fn reserve_entities(&self, count: u32) -> impl Iterator<Item = Entity> + '_ {
self.world.reserve_entities(count)
}
pub fn query_par<Q: Query + Subset>(&self) -> QueryBorrow<'_, Q> {
self.try_query()
.expect("Failed to execute query on subworld")
}
}