diff options
-rw-r--r-- | ecs/examples/with_local.rs | 76 | ||||
-rw-r--r-- | ecs/src/component.rs | 34 | ||||
-rw-r--r-- | ecs/src/system.rs | 24 | ||||
-rw-r--r-- | ecs/src/system/stateful.rs | 67 |
4 files changed, 199 insertions, 2 deletions
diff --git a/ecs/examples/with_local.rs b/ecs/examples/with_local.rs new file mode 100644 index 0000000..d7af0e0 --- /dev/null +++ b/ecs/examples/with_local.rs @@ -0,0 +1,76 @@ +use ecs::component::Local; +use ecs::system::{Into, System}; +use ecs::{Query, World}; + +struct SomeData +{ + num: u64, +} + +struct Name +{ + name: String, +} + +struct SayHelloState +{ + cnt: usize, +} + +fn say_hello(mut query: Query<(SomeData, String)>, mut state: Local<SayHelloState>) +{ + for (data, text) in query.iter_mut() { + println!("Hello there. Count {}: {}: {}", state.cnt, text, data.num); + + state.cnt += 1; + } +} + +fn say_whats_up(mut query: Query<(SomeData, Name)>, mut state: Local<SayHelloState>) +{ + for (data, name) in query.iter_mut() { + println!( + "Whats up, {}. Number is {}. Count {}", + name.name, data.num, state.cnt + ); + + state.cnt += 1; + } +} + +#[derive(Debug, PartialEq, Eq, Hash)] +enum Event +{ + Update, +} + +fn main() +{ + let mut world = World::<Event>::new(); + + world.register_system( + Event::Update, + say_hello.into_system().initialize(SayHelloState { cnt: 0 }), + ); + + world.register_system( + Event::Update, + say_whats_up + .into_system() + .initialize(SayHelloState { cnt: 0 }), + ); + + world.create_entity(( + SomeData { num: 987_654 }, + "Yoo".to_string(), + Name { name: "Bob".to_string() }, + )); + + world.create_entity((SomeData { num: 345 }, "Haha".to_string())); + + world.emit(&Event::Update); + + println!("Haha"); + + world.emit(&Event::Update); +} diff --git a/ecs/src/component.rs b/ecs/src/component.rs index 4829050..8119e93 100644 --- a/ecs/src/component.rs +++ b/ecs/src/component.rs @@ -1,5 +1,6 @@ use std::any::{Any, TypeId}; use std::fmt::Debug; +use std::ops::{Deref, DerefMut}; use seq_macro::seq; @@ -112,3 +113,36 @@ macro_rules! inner { seq!(C in 0..=64 { inner!(C); }); + +/// Holds a component which is local to a single system. +#[derive(Debug)] +pub struct Local<'world, Value> +{ + value: &'world mut Value, +} + +impl<'world, Value> Local<'world, Value> +{ + pub(crate) fn new(value: &'world mut Value) -> Self + { + Self { value } + } +} + +impl<'world, Value> Deref for Local<'world, Value> +{ + type Target = Value; + + fn deref(&self) -> &Self::Target + { + self.value + } +} + +impl<'world, Value> DerefMut for Local<'world, Value> +{ + fn deref_mut(&mut self) -> &mut Self::Target + { + &mut self.value + } +} diff --git a/ecs/src/system.rs b/ecs/src/system.rs index ecf1885..8f4d0b0 100644 --- a/ecs/src/system.rs +++ b/ecs/src/system.rs @@ -1,14 +1,21 @@ use std::any::Any; +use std::convert::Infallible; use std::fmt::Debug; use crate::component::Sequence as ComponentSequence; use crate::{ComponentStorage, Query}; +pub mod stateful; + pub trait System<Impl>: 'static { type Query<'a>; - fn run(&self, component_storage: &mut ComponentStorage); + type Input; + + fn initialize(self, input: Self::Input) -> Self; + + fn run(&mut self, component_storage: &mut ComponentStorage); fn into_type_erased(self) -> TypeErased; } @@ -18,9 +25,15 @@ where Func: Fn(Query<Comps>) + 'static, Comps: ComponentSequence, { + type Input = Infallible; type Query<'a> = Query<'a, Comps>; - fn run(&self, component_storage: &mut ComponentStorage) + fn initialize(self, _input: Self::Input) -> Self + { + self + } + + fn run(&mut self, component_storage: &mut ComponentStorage) { self(Query::new(component_storage)); } @@ -38,6 +51,13 @@ where } } +pub trait Into<Impl> +{ + type System; + + fn into_system(self) -> Self::System; +} + pub struct TypeErased { data: Box<dyn Any>, diff --git a/ecs/src/system/stateful.rs b/ecs/src/system/stateful.rs new file mode 100644 index 0000000..b641cf2 --- /dev/null +++ b/ecs/src/system/stateful.rs @@ -0,0 +1,67 @@ +use std::marker::PhantomData; + +use crate::component::Local; +use crate::system::{System, TypeErased}; +use crate::{ComponentStorage, Query}; + +/// A stateful system. +pub struct Stateful<Func, LocalComponent, Comps> +{ + func: Func, + local_component: Option<LocalComponent>, + _comps_pd: PhantomData<Comps>, +} + +impl<Func: 'static, Comps: 'static, LocalComponent: 'static> + System<fn(Query<Comps>, Local<LocalComponent>)> + for Stateful<Func, LocalComponent, Comps> +where + Func: Fn(Query<Comps>, Local<LocalComponent>), +{ + type Input = LocalComponent; + type Query<'a> = Query<'a, Comps>; + + fn initialize(mut self, input: Self::Input) -> Self + { + self.local_component = Some(input); + + self + } + + fn run(&mut self, component_storage: &mut ComponentStorage) + { + (self.func)( + Query::new(component_storage), + Local::new(self.local_component.as_mut().unwrap()), + ); + } + + fn into_type_erased(self) -> TypeErased + { + TypeErased { + data: Box::new(self), + func: Box::new(move |data, component_storage| { + let this = data.downcast_mut::<Self>().unwrap(); + + this.run(component_storage); + }), + } + } +} + +impl<Func: 'static, Comps, LocalComponent: 'static> + crate::system::Into<fn(Query<Comps>, Local<LocalComponent>)> for Func +where + Func: Fn(Query<Comps>, Local<LocalComponent>), +{ + type System = Stateful<Func, LocalComponent, Comps>; + + fn into_system(self) -> Self::System + { + Self::System { + func: self, + local_component: None, + _comps_pd: PhantomData, + } + } +} |