| @@ -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" | |||
| @@ -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<T> { | |||
| 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> = <<T as System<'a>>::SystemData as DynamicSystemData<'a>>::Accessor; | |||
| pub type AccessorType<'a, T> = | |||
| <<T as WithSystemData<'a>>::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>; | |||
| @@ -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<S>(mut self, system: S, name: &str, dependencies: &[&str]) -> Result<Self, Error> | |||
| 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<S>(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() { | |||
| @@ -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<Box<dyn Future<Output = ()> + Send + 'a>>; | |||
| pub type BoxedDispatchable = Box<dyn for<'a> 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>, | |||
| <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 resource::Resources; | |||
| pub use storage::VecStorage; | |||
| pub use system::System; | |||
| pub use system::{AsyncSystem, System}; | |||
| pub use world::World; | |||
| @@ -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}; | |||
| @@ -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(); | |||
| <Self::SystemData as DynamicSystemData>::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<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; | |||
| } | |||
| pub trait WithSystemData<'a> { | |||
| type SystemData: DynamicSystemData<'a>; | |||
| } | |||
| /* SystemData */ | |||
| impl<'a, T> SystemData<'a> for PhantomData<T> | |||