| @@ -7,6 +7,7 @@ edition = "2018" | |||||
| [dependencies] | [dependencies] | ||||
| async-ecs-derive = "0.1" | async-ecs-derive = "0.1" | ||||
| env_logger = "0.8" | env_logger = "0.8" | ||||
| futures = "0.3" | |||||
| hashbrown = "0.9" | hashbrown = "0.9" | ||||
| hibitset = "0.6" | hibitset = "0.6" | ||||
| log = "0.4" | log = "0.4" | ||||
| @@ -3,7 +3,7 @@ use std::ops::Deref; | |||||
| use crate::{ | use crate::{ | ||||
| resource::ResourceId, | resource::ResourceId, | ||||
| system::{DynamicSystemData, System, SystemData}, | |||||
| system::{DynamicSystemData, SystemData, WithSystemData}, | |||||
| }; | }; | ||||
| pub trait Accessor: Sized { | pub trait Accessor: Sized { | ||||
| @@ -28,14 +28,15 @@ pub struct StaticAccessor<T> { | |||||
| pub enum AccessorCow<'a, 'b, T> | pub enum AccessorCow<'a, 'b, T> | ||||
| where | where | ||||
| AccessorType<'a, T>: 'b, | AccessorType<'a, T>: 'b, | ||||
| T: System<'a> + ?Sized, | |||||
| T: WithSystemData<'a> + ?Sized, | |||||
| 'a: 'b, | 'a: 'b, | ||||
| { | { | ||||
| Borrow(&'b AccessorType<'a, T>), | Borrow(&'b AccessorType<'a, T>), | ||||
| Owned(AccessorType<'a, T>), | Owned(AccessorType<'a, T>), | ||||
| } | } | ||||
| pub type AccessorType<'a, T> = <<T as System<'a>>::SystemData as DynamicSystemData<'a>>::Accessor; | |||||
| pub type AccessorType<'a, T> = | |||||
| <<T as WithSystemData<'a>>::SystemData as DynamicSystemData<'a>>::Accessor; | |||||
| /* StaticAccessor */ | /* StaticAccessor */ | ||||
| @@ -63,7 +64,7 @@ where | |||||
| impl<'a, 'b, T> Deref for AccessorCow<'a, 'b, T> | impl<'a, 'b, T> Deref for AccessorCow<'a, 'b, T> | ||||
| where | where | ||||
| AccessorType<'a, T>: 'b, | AccessorType<'a, T>: 'b, | ||||
| T: System<'a> + ?Sized + 'b, | |||||
| T: WithSystemData<'a> + ?Sized + 'b, | |||||
| 'a: 'b, | 'a: 'b, | ||||
| { | { | ||||
| type Target = AccessorType<'a, T>; | type Target = AccessorType<'a, T>; | ||||
| @@ -3,7 +3,7 @@ use std::fmt::Debug; | |||||
| use tokio::{spawn, sync::watch::channel}; | 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}; | use super::{task::execute, BoxedDispatchable, Dispatcher, Error, Receiver, Sender, SharedWorld}; | ||||
| @@ -62,7 +62,7 @@ impl Builder { | |||||
| pub fn with<S>(mut self, system: S, name: &str, dependencies: &[&str]) -> Result<Self, Error> | pub fn with<S>(mut self, system: S, name: &str, dependencies: &[&str]) -> Result<Self, Error> | ||||
| where | where | ||||
| S: for<'s> System<'s> + Send + 'static, | |||||
| S: for<'s> AsyncSystem<'s> + Send + 'static, | |||||
| { | { | ||||
| self.add(system, name, dependencies)?; | self.add(system, name, dependencies)?; | ||||
| @@ -76,7 +76,7 @@ impl Builder { | |||||
| dependencies: &[&str], | dependencies: &[&str], | ||||
| ) -> Result<&mut Self, Error> | ) -> Result<&mut Self, Error> | ||||
| where | where | ||||
| S: for<'s> System<'s> + Send + 'static, | |||||
| S: for<'s> AsyncSystem<'s> + Send + 'static, | |||||
| { | { | ||||
| let name = name.to_owned(); | let name = name.to_owned(); | ||||
| let id = self.next_id(); | let id = self.next_id(); | ||||
| @@ -208,7 +208,7 @@ impl Default for Builder { | |||||
| impl Item { | impl Item { | ||||
| fn new<S>(name: String, system: S) -> Self | fn new<S>(name: String, system: S) -> Self | ||||
| where | where | ||||
| S: for<'s> System<'s> + Send + 'static, | |||||
| S: for<'s> AsyncSystem<'s> + Send + 'static, | |||||
| { | { | ||||
| let (sender, receiver) = channel(()); | let (sender, receiver) = channel(()); | ||||
| @@ -231,7 +231,11 @@ impl Item { | |||||
| mod tests { | mod tests { | ||||
| use super::*; | use super::*; | ||||
| use crate::{access::AccessorCow, system::DynamicSystemData, world::World}; | |||||
| use crate::{ | |||||
| access::AccessorCow, | |||||
| system::{DynamicSystemData, System}, | |||||
| world::World, | |||||
| }; | |||||
| #[test] | #[test] | ||||
| fn dependencies_on_read_and_write() { | fn dependencies_on_read_and_write() { | ||||
| @@ -1,21 +1,28 @@ | |||||
| use std::ops::Deref; | |||||
| use std::pin::Pin; | |||||
| use futures::future::{Future, FutureExt}; | |||||
| use crate::{ | use crate::{ | ||||
| system::{DynamicSystemData, System}, | |||||
| system::{AsyncSystem, DynamicSystemData}, | |||||
| world::World, | world::World, | ||||
| }; | }; | ||||
| pub type BoxedFuture<'a> = Pin<Box<dyn Future<Output = ()> + Send + 'a>>; | |||||
| pub type BoxedDispatchable = Box<dyn for<'a> Dispatchable<'a> + Send>; | pub type BoxedDispatchable = Box<dyn for<'a> Dispatchable<'a> + Send>; | ||||
| pub trait Dispatchable<'a> { | 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 | impl<'a, T> Dispatchable<'a> for T | ||||
| where | where | ||||
| T: System<'a>, | |||||
| T: AsyncSystem<'a>, | |||||
| <T as 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() | |||||
| } | } | ||||
| } | } | ||||
| @@ -15,5 +15,5 @@ pub use access::{Join, ReadStorage, WriteStorage}; | |||||
| pub use dispatcher::Dispatcher; | pub use dispatcher::Dispatcher; | ||||
| pub use resource::Resources; | pub use resource::Resources; | ||||
| pub use storage::VecStorage; | pub use storage::VecStorage; | ||||
| pub use system::System; | |||||
| pub use system::{AsyncSystem, System}; | |||||
| pub use world::World; | pub use world::World; | ||||
| @@ -2,8 +2,8 @@ use std::io::Error as IoError; | |||||
| use std::time::{Duration, Instant}; | use std::time::{Duration, Instant}; | ||||
| use async_ecs::{ | 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 async_ecs_derive::Component; | ||||
| use log::info; | use log::info; | ||||
| @@ -71,8 +71,8 @@ async fn run() -> Result<(), Error> { | |||||
| Ok(()) | 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)] | #[derive(Debug, Component)] | ||||
| #[storage(VecStorage)] | #[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 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() { | for (velocity, acceleration) in (&mut velocity, &acceleration).join() { | ||||
| velocity.x += acceleration.x; | velocity.x += acceleration.x; | ||||
| velocity.y += acceleration.y; | velocity.y += acceleration.y; | ||||
| } | } | ||||
| futures::future::ready(()) | |||||
| /* | /* | ||||
| use specs::{prelude::ParallelIterator, ParJoin}; | use specs::{prelude::ParallelIterator, ParJoin}; | ||||
| @@ -1,15 +1,21 @@ | |||||
| mod system_data; | mod system_data; | ||||
| pub use system_data::{DynamicSystemData, SystemData}; | |||||
| pub use system_data::{DynamicSystemData, SystemData, WithSystemData}; | |||||
| use futures::future::{ready, Future, Ready}; | |||||
| use crate::{ | use crate::{ | ||||
| access::{Accessor, AccessorCow, AccessorType}, | access::{Accessor, AccessorCow, AccessorType}, | ||||
| world::World, | world::World, | ||||
| }; | }; | ||||
| pub trait System<'a> { | |||||
| /* System */ | |||||
| pub trait System<'a>: Sized { | |||||
| type SystemData: DynamicSystemData<'a>; | type SystemData: DynamicSystemData<'a>; | ||||
| fn init(&mut self) {} | |||||
| fn run(&mut self, data: Self::SystemData); | fn run(&mut self, data: Self::SystemData); | ||||
| fn accessor<'b>(&'b self) -> AccessorCow<'a, 'b, Self> { | fn accessor<'b>(&'b self) -> AccessorCow<'a, 'b, Self> { | ||||
| @@ -19,6 +25,8 @@ pub trait System<'a> { | |||||
| } | } | ||||
| fn setup(&mut self, world: &mut World) { | fn setup(&mut self, world: &mut World) { | ||||
| self.init(); | |||||
| <Self::SystemData as DynamicSystemData>::setup(&self.accessor(), world) | <Self::SystemData as DynamicSystemData>::setup(&self.accessor(), world) | ||||
| } | } | ||||
| @@ -29,3 +37,73 @@ pub trait System<'a> { | |||||
| let _ = world; | let _ = world; | ||||
| } | } | ||||
| } | } | ||||
| /* AsyncSystem */ | |||||
| pub trait AsyncSystem<'a>: Sized { | |||||
| type SystemData: DynamicSystemData<'a>; | |||||
| type Future: Future<Output = ()> + 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(); | |||||
| <Self::SystemData as DynamicSystemData>::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 = <T as AsyncSystem<'a>>::SystemData; | |||||
| } | |||||
| @@ -24,6 +24,10 @@ pub trait DynamicSystemData<'a> { | |||||
| fn fetch(access: &Self::Accessor, world: &'a World) -> Self; | fn fetch(access: &Self::Accessor, world: &'a World) -> Self; | ||||
| } | } | ||||
| pub trait WithSystemData<'a> { | |||||
| type SystemData: DynamicSystemData<'a>; | |||||
| } | |||||
| /* SystemData */ | /* SystemData */ | ||||
| impl<'a, T> SystemData<'a> for PhantomData<T> | impl<'a, T> SystemData<'a> for PhantomData<T> | ||||