use std::any::{self, Any, TypeId};
use std::collections::HashSet;
use crate::entity::{ealloc, referrer};
use crate::util::DbgTypeId;
use crate::{comp, storage, system, world, Archetype, Global};
pub struct Spec {
pub debug_name: String,
pub dependencies: Vec<Dependency>,
pub global_requests: Vec<GlobalRequest>,
pub simple_requests: Vec<SimpleRequest>,
pub isotope_requests: Vec<IsotopeRequest>,
pub entity_creator_requests: Vec<EntityCreatorRequest>,
}
pub enum Dependency {
Before(Box<dyn system::Partition>),
After(Box<dyn system::Partition>),
}
impl Dependency {
pub fn before(p: impl system::Partition) -> Self { Self::Before(Box::new(p)) }
pub fn after(p: impl system::Partition) -> Self { Self::After(Box::new(p)) }
}
pub struct GlobalRequest {
pub(crate) ty: DbgTypeId,
pub(crate) vtable: referrer::SingleVtable,
pub(crate) initial: GlobalInitial,
pub(crate) mutable: bool,
pub(crate) strong_refs: HashSet<DbgTypeId>,
}
#[derive(Clone, Copy)]
pub enum GlobalInitial {
Sync(fn() -> Box<dyn Any + Send + Sync>),
Unsync(fn() -> Box<dyn Any>),
}
impl GlobalRequest {
pub fn new_sync<G: Global + Send + Sync>(mutable: bool) -> Self {
let mut visitor = referrer::VisitTypeArg::new();
G::visit_type(&mut visitor);
Self {
ty: DbgTypeId::of::<G>(),
vtable: referrer::SingleVtable::of::<G>(),
initial: GlobalInitial::Sync(|| Box::new(G::initial())),
mutable,
strong_refs: visitor.found_archs,
}
}
pub fn new_unsync<G: Global>(mutable: bool) -> Self {
let mut visitor = referrer::VisitTypeArg::new();
G::visit_type(&mut visitor);
Self {
ty: DbgTypeId::of::<G>(),
vtable: referrer::SingleVtable::of::<G>(),
initial: GlobalInitial::Unsync(|| Box::new(G::initial())),
mutable,
strong_refs: visitor.found_archs,
}
}
pub fn maybe_uninit<A: Archetype>(mut self) -> Self {
let present = self.strong_refs.remove(&TypeId::of::<A>());
if !present {
panic!("No strong references to `{}` detected in `{}`", any::type_name::<A>(), self.ty);
}
self
}
pub fn sync(&self) -> bool { matches!(&self.initial, GlobalInitial::Sync(..)) }
}
#[derive(Clone, Copy)]
pub(crate) struct ArchetypeDescriptor {
pub(crate) id: DbgTypeId,
pub(crate) builder: fn() -> (ealloc::AnyBuilder, Box<dyn world::typed::AnyBuilder>),
}
impl ArchetypeDescriptor {
fn of<A: Archetype>() -> Self {
Self {
id: DbgTypeId::of::<A>(),
builder: || (ealloc::builder::<A>(), Box::new(world::typed::builder::<A>())),
}
}
}
pub struct SimpleRequest {
pub(crate) arch: ArchetypeDescriptor,
pub(crate) comp: DbgTypeId,
pub(crate) storage_builder: fn() -> Box<dyn Any>,
pub(crate) mutable: bool,
pub(crate) strong_refs: HashSet<DbgTypeId>,
}
impl SimpleRequest {
pub fn new<A: Archetype, C: comp::Simple<A>>(mutable: bool) -> Self {
let mut visitor = referrer::VisitTypeArg::new();
C::visit_type(&mut visitor);
Self {
arch: ArchetypeDescriptor::of::<A>(),
comp: DbgTypeId::of::<C>(),
mutable,
storage_builder: storage::simple::builder::<A, C> as fn() -> Box<dyn Any>,
strong_refs: visitor.found_archs,
}
}
pub fn maybe_uninit<A: Archetype>(mut self) -> Self {
let present = self.strong_refs.remove(&TypeId::of::<A>());
if !present {
panic!(
"No strong references to `{}` detected in `{}`",
any::type_name::<A>(),
self.comp
);
}
self
}
}
pub struct IsotopeRequest {
pub(crate) arch: ArchetypeDescriptor,
pub(crate) comp: DbgTypeId,
pub(crate) map_builder: fn() -> Box<dyn Any>,
pub(crate) discrim: Option<Vec<usize>>,
pub(crate) mutable: bool,
pub(crate) strong_refs: HashSet<DbgTypeId>,
}
impl IsotopeRequest {
pub fn new<A: Archetype, C: comp::Isotope<A>>(
discrim: Option<Vec<usize>>,
mutable: bool,
) -> Self {
let mut visitor = referrer::VisitTypeArg::new();
C::visit_type(&mut visitor);
Self {
arch: ArchetypeDescriptor::of::<A>(),
comp: DbgTypeId::of::<C>(),
discrim,
mutable,
map_builder: || Box::new(storage::IsotopeMap::<A, C>::new_any()),
strong_refs: visitor.found_archs,
}
}
pub fn maybe_uninit<A: Archetype>(mut self) -> Self {
let present = self.strong_refs.remove(&TypeId::of::<A>());
if !present {
panic!(
"No strong references to `{}` detected in `{}`",
any::type_name::<A>(),
self.comp
);
}
self
}
}
pub struct EntityCreatorRequest {
pub(crate) arch: DbgTypeId,
pub(crate) no_partition: bool,
}
impl EntityCreatorRequest {
pub fn new<A: Archetype>() -> Self { Self { arch: DbgTypeId::of::<A>(), no_partition: false } }
pub fn no_partition(self) -> Self { Self { no_partition: true, ..self } }
}