diff options
Diffstat (limited to 'ecs/src/system')
| -rw-r--r-- | ecs/src/system/observer.rs | 276 | ||||
| -rw-r--r-- | ecs/src/system/stateful.rs | 127 | 
2 files changed, 402 insertions, 1 deletions
diff --git a/ecs/src/system/observer.rs b/ecs/src/system/observer.rs new file mode 100644 index 0000000..5455fd4 --- /dev/null +++ b/ecs/src/system/observer.rs @@ -0,0 +1,276 @@ +use std::fmt::Debug; +use std::marker::PhantomData; +use std::mem::transmute; +use std::slice::Iter as SliceIter; + +use ecs_macros::Component; +use seq_macro::seq; + +use crate::component::Component; +use crate::entity::Handle as EntityHandle; +use crate::event::Emitted as EmittedEvent; +use crate::pair::Pair; +use crate::system::{ +    Metadata, +    NoCallbacks, +    Param, +    System, +    TypeErased as TypeErasedSystem, +}; +use crate::uid::Uid; +use crate::util::Array; +use crate::World; + +pub trait Observed +{ +    type Events: Array<Pair<Uid, Uid>>; + +    fn events() -> Self::Events; +} + +impl<Relation, Target> Observed for Pair<Relation, Target> +where +    Relation: Component, +    Target: Component, +{ +    type Events = [Pair<Uid, Uid>; 1]; + +    fn events() -> Self::Events +    { +        [Pair::new::<Relation>(Target::id())] +    } +} + +/// Observer system. +pub trait Observer<'world, Impl>: System<'world, Impl> +{ +    type ObservedEvents: Array<Pair<Uid, Uid>>; + +    fn observed_events() -> Self::ObservedEvents; + +    fn finish_observer(self) -> (WrapperComponent, Self::Callbacks); +} + +pub struct Observe<'world, ObservedT: Observed> +{ +    _pd: PhantomData<ObservedT>, +    world: &'world World, +    emitted_event: EmittedEvent<'world>, +} + +impl<'world, ObservedT: Observed> Observe<'world, ObservedT> +{ +    pub fn new(world: &'world World, emitted_event: EmittedEvent<'world>) -> Self +    { +        Self { +            _pd: PhantomData, +            world, +            emitted_event, +        } +    } + +    #[must_use] +    pub fn event(&self) -> Uid +    { +        self.emitted_event.event +    } +} + +impl<ObservedT: Observed> Observe<'_, ObservedT> +{ +    #[must_use] +    pub fn iter(&self) -> ObserveIter<'_> +    { +        ObserveIter { +            world: self.world, +            inner: self.emitted_event.match_ids.iter(), +        } +    } +} + +impl<'a, ObservedT: Observed> IntoIterator for &'a Observe<'_, ObservedT> +{ +    type IntoIter = ObserveIter<'a>; +    type Item = EntityHandle<'a>; + +    fn into_iter(self) -> Self::IntoIter +    { +        self.iter() +    } +} + +pub struct ObserveIter<'observe> +{ +    world: &'observe World, +    inner: SliceIter<'observe, Uid>, +} + +impl<'observe> Iterator for ObserveIter<'observe> +{ +    type Item = EntityHandle<'observe>; + +    fn next(&mut self) -> Option<Self::Item> +    { +        let target = *self.inner.next()?; + +        self.world.get_entity(target) +    } +} + +macro_rules! impl_observer { +    ($c: tt) => { +        seq!(I in 0..$c { +            impl<'world, ObservedT, Func, #(TParam~I,)*> System< +                'world, +                fn(Observe<'world, ObservedT>, #(TParam~I,)*) +            > for Func +            where +                ObservedT: Observed, +                Func: Fn(Observe<'world, ObservedT>, #(TParam~I,)*) + Copy + 'static, +                #(TParam~I: Param<'world, Input = ()>,)* +            { +                type Callbacks = NoCallbacks; + +                fn finish(self) -> (TypeErasedSystem, NoCallbacks) +                { +                    unimplemented!(); +                } +            } + +            impl<'world, ObservedT, Func, #(TParam~I,)*> Observer< +                'world, +                fn(Observe<'world, ObservedT>, #(TParam~I,)*) +            > for Func +            where +                ObservedT: Observed, +                Func: Fn(Observe<'world, ObservedT>, #(TParam~I,)*) + Copy + 'static, +                #(TParam~I: Param<'world, Input = ()>,)* +            { +                type ObservedEvents = ObservedT::Events; + +                fn observed_events() -> Self::ObservedEvents +                { +                    ObservedT::events() +                } + +                fn finish_observer(self) -> (WrapperComponent, NoCallbacks) +                { +                    let wrapper_comp = WrapperComponent { +                        run: Box::new(move |world, metadata, emitted_event| { +                            // SAFETY: The caller of TypeErased::run ensures the lifetime +                            // is correct +                            let world = unsafe { &*std::ptr::from_ref(world) }; + +                            // SAFETY: The caller of TypeErased::run ensures the lifetime +                            // is correct +                            let emitted_event = unsafe { +                                transmute::<EmittedEvent<'_>, EmittedEvent<'_>>( +                                    emitted_event +                                ) +                            }; + +                            self(Observe::new(world, emitted_event), #({ +                                TParam~I::new(world, &metadata) +                            },)*); +                        }), +                    }; + +                    (wrapper_comp, NoCallbacks) +                } +            } +        }); +    }; +} + +seq!(C in 1..16 { +    impl_observer!(C); +}); + +impl<'world, ObservedT, Func> System<'world, fn(Observe<'world, ObservedT>)> for Func +where +    ObservedT: Observed, +    Func: Fn(Observe<'world, ObservedT>) + Copy + 'static, +{ +    type Callbacks = NoCallbacks; + +    fn finish(self) -> (TypeErasedSystem, NoCallbacks) +    { +        const { +            panic!("Observers cannot be used as regular systems"); +        } +    } +} + +impl<'world, ObservedT, Func> Observer<'world, fn(Observe<'world, ObservedT>)> for Func +where +    ObservedT: Observed, +    Func: Fn(Observe<'world, ObservedT>) + Copy + 'static, +{ +    type ObservedEvents = ObservedT::Events; + +    fn observed_events() -> Self::ObservedEvents +    { +        ObservedT::events() +    } + +    fn finish_observer(self) -> (WrapperComponent, NoCallbacks) +    { +        let wrapper_comp = WrapperComponent { +            run: Box::new(move |world, _metadata, emitted_event| { +                // SAFETY: The caller of TypeErased::run ensures the lifetime +                // is correct +                let world = unsafe { &*std::ptr::from_ref(world) }; + +                // SAFETY: The caller of TypeErased::run ensures the lifetime +                // is correct +                let emitted_event = unsafe { +                    transmute::<EmittedEvent<'_>, EmittedEvent<'_>>(emitted_event) +                }; + +                self(Observe::new(world, emitted_event)); +            }), +        }; + +        (wrapper_comp, NoCallbacks) +    } +} + +#[derive(Component)] +pub struct WrapperComponent +{ +    run: Box<RunFn>, +} + +impl WrapperComponent +{ +    pub fn new(run: impl Fn(&World, Metadata, EmittedEvent<'_>) + 'static) -> Self +    { +        Self { run: Box::new(run) } +    } + +    /// Runs the observer system. +    /// +    /// # Safety +    /// `world` must live at least as long as the [`World`] the system belongs to. +    pub unsafe fn run( +        &self, +        world: &World, +        metadata: Metadata, +        emitted_event: EmittedEvent<'_>, +    ) +    { +        (self.run)(world, metadata, emitted_event); +    } +} + +impl Debug for WrapperComponent +{ +    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result +    { +        formatter +            .debug_struct("WrapperComponent") +            .finish_non_exhaustive() +    } +} + +type RunFn = dyn Fn(&World, Metadata, EmittedEvent<'_>); diff --git a/ecs/src/system/stateful.rs b/ecs/src/system/stateful.rs index 7b2b608..e74ef31 100644 --- a/ecs/src/system/stateful.rs +++ b/ecs/src/system/stateful.rs @@ -1,10 +1,18 @@ +use std::mem::transmute;  use std::panic::{RefUnwindSafe, UnwindSafe};  use seq_macro::seq;  use crate::component::local::SystemWithLocalComponents;  use crate::component::Parts as ComponentParts; +use crate::event::Emitted as EmittedEvent;  use crate::system::initializable::{Initializable, MaybeInitializableParamTuple}; +use crate::system::observer::{ +    Observe, +    Observed, +    Observer, +    WrapperComponent as ObserverWrapperComponent, +};  use crate::system::{Into as IntoSystem, Metadata, Param, System, TypeErased};  use crate::World; @@ -68,9 +76,10 @@ macro_rules! impl_system {                  }              } -            impl<Func, #(TParam~I,)*> IntoSystem<fn(#(TParam~I,)*)> +            impl<'world, Func, #(TParam~I,)*> IntoSystem<'world, fn(#(TParam~I,)*)>                  for Func              where +                #(TParam~I: Param<'world>,)*                  Func: Fn(#(TParam~I,)*) + Copy + 'static,              {                  type System = Stateful<Func>; @@ -123,3 +132,119 @@ fn init_initializable_params<'world, SystemT, Params>(  {      Params::init_initializable(system, inputs);  } + +macro_rules! impl_observer { +    ($c: tt) => { +        seq!(I in 0..$c { +            impl<'world, ObservedT, Func, #(TParam~I,)*> System< +                'world, +                fn(Observe<'world, ObservedT>, #(TParam~I,)*) +            > for Stateful<Func> +            where +                ObservedT: Observed, +                Func: Fn(Observe<'world, ObservedT>, #(TParam~I,)*) + Copy + 'static, +                #(TParam~I: Param<'world>,)* +            { +                type Callbacks = Callbacks; + +                fn finish(self) -> (TypeErased, Callbacks) +                { +                    unimplemented!(); +                } +            } + +            impl<'world, ObservedT, Func, #(TParam~I,)*> Initializable< +                'world, +                fn(Observe<'world, ObservedT>, #(TParam~I,)*) +            > for Stateful<Func> +            where +                ObservedT: Observed, +                Func: Fn(Observe<'world, ObservedT>, #(TParam~I,)*) + Copy + 'static, +                #(TParam~I: Param<'world>,)* +                (#(TParam~I,)*): MaybeInitializableParamTuple<'world, Self> +            { +                type Inputs = < +                    (#(TParam~I,)*) as MaybeInitializableParamTuple<'world, Self> +                >::Inputs; + +                fn initialize(mut self, inputs: Self::Inputs) -> Self +                { +                    init_initializable_params::<_, (#(TParam~I,)*)>(&mut self, inputs); + +                    self +                } +            } + +            impl<'world, ObservedT, Func, #(TParam~I,)*> Observer< +                'world, +                fn(Observe<'world, ObservedT>, #(TParam~I,)*) +            > for Stateful<Func> +            where +                ObservedT: Observed, +                Func: Fn(Observe<'world, ObservedT>, #(TParam~I,)*) + Copy + 'static, +                #(TParam~I: Param<'world>,)* +            { +                type ObservedEvents = ObservedT::Events; + +                fn observed_events() -> Self::ObservedEvents +                { +                    ObservedT::events() +                } + +                fn finish_observer(self) -> (ObserverWrapperComponent, Callbacks) +                { +                    let Self { func, local_components } = self; + +                    let callbacks = Callbacks { local_components }; + +                    let wrapper_comp = ObserverWrapperComponent::new( +                        move |world, metadata, emitted_event| { +                            // SAFETY: The caller of TypeErased::run ensures the lifetime +                            // is correct +                            let world = unsafe { &*std::ptr::from_ref(world) }; + +                            // SAFETY: The caller of TypeErased::run ensures the lifetime +                            // is correct +                            let emitted_event = unsafe { +                                transmute::<EmittedEvent<'_>, EmittedEvent<'_>>( +                                    emitted_event +                                ) +                            }; + +                            func(Observe::new(world, emitted_event), #({ +                                TParam~I::new(world, &metadata) +                            },)*); +                        }, +                    ); + +                    (wrapper_comp, callbacks) +                } +            } + +            impl<'world, Func, ObservedT, #(TParam~I,)*> IntoSystem< +                'world, +                fn(Observe<'world, ObservedT>, +                #(TParam~I,)*) +            > for Func +            where +                ObservedT: Observed, +                #(TParam~I: Param<'world>,)* +                Func: Fn(Observe<'world, ObservedT>, #(TParam~I,)*) + Copy + 'static, +            { +                type System = Stateful<Func>; + +                fn into_system(self) -> Stateful<Func> +                { +                    Stateful { +                        func: self, +                        local_components: Vec::new(), // TODO: Use Vec::with_capacity +                    } +                } +            } +        }); +    }; +} + +seq!(C in 1..16 { +    impl_observer!(C); +});  | 
