use alloc::borrow::Cow;
use alloc::collections::BTreeMap;
#[cfg(not(feature = "std"))]
use alloc::{boxed::Box, vec, vec::Vec};
use core::any::TypeId;
use core::cmp::Ordering;
use core::hash::{Hash, Hasher};
use core::marker::PhantomData;
use core::ops::{Deref, DerefMut, Index};
use core::ptr::NonNull;
use core::{any, fmt};
use evenio_macros::all_tuples;
pub use evenio_macros::HandlerParam;
use crate::access::{Access, ComponentAccess};
use crate::aliased_box::AliasedBox;
use crate::archetype::Archetype;
use crate::bit_set::BitSet;
use crate::component::ComponentIdx;
use crate::entity::EntityLocation;
use crate::event::{EventId, EventPtr, GlobalEvent, GlobalEventIdx, TargetedEventIdx};
use crate::map::TypeIdMap;
use crate::slot_map::{Key, SlotMap};
use crate::sparse::SparseIndex;
use crate::world::{UnsafeWorldCell, World};
#[derive(Debug)]
pub struct Handlers {
infos: SlotMap<HandlerInfo>,
by_global_event: Vec<HandlerList>,
by_type_id: TypeIdMap<HandlerInfoPtr>,
insert_counter: u64,
by_insert_order: BTreeMap<u64, HandlerInfoPtr>,
}
impl Handlers {
pub(crate) fn new() -> Self {
Self {
infos: SlotMap::new(),
by_global_event: vec![],
by_type_id: Default::default(),
insert_counter: 0,
by_insert_order: BTreeMap::new(),
}
}
pub(crate) fn add(&mut self, info: HandlerInfo) -> HandlerId {
let ptr = info.ptr();
if let Some(type_id) = info.type_id() {
assert!(self.by_type_id.insert(type_id, ptr).is_none());
}
let Some(k) = self.infos.insert_with(|k| {
let id = HandlerId(k);
let inner = unsafe { &mut *ptr.0.as_ptr() };
inner.id = id;
inner.order = self.insert_counter;
if let EventId::Global(id) = info.received_event() {
let idx = id.index().0 as usize;
if idx >= self.by_global_event.len() {
self.by_global_event
.resize_with(idx + 1, HandlerList::default);
}
self.by_global_event[idx].insert(ptr, info.priority())
}
info
}) else {
panic!("too many handlers")
};
self.by_insert_order.insert(self.insert_counter, ptr);
self.insert_counter += 1;
debug_assert_eq!(self.infos.len(), self.by_insert_order.len() as u32);
HandlerId(k)
}
pub(crate) fn remove(&mut self, id: HandlerId) -> Option<HandlerInfo> {
let info = self.infos.remove(id.0)?;
if let EventId::Global(event_id) = info.received_event() {
let list = &mut self.by_global_event[event_id.index().0 as usize];
list.remove(info.ptr());
}
if let Some(type_id) = info.type_id() {
self.by_type_id.remove(&type_id);
}
self.by_insert_order.remove(&info.order());
debug_assert_eq!(self.infos.len(), self.by_insert_order.len() as u32);
Some(info)
}
pub(crate) fn register_event(&mut self, event_idx: GlobalEventIdx) {
let idx = event_idx.0 as usize;
if idx >= self.by_global_event.len() {
self.by_global_event
.resize_with(idx + 1, HandlerList::default);
}
}
pub(crate) fn get_global_list(&self, idx: GlobalEventIdx) -> Option<&HandlerList> {
self.by_global_event.get(idx.0 as usize)
}
pub fn get(&self, id: HandlerId) -> Option<&HandlerInfo> {
self.infos.get(id.0)
}
pub(crate) fn get_mut(&mut self, id: HandlerId) -> Option<&mut HandlerInfo> {
self.infos.get_mut(id.0)
}
pub fn get_by_index(&self, idx: HandlerIdx) -> Option<&HandlerInfo> {
self.infos.get_by_index(idx.0).map(|(_, v)| v)
}
pub fn get_by_type_id(&self, id: TypeId) -> Option<&HandlerInfo> {
self.by_type_id.get(&id).map(|p| unsafe { p.as_info() })
}
pub fn contains(&self, id: HandlerId) -> bool {
self.get(id).is_some()
}
pub fn iter(&self) -> impl Iterator<Item = &HandlerInfo> {
self.by_insert_order
.values()
.map(|ptr| unsafe { ptr.as_info() })
}
pub(crate) fn iter_mut(&mut self) -> impl Iterator<Item = &mut HandlerInfo> {
self.by_insert_order
.values_mut()
.map(|ptr| unsafe { ptr.as_info_mut() })
}
}
impl Index<HandlerId> for Handlers {
type Output = HandlerInfo;
fn index(&self, index: HandlerId) -> &Self::Output {
if let Some(info) = self.get(index) {
info
} else {
panic!("no such handler with ID of {index:?} exists")
}
}
}
impl Index<HandlerIdx> for Handlers {
type Output = HandlerInfo;
fn index(&self, index: HandlerIdx) -> &Self::Output {
if let Some(info) = self.get_by_index(index) {
info
} else {
panic!("no such handler with index of {index:?} exists")
}
}
}
impl Index<TypeId> for Handlers {
type Output = HandlerInfo;
fn index(&self, index: TypeId) -> &Self::Output {
if let Some(info) = self.get_by_type_id(index) {
info
} else {
panic!("no such handler with type ID of {index:?} exists")
}
}
}
unsafe impl HandlerParam for &'_ Handlers {
type State = ();
type This<'a> = &'a Handlers;
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.handlers()
}
fn refresh_archetype(_state: &mut Self::State, _arch: &Archetype) {}
fn remove_archetype(_state: &mut Self::State, _arch: &Archetype) {}
}
#[repr(transparent)]
pub struct HandlerInfo(AliasedBox<HandlerInfoInner>);
#[derive(Clone, Copy, Debug)]
#[repr(transparent)]
pub(crate) struct HandlerInfoPtr(NonNull<HandlerInfoInner>);
impl HandlerInfoPtr {
pub(crate) unsafe fn as_info(&self) -> &HandlerInfo {
&*(self as *const Self as *const HandlerInfo)
}
pub(crate) unsafe fn as_info_mut(&mut self) -> &mut HandlerInfo {
&mut *(self as *mut Self as *mut HandlerInfo)
}
}
impl PartialEq for HandlerInfoPtr {
fn eq(&self, other: &Self) -> bool {
self.cmp(other).is_eq()
}
}
impl Eq for HandlerInfoPtr {}
impl PartialOrd for HandlerInfoPtr {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for HandlerInfoPtr {
fn cmp(&self, other: &Self) -> Ordering {
self.0.cast::<()>().cmp(&other.0.cast::<()>())
}
}
impl Hash for HandlerInfoPtr {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.cast::<()>().hash(state)
}
}
pub(crate) struct HandlerInfoInner<H: ?Sized = dyn Handler> {
pub(crate) name: Cow<'static, str>,
pub(crate) id: HandlerId,
pub(crate) type_id: Option<TypeId>,
pub(crate) order: u64,
pub(crate) received_event: EventId,
pub(crate) received_event_access: Access,
pub(crate) targeted_event_component_access: ComponentAccess,
pub(crate) sent_untargeted_events: BitSet<GlobalEventIdx>,
pub(crate) sent_targeted_events: BitSet<TargetedEventIdx>,
pub(crate) event_queue_access: Access,
pub(crate) component_access: ComponentAccess,
pub(crate) archetype_filter: ComponentAccess,
pub(crate) referenced_components: BitSet<ComponentIdx>,
pub(crate) priority: HandlerPriority,
pub(crate) handler: H,
}
impl HandlerInfo {
pub(crate) fn new<H: Handler>(inner: HandlerInfoInner<H>) -> Self {
let b: Box<HandlerInfoInner> = Box::new(inner);
Self(b.into())
}
pub fn name(&self) -> &str {
unsafe { &(*AliasedBox::as_ptr(&self.0)).name }
}
pub fn id(&self) -> HandlerId {
unsafe { (*AliasedBox::as_ptr(&self.0)).id }
}
pub fn type_id(&self) -> Option<TypeId> {
unsafe { (*AliasedBox::as_ptr(&self.0)).type_id }
}
pub(crate) fn order(&self) -> u64 {
unsafe { (*AliasedBox::as_ptr(&self.0)).order }
}
pub fn received_event(&self) -> EventId {
unsafe { (*AliasedBox::as_ptr(&self.0)).received_event }
}
pub fn received_event_access(&self) -> Access {
unsafe { (*AliasedBox::as_ptr(&self.0)).received_event_access }
}
pub fn targeted_event_component_access(&self) -> Option<&ComponentAccess> {
self.received_event()
.is_targeted()
.then(|| unsafe { &(*AliasedBox::as_ptr(&self.0)).targeted_event_component_access })
}
pub fn sent_global_events(
&self,
) -> impl Iterator<Item = GlobalEventIdx> + Clone + fmt::Debug + '_ {
self.sent_global_events_bitset().iter()
}
pub(crate) fn sent_global_events_bitset(&self) -> &BitSet<GlobalEventIdx> {
unsafe { &(*AliasedBox::as_ptr(&self.0)).sent_untargeted_events }
}
pub fn sent_targeted_events(
&self,
) -> impl Iterator<Item = TargetedEventIdx> + Clone + fmt::Debug + '_ {
self.sent_targeted_events_bitset().iter()
}
pub(crate) fn sent_targeted_events_bitset(&self) -> &BitSet<TargetedEventIdx> {
unsafe { &(*AliasedBox::as_ptr(&self.0)).sent_targeted_events }
}
pub fn event_queue_access(&self) -> Access {
unsafe { (*AliasedBox::as_ptr(&self.0)).event_queue_access }
}
pub fn component_access(&self) -> &ComponentAccess {
unsafe { &(*AliasedBox::as_ptr(&self.0)).component_access }
}
pub fn archetype_filter(&self) -> &ComponentAccess {
unsafe { &(*AliasedBox::as_ptr(&self.0)).archetype_filter }
}
pub fn referenced_components(
&self,
) -> impl Iterator<Item = ComponentIdx> + Clone + fmt::Debug + '_ {
unsafe { &(*AliasedBox::as_ptr(&self.0)).referenced_components }.iter()
}
pub fn references_component(&self, idx: ComponentIdx) -> bool {
unsafe { &(*AliasedBox::as_ptr(&self.0)).referenced_components }.contains(idx)
}
pub fn priority(&self) -> HandlerPriority {
unsafe { (*AliasedBox::as_ptr(&self.0)).priority }
}
pub(crate) fn ptr(&self) -> HandlerInfoPtr {
HandlerInfoPtr(AliasedBox::as_non_null(&self.0))
}
pub(crate) fn handler_mut(&mut self) -> &mut dyn Handler {
unsafe { &mut (*AliasedBox::as_mut_ptr(&mut self.0)).handler }
}
}
impl fmt::Debug for HandlerInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("")
.field("name", &self.name())
.field("id", &self.id())
.field("type_id", &self.type_id())
.field("order", &self.order())
.field("received_event", &self.received_event())
.field("received_event_access", &self.received_event_access())
.field("targeted_event_component_access", &self.targeted_event_component_access())
.field("sent_global_events", &self.sent_global_events())
.field("sent_targeted_events", &self.sent_targeted_events())
.field("event_queue_access", &self.event_queue_access())
.field("component_access", &self.component_access())
.field("archetype_filter", &self.archetype_filter())
.field("referenced_components", &self.referenced_components())
.field("priority", &self.priority())
.finish_non_exhaustive()
}
}
#[derive(Debug, Default)]
pub(crate) struct HandlerList {
before: u32,
after: u32,
entries: Vec<HandlerInfoPtr>,
}
unsafe impl Sync for HandlerList {}
impl HandlerList {
pub(crate) const fn new() -> HandlerList {
Self {
before: 0,
after: 0,
entries: vec![],
}
}
pub(crate) fn insert(&mut self, ptr: HandlerInfoPtr, priority: HandlerPriority) {
assert!(self.entries.len() < u32::MAX as usize);
match priority {
HandlerPriority::High => {
self.entries.insert(self.before as usize, ptr);
self.before += 1;
self.after += 1;
}
HandlerPriority::Medium => {
self.entries.insert(self.after as usize, ptr);
self.after += 1;
}
HandlerPriority::Low => {
self.entries.push(ptr);
}
}
}
pub(crate) fn remove(&mut self, ptr: HandlerInfoPtr) -> bool {
if let Some(idx) = self.entries.iter().position(|&p| p == ptr) {
self.entries.remove(idx);
let idx = idx as u32;
if idx < self.after {
self.after -= 1;
if idx < self.before {
self.before -= 1;
}
}
true
} else {
false
}
}
pub(crate) fn slice(&self) -> &[HandlerInfoPtr] {
&self.entries
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug)]
pub struct HandlerId(Key);
impl HandlerId {
pub const NULL: Self = Self(Key::NULL);
pub const fn index(self) -> HandlerIdx {
HandlerIdx(self.0.index())
}
pub const fn generation(self) -> u32 {
self.0.generation().get()
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct HandlerIdx(pub u32);
unsafe impl SparseIndex for HandlerIdx {
const MAX: Self = Self(u32::MAX);
fn index(self) -> usize {
self.0.index()
}
fn from_index(idx: usize) -> Self {
Self(u32::from_index(idx))
}
}
#[diagnostic::on_unimplemented(
message = "the type `{Self}` is not a valid handler",
note = "it is likely that one of the handler's function parameters is not a valid \
`HandlerParam`",
note = "try removing parameters individually until `IntoHandler<_>` is implemented"
)]
pub trait IntoHandler<Marker>: Sized {
type Handler: Handler;
fn into_handler(self) -> Self::Handler;
fn no_type_id(self) -> NoTypeId<Self::Handler> {
NoTypeId(self.into_handler())
}
fn high(self) -> HighPriority<Self::Handler> {
HighPriority(self.into_handler())
}
fn low(self) -> LowPriority<Self::Handler> {
LowPriority(self.into_handler())
}
}
#[doc(hidden)]
#[derive(Debug)]
pub enum FunctionHandlerMarker {}
impl<Marker, F> IntoHandler<(FunctionHandlerMarker, Marker)> for F
where
Marker: 'static,
F: HandlerParamFunction<Marker>,
{
type Handler = FunctionHandler<Marker, F>;
fn into_handler(self) -> Self::Handler {
FunctionHandler::new(self)
}
}
impl<H: Handler> IntoHandler<()> for H {
type Handler = Self;
fn into_handler(self) -> Self::Handler {
self
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug)]
pub struct NoTypeId<S>(pub S);
impl<H: Handler> Handler for NoTypeId<H> {
fn type_id(&self) -> Option<TypeId> {
None
}
fn name(&self) -> Cow<'static, str> {
self.0.name()
}
fn init(&mut self, world: &mut World, config: &mut HandlerConfig) -> Result<(), InitError> {
self.0.init(world, config)
}
unsafe fn run(
&mut self,
info: &HandlerInfo,
event_ptr: EventPtr,
target_location: EntityLocation,
world: UnsafeWorldCell,
) {
self.0.run(info, event_ptr, target_location, world)
}
fn refresh_archetype(&mut self, arch: &Archetype) {
self.0.refresh_archetype(arch)
}
fn remove_archetype(&mut self, arch: &Archetype) {
self.0.remove_archetype(arch)
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug)]
pub struct HighPriority<S>(pub S);
impl<H: Handler> Handler for HighPriority<H> {
fn type_id(&self) -> Option<TypeId> {
self.0.type_id()
}
fn name(&self) -> Cow<'static, str> {
self.0.name()
}
fn init(&mut self, world: &mut World, config: &mut HandlerConfig) -> Result<(), InitError> {
let res = self.0.init(world, config);
config.set_priority(HandlerPriority::High);
res
}
unsafe fn run(
&mut self,
info: &HandlerInfo,
event_ptr: EventPtr,
target_location: EntityLocation,
world: UnsafeWorldCell,
) {
self.0.run(info, event_ptr, target_location, world)
}
fn refresh_archetype(&mut self, arch: &Archetype) {
self.0.refresh_archetype(arch)
}
fn remove_archetype(&mut self, arch: &Archetype) {
self.0.remove_archetype(arch)
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug)]
pub struct LowPriority<S>(pub S);
impl<H: Handler> Handler for LowPriority<H> {
fn type_id(&self) -> Option<TypeId> {
self.0.type_id()
}
fn name(&self) -> Cow<'static, str> {
self.0.name()
}
fn init(&mut self, world: &mut World, config: &mut HandlerConfig) -> Result<(), InitError> {
let res = self.0.init(world, config);
config.set_priority(HandlerPriority::Low);
res
}
unsafe fn run(
&mut self,
info: &HandlerInfo,
event_ptr: EventPtr,
target_location: EntityLocation,
world: UnsafeWorldCell,
) {
self.0.run(info, event_ptr, target_location, world)
}
fn refresh_archetype(&mut self, arch: &Archetype) {
self.0.refresh_archetype(arch)
}
fn remove_archetype(&mut self, arch: &Archetype) {
self.0.remove_archetype(arch)
}
}
pub trait Handler: 'static {
fn type_id(&self) -> Option<TypeId>;
fn name(&self) -> Cow<'static, str>;
fn init(&mut self, world: &mut World, config: &mut HandlerConfig) -> Result<(), InitError>;
unsafe fn run(
&mut self,
info: &HandlerInfo,
event_ptr: EventPtr,
target_location: EntityLocation,
world: UnsafeWorldCell,
);
fn refresh_archetype(&mut self, arch: &Archetype);
fn remove_archetype(&mut self, arch: &Archetype);
}
#[derive(Clone, Debug)]
pub struct InitError(pub Box<str>);
impl fmt::Display for InitError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", &self.0)
}
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl std::error::Error for InitError {}
#[derive(Clone, Default, Debug)]
pub struct HandlerConfig {
pub(crate) priority: HandlerPriority,
pub(crate) received_event: ReceivedEventId,
pub(crate) received_event_access: MaybeInvalidAccess,
pub(crate) targeted_event_component_access: ComponentAccess,
pub(crate) sent_global_events: BitSet<GlobalEventIdx>,
pub(crate) sent_targeted_events: BitSet<TargetedEventIdx>,
pub(crate) event_queue_access: MaybeInvalidAccess,
pub(crate) component_accesses: Vec<ComponentAccess>,
pub(crate) referenced_components: BitSet<ComponentIdx>,
}
impl HandlerConfig {
pub fn new() -> Self {
Self::default()
}
pub fn set_priority(&mut self, priority: HandlerPriority) {
self.priority = priority;
}
pub fn set_received_event<E: Into<EventId>>(&mut self, event: E) {
let event = event.into();
self.received_event = match self.received_event {
ReceivedEventId::None => ReceivedEventId::Ok(event),
ReceivedEventId::Ok(old_event) => {
if old_event == event {
ReceivedEventId::Ok(event)
} else {
ReceivedEventId::Invalid
}
}
ReceivedEventId::Invalid => ReceivedEventId::Invalid,
};
}
pub fn set_received_event_access(&mut self, access: Access) {
self.received_event_access = match self.received_event_access {
MaybeInvalidAccess::Ok(old_access) => access
.join(old_access)
.map_or(MaybeInvalidAccess::Invalid, MaybeInvalidAccess::Ok),
MaybeInvalidAccess::Invalid => MaybeInvalidAccess::Invalid,
};
}
pub fn set_targeted_event_component_access(&mut self, component_access: ComponentAccess) {
self.targeted_event_component_access = component_access;
}
pub fn insert_sent_global_event(&mut self, event: GlobalEventIdx) -> bool {
self.sent_global_events.insert(event)
}
pub fn insert_sent_targeted_event(&mut self, event: TargetedEventIdx) -> bool {
self.sent_targeted_events.insert(event)
}
pub fn set_event_queue_access(&mut self, access: Access) {
self.event_queue_access = match self.event_queue_access {
MaybeInvalidAccess::Ok(old_access) => access
.join(old_access)
.map_or(MaybeInvalidAccess::Invalid, MaybeInvalidAccess::Ok),
MaybeInvalidAccess::Invalid => MaybeInvalidAccess::Invalid,
};
}
pub fn push_component_access(&mut self, component_access: ComponentAccess) {
self.component_accesses.push(component_access);
}
pub fn insert_referenced_components(&mut self, comp: ComponentIdx) {
self.referenced_components.insert(comp);
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default, Debug)]
pub enum HandlerPriority {
High,
#[default]
Medium,
Low,
}
#[derive(Copy, Clone, Default, Debug)]
pub(crate) enum ReceivedEventId {
#[default]
None,
Ok(EventId),
Invalid,
}
#[derive(Copy, Clone, Debug)]
pub(crate) enum MaybeInvalidAccess {
Ok(Access),
Invalid,
}
impl Default for MaybeInvalidAccess {
fn default() -> Self {
Self::Ok(Access::default())
}
}
pub unsafe trait HandlerParam {
type State: 'static;
type This<'a>;
fn init(world: &mut World, config: &mut HandlerConfig) -> Result<Self::State, InitError>;
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>;
fn refresh_archetype(state: &mut Self::State, arch: &Archetype);
fn remove_archetype(state: &mut Self::State, arch: &Archetype);
}
unsafe impl<T> HandlerParam for PhantomData<T> {
type State = ();
type This<'a> = Self;
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> {
Self
}
fn refresh_archetype(_state: &mut Self::State, _arch: &Archetype) {}
fn remove_archetype(_state: &mut Self::State, _arch: &Archetype) {}
}
macro_rules! impl_handler_param_tuple {
($(($P:ident, $s:ident)),*) => {
#[allow(unused_variables, clippy::unused_unit)]
unsafe impl<$($P: HandlerParam),*> HandlerParam for ($($P,)*) {
type State = ($($P::State,)*);
type This<'a> = ($($P::This<'a>,)*);
#[inline]
fn init(world: &mut World, config: &mut HandlerConfig) -> Result<Self::State, InitError> {
Ok((
$(
$P::init(world, config)?,
)*
))
}
#[inline]
unsafe fn get<'a>(
($($s,)*): &'a mut Self::State,
info: &'a HandlerInfo,
event_ptr: EventPtr<'a>,
target_location: EntityLocation,
world: UnsafeWorldCell<'a>,
) -> Self::This<'a> {
(
$(
$P::get($s, info, event_ptr, target_location, world),
)*
)
}
fn refresh_archetype(
($($s,)*): &mut Self::State,
arch: &Archetype
)
{
$(
$P::refresh_archetype($s, arch);
)*
}
fn remove_archetype(
($($s,)*): &mut Self::State,
arch: &Archetype
)
{
$(
$P::remove_archetype($s, arch);
)*
}
}
}
}
all_tuples!(impl_handler_param_tuple, 0, 15, P, s);
pub struct FunctionHandler<Marker, F: HandlerParamFunction<Marker>> {
func: F,
state: Option<<F::Param as HandlerParam>::State>,
}
impl<Marker, F> FunctionHandler<Marker, F>
where
F: HandlerParamFunction<Marker>,
{
pub fn new(func: F) -> Self {
Self { func, state: None }
}
}
impl<Marker, F> fmt::Debug for FunctionHandler<Marker, F>
where
F: HandlerParamFunction<Marker> + fmt::Debug,
<F::Param as HandlerParam>::State: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("FunctionHandler")
.field("func", &self.func)
.field("state", &self.state)
.finish()
}
}
impl<Marker, F> Handler for FunctionHandler<Marker, F>
where
F: HandlerParamFunction<Marker>,
Marker: 'static,
{
fn type_id(&self) -> Option<TypeId> {
Some(TypeId::of::<F>())
}
fn name(&self) -> Cow<'static, str> {
Cow::Borrowed(any::type_name::<F>())
}
fn init(&mut self, world: &mut World, config: &mut HandlerConfig) -> Result<(), InitError> {
self.state = Some(<F::Param as HandlerParam>::init(world, config)?);
Ok(())
}
unsafe fn run(
&mut self,
handler_info: &HandlerInfo,
event_ptr: EventPtr,
target_location: EntityLocation,
world: UnsafeWorldCell,
) {
let state = unsafe { self.state.as_mut().unwrap_unchecked() };
let param =
<F::Param as HandlerParam>::get(state, handler_info, event_ptr, target_location, world);
self.func.run(param);
}
fn refresh_archetype(&mut self, arch: &Archetype) {
let state = unsafe { self.state.as_mut().unwrap_unchecked() };
F::Param::refresh_archetype(state, arch)
}
fn remove_archetype(&mut self, arch: &Archetype) {
let state = unsafe { self.state.as_mut().unwrap_unchecked() };
F::Param::remove_archetype(state, arch)
}
}
pub trait HandlerParamFunction<Marker>: 'static {
type Param: HandlerParam;
fn run(&mut self, param: <Self::Param as HandlerParam>::This<'_>);
}
macro_rules! impl_handler_param_function {
($(($P:ident, $p:ident)),*) => {
impl<F, $($P: HandlerParam),*> HandlerParamFunction<fn($($P),*)> for F
where
F: FnMut($($P),*) + FnMut($($P::This<'_>),*) + 'static,
{
type Param = ($($P,)*);
fn run(
&mut self,
($($p,)*): <Self::Param as HandlerParam>::This<'_>
) {
(self)($($p),*)
}
}
}
}
all_tuples!(impl_handler_param_function, 0, 15, P, p);
#[derive(Debug)]
pub struct Local<'a, T> {
state: &'a mut T,
}
unsafe impl<T: Default + 'static> HandlerParam for Local<'_, T> {
type State = T;
type This<'a> = Local<'a, T>;
fn init(_world: &mut World, _config: &mut HandlerConfig) -> Result<Self::State, InitError> {
Ok(T::default())
}
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> {
Local { state }
}
fn refresh_archetype(_state: &mut Self::State, _arch: &Archetype) {}
fn remove_archetype(_state: &mut Self::State, _arch: &Archetype) {}
}
impl<T> Deref for Local<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.state
}
}
impl<T> DerefMut for Local<'_, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.state
}
}
impl<T: fmt::Display> fmt::Display for Local<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.state.fmt(f)
}
}
unsafe impl HandlerParam for &'_ HandlerInfo {
type State = ();
type This<'a> = &'a HandlerInfo;
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> {
info
}
fn refresh_archetype(_state: &mut Self::State, _arch: &Archetype) {}
fn remove_archetype(_state: &mut Self::State, _arch: &Archetype) {}
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
unsafe impl<P: HandlerParam> HandlerParam for std::sync::Mutex<P> {
type State = P::State;
type This<'a> = std::sync::Mutex<P::This<'a>>;
fn init(world: &mut World, config: &mut HandlerConfig) -> Result<Self::State, InitError> {
P::init(world, config)
}
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> {
std::sync::Mutex::new(P::get(state, info, event_ptr, target_location, world))
}
fn refresh_archetype(state: &mut Self::State, arch: &Archetype) {
P::refresh_archetype(state, arch)
}
fn remove_archetype(state: &mut Self::State, arch: &Archetype) {
P::remove_archetype(state, arch)
}
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
unsafe impl<P: HandlerParam> HandlerParam for std::sync::RwLock<P> {
type State = P::State;
type This<'a> = std::sync::RwLock<P::This<'a>>;
fn init(world: &mut World, config: &mut HandlerConfig) -> Result<Self::State, InitError> {
P::init(world, config)
}
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> {
std::sync::RwLock::new(P::get(state, info, event_ptr, target_location, world))
}
fn refresh_archetype(state: &mut Self::State, arch: &Archetype) {
P::refresh_archetype(state, arch)
}
fn remove_archetype(state: &mut Self::State, arch: &Archetype) {
P::remove_archetype(state, arch)
}
}
#[derive(GlobalEvent, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct AddHandler(pub HandlerId);
#[derive(GlobalEvent, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct RemoveHandler(pub HandlerId);
#[cfg(test)]
mod tests {
use evenio::prelude::*;
use super::*;
use crate::event::GlobalEvents;
#[test]
#[allow(dead_code)]
fn derive_handler_param() {
#[derive(HandlerParam)]
struct UnitParam;
#[derive(HandlerParam)]
struct ParamWithLifetime<'a> {
foo: &'a Handlers,
}
#[derive(HandlerParam)]
struct ParamWithTwoLifetimes<'a, 'b> {
foo: &'a Handlers,
bar: &'b GlobalEvents,
}
#[derive(HandlerParam)]
struct ParamWithTypeParam<'a, T> {
foo: &'a Handlers,
bar: T,
}
#[derive(HandlerParam)]
struct TupleStructParam<'a>(&'a Handlers, &'a GlobalEvents);
assert_handler_param::<UnitParam>();
assert_handler_param::<ParamWithLifetime>();
assert_handler_param::<ParamWithTwoLifetimes>();
assert_handler_param::<ParamWithTypeParam<()>>();
fn assert_handler_param<P: HandlerParam>() {}
}
#[test]
fn handler_run_order() {
let mut world = World::new();
#[derive(TargetedEvent)]
struct E;
#[derive(Component)]
struct Tracker(String);
fn a(_: Receiver<E, &mut Tracker>) {
unreachable!()
}
fn b(r: Receiver<E, &mut Tracker>) {
assert_eq!(r.query.0, "");
r.query.0.push('b');
}
fn c(r: Receiver<E, &Tracker>) {
assert_eq!(r.query.0, "b");
}
let a_id = world.add_handler(a);
world.add_handler(b);
world.remove_handler(a_id);
world.add_handler(c);
let e = world.spawn();
world.insert(e, Tracker(String::new()));
world.send_to(e, E);
}
#[test]
fn handler_info_aliasing() {
let mut world = World::new();
#[derive(GlobalEvent)]
struct E;
world.add_handler(|_: Receiver<E>, info: &HandlerInfo| {
let _foo = info.name();
let _bar = info.received_event();
let _baz = info.referenced_components();
let _ = format!("{info:?}");
});
world.send(E);
}
}