use alloc::borrow::Cow;
use alloc::collections::BTreeSet;
use core::alloc::Layout;
use core::any::TypeId;
use core::ops::Index;
use ahash::RandomState;
pub use evenio_macros::Component;
use crate::archetype::{Archetype, ArchetypeIdx};
use crate::drop::DropFn;
use crate::entity::EntityLocation;
use crate::event::{EventPtr, GlobalEvent, TargetedEventId};
use crate::handler::{HandlerConfig, HandlerInfo, HandlerParam, InitError};
use crate::map::{Entry, IndexSet, TypeIdMap};
use crate::mutability::{Mutability, MutabilityMarker};
use crate::prelude::World;
use crate::slot_map::{Key, SlotMap};
use crate::sparse::SparseIndex;
use crate::world::UnsafeWorldCell;
#[derive(Debug)]
pub struct Components {
infos: SlotMap<ComponentInfo>,
by_type_id: TypeIdMap<ComponentId>,
}
impl Components {
pub(crate) fn new() -> Self {
Self {
infos: SlotMap::new(),
by_type_id: TypeIdMap::default(),
}
}
pub(crate) fn add(&mut self, desc: ComponentDescriptor) -> (ComponentId, bool) {
if let Some(type_id) = desc.type_id {
return match self.by_type_id.entry(type_id) {
Entry::Vacant(v) => {
let Some(k) = self.infos.insert_with(|k| ComponentInfo {
name: desc.name,
id: ComponentId(k),
type_id: desc.type_id,
layout: desc.layout,
drop: desc.drop,
mutability: desc.mutability,
insert_events: BTreeSet::new(),
remove_events: BTreeSet::new(),
member_of: IndexSet::with_hasher(RandomState::new()),
}) else {
panic!("too many components")
};
(*v.insert(ComponentId(k)), true)
}
Entry::Occupied(o) => (*o.get(), false),
};
}
let Some(k) = self.infos.insert_with(|k| ComponentInfo {
name: desc.name,
id: ComponentId(k),
type_id: desc.type_id,
layout: desc.layout,
drop: desc.drop,
mutability: desc.mutability,
insert_events: BTreeSet::new(),
remove_events: BTreeSet::new(),
member_of: IndexSet::with_hasher(RandomState::new()),
}) else {
panic!("too many components")
};
(ComponentId(k), true)
}
pub(crate) fn remove(&mut self, component_id: ComponentId) -> Option<ComponentInfo> {
let info = self.infos.remove(component_id.0)?;
if let Some(type_id) = info.type_id {
self.by_type_id.remove(&type_id);
}
Some(info)
}
pub fn get(&self, id: ComponentId) -> Option<&ComponentInfo> {
self.infos.get(id.0)
}
pub fn get_by_index(&self, idx: ComponentIdx) -> Option<&ComponentInfo> {
self.infos.get_by_index(idx.0).map(|(_, v)| v)
}
pub(crate) fn get_by_index_mut(&mut self, idx: ComponentIdx) -> Option<&mut ComponentInfo> {
self.infos.get_by_index_mut(idx.0).map(|(_, v)| v)
}
pub fn get_by_type_id(&self, type_id: TypeId) -> Option<&ComponentInfo> {
let id = *self.by_type_id.get(&type_id)?;
Some(unsafe { self.get(id).unwrap_unchecked() })
}
pub fn contains(&self, id: ComponentId) -> bool {
self.get(id).is_some()
}
pub fn iter(&self) -> impl Iterator<Item = &ComponentInfo> {
self.infos.iter().map(|(_, v)| v)
}
}
impl Index<ComponentId> for Components {
type Output = ComponentInfo;
fn index(&self, index: ComponentId) -> &Self::Output {
if let Some(info) = self.get(index) {
info
} else {
panic!("no such component with ID of {index:?} exists")
}
}
}
impl Index<ComponentIdx> for Components {
type Output = ComponentInfo;
fn index(&self, index: ComponentIdx) -> &Self::Output {
if let Some(info) = self.get_by_index(index) {
info
} else {
panic!("no such component with index of {index:?} exists")
}
}
}
impl Index<TypeId> for Components {
type Output = ComponentInfo;
fn index(&self, index: TypeId) -> &Self::Output {
if let Some(info) = self.get_by_type_id(index) {
info
} else {
panic!("no such component with type ID of {index:?} exists")
}
}
}
unsafe impl HandlerParam for &'_ Components {
type State = ();
type This<'a> = &'a Components;
fn init(_world: &mut World, _config: &mut HandlerConfig) -> Result<Self::State, InitError> {
Ok(())
}
unsafe fn get<'a>(
_state: &'a mut Self::State,
_info: &'a HandlerInfo,
_event_ptr: EventPtr<'a>,
_target_location: EntityLocation,
world: UnsafeWorldCell<'a>,
) -> Self::This<'a> {
world.components()
}
fn refresh_archetype(_state: &mut Self::State, _arch: &Archetype) {}
fn remove_archetype(_state: &mut Self::State, _arch: &Archetype) {}
}
#[derive(Debug)]
pub struct ComponentInfo {
name: Cow<'static, str>,
id: ComponentId,
type_id: Option<TypeId>,
layout: Layout,
drop: DropFn,
mutability: Mutability,
pub(crate) insert_events: BTreeSet<TargetedEventId>,
pub(crate) remove_events: BTreeSet<TargetedEventId>,
pub(crate) member_of: IndexSet<ArchetypeIdx>,
}
impl ComponentInfo {
pub fn name(&self) -> &str {
&self.name
}
pub fn id(&self) -> ComponentId {
self.id
}
pub fn type_id(&self) -> Option<TypeId> {
self.type_id
}
pub fn layout(&self) -> Layout {
self.layout
}
pub fn drop(&self) -> DropFn {
self.drop
}
pub fn mutability(&self) -> Mutability {
self.mutability
}
pub fn insert_events(&self) -> &BTreeSet<TargetedEventId> {
&self.insert_events
}
pub fn remove_events(&self) -> &BTreeSet<TargetedEventId> {
&self.remove_events
}
}
pub trait Component: 'static {
type Mutability: MutabilityMarker;
}
#[derive(Clone, Debug)]
pub struct ComponentDescriptor {
pub name: Cow<'static, str>,
pub type_id: Option<TypeId>,
pub layout: Layout,
pub drop: DropFn,
pub mutability: Mutability,
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug)]
pub struct ComponentId(Key);
impl ComponentId {
pub const NULL: Self = Self(Key::NULL);
pub const fn new(index: u32, generation: u32) -> Option<Self> {
match Key::new(index, generation) {
Some(k) => Some(Self(k)),
None => None,
}
}
pub const fn index(self) -> ComponentIdx {
ComponentIdx(self.0.index())
}
pub const fn generation(self) -> u32 {
self.0.generation().get()
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug)]
pub struct ComponentIdx(pub u32);
unsafe impl SparseIndex for ComponentIdx {
const MAX: Self = Self(u32::MAX);
fn index(self) -> usize {
self.0.index()
}
fn from_index(idx: usize) -> Self {
Self(u32::from_index(idx))
}
}
#[derive(GlobalEvent, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct AddComponent(pub ComponentId);
#[derive(GlobalEvent, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct RemoveComponent(pub ComponentId);
#[cfg(test)]
mod tests {
use crate::prelude::*;
#[derive(GlobalEvent)]
struct E;
#[test]
fn remove_component() {
#[derive(Component)]
struct A(String);
#[derive(Component, PartialEq, Debug)]
struct B(Vec<String>);
let mut world = World::new();
let c1 = world.add_component::<A>();
let e1 = world.spawn();
world.insert(e1, A("hello".into()));
let s1 = world.add_handler(|_: Receiver<E>, Single(A(a)): Single<&mut A>| {
a.push_str("hello");
});
world.send(E);
assert!(world.remove_component(c1).is_some());
assert!(!world.handlers().contains(s1));
assert!(!world.entities().contains(e1));
assert_eq!(
world.archetypes().len(),
1,
"only the empty archetype should be present"
);
let c2 = world.add_component::<B>();
let e2 = world.spawn();
assert!(world.entities().contains(e2));
world.insert(e2, B(vec![]));
let s2 = world.add_handler(|_: Receiver<E>, Single(B(b)): Single<&mut B>| {
b.push("hello".into());
});
world.send(E);
assert_eq!(world.get::<B>(e2), Some(&B(vec!["hello".into()])));
assert!(world.remove_component(c2).is_some());
assert!(!world.handlers().contains(s2));
assert!(!world.entities().contains(e2));
assert_eq!(world.archetypes().len(), 1);
}
#[test]
fn component_member_of() {
let mut world = World::new();
#[derive(Component)]
struct A;
#[derive(Component)]
struct B;
#[derive(Component)]
struct C;
let c1 = world.add_component::<A>();
let c2 = world.add_component::<B>();
let c3 = world.add_component::<C>();
let e1 = world.spawn();
let e2 = world.spawn();
let e3 = world.spawn();
world.insert(e1, A);
world.insert(e2, A);
world.insert(e2, B);
world.insert(e3, A);
world.insert(e3, B);
world.insert(e3, C);
assert_eq!(world.components()[c1].member_of.len(), 3);
assert_eq!(world.components()[c2].member_of.len(), 2);
assert_eq!(world.components()[c3].member_of.len(), 1);
world.remove_component(c3);
assert_eq!(world.components()[c1].member_of.len(), 2);
assert_eq!(world.components()[c2].member_of.len(), 1);
world.remove_component(c2);
assert_eq!(world.components()[c1].member_of.len(), 1);
}
}