diff options
Diffstat (limited to 'ecs/src/system/stateful.rs')
| -rw-r--r-- | ecs/src/system/stateful.rs | 293 | 
1 files changed, 193 insertions, 100 deletions
| diff --git a/ecs/src/system/stateful.rs b/ecs/src/system/stateful.rs index 80ac346..e74ef31 100644 --- a/ecs/src/system/stateful.rs +++ b/ecs/src/system/stateful.rs @@ -1,150 +1,243 @@ -use std::any::{Any, TypeId}; +use std::mem::transmute;  use std::panic::{RefUnwindSafe, UnwindSafe}; -use hashbrown::HashMap;  use seq_macro::seq; -use crate::component::Component; -use crate::lock::Lock; -use crate::system::{ -    ComponentRefMut, -    Into as IntoSystem, -    Param, -    ParamWithInputFilter, -    System, -    TypeErased, +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::tuple::{ -    Reduce as TupleReduce, -    Tuple, -    WithAllElemLtStatic as TupleWithAllElemLtStatic, -}; -use crate::uid::Uid; +use crate::system::{Into as IntoSystem, Metadata, Param, System, TypeErased};  use crate::World;  /// A stateful system.  pub struct Stateful<Func>  {      func: Func, -    local_components: HashMap<Uid, Lock<Box<dyn Component>>>, +    local_components: Vec<ComponentParts>,  }  macro_rules! impl_system {      ($c: tt) => {          seq!(I in 0..$c { -            impl<'world, Func, #(TParam~I,)*> System<'world, fn(&'world (), #(TParam~I,)*)> -                for Stateful<Func> +            impl<'world, Func, #(TParam~I,)*> +                System<'world, fn(&'world (), #(TParam~I,)*)> for Stateful<Func>              where                  Func: Fn(#(TParam~I,)*) + Copy + RefUnwindSafe + UnwindSafe + 'static, -                #(TParam~I: Param<'world>,)* -                #(TParam~I::Input: 'static,)* -                (#(TParam~I::Input,)*): TupleReduce< -                    ParamWithInputFilter, -                    Out: Tuple<InOptions: TupleWithAllElemLtStatic> -                >, +                #(TParam~I: Param<'world, Input: 'static>,)*              { -                type Input = -                    <(#(TParam~I::Input,)*) as TupleReduce<ParamWithInputFilter>>::Out; +                type Callbacks = Callbacks; -                fn initialize(mut self, input: Self::Input) -> Self +                fn finish(self) -> (TypeErased, Self::Callbacks)                  { -                    let mut option_input = input.into_in_options(); - -                    let mut index = 0; - -                    #( -                        if TypeId::of::<TParam~I::Input>() != -                            TypeId::of::<()>() -                        { -                            let input = option_input -                                .get_mut::<Option<TParam~I::Input>>(index) -                                .expect("Input element index out of range") -                                .take() -                                .expect("Input element is already taken"); - -                            TParam~I::initialize( -                                &mut self, -                                input -                            ); - -                            #[allow(unused_assignments)] -                            { -                                index += 1; -                            } -                        } -                    )* +                    let Self { func, local_components } = self; -                    self +                    let callbacks = Callbacks { local_components }; + +                    let type_erased = TypeErased { +                        run: Box::new(move |world, metadata| { +                            // SAFETY: The caller of TypeErased::run ensures the lifetime +                            // is correct +                            let world = unsafe { &*std::ptr::from_ref(world) }; + +                            func(#({ +                                TParam~I::new(&world, &metadata) +                            },)*); +                        }), +                    }; + + +                    (type_erased, callbacks)                  } +            } -                fn run<'this>(&'this self, world: &'world World) -                where -                    'this: 'world +            impl<'world, Func, #(TParam~I,)*> +                Initializable<'world, fn(&'world (), #(TParam~I,)*)> for Stateful<Func> +            where +                Func: Fn(#(TParam~I,)*) + Copy + RefUnwindSafe + UnwindSafe + 'static, +                #(TParam~I: Param<'world, Input: 'static>,)* +                (#(TParam~I,)*): MaybeInitializableParamTuple<'world, Self> +            { +                type Inputs = < +                    (#(TParam~I,)*) as MaybeInitializableParamTuple<'world, Self> +                >::Inputs; + +                fn initialize(mut self, inputs: Self::Inputs) -> Self                  { -                    let func = self.func; +                    init_initializable_params::<_, (#(TParam~I,)*)>(&mut self, inputs); -                    func(#({ -                        TParam~I::new(self, &world) -                    },)*); +                    self                  } +            } -                fn into_type_erased(self) -> TypeErased +            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>; + +                fn into_system(self) -> Self::System                  { -                    TypeErased { -                        data: Box::new(self), -                        run: Box::new(|data, world| { -                            // SAFETY: The caller of TypeErased::run ensures the lifetime -                            // is correct -                            let data = unsafe { &*std::ptr::from_ref::<dyn Any>(data) }; +                    Self::System { +                        func: self, +                        local_components: Vec::new(), // TODO: Use Vec::with_capacity +                    } +                } +            } +        }); +    }; +} -                            let me = data.downcast_ref::<Self>().unwrap(); +seq!(C in 1..16 { +    impl_system!(C); +}); -                            // SAFETY: The caller of TypeErased::run ensures the lifetime -                            // is correct -                            let world = unsafe { &*std::ptr::from_ref(world) }; +impl<Func> SystemWithLocalComponents for Stateful<Func> +{ +    fn add_local_component(&mut self, component_parts: ComponentParts) +    { +        self.local_components.push(component_parts); +    } +} -                            me.run(world); -                        }), -                    } +#[derive(Debug)] +pub struct Callbacks +{ +    local_components: Vec<ComponentParts>, +} + +impl crate::system::Callbacks for Callbacks +{ +    fn on_created(&mut self, world: &mut World, metadata: Metadata) +    { +        for local_comp_parts in self.local_components.drain(..) { +            world.add_component(metadata.ent_id, local_comp_parts); +        } +    } +} + +fn init_initializable_params<'world, SystemT, Params>( +    system: &mut SystemT, +    inputs: Params::Inputs, +) where +    Params: MaybeInitializableParamTuple<'world, SystemT>, +{ +    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!();                  } +            } -                fn get_local_component_mut<LocalComponent: Component>( -                    &self, -                ) -> Option<ComponentRefMut<LocalComponent>> +            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                  { -                    let local_component = self.local_components -                        .get(&LocalComponent::id())? -                        .write_nonblock() -                        .expect("Failed to aquire read-write local component lock"); +                    init_initializable_params::<_, (#(TParam~I,)*)>(&mut self, inputs); -                    Some(ComponentRefMut::new(local_component)) +                    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 set_local_component<LocalComponent: Component>( -                    &mut self, -                    local_component: LocalComponent, -                ) +                fn observed_events() -> Self::ObservedEvents                  { -                    self.local_components -                        .insert( -                            LocalComponent::id(), -                            Lock::new(Box::new(local_component)) -                        ); +                    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<Func, #(TParam~I,)*> IntoSystem<fn(#(TParam~I,)*)> -                for Func +            impl<'world, Func, ObservedT, #(TParam~I,)*> IntoSystem< +                'world, +                fn(Observe<'world, ObservedT>, +                #(TParam~I,)*) +            > for Func              where -                Func: Fn(#(TParam~I,)*) + Copy + 'static, +                ObservedT: Observed, +                #(TParam~I: Param<'world>,)* +                Func: Fn(Observe<'world, ObservedT>, #(TParam~I,)*) + Copy + 'static,              {                  type System = Stateful<Func>; -                fn into_system(self) -> Self::System +                fn into_system(self) -> Stateful<Func>                  { -                    Self::System { +                    Stateful {                          func: self, -                        local_components: HashMap::new(), +                        local_components: Vec::new(), // TODO: Use Vec::with_capacity                      }                  }              } @@ -153,5 +246,5 @@ macro_rules! impl_system {  }  seq!(C in 1..16 { -    impl_system!(C); +    impl_observer!(C);  }); | 
