mod container;
mod builders;
mod any_system;
pub use self::container::{
Systems, Priority, StatsType, SystemId,
PredecessorsCache, SystemHandle
};
#[cfg(feature="parallel_systems")]
pub use self::container::{SendSystems, SendSystemsStats};
pub use self::builders::*;
pub use self::any_system::AnySystem;
use std::cell::UnsafeCell;
use std::any::{Any, TypeId};
use crate::resource::ResourcesCreation;
use crate::storage::{SubStorages, StorageRegistry};
use crate::component::{self, Component};
use crate::bitmask::Bitmask;
use crate::{Entities, Resources, EntitiesThreadLocal, ResourcesThreadLocal, EntitiesCreation};
#[cfg(feature="debug_parameters")]
use crate::debug::SystemDebug;
#[cfg(feature="async")]
use futures::Future;
#[cfg(feature="async")]
use futures::task::{ArcWake, waker_ref, Context, Poll};
#[cfg(feature="async")]
use std::pin::Pin;
#[cfg(feature="async")]
use std::cell::Cell;
#[cfg(feature="async")]
use std::sync::Arc;
pub trait System: Send{
fn run(&mut self, entities: Entities, resources: Resources);
fn checks(_: &mut StorageRegistry) -> Option<SystemConditionSend> where Self: Sized { None }
fn name() -> Option<&'static str> where Self: Sized { None }
fn before() -> Vec<SystemId> where Self: Sized { vec![] }
fn after() -> Vec<SystemId> where Self: Sized { vec![] }
fn updates() -> Vec<TypeId> where Self: Sized { vec![] }
fn needs() -> Vec<TypeId> where Self: Sized { vec![] }
fn reads() -> Vec<TypeId> where Self: Sized { vec![] }
fn writes() -> Vec<TypeId> where Self: Sized { vec![] }
fn file_line_info(&self) -> &'static str { "" }
}
pub trait SystemThreadLocal{
fn run(&mut self, entities: EntitiesThreadLocal, resources: ResourcesThreadLocal);
fn checks(_: &mut StorageRegistry) -> Option<SystemConditionThreadLocal> where Self: Sized { None }
fn name() -> Option<&'static str> where Self: Sized { None }
fn runs_on_gpu() -> bool where Self: Sized { false }
fn before() -> Vec<SystemId> where Self: Sized { vec![] }
fn after() -> Vec<SystemId> where Self: Sized { vec![] }
fn updates() -> Vec<TypeId> where Self: Sized { vec![] }
fn needs() -> Vec<TypeId> where Self: Sized { vec![] }
fn reads() -> Vec<TypeId> where Self: Sized { vec![] }
fn writes() -> Vec<TypeId> where Self: Sized { vec![] }
fn file_line_info(&self) -> &'static str { "" }
}
impl<F: FnMut(Entities, Resources) + Send> System for F{
fn run(&mut self, e: Entities, r: Resources){
(*self)(e,r)
}
}
impl<F: FnMut(EntitiesThreadLocal, ResourcesThreadLocal)> SystemThreadLocal for F{
fn run(&mut self, e: EntitiesThreadLocal, r: ResourcesThreadLocal){
(*self)(e,r)
}
}
pub trait SystemWithData<D: Send + 'static>: Send{
fn run(&mut self, data: &mut D, entities: Entities, resources: Resources);
fn checks(_: &mut StorageRegistry) -> Option<SystemConditionSend> where Self: Sized { None }
fn name() -> Option<&'static str> where Self: Sized { None }
fn before() -> Vec<SystemId> where Self: Sized { vec![] }
fn after() -> Vec<SystemId> where Self: Sized { vec![] }
fn updates() -> Vec<TypeId> where Self: Sized { vec![] }
fn needs() -> Vec<TypeId> where Self: Sized { vec![] }
fn reads() -> Vec<TypeId> where Self: Sized { vec![] }
fn writes() -> Vec<TypeId> where Self: Sized { vec![] }
fn file_line_info(&self) -> &'static str { "" }
}
impl<D: Send + 'static, F: FnMut(&mut D, Entities, Resources) + Send> SystemWithData<D> for F {
fn run(&mut self, data: &mut D, entities: Entities, resources: Resources){
self(data, entities, resources)
}
}
impl<D: Send + 'static, S: SystemWithData<D> + Send> System for (S, D){
fn run(&mut self, entities: Entities, resources: Resources){
self.0.run(&mut self.1, entities, resources)
}
fn checks(entities: &mut StorageRegistry) -> Option<SystemConditionSend> where Self: Sized {
S::checks(entities)
}
fn name() -> Option<&'static str> where Self: Sized { S::name() }
fn before() -> Vec<SystemId> where Self: Sized { S::before() }
fn after() -> Vec<SystemId> where Self: Sized { S::after() }
fn updates() -> Vec<TypeId> where Self: Sized { S::updates() }
fn needs() -> Vec<TypeId> where Self: Sized { S::needs() }
fn reads() -> Vec<TypeId> where Self: Sized { vec![] }
fn writes() -> Vec<TypeId> where Self: Sized { vec![] }
fn file_line_info(&self) -> &'static str { "" }
}
pub trait SystemWithDataThreadLocal<D: 'static>{
fn run(&mut self, data: &mut D, entities: EntitiesThreadLocal, resources: ResourcesThreadLocal);
fn checks(_: &mut StorageRegistry) -> Option<SystemConditionThreadLocal> where Self: Sized { None }
fn name() -> Option<&'static str> where Self: Sized { None }
fn runs_on_gpu() -> bool where Self: Sized { false }
fn before() -> Vec<SystemId> where Self: Sized { vec![] }
fn after() -> Vec<SystemId> where Self: Sized { vec![] }
fn updates() -> Vec<TypeId> where Self: Sized { vec![] }
fn needs() -> Vec<TypeId> where Self: Sized { vec![] }
fn reads() -> Vec<TypeId> where Self: Sized { vec![] }
fn writes() -> Vec<TypeId> where Self: Sized { vec![] }
fn file_line_info(&self) -> &'static str { "" }
}
impl<D: 'static, F: FnMut(&mut D, EntitiesThreadLocal, ResourcesThreadLocal)> SystemWithDataThreadLocal<D> for F {
fn run(&mut self, data: &mut D, entities: EntitiesThreadLocal, resources: ResourcesThreadLocal){
self(data, entities, resources)
}
}
impl<D: 'static, S: SystemWithDataThreadLocal<D>> SystemThreadLocal for (S, D){
fn run(&mut self, entities: EntitiesThreadLocal, resources: ResourcesThreadLocal){
self.0.run(&mut self.1, entities, resources)
}
fn checks(e: &mut StorageRegistry) -> Option<SystemConditionThreadLocal>
where Self: Sized
{
S::checks(e)
}
fn name() -> Option<&'static str> where Self: Sized { S::name() }
fn runs_on_gpu() -> bool where Self: Sized { S::runs_on_gpu() }
fn before() -> Vec<SystemId> where Self: Sized { S::before() }
fn after() -> Vec<SystemId> where Self: Sized { S::after() }
fn updates() -> Vec<TypeId> where Self: Sized { S::updates() }
fn needs() -> Vec<TypeId> where Self: Sized { S::needs() }
fn reads() -> Vec<TypeId> where Self: Sized { vec![] }
fn writes() -> Vec<TypeId> where Self: Sized { vec![] }
fn file_line_info(&self) -> &'static str { "" }
}
pub trait CreationSystem{
fn run(&mut self, entities: EntitiesCreation, resources: ResourcesCreation);
fn checks(_: &mut StorageRegistry) -> Option<SystemConditionCreation> where Self: Sized {
None
}
fn name() -> Option<&'static str> where Self: Sized { None }
fn runs_on_gpu() -> bool where Self: Sized { false }
fn before() -> Vec<SystemId> where Self: Sized { vec![] }
fn after() -> Vec<SystemId> where Self: Sized { vec![] }
fn updates() -> Vec<TypeId> where Self: Sized { vec![] }
fn needs() -> Vec<TypeId> where Self: Sized { vec![] }
fn creates() -> Vec<TypeId> where Self: Sized { vec![] }
fn reads() -> Vec<TypeId> where Self: Sized { vec![] }
fn writes() -> Vec<TypeId> where Self: Sized { vec![] }
fn file_line_info(&self) -> &'static str { "" }
}
pub trait CreationSystemWithData<D: 'static>{
fn run(&mut self, data: &mut D, entities: EntitiesCreation, resources: ResourcesCreation);
fn checks(_: &mut StorageRegistry) -> Option<SystemConditionCreation> where Self: Sized { None }
fn name() -> Option<&'static str> where Self: Sized { None }
fn runs_on_gpu() -> bool where Self: Sized { false }
fn before() -> Vec<SystemId> where Self: Sized { vec![] }
fn after() -> Vec<SystemId> where Self: Sized { vec![] }
fn updates() -> Vec<TypeId> where Self: Sized { vec![] }
fn needs() -> Vec<TypeId> where Self: Sized { vec![] }
fn creates() -> Vec<TypeId> where Self: Sized { vec![] }
fn reads() -> Vec<TypeId> where Self: Sized { vec![] }
fn writes() -> Vec<TypeId> where Self: Sized { vec![] }
fn file_line_info(&self) -> &'static str { "" }
}
pub trait SystemOnce: Send{
fn run(self, entities: Entities, resources: Resources);
fn checks(_: &mut StorageRegistry) -> Option<SystemConditionSendOnce> where Self: Sized { None }
fn name() -> Option<&'static str> where Self: Sized { None }
fn before() -> Vec<SystemId> where Self: Sized { vec![] }
fn after() -> Vec<SystemId> where Self: Sized { vec![] }
fn updates() -> Vec<TypeId> where Self: Sized { vec![] }
fn needs() -> Vec<TypeId> where Self: Sized { vec![] }
fn reads() -> Vec<TypeId> where Self: Sized { vec![] }
fn writes() -> Vec<TypeId> where Self: Sized { vec![] }
fn file_line_info(&self) -> &'static str { "" }
}
impl<F: FnOnce(Entities, Resources) + Send> SystemOnce for F{
fn run(self, e: Entities, r: Resources){
(self)(e,r)
}
}
pub struct SystemOnceRunner{
runner: UnsafeCell<Box<dyn FnMut(Entities, Resources) + Send>>
}
unsafe impl Sync for SystemOnceRunner{}
impl SystemOnceRunner{
pub fn new<S: SystemOnce + 'static>(system: S) -> SystemOnceRunner{
let mut system = Some(system);
SystemOnceRunner{
runner: UnsafeCell::new(Box::new(move |entities, resources|
if let Some(system) = system.take(){
system.run(entities, resources)
}
))
}
}
pub fn run(&self, entities: Entities, resources: Resources){
unsafe{ (*self.runner.get())(entities, resources) }
}
}
pub trait SystemOnceThreadLocal {
fn run(self, entities: EntitiesThreadLocal, resources: ResourcesThreadLocal);
fn checks(_: &mut StorageRegistry) -> Option<SystemConditionThreadLocalOnce> where Self: Sized { None }
fn name() -> Option<&'static str> where Self: Sized { None }
fn runs_on_gpu() -> bool where Self: Sized { false }
fn before() -> Vec<SystemId> where Self: Sized { vec![] }
fn after() -> Vec<SystemId> where Self: Sized { vec![] }
fn updates() -> Vec<TypeId> where Self: Sized { vec![] }
fn needs() -> Vec<TypeId> where Self: Sized { vec![] }
fn reads() -> Vec<TypeId> where Self: Sized { vec![] }
fn writes() -> Vec<TypeId> where Self: Sized { vec![] }
fn file_line_info(&self) -> &'static str { "" }
}
impl<F: FnOnce(EntitiesThreadLocal, ResourcesThreadLocal) + Send> SystemOnceThreadLocal for F{
fn run(self, e: EntitiesThreadLocal, r: ResourcesThreadLocal){
(self)(e,r)
}
}
pub struct SystemOnceThreadLocalRunner{
runner: Box<dyn FnMut(EntitiesThreadLocal, ResourcesThreadLocal)>
}
impl SystemOnceThreadLocalRunner{
pub fn new<S: SystemOnceThreadLocal + 'static>(system: S) -> SystemOnceThreadLocalRunner{
let mut system = Some(system);
SystemOnceThreadLocalRunner{
runner: Box::new(move |entities, resources|
if let Some(system) = system.take(){
system.run(entities, resources)
}
)
}
}
pub fn run(&mut self, entities: EntitiesThreadLocal, resources: ResourcesThreadLocal){
(*self.runner)(entities, resources)
}
}
pub trait CreationSystemOnce {
fn run(self, entities: EntitiesCreation, resources: ResourcesCreation);
fn checks(_: &mut StorageRegistry) -> Option<SystemConditionCreationOnce> where Self: Sized { None }
fn name() -> Option<&'static str> where Self: Sized { None }
fn runs_on_gpu() -> bool where Self: Sized { false }
fn before() -> Vec<SystemId> where Self: Sized { vec![] }
fn after() -> Vec<SystemId> where Self: Sized { vec![] }
fn updates() -> Vec<TypeId> where Self: Sized { vec![] }
fn needs() -> Vec<TypeId> where Self: Sized { vec![] }
fn creates() -> Vec<TypeId> where Self: Sized { vec![] }
fn reads() -> Vec<TypeId> where Self: Sized { vec![] }
fn writes() -> Vec<TypeId> where Self: Sized { vec![] }
fn file_line_info(&self) -> &'static str { "" }
}
impl<F: FnOnce(EntitiesCreation, ResourcesCreation) + Send> CreationSystemOnce for F{
fn run(self, e: EntitiesCreation, r: ResourcesCreation){
(self)(e,r)
}
}
pub struct CreationSystemOnceRunner{
runner: Box<dyn FnMut(EntitiesCreation, ResourcesCreation)>
}
impl CreationSystemOnceRunner{
pub fn new<S: CreationSystemOnce + 'static>(system: S) -> CreationSystemOnceRunner{
let mut system = Some(system);
CreationSystemOnceRunner{
runner: Box::new(move |entities, resources|
if let Some(system) = system.take(){
system.run(entities, resources)
}
)
}
}
pub fn run(&mut self, entities: EntitiesCreation, resources: ResourcesCreation){
(*self.runner)(entities, resources)
}
}
#[cfg(feature = "async")]
pub trait CreationSystemAsync{
fn run(self, entities: EntitiesCreation) -> Pin<Box<dyn Future<Output = ()>>>;
fn checks(_: &mut StorageRegistry) -> Option<SystemConditionCreationAsync> where Self: Sized {
None
}
fn name() -> Option<&'static str> where Self: Sized { None }
fn runs_on_gpu() -> bool where Self: Sized { false }
fn before() -> Vec<SystemId> where Self: Sized { vec![] }
fn after() -> Vec<SystemId> where Self: Sized { vec![] }
fn updates() -> Vec<TypeId> where Self: Sized { vec![] }
fn needs() -> Vec<TypeId> where Self: Sized { vec![] }
fn creates() -> Vec<TypeId> where Self: Sized { vec![] }
fn reads() -> Vec<TypeId> where Self: Sized { vec![] }
fn writes() -> Vec<TypeId> where Self: Sized { vec![] }
fn file_line_info(&self) -> &'static str { "" }
}
#[cfg(feature = "async")]
pub struct Task{
future: UnsafeCell<Option<Pin<Box<dyn Future<Output = ()>>>>>,
ready: Cell<bool>,
}
#[cfg(feature = "async")]
impl Task{
pub fn new(future: Pin<Box<dyn Future<Output = ()>>>) -> Task{
Task{
future: UnsafeCell::new(Some(future)),
ready: Cell::new(true)
}
}
pub fn is_ready(&self) -> bool{
self.ready.get()
}
pub fn future(&self) -> Option<Pin<Box<dyn Future<Output = ()>>>>{
unsafe{ (*self.future.get()).take() }
}
pub fn reset_future(&self, future: Pin<Box<dyn Future<Output = ()>>>){
unsafe{ *self.future.get() = Some(future) }
}
pub fn run(arc_self: &Arc<Self>) -> Poll<()> {
if arc_self.is_ready(){
let waker = waker_ref(arc_self);
let context = &mut Context::from_waker(&*waker);
arc_self.ready.set(false);
if let Some(mut future) = arc_self.future(){
let poll_res = future.as_mut().poll(context);
if Poll::Pending == poll_res{
arc_self.reset_future(future)
}
poll_res
}else{
Poll::Pending
}
}else{
Poll::Pending
}
}
}
#[cfg(feature = "async")]
unsafe impl Send for Task{}
#[cfg(feature = "async")]
unsafe impl Sync for Task{}
#[cfg(feature = "async")]
impl ArcWake for Task {
fn wake_by_ref(arc_self: &Arc<Self>) {
arc_self.ready.set(true)
}
}
impl<F: FnMut(EntitiesCreation, ResourcesCreation)> CreationSystem for F{
fn run(&mut self, entities: EntitiesCreation, resources: ResourcesCreation){
self(entities, resources)
}
}
impl<D: 'static, F: FnMut(&mut D, EntitiesCreation, ResourcesCreation)> CreationSystemWithData<D> for F{
fn run(&mut self, data: &mut D, entities: EntitiesCreation, resources: ResourcesCreation){
self(data, entities, resources)
}
}
#[cfg(feature = "async")]
impl<F: FnOnce(CreationProxy) -> Pin<Box<dyn Future<Output = ()>>>> CreationSystemAsync for F{
fn run(self, entities: CreationProxy) -> Pin<Box<dyn Future<Output = ()>>>{
self(entities)
}
}
impl<D: 'static, S: CreationSystemWithData<D>> CreationSystem for (S, D) {
fn run(&mut self, entities: EntitiesCreation, resources: ResourcesCreation){
self.0.run(&mut self.1, entities, resources)
}
fn checks(entities: &mut StorageRegistry) -> Option<SystemConditionCreation> where Self: Sized {
S::checks(entities)
}
fn name() -> Option<&'static str> where Self: Sized { S::name() }
fn runs_on_gpu() -> bool where Self: Sized { S::runs_on_gpu() }
fn before() -> Vec<SystemId> where Self: Sized { S::before() }
fn after() -> Vec<SystemId> where Self: Sized { S::after() }
fn updates() -> Vec<TypeId> where Self: Sized { S::updates() }
fn needs() -> Vec<TypeId> where Self: Sized { S::needs() }
fn creates() -> Vec<TypeId> where Self: Sized { S::creates() }
fn reads() -> Vec<TypeId> where Self: Sized { vec![] }
fn writes() -> Vec<TypeId> where Self: Sized { vec![] }
fn file_line_info(&self) -> &'static str { "" }
}
#[derive(Debug)]
pub enum SystemCondition{
StorageChanged(component::Id),
HasComponents(Bitmask),
ResourcesChanged(TypeId, Box<dyn Any>),
HasResource(TypeId),
All(Vec<SystemCondition>),
Any(Vec<SystemCondition>),
Not(Box<SystemCondition>),
}
unsafe impl Send for SystemCondition{}
unsafe impl Sync for SystemCondition{}
impl SystemCondition{
pub fn all(all: Vec<SystemCondition>) -> SystemCondition{
SystemCondition::All(all)
}
pub fn any(any: Vec<SystemCondition>) -> SystemCondition{
SystemCondition::Any(any)
}
pub fn storage_changed<C: Component>() -> SystemCondition{
SystemCondition::StorageChanged(TypeId::of::<C>())
}
pub fn has_resource<R: 'static>() -> SystemCondition{
SystemCondition::HasResource(TypeId::of::<R>())
}
pub fn has_any(mask: Bitmask) -> SystemCondition{
SystemCondition::HasComponents(mask)
}
pub fn not(condition: SystemCondition) -> SystemCondition{
SystemCondition::Not(Box::new(condition))
}
pub fn resource_changed<R: 'static, F: 'static + Send + Fn(&R) -> bool>(f: F) -> SystemCondition{
let boxed: Box<dyn Fn(&R) -> bool> = Box::new(f);
SystemCondition::ResourcesChanged(TypeId::of::<R>(), Box::new(boxed))
}
pub fn else_run<Else>(self, cond_else: Else) -> SystemConditionElse<Else>{
SystemConditionElse{
condition: self,
cond_else: Some(cond_else),
}
}
pub fn build<Else>(self) -> SystemConditionElse<Else>{
SystemConditionElse{
condition: self,
cond_else: None,
}
}
fn check_should_run(&self, storages: &SubStorages, resources: &Resources) -> bool{
match self{
SystemCondition::StorageChanged(id) => storages.check_storage_changed(*id),
SystemCondition::HasComponents(mask) => {
storages.any_has_mask(mask.clone())
}
SystemCondition::Not(condition) => !condition.check_should_run(storages, resources),
SystemCondition::Any(checks) => checks.iter()
.any(|check| check.check_should_run(storages, resources)),
SystemCondition::All(checks) => checks.iter()
.all(|check| check.check_should_run(storages, resources)),
SystemCondition::ResourcesChanged(id, func) => {
resources.check_resource(id, func)
}
SystemCondition::HasResource(id) => resources.has_resource(id)
}
}
fn check_should_run_thread_local(&self, storages: &SubStorages, resources: &ResourcesThreadLocal) -> bool{
match self{
SystemCondition::StorageChanged(id) => storages.check_storage_changed(*id),
SystemCondition::HasComponents(mask) => {
storages.any_has_mask(mask.clone())
}
SystemCondition::Not(condition) =>
!condition.check_should_run_thread_local(storages, resources),
SystemCondition::Any(checks) => checks.iter()
.any(|check| check.check_should_run_thread_local(storages, resources)),
SystemCondition::All(checks) => checks.iter()
.all(|check| check.check_should_run_thread_local(storages, resources)),
SystemCondition::ResourcesChanged(id, func) => {
resources.check_resource(id, func)
}
SystemCondition::HasResource(id) => resources.has_resource(id)
}
}
fn check_should_run_creation(&self, storages: &SubStorages, resources: &ResourcesCreation) -> bool{
match self{
SystemCondition::StorageChanged(id) => storages.check_storage_changed(*id),
SystemCondition::HasComponents(mask) => {
storages.any_has_mask(mask.clone())
}
SystemCondition::Not(condition) =>
!condition.check_should_run_creation(storages, resources),
SystemCondition::Any(checks) => checks.iter()
.any(|check| check.check_should_run_creation(storages, resources)),
SystemCondition::All(checks) => checks.iter()
.all(|check| check.check_should_run_creation(storages, resources)),
SystemCondition::ResourcesChanged(id, func) => {
resources.check_resource(id, func)
}
SystemCondition::HasResource(id) => resources.has_resource(id)
}
}
}
pub struct SystemConditionElse<Else>{
condition: SystemCondition,
cond_else: Option<Else>,
}
impl<Else> SystemConditionElse<Else>{
pub fn build<TraitObject>(self) -> SystemConditionElse<TraitObject>
where Else: AnySystem<TraitObject>
{
let els = self.cond_else.map(|els| els.into_trait_object());
SystemConditionElse {
condition: self.condition,
cond_else: els
}
}
pub fn condition_else(self) -> (Option<SystemCondition>, Option<Else>){
(Some(self.condition), self.cond_else)
}
}
pub type SystemConditionSend = SystemConditionElse<SyncSystem>;
pub type SystemConditionSendOnce = SystemConditionElse<SystemOnceRunner>;
pub type SystemConditionThreadLocal = SystemConditionElse<Box<dyn SystemThreadLocal>>;
pub type SystemConditionThreadLocalOnce = SystemConditionElse<SystemOnceThreadLocalRunner>;
pub type SystemConditionCreation = SystemConditionElse<Box<dyn CreationSystem>>;
pub type SystemConditionCreationOnce = SystemConditionElse<CreationSystemOnceRunner>;
#[cfg(feature = "async")]
pub type SystemConditionCreationAsync = SystemConditionElse<Box<dyn CreationSystemAsync>>;
pub struct SyncSystem(UnsafeCell<Box<dyn System>>);
impl SyncSystem{
fn new<S: System + 'static>(s: S) -> SyncSystem{
SyncSystem(UnsafeCell::new(Box::new(s)))
}
unsafe fn borrow_mut(&self) -> &mut dyn System{
&mut **self.0.get()
}
fn _borrow(&self) -> &dyn System{
unsafe{ &**self.0.get() }
}
#[allow(dead_code)]
fn file_line_info(&self) -> &'static str {
self._borrow().file_line_info()
}
}
unsafe impl Send for SyncSystem{}
unsafe impl Sync for SyncSystem{}
pub trait Barrier{
fn name() -> Option<&'static str> where Self: Sized { None }
fn before() -> Vec<SystemId> where Self: Sized { vec![] }
fn after() -> Vec<SystemId> where Self: Sized { vec![] }
}