use alloc::boxed::Box;
use crate::{
event::{Event, EventKey},
observer::{Observer, On},
reflect::from_reflect_with_fallback,
world::{DeferredWorld, World},
};
use bevy_reflect::{FromReflect, FromType, PartialReflect, Reflect, TypePath, TypeRegistry};
#[derive(Clone)]
pub struct ReflectEvent(ReflectEventFns);
#[derive(Clone)]
pub struct ReflectEventFns {
pub trigger: fn(&mut World, &dyn PartialReflect, &TypeRegistry),
pub create_observer: fn(Box<dyn Fn(&dyn Reflect, DeferredWorld) + Send + Sync>) -> Observer,
pub register_event_key: fn(&mut World) -> EventKey,
}
impl ReflectEventFns {
pub fn new<'a, T: Event + FromReflect + TypePath>() -> Self
where
T::Trigger<'a>: Default,
{
<ReflectEvent as FromType<T>>::from_type().0
}
}
impl ReflectEvent {
pub fn trigger(&self, world: &mut World, event: &dyn PartialReflect, registry: &TypeRegistry) {
(self.0.trigger)(world, event, registry);
}
pub fn create_observer(
&self,
callback: Box<dyn Fn(&dyn Reflect, DeferredWorld) + Send + Sync>,
) -> Observer {
(self.0.create_observer)(callback)
}
pub fn register_event_key(&self, world: &mut World) -> EventKey {
(self.0.register_event_key)(world)
}
pub fn new(fns: ReflectEventFns) -> Self {
ReflectEvent(fns)
}
pub fn fn_pointers(&self) -> &ReflectEventFns {
&self.0
}
}
impl<'a, E: Event + Reflect + TypePath> FromType<E> for ReflectEvent
where
<E as Event>::Trigger<'a>: Default,
{
fn from_type() -> Self {
ReflectEvent(ReflectEventFns {
trigger: |world, reflected_event, registry| {
let event = from_reflect_with_fallback::<E>(reflected_event, world, registry);
world.trigger(event);
},
create_observer: |callback| {
Observer::new(move |event: On<E>, world: DeferredWorld| {
callback((*event).as_reflect(), world);
})
},
register_event_key: |world| world.register_event_key::<E>(),
})
}
}