use std::any::{self, Any};
use std::collections::HashMap;
use std::marker::PhantomData;
use parking_lot::lock_api::ArcRwLockWriteGuard;
use crate::storage::simple::AnySimpleStorage;
use crate::util::DbgTypeId;
use crate::{comp, storage, Archetype};
pub struct Map<A: Archetype> {
simple: HashMap<DbgTypeId, Box<dyn Any + Send + Sync>>,
isotope: HashMap<DbgTypeId, Box<dyn Any + Send + Sync>>,
_ph: PhantomData<A>,
}
impl<A: Archetype> Default for Map<A> {
fn default() -> Self {
Map { simple: HashMap::new(), isotope: HashMap::new(), _ph: PhantomData }
}
}
pub(crate) type IsotopeMap<A, C> = Vec<(<C as comp::Isotope<A>>::Discrim, C)>;
impl<A: Archetype> Map<A> {
pub fn insert_simple<C: comp::Simple<A>>(&mut self, comp: C) {
let prev = self.simple.insert(DbgTypeId::of::<C>(), Box::new(comp));
if prev.is_some() {
panic!("Cannot insert the same simple component into the same comp::Map twice");
}
}
pub(crate) fn remove_simple<C: comp::Simple<A>>(&mut self) -> Option<C> {
Some(*self.simple.remove(&DbgTypeId::of::<C>())?.downcast().expect("TypeId mismatch"))
}
pub fn insert_isotope<C: comp::Isotope<A>>(&mut self, discrim: C::Discrim, comp: C) {
let entry = self.isotope.entry(DbgTypeId::of::<C>());
entry
.or_insert_with(|| Box::<IsotopeMap<A, C>>::default())
.downcast_mut::<IsotopeMap<A, C>>()
.expect("TypeId mismatch")
.push((discrim, comp));
}
pub(crate) fn remove_isotope<C: comp::Isotope<A>>(&mut self) -> IsotopeMap<A, C> {
match self.isotope.remove(&DbgTypeId::of::<C>()) {
Some(map) => *map.downcast().expect("TypeId mismatch"),
None => Vec::new(),
}
}
pub fn simple_len(&self) -> usize { self.simple.len() }
pub fn isotope_type_count(&self) -> usize { self.isotope.len() }
}
pub type DepList = Vec<(DbgTypeId, fn() -> Box<dyn Any>)>;
pub struct Initer<A: Archetype, C: comp::SimpleOrIsotope<A>> {
pub f: &'static dyn InitFn<A, C>,
}
pub trait InitFn<A: Archetype, C: comp::SimpleOrIsotope<A>>: Send + Sync + 'static {
fn init(&self, dep_getter: DepGetter<'_, A>) -> C;
fn deps(&self) -> DepList;
}
pub struct DepGetter<'t, A: Archetype> {
pub(crate) inner: &'t dyn DepGetterInner<A>,
pub(crate) entity: A::RawEntity,
}
impl<'t, A: Archetype> Clone for DepGetter<'t, A> {
fn clone(&self) -> Self { *self }
}
impl<'t, A: Archetype> Copy for DepGetter<'t, A> {}
pub(crate) trait DepGetterInner<A: Archetype> {
fn get(
&self,
ty: DbgTypeId,
) -> ArcRwLockWriteGuard<parking_lot::RawRwLock, dyn AnySimpleStorage<A>>;
}
macro_rules! impl_simple_init_fn {
($($deps:ident)*) => {
impl<
A: Archetype, C: comp::SimpleOrIsotope<A>,
$($deps: comp::Simple<A>,)*
> InitFn<A, C> for fn(
$(&$deps,)*
) -> C {
fn init(
&self,
#[allow(unused_variables)] dep_getter: DepGetter<'_, A>,
) -> C {
(self)(
$(
match dep_getter.inner.get(DbgTypeId::of::<$deps>()).get_any(dep_getter.entity) {
Some(comp) => comp.downcast_ref::<$deps>().expect("TypeId mismatch"),
None => panic!(
"Cannot create an entity of type `{}` without explicitly passing a component of type `{}`, or `{}` to invoke its auto-initializer",
any::type_name::<A>(),
any::type_name::<C>(),
any::type_name::<$deps>(),
),
},
)*
)
}
fn deps(&self) -> DepList {
vec![
$((DbgTypeId::of::<$deps>(), storage::simple::builder::<A, $deps>),)*
]
}
}
}
}
macro_rules! impl_simple_init_fn_accumulate {
($feature:literal $first:ident $($rest:tt)*) => {
impl_simple_init_fn_accumulate!($feature $($rest)*);
#[cfg(feature = $feature)]
impl_simple_init_fn_accumulate!(@MIXED $first $($rest)*);
};
($outer_feature:literal $inner_feature:literal $($rest:tt)*) => {
impl_simple_init_fn_accumulate!($inner_feature $($rest)*);
};
($outer_feature:literal @ALWAYS $($rest:tt)*) => {
impl_simple_init_fn_accumulate!(@ALWAYS $($rest)*);
};
(@ALWAYS $first:ident $($rest:tt)*) => {
impl_simple_init_fn_accumulate!(@ALWAYS $($rest)*);
impl_simple_init_fn!($first $($rest)*);
};
(@ALWAYS) => {
#[allow(unused_variables)]
const _: () = {
impl_simple_init_fn!();
};
};
(@MIXED $($idents_front:ident)* $($feature:literal $($idents_feature:ident)*)* @ALWAYS $($idents_always:ident)*) => {
impl_simple_init_fn!($($idents_front)* $($($idents_feature)*)* $($idents_always)*);
};
}
impl_simple_init_fn_accumulate!(
"tuple-impl-32-init-fn" T1 T2 T3 T4 T5 T6 T7 T8
"tuple-impl-24-init-fn" T9 T10 T11 T12 T13 T14 T15 T16
"tuple-impl-16-init-fn" T17 T18 T19 T20 T21 T22 T23 T24
"tuple-impl-8-init-fn" T25 T26 T27 T28
@ALWAYS T29 T30 T31 T32
);
#[cfg(test)]
mod tests;