@@ -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> | |||