use std::sync::Arc;
use super::systems;
use crate::async_dispatcher;
use async_dispatcher::{
AcquireResources, AcquiredResourcesLockGuards, Dispatcher, DispatcherBuilder, RequiresResources,
};
use systems::ResourceId;
impl crate::async_dispatcher::ResourceIdTrait for ResourceId {}
impl<T: systems::Resource> RequiresResources<ResourceId> for systems::Read<T> {
fn reads() -> Vec<ResourceId> {
vec![ResourceId::new::<T>()]
}
fn writes() -> Vec<ResourceId> {
vec![]
}
}
impl<T: systems::Resource> RequiresResources<ResourceId> for systems::Write<T> {
fn reads() -> Vec<ResourceId> {
vec![]
}
fn writes() -> Vec<ResourceId> {
vec![ResourceId::new::<T>()]
}
}
pub struct AcquiredResources<T>
where
T: RequiresResources<ResourceId> + 'static + Send,
{
_lock_guards: AcquiredResourcesLockGuards<T>,
world: Arc<systems::World>,
}
impl<T> AcquiredResources<T>
where
T: RequiresResources<ResourceId> + 'static + Send,
{
pub fn visit<'a, F>(&'a self, f: F)
where
F: FnOnce(T::Borrow),
T: systems::DataRequirement<'a>,
{
let fetched = T::fetch(&self.world);
(f)(fetched);
}
}
pub fn acquire_resources<T>(
dispatcher: Arc<Dispatcher<ResourceId>>,
world: Arc<systems::World>,
) -> impl futures::future::Future<Item = AcquiredResources<T>, Error = ()>
where
T: RequiresResources<ResourceId> + 'static + Send,
{
use futures::future::Future;
Box::new(
AcquireResources::new(dispatcher, T::required_resources()).map(move |lock_guards| {
AcquiredResources {
_lock_guards: lock_guards,
world,
}
}),
)
}
pub struct MinimumDispatcherBuilder {
dispatcher_builder: DispatcherBuilder<ResourceId>,
world: systems::World,
}
impl MinimumDispatcherBuilder {
pub fn new() -> Self {
MinimumDispatcherBuilder {
dispatcher_builder: DispatcherBuilder::new(),
world: systems::World::new(),
}
}
pub fn from_world(world: systems::World) -> MinimumDispatcherBuilder {
let mut dispatcher_builder = DispatcherBuilder::new();
for resource in world.keys() {
dispatcher_builder.register_resource_id(resource.clone());
}
MinimumDispatcherBuilder {
dispatcher_builder,
world,
}
}
pub fn with_resource<T: systems::Resource>(mut self, resource: T) -> Self {
self.insert_resource(resource);
self
}
pub fn insert_resource<T: systems::Resource>(&mut self, resource: T) {
self.world.insert(resource);
self.dispatcher_builder
.register_resource_id(ResourceId::new::<T>());
}
pub fn world(&self) -> &systems::World {
&self.world
}
pub fn build(self) -> MinimumDispatcher {
let dispatcher = self.dispatcher_builder.build();
let world = Arc::new(self.world);
MinimumDispatcher { dispatcher, world }
}
}
pub struct MinimumDispatcher {
dispatcher: Dispatcher<ResourceId>,
world: Arc<systems::World>,
}
impl MinimumDispatcher {
pub fn enter_game_loop<F, FutureT>(self, f: F) -> systems::World
where
F: Fn(Arc<MinimumDispatcherContext>) -> FutureT + Send + Sync + 'static,
FutureT: futures::future::Future<Item = (), Error = ()> + Send + 'static,
{
let world = self.world.clone();
self.dispatcher.enter_game_loop(move |dispatcher| {
let ctx = Arc::new(MinimumDispatcherContext {
dispatcher: dispatcher.clone(),
world: world.clone(),
});
(f)(ctx)
});
let world = Arc::try_unwrap(self.world).unwrap_or_else(|_| {
unreachable!();
});
world
}
}
pub struct MinimumDispatcherContext {
dispatcher: Arc<Dispatcher<ResourceId>>,
world: Arc<systems::World>,
}
impl MinimumDispatcherContext {
pub fn end_game_loop(&self) {
self.dispatcher.end_game_loop();
}
pub fn dispatcher(&self) -> Arc<Dispatcher<ResourceId>> {
self.dispatcher.clone()
}
pub fn world(&self) -> Arc<systems::World> {
self.world.clone()
}
pub fn run_fn<RequirementT, F>(
&self,
f: F,
) -> Box<impl futures::future::Future<Item = (), Error = ()>>
where
RequirementT: RequiresResources<ResourceId> + 'static + Send,
F: Fn(AcquiredResources<RequirementT>) + 'static,
{
use futures::future::Future;
Box::new(
acquire_resources::<RequirementT>(self.dispatcher.clone(), self.world.clone()).map(
move |acquired_resources| {
(f)(acquired_resources);
},
),
)
}
pub fn run_task<T>(
&self,
mut task: T,
) -> Box<impl futures::future::Future<Item = (), Error = ()>>
where
T: systems::Task,
{
use futures::future::Future;
Box::new(
acquire_resources::<T::RequiredResources>(self.dispatcher.clone(), self.world.clone())
.map(move |acquired_resources| {
acquired_resources.visit(move |resources| {
task.run(resources);
});
}),
)
}
}