use crate::World;
use super::{
SystemCondition, SystemConditionElse, System, CreationSystem, SystemThreadLocal,
AnySystem, SyncSystem, SystemOnce, SystemOnceThreadLocal, CreationSystemOnce,
SystemOnceRunner, SystemOnceThreadLocalRunner, CreationSystemOnceRunner
};
use super::container::StatsType;
use std::any::TypeId;
macro_rules! impl_builders {
($Builder: ident, $BuilderConditions: ident, $BuilderElse: ident, $SystemTy: ident, $ElseTy: path, $constructor_method: ident) => {
#[must_use = "Systems built with a Builder won't be created until the build method is called"]
pub struct $Builder<'a, 'n, S>{
system: S,
name: Option<&'n str>,
needs: Option<Vec<TypeId>>,
updates: Option<Vec<TypeId>>,
reads: Option<Vec<TypeId>>,
writes: Option<Vec<TypeId>>,
world: &'a mut World,
}
#[must_use = "Systems built with a Builder won't be created until the build method is called"]
pub struct $BuilderConditions<'a, 'n, S>{
system: S,
name: Option<&'n str>,
conditions: SystemCondition,
needs: Option<Vec<TypeId>>,
updates: Option<Vec<TypeId>>,
reads: Option<Vec<TypeId>>,
writes: Option<Vec<TypeId>>,
world: &'a mut World,
}
#[must_use = "Systems built with a Builder won't be created until the build method is called"]
pub struct $BuilderElse<'a, 'n, S, Else>{
system: S,
name: Option<&'n str>,
else_run: SystemConditionElse<Else>,
needs: Option<Vec<TypeId>>,
updates: Option<Vec<TypeId>>,
reads: Option<Vec<TypeId>>,
writes: Option<Vec<TypeId>>,
world: &'a mut World,
}
impl<'a, 'n, S: 'static + $SystemTy> $Builder<'a, 'n, S>{
pub(crate) fn new(system: S, world: &mut World) -> $Builder<S>{
$Builder{
system,
name: None,
world,
needs: None,
updates: None,
reads: None,
writes: None,
}
}
pub fn name(mut self, name: &'n str) -> $Builder<'a, 'n, S>{
self.name = Some(name);
self
}
pub fn conditions(self, conditions: SystemCondition) -> $BuilderConditions<'a, 'n, S>{
$BuilderConditions{
system: self.system,
name: self.name,
conditions,
world: self.world,
needs: self.needs,
updates: self.updates,
reads: self.reads,
writes: self.writes,
}
}
pub fn needs<T: 'static>(mut self) -> $Builder<'a, 'n, S>{
self.needs.get_or_insert(vec![]).push(TypeId::of::<T>());
self
}
pub fn updates<T: 'static>(mut self) -> $Builder<'a, 'n, S>{
self.updates.get_or_insert(vec![]).push(TypeId::of::<T>());
self
}
pub fn reads<T: 'static>(mut self) -> $Builder<'a, 'n, S>{
self.reads.get_or_insert(vec![]).push(TypeId::of::<T>());
self
}
pub fn writes<T: 'static>(mut self) -> $Builder<'a, 'n, S>{
self.writes.get_or_insert(vec![]).push(TypeId::of::<T>());
self
}
pub fn dependencies_from<S2: $SystemTy>(mut self) -> $Builder<'a, 'n, S>{
self.needs = Some(S2::needs());
self.updates = Some(S2::updates());
self
}
pub fn build(self) -> &'a mut World{
let stats = self.name.map(|n| StatsType::Cpu(n));
self.world.$constructor_method(
self.system,
stats,
None,
self.needs,
self.updates,
self.reads,
self.writes
)
}
}
impl<'a, 'n, S: 'static + $SystemTy> $BuilderConditions<'a, 'n, S>{
pub fn name(mut self, name: &'n str) -> $BuilderConditions<'a, 'n, S>{
self.name = Some(name);
self
}
pub fn else_run<Else>(self, else_run: Else) -> $BuilderElse<'a, 'n, S, Else>{
let else_run = self.conditions.else_run(else_run);
$BuilderElse{
system: self.system,
name: self.name,
else_run,
world: self.world,
needs: self.needs,
updates: self.updates,
reads: self.reads,
writes: self.writes,
}
}
pub fn needs<T: 'static>(mut self) -> $BuilderConditions<'a, 'n, S>{
self.needs.get_or_insert(vec![]).push(TypeId::of::<T>());
self
}
pub fn updates<T: 'static>(mut self) -> $BuilderConditions<'a, 'n, S>{
self.updates.get_or_insert(vec![]).push(TypeId::of::<T>());
self
}
pub fn reads<T: 'static>(mut self) -> $BuilderConditions<'a, 'n, S>{
self.reads.get_or_insert(vec![]).push(TypeId::of::<T>());
self
}
pub fn writes<T: 'static>(mut self) -> $BuilderConditions<'a, 'n, S>{
self.writes.get_or_insert(vec![]).push(TypeId::of::<T>());
self
}
pub fn dependencies_from<S2: $SystemTy>(mut self) -> $BuilderConditions<'a, 'n, S>{
self.needs = Some(S2::needs());
self.updates = Some(S2::updates());
self
}
pub fn build(self) -> &'a mut World{
let stats = self.name.map(|n| StatsType::Cpu(n));
self.world.$constructor_method(
self.system,
stats,
Some(self.conditions.build()),
self.needs,
self.updates,
self.reads,
self.writes,
)
}
}
impl<'a, 'n, S: 'static + $SystemTy, Else: $ElseTy> $BuilderElse<'a, 'n, S, Else>{
pub fn name(mut self, name: &'n str) -> $BuilderElse<'a, 'n, S, Else>{
self.name = Some(name);
self
}
pub fn needs<T: 'static>(mut self) -> $BuilderElse<'a, 'n, S, Else>{
self.needs.get_or_insert(vec![]).push(TypeId::of::<T>());
self
}
pub fn updates<T: 'static>(mut self) -> $BuilderElse<'a, 'n, S, Else>{
self.updates.get_or_insert(vec![]).push(TypeId::of::<T>());
self
}
pub fn reads<T: 'static>(mut self) -> $BuilderElse<'a, 'n, S, Else>{
self.reads.get_or_insert(vec![]).push(TypeId::of::<T>());
self
}
pub fn writes<T: 'static>(mut self) -> $BuilderElse<'a, 'n, S, Else>{
self.writes.get_or_insert(vec![]).push(TypeId::of::<T>());
self
}
pub fn dependencies_from<S2: $SystemTy>(mut self) -> $BuilderElse<'a, 'n, S, Else>{
self.needs = Some(S2::needs());
self.updates = Some(S2::updates());
self
}
pub fn build(self) -> &'a mut World{
let stats = self.name.map(|n| StatsType::Cpu(n));
self.world.$constructor_method(
self.system,
stats,
Some(self.else_run.build()),
self.needs,
self.updates,
self.reads,
self.writes,
)
}
}
};
}
impl_builders!(
Builder,
BuilderConditions,
BuilderElse,
System,
AnySystem<SyncSystem>,
add_any_send_system
);
impl_builders!(
BuilderOnce,
BuilderOnceConditions,
BuilderOnceElse,
SystemOnce,
AnySystem<SystemOnceRunner>,
add_any_send_system_once
);
impl_builders!(
BuilderThreadLocal,
BuilderConditionsThreadLocal,
BuilderElseThreadLocal,
SystemThreadLocal,
AnySystem<Box<dyn SystemThreadLocal>>,
add_any_thread_local_system
);
impl_builders!(
BuilderOnceThreadLocal,
BuilderOnceConditionsThreadLocal,
BuilderOnceElseThreadLocal,
SystemOnceThreadLocal,
AnySystem<SystemOnceThreadLocalRunner>,
add_any_thread_local_system_once
);
impl_builders!(
BuilderCreation,
BuilderConditionsCreation,
BuilderElseCreation,
CreationSystem,
AnySystem<Box<dyn CreationSystem>>,
add_any_creation_system
);
impl_builders!(
BuilderCreationOnce,
BuilderConditionsCreationOnce,
BuilderElseCreationOnce,
CreationSystemOnce,
AnySystem<CreationSystemOnceRunner>,
add_any_creation_system_once
);