use hashbrown::HashMap;
use mopa::Any;
use std::marker::PhantomData;
mod trust_cell;
pub use trust_cell::Ref;
pub use trust_cell::RefMut;
pub use trust_cell::TrustCell;
mod dispatch;
pub use dispatch::AcquiredResources;
pub use dispatch::MinimumDispatcher;
pub use dispatch::MinimumDispatcherBuilder;
pub use dispatch::MinimumDispatcherContext;
use crate::systems;
use std::any::TypeId;
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct ResourceId {
type_id: TypeId,
}
impl ResourceId {
#[inline]
pub fn new<T: 'static>() -> Self {
ResourceId {
type_id: std::any::TypeId::of::<T>(),
}
}
}
pub trait Resource: Any + Send + Sync + 'static {}
mod __resource_mopafy_scope {
#![allow(clippy::all)]
use mopa::mopafy;
use super::Resource;
mopafy!(Resource);
}
impl<T> Resource for T where T: Any + Send + Sync {}
pub struct WorldBuilder {
world: World,
}
impl WorldBuilder {
pub fn new() -> Self {
WorldBuilder {
world: World::new(),
}
}
pub fn with_resource<R>(mut self, r: R) -> Self
where
R: Resource,
{
self.world.insert(r);
self
}
pub fn insert<R>(&mut self, r: R)
where
R: Resource,
{
self.world.insert(r);
}
pub fn build(self) -> World {
self.world
}
}
#[derive(Default)]
pub struct World {
resources: HashMap<ResourceId, TrustCell<Box<dyn Resource>>>,
}
impl World {
pub fn new() -> Self {
World {
resources: HashMap::new(),
}
}
pub fn insert<R>(&mut self, r: R)
where
R: Resource,
{
self.insert_by_id(ResourceId::new::<R>(), r);
}
pub fn remove<R>(&mut self) -> Option<R>
where
R: Resource,
{
self.remove_by_id(ResourceId::new::<R>())
}
fn insert_by_id<R>(&mut self, id: ResourceId, r: R)
where
R: Resource,
{
self.resources.insert(id, TrustCell::new(Box::new(r)));
}
fn remove_by_id<R>(&mut self, id: ResourceId) -> Option<R>
where
R: Resource,
{
self.resources
.remove(&id)
.map(TrustCell::into_inner)
.map(|x: Box<dyn Resource>| x.downcast())
.map(|x: Result<Box<R>, _>| x.ok().unwrap())
.map(|x| *x)
}
pub fn fetch<R: Resource>(&self) -> ReadBorrow<R> {
self.try_fetch().unwrap()
}
pub fn try_fetch<R: Resource>(&self) -> Option<ReadBorrow<R>> {
let res_id = ResourceId::new::<R>();
self.resources.get(&res_id).map(|r| ReadBorrow {
inner: Ref::map(r.borrow(), Box::as_ref),
phantom: PhantomData,
})
}
pub fn fetch_mut<R: Resource>(&self) -> WriteBorrow<R> {
self.try_fetch_mut().unwrap()
}
pub fn try_fetch_mut<R: Resource>(&self) -> Option<WriteBorrow<R>> {
let res_id = ResourceId::new::<R>();
self.resources.get(&res_id).map(|r| WriteBorrow::<R> {
inner: RefMut::map(r.borrow_mut(), Box::as_mut),
phantom: PhantomData,
})
}
pub fn has_value<R>(&self) -> bool
where
R: Resource,
{
self.has_value_raw(ResourceId::new::<R>())
}
pub fn has_value_raw(&self, id: ResourceId) -> bool {
self.resources.contains_key(&id)
}
pub fn keys(&self) -> impl Iterator<Item = &ResourceId> {
self.resources.iter().map(|x| x.0)
}
}
pub trait DataRequirement<'a> {
type Borrow: DataBorrow;
fn fetch(world: &'a World) -> Self::Borrow;
}
impl<'a> DataRequirement<'a> for () {
type Borrow = ();
fn fetch(_: &'a World) -> Self::Borrow {}
}
pub struct Read<T: Resource> {
phantom_data: PhantomData<T>,
}
impl<'a, T: Resource> DataRequirement<'a> for Read<T> {
type Borrow = ReadBorrow<'a, T>;
fn fetch(world: &'a World) -> Self::Borrow {
world.fetch::<T>()
}
}
pub struct Write<T: Resource> {
phantom_data: PhantomData<T>,
}
impl<'a, T: Resource> DataRequirement<'a> for Write<T> {
type Borrow = WriteBorrow<'a, T>;
fn fetch(world: &'a World) -> Self::Borrow {
world.fetch_mut::<T>()
}
}
pub trait DataBorrow {}
impl DataBorrow for () {}
pub struct ReadBorrow<'a, T> {
inner: Ref<'a, dyn Resource>,
phantom: PhantomData<&'a T>,
}
impl<'a, T> DataBorrow for ReadBorrow<'a, T> {}
impl<'a, T> std::ops::Deref for ReadBorrow<'a, T>
where
T: Resource,
{
type Target = T;
fn deref(&self) -> &T {
unsafe { self.inner.downcast_ref_unchecked() }
}
}
impl<'a, T> Clone for ReadBorrow<'a, T> {
fn clone(&self) -> Self {
ReadBorrow {
inner: self.inner.clone(),
phantom: PhantomData,
}
}
}
pub struct WriteBorrow<'a, T> {
inner: RefMut<'a, dyn Resource>,
phantom: PhantomData<&'a mut T>,
}
impl<'a, T> DataBorrow for WriteBorrow<'a, T> {}
impl<'a, T> std::ops::Deref for WriteBorrow<'a, T>
where
T: Resource,
{
type Target = T;
fn deref(&self) -> &T {
unsafe { self.inner.downcast_ref_unchecked() }
}
}
impl<'a, T> std::ops::DerefMut for WriteBorrow<'a, T>
where
T: Resource,
{
fn deref_mut(&mut self) -> &mut T {
unsafe { self.inner.downcast_mut_unchecked() }
}
}
pub trait Task {
type RequiredResources: for<'a> DataRequirement<'a>
+ crate::async_dispatcher::RequiresResources<ResourceId>
+ Send
+ 'static;
fn run(&mut self, data: <Self::RequiredResources as DataRequirement>::Borrow);
}
macro_rules! impl_data {
( $($ty:ident),* ) => {
impl<$($ty),*> DataBorrow for ( $( $ty , )* )
where $( $ty : DataBorrow ),*
{
}
impl<'a, $($ty),*> DataRequirement<'a> for ( $( $ty , )* )
where $( $ty : DataRequirement<'a> ),*
{
type Borrow = ( $( <$ty as DataRequirement<'a>>::Borrow, )* );
fn fetch(world: &'a World) -> Self::Borrow {
#![allow(unused_variables)]
( $( <$ty as DataRequirement<'a>>::fetch(world), )* )
}
}
};
}
mod impl_data {
#![cfg_attr(rustfmt, rustfmt_skip)]
use super::*;
impl_data!(A);
impl_data!(A, B);
impl_data!(A, B, C);
impl_data!(A, B, C, D);
impl_data!(A, B, C, D, E);
impl_data!(A, B, C, D, E, F);
impl_data!(A, B, C, D, E, F, G);
impl_data!(A, B, C, D, E, F, G, H);
impl_data!(A, B, C, D, E, F, G, H, I);
impl_data!(A, B, C, D, E, F, G, H, I, J);
impl_data!(A, B, C, D, E, F, G, H, I, J, K);
impl_data!(A, B, C, D, E, F, G, H, I, J, K, L);
impl_data!(A, B, C, D, E, F, G, H, I, J, K, L, M);
impl_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
impl_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
impl_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
impl_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q);
impl_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R);
impl_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S);
impl_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T);
impl_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U);
impl_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V);
impl_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W);
impl_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X);
impl_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y);
impl_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z);
}