use alloc::borrow::Cow;
use core::alloc::Layout;
use core::any::TypeId;
use core::ops::Index;
pub use evenio_macros::TargetedEvent;
use super::global::GlobalEvent;
use super::{Event, EventDescriptor, EventKind, EventPtr, Mutability};
use crate::archetype::Archetype;
use crate::drop::DropFn;
use crate::entity::EntityLocation;
use crate::handler::{HandlerConfig, HandlerInfo, HandlerParam, InitError};
use crate::map::{Entry, TypeIdMap};
use crate::slot_map::{Key, SlotMap};
use crate::sparse::SparseIndex;
use crate::world::{UnsafeWorldCell, World};
pub trait TargetedEvent: Event<EventIdx = TargetedEventIdx> {}
impl<E: Event<EventIdx = TargetedEventIdx>> TargetedEvent for E {}
#[derive(Debug)]
pub struct TargetedEvents {
infos: SlotMap<TargetedEventInfo>,
by_type_id: TypeIdMap<TargetedEventId>,
}
impl TargetedEvents {
pub(crate) fn new() -> Self {
Self {
infos: SlotMap::new(),
by_type_id: TypeIdMap::default(),
}
}
pub(crate) fn add(&mut self, desc: EventDescriptor) -> (TargetedEventId, bool) {
let mut info = TargetedEventInfo {
id: TargetedEventId::NULL,
name: desc.name,
kind: desc.kind,
type_id: desc.type_id,
layout: desc.layout,
drop: desc.drop,
mutability: desc.mutability,
};
let insert = || {
TargetedEventId(
self.infos
.insert_with(|id| {
info.id = TargetedEventId(id);
info
})
.expect("too many targeted events"),
)
};
if let Some(type_id) = desc.type_id {
match self.by_type_id.entry(type_id) {
Entry::Vacant(v) => (*v.insert(insert()), true),
Entry::Occupied(o) => (*o.get(), false),
}
} else {
(insert(), true)
}
}
pub fn get(&self, id: TargetedEventId) -> Option<&TargetedEventInfo> {
self.infos.get(id.0)
}
#[inline]
pub fn get_by_index(&self, idx: TargetedEventIdx) -> Option<&TargetedEventInfo> {
Some(self.infos.get_by_index(idx.0)?.1)
}
pub fn get_by_type_id(&self, type_id: TypeId) -> Option<&TargetedEventInfo> {
let idx = *self.by_type_id.get(&type_id)?;
Some(unsafe { self.get(idx).unwrap_unchecked() })
}
pub fn contains(&self, id: TargetedEventId) -> bool {
self.get(id).is_some()
}
pub(crate) fn remove(&mut self, id: TargetedEventId) -> Option<TargetedEventInfo> {
let info = self.infos.remove(id.0)?;
if let Some(type_id) = info.type_id {
self.by_type_id.remove(&type_id);
}
Some(info)
}
pub fn iter(&self) -> impl Iterator<Item = &TargetedEventInfo> {
self.infos.iter().map(|(_, v)| v)
}
}
impl Index<TargetedEventId> for TargetedEvents {
type Output = TargetedEventInfo;
fn index(&self, index: TargetedEventId) -> &Self::Output {
if let Some(info) = self.get(index) {
info
} else {
panic!("no such targeted event with ID of {index:?} exists")
}
}
}
impl Index<TargetedEventIdx> for TargetedEvents {
type Output = TargetedEventInfo;
fn index(&self, index: TargetedEventIdx) -> &Self::Output {
if let Some(info) = self.get_by_index(index) {
info
} else {
panic!("no such targeted event with index of {index:?} exists")
}
}
}
impl Index<TypeId> for TargetedEvents {
type Output = TargetedEventInfo;
fn index(&self, index: TypeId) -> &Self::Output {
if let Some(info) = self.get_by_type_id(index) {
info
} else {
panic!("no such targeted event with type ID of {index:?} exists")
}
}
}
unsafe impl HandlerParam for &'_ TargetedEvents {
type State = ();
type This<'a> = &'a TargetedEvents;
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.targeted_events()
}
fn refresh_archetype(_state: &mut Self::State, _arch: &Archetype) {}
fn remove_archetype(_state: &mut Self::State, _arch: &Archetype) {}
}
#[derive(Debug)]
pub struct TargetedEventInfo {
name: Cow<'static, str>,
id: TargetedEventId,
kind: EventKind,
type_id: Option<TypeId>,
layout: Layout,
drop: DropFn,
mutability: Mutability,
}
impl TargetedEventInfo {
pub fn name(&self) -> &str {
&self.name
}
pub fn id(&self) -> TargetedEventId {
self.id
}
pub fn kind(&self) -> EventKind {
self.kind
}
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
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default, Hash, Debug)]
pub struct TargetedEventId(Key);
impl TargetedEventId {
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) -> TargetedEventIdx {
TargetedEventIdx(self.0.index())
}
pub const fn generation(self) -> u32 {
self.0.generation().get()
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct TargetedEventIdx(pub u32);
unsafe impl SparseIndex for TargetedEventIdx {
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 AddTargetedEvent(pub TargetedEventId);
#[derive(GlobalEvent, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct RemoveTargetedEvent(pub TargetedEventId);