From 3658c9322abd6ac1e43c2a136246f34f5be316a7 Mon Sep 17 00:00:00 2001 From: Bergmann89 Date: Sun, 25 Oct 2020 03:08:41 +0100 Subject: [PATCH] Implemented async systems --- async-ecs/Cargo.toml | 1 + async-ecs/src/access/accessor.rs | 9 +-- async-ecs/src/dispatcher/builder.rs | 14 ++-- async-ecs/src/dispatcher/dispatchable.rs | 19 ++++-- async-ecs/src/lib.rs | 2 +- async-ecs/src/main.rs | 15 +++-- async-ecs/src/system/mod.rs | 82 +++++++++++++++++++++++- async-ecs/src/system/system_data.rs | 4 ++ 8 files changed, 122 insertions(+), 24 deletions(-) diff --git a/async-ecs/Cargo.toml b/async-ecs/Cargo.toml index 58fd546..d348b91 100644 --- a/async-ecs/Cargo.toml +++ b/async-ecs/Cargo.toml @@ -7,6 +7,7 @@ edition = "2018" [dependencies] async-ecs-derive = "0.1" env_logger = "0.8" +futures = "0.3" hashbrown = "0.9" hibitset = "0.6" log = "0.4" diff --git a/async-ecs/src/access/accessor.rs b/async-ecs/src/access/accessor.rs index 1d4fbe9..367bc7c 100644 --- a/async-ecs/src/access/accessor.rs +++ b/async-ecs/src/access/accessor.rs @@ -3,7 +3,7 @@ use std::ops::Deref; use crate::{ resource::ResourceId, - system::{DynamicSystemData, System, SystemData}, + system::{DynamicSystemData, SystemData, WithSystemData}, }; pub trait Accessor: Sized { @@ -28,14 +28,15 @@ pub struct StaticAccessor { pub enum AccessorCow<'a, 'b, T> where AccessorType<'a, T>: 'b, - T: System<'a> + ?Sized, + T: WithSystemData<'a> + ?Sized, 'a: 'b, { Borrow(&'b AccessorType<'a, T>), Owned(AccessorType<'a, T>), } -pub type AccessorType<'a, T> = <>::SystemData as DynamicSystemData<'a>>::Accessor; +pub type AccessorType<'a, T> = + <>::SystemData as DynamicSystemData<'a>>::Accessor; /* StaticAccessor */ @@ -63,7 +64,7 @@ where impl<'a, 'b, T> Deref for AccessorCow<'a, 'b, T> where AccessorType<'a, T>: 'b, - T: System<'a> + ?Sized + 'b, + T: WithSystemData<'a> + ?Sized + 'b, 'a: 'b, { type Target = AccessorType<'a, T>; diff --git a/async-ecs/src/dispatcher/builder.rs b/async-ecs/src/dispatcher/builder.rs index 9396b6c..4d41495 100644 --- a/async-ecs/src/dispatcher/builder.rs +++ b/async-ecs/src/dispatcher/builder.rs @@ -3,7 +3,7 @@ use std::fmt::Debug; use tokio::{spawn, sync::watch::channel}; -use crate::{access::Accessor, resource::ResourceId, system::System}; +use crate::{access::Accessor, resource::ResourceId, system::AsyncSystem}; use super::{task::execute, BoxedDispatchable, Dispatcher, Error, Receiver, Sender, SharedWorld}; @@ -62,7 +62,7 @@ impl Builder { pub fn with(mut self, system: S, name: &str, dependencies: &[&str]) -> Result where - S: for<'s> System<'s> + Send + 'static, + S: for<'s> AsyncSystem<'s> + Send + 'static, { self.add(system, name, dependencies)?; @@ -76,7 +76,7 @@ impl Builder { dependencies: &[&str], ) -> Result<&mut Self, Error> where - S: for<'s> System<'s> + Send + 'static, + S: for<'s> AsyncSystem<'s> + Send + 'static, { let name = name.to_owned(); let id = self.next_id(); @@ -208,7 +208,7 @@ impl Default for Builder { impl Item { fn new(name: String, system: S) -> Self where - S: for<'s> System<'s> + Send + 'static, + S: for<'s> AsyncSystem<'s> + Send + 'static, { let (sender, receiver) = channel(()); @@ -231,7 +231,11 @@ impl Item { mod tests { use super::*; - use crate::{access::AccessorCow, system::DynamicSystemData, world::World}; + use crate::{ + access::AccessorCow, + system::{DynamicSystemData, System}, + world::World, + }; #[test] fn dependencies_on_read_and_write() { diff --git a/async-ecs/src/dispatcher/dispatchable.rs b/async-ecs/src/dispatcher/dispatchable.rs index d94df2d..7b7cef4 100644 --- a/async-ecs/src/dispatcher/dispatchable.rs +++ b/async-ecs/src/dispatcher/dispatchable.rs @@ -1,21 +1,28 @@ +use std::ops::Deref; +use std::pin::Pin; + +use futures::future::{Future, FutureExt}; + use crate::{ - system::{DynamicSystemData, System}, + system::{AsyncSystem, DynamicSystemData}, world::World, }; +pub type BoxedFuture<'a> = Pin + Send + 'a>>; pub type BoxedDispatchable = Box Dispatchable<'a> + Send>; pub trait Dispatchable<'a> { - fn run(&mut self, world: &'a World); + fn run(&mut self, world: &'a World) -> BoxedFuture<'a>; } impl<'a, T> Dispatchable<'a> for T where - T: System<'a>, + T: AsyncSystem<'a>, + >::Future: Send, { - fn run(&mut self, world: &'a World) { - let data = T::SystemData::fetch(&self.accessor(), world); + fn run(&mut self, world: &'a World) -> BoxedFuture<'a> { + let data = T::SystemData::fetch(self.accessor().deref(), world); - self.run(data); + self.run(data).boxed() } } diff --git a/async-ecs/src/lib.rs b/async-ecs/src/lib.rs index 4af94a8..2dfa45d 100644 --- a/async-ecs/src/lib.rs +++ b/async-ecs/src/lib.rs @@ -15,5 +15,5 @@ pub use access::{Join, ReadStorage, WriteStorage}; pub use dispatcher::Dispatcher; pub use resource::Resources; pub use storage::VecStorage; -pub use system::System; +pub use system::{AsyncSystem, System}; pub use world::World; diff --git a/async-ecs/src/main.rs b/async-ecs/src/main.rs index 986d8ba..32256c8 100644 --- a/async-ecs/src/main.rs +++ b/async-ecs/src/main.rs @@ -2,8 +2,8 @@ use std::io::Error as IoError; use std::time::{Duration, Instant}; use async_ecs::{ - dispatcher::Error as DispatcherError, Dispatcher, Join, ReadStorage, System, VecStorage, World, - WriteStorage, + dispatcher::Error as DispatcherError, AsyncSystem, Dispatcher, Join, ReadStorage, System, + VecStorage, World, WriteStorage, }; use async_ecs_derive::Component; use log::info; @@ -71,8 +71,8 @@ async fn run() -> Result<(), Error> { Ok(()) } -const ENTITY_COUNT: usize = 100_000; -const REPEAT_COUNT: u32 = 100; +const ENTITY_COUNT: usize = 1_000_000; +const REPEAT_COUNT: u32 = 10; #[derive(Debug, Component)] #[storage(VecStorage)] @@ -156,15 +156,18 @@ impl<'a> System<'a> for Move { } } -impl<'a> System<'a> for Accelerate { +impl<'a> AsyncSystem<'a> for Accelerate { type SystemData = (WriteStorage<'a, Velocity>, ReadStorage<'a, Acceleration>); + type Future = futures::future::Ready<()>; - fn run(&mut self, (mut velocity, acceleration): Self::SystemData) { + fn run(&mut self, (mut velocity, acceleration): Self::SystemData) -> Self::Future { for (velocity, acceleration) in (&mut velocity, &acceleration).join() { velocity.x += acceleration.x; velocity.y += acceleration.y; } + futures::future::ready(()) + /* use specs::{prelude::ParallelIterator, ParJoin}; diff --git a/async-ecs/src/system/mod.rs b/async-ecs/src/system/mod.rs index 79bb413..e20b7c1 100644 --- a/async-ecs/src/system/mod.rs +++ b/async-ecs/src/system/mod.rs @@ -1,15 +1,21 @@ mod system_data; -pub use system_data::{DynamicSystemData, SystemData}; +pub use system_data::{DynamicSystemData, SystemData, WithSystemData}; + +use futures::future::{ready, Future, Ready}; use crate::{ access::{Accessor, AccessorCow, AccessorType}, world::World, }; -pub trait System<'a> { +/* System */ + +pub trait System<'a>: Sized { type SystemData: DynamicSystemData<'a>; + fn init(&mut self) {} + fn run(&mut self, data: Self::SystemData); fn accessor<'b>(&'b self) -> AccessorCow<'a, 'b, Self> { @@ -19,6 +25,8 @@ pub trait System<'a> { } fn setup(&mut self, world: &mut World) { + self.init(); + ::setup(&self.accessor(), world) } @@ -29,3 +37,73 @@ pub trait System<'a> { let _ = world; } } + +/* AsyncSystem */ + +pub trait AsyncSystem<'a>: Sized { + type SystemData: DynamicSystemData<'a>; + type Future: Future + Send + 'a; + + fn init(&mut self) {} + + fn run(&mut self, data: Self::SystemData) -> Self::Future; + + fn accessor<'b>(&'b self) -> AccessorCow<'a, 'b, Self> { + AccessorCow::Owned( + AccessorType::<'a, Self>::try_new().expect("Missing implementation for `accessor`"), + ) + } + + fn setup(&mut self, world: &mut World) { + self.init(); + + ::setup(&self.accessor(), world) + } + + fn dispose(self, world: &mut World) + where + Self: Sized, + { + let _ = world; + } +} + +impl<'a, T> AsyncSystem<'a> for T +where + T: System<'a>, +{ + type SystemData = T::SystemData; + type Future = Ready<()>; + + fn init(&mut self) { + T::init(self); + } + + fn run(&mut self, data: Self::SystemData) -> Self::Future { + T::run(self, data); + + ready(()) + } + + fn accessor<'b>(&'b self) -> AccessorCow<'a, 'b, Self> { + T::accessor(self) + } + + fn setup(&mut self, world: &mut World) { + T::setup(self, world) + } + + fn dispose(self, world: &mut World) + where + Self: Sized, + { + T::dispose(self, world) + } +} + +impl<'a, T> WithSystemData<'a> for T +where + T: AsyncSystem<'a>, +{ + type SystemData = >::SystemData; +} diff --git a/async-ecs/src/system/system_data.rs b/async-ecs/src/system/system_data.rs index b5959f9..3d50ae7 100644 --- a/async-ecs/src/system/system_data.rs +++ b/async-ecs/src/system/system_data.rs @@ -24,6 +24,10 @@ pub trait DynamicSystemData<'a> { fn fetch(access: &Self::Accessor, world: &'a World) -> Self; } +pub trait WithSystemData<'a> { + type SystemData: DynamicSystemData<'a>; +} + /* SystemData */ impl<'a, T> SystemData<'a> for PhantomData