pub trait System<'a>: Send{
fn run(&mut self, ::Entities<'a>, ::Resources<'a>);
}
pub trait SystemThreadLocal<'a>{
fn run(&mut self, ::EntitiesThreadLocal<'a>, ::ResourcesThreadLocal<'a>);
}
impl<'a, F: FnMut(::Entities<'a>, ::Resources<'a>) + Send> System<'a> for F{
fn run(&mut self, e: ::Entities<'a>, r: ::Resources<'a>){
(*self)(e,r)
}
}
impl<'a, F: FnMut(::EntitiesThreadLocal<'a>, ::ResourcesThreadLocal<'a>)> SystemThreadLocal<'a> for F{
fn run(&mut self, e: ::EntitiesThreadLocal<'a>, r: ::ResourcesThreadLocal<'a>){
(*self)(e,r)
}
}
pub trait SystemResources<'a>: Send{
fn run(&mut self, ::Resources<'a>);
}
impl<'a, F: FnMut(::Resources<'a>) + Send> SystemResources<'a> for F{
fn run(&mut self, e: ::Resources<'a>){
(*self)(e)
}
}
impl<'a> System<'a> for SystemResources<'a>{
fn run(&mut self, _: ::Entities<'a>, r: ::Resources<'a>){
self.run(r)
}
}
pub trait SystemEntities<'a>: Send{
fn run(&mut self, ::Entities<'a>);
}
impl<'a, F: FnMut(::Entities<'a>) + Send> SystemEntities<'a> for F{
fn run(&mut self, e: ::Entities<'a>){
(*self)(e)
}
}
impl<'a> System<'a> for SystemEntities<'a>{
fn run(&mut self, e: ::Entities<'a>, _: ::Resources<'a>){
self.run(e)
}
}
pub trait SystemWithData<'a, D: Send + 'static>: Send{
fn run(&mut self, data: &mut D, entities: ::Entities, resources: ::Resources);
}
impl<'a, D: Send + 'static, F: FnMut(&mut D,::Entities, ::Resources) + Send> SystemWithData<'a, D> for F {
fn run(&mut self, data: &mut D, entities: ::Entities, resources: ::Resources){
self(data, entities, resources)
}
}
impl<'a, D: Send + 'static, S: SystemWithData<'a,D> + Send> System<'a> for (S, D){
fn run(&mut self, entities: ::Entities, resources: ::Resources){
self.0.run(&mut self.1, entities, resources)
}
}
pub trait SystemWithDataThreadLocal<'a, D: 'static>{
fn run(&mut self, data: &mut D, entities: ::EntitiesThreadLocal, resources: ::ResourcesThreadLocal);
}
impl<'a, D: 'static, F: FnMut(&mut D,::EntitiesThreadLocal, ::ResourcesThreadLocal)> SystemWithDataThreadLocal<'a, D> for F {
fn run(&mut self, data: &mut D, entities: ::EntitiesThreadLocal, resources: ::ResourcesThreadLocal){
self(data, entities, resources)
}
}
impl<'a, D: 'static, S: SystemWithDataThreadLocal<'a,D>> SystemThreadLocal<'a> for (S, D){
fn run(&mut self, entities: ::EntitiesThreadLocal, resources: ::ResourcesThreadLocal){
self.0.run(&mut self.1, entities, resources)
}
}
pub trait CreationSystem<'a>{
fn run(&mut self, entities: ::CreationProxy<'a>, resources: ::ResourcesThreadLocal<'a>);
}
pub trait CreationSystemWithData<'a, D: 'static>{
fn run(&mut self, data: &mut D, entities: ::CreationProxy<'a>, resources: ::ResourcesThreadLocal<'a>);
}
impl<'a, F: FnMut(::CreationProxy<'a>, ::ResourcesThreadLocal<'a>)> CreationSystem<'a> for F{
fn run(&mut self, entities: ::CreationProxy<'a>, resources: ::ResourcesThreadLocal<'a>){
self(entities, resources)
}
}
impl<'a, D: 'static, F: FnMut(&mut D, ::CreationProxy<'a>, ::ResourcesThreadLocal<'a>)> CreationSystemWithData<'a, D> for F{
fn run(&mut self, data: &mut D, entities: ::CreationProxy<'a>, resources: ::ResourcesThreadLocal<'a>){
self(data, entities, resources)
}
}
impl<'a, D: 'static, S: CreationSystemWithData<'a, D>> CreationSystem<'a> for (S, D) {
fn run(&mut self, entities: ::CreationProxy<'a>, resources: ::ResourcesThreadLocal<'a>){
self.0.run(&mut self.1, entities, resources)
}
}
#[cfg(feature="stats_events")]
use std::time;
#[cfg(feature="stats_events")]
use hashbrown::HashMap;
#[cfg(feature="stats_events")]
use seitan::{StreamT, SenderRc, Property};
use std::cell::UnsafeCell;
use entity::{Entities, EntitiesThreadLocal, CreationProxy};
#[cfg(feature="debug_parameters")]
use debug::{EntitiesDebug, SystemDebug};
use resource::{Resources, ResourcesThreadLocal};
#[cfg(feature="debug_concurrency")]
use std::intrinsics::type_name;
#[derive(Default)]
pub struct Systems{
systems: Vec<(Option<String>, SyncSystem)>,
systems_thread_local: Vec<(Option<String>, Box<for<'a> SystemThreadLocal<'a>>)>,
systems_creation: Vec<(Option<String>, Box<for<'a> CreationSystem<'a>>)>,
#[cfg(feature = "debug_parameters")]
systems_debug: Vec<(Option<String>, Box<for<'a> SystemDebug<'a>>)>,
#[cfg(feature="stats_events")]
stats: Vec<(String, time::Duration)>,
#[cfg(feature="stats_events")]
gpu_stats: Vec<(String, time::Duration)>,
#[cfg(feature="stats_events")]
stats_events: HashMap<String, SenderRc<'static, time::Duration>>,
#[cfg(all(feature="stats_events", feature="glin"))]
gpu_stats_counters: HashMap<String, glin::query::Duration>,
#[cfg(feature="stats_events")]
gpu_stats_events: HashMap<String, SenderRc<'static, time::Duration>>,
#[cfg(feature="stats_events")]
enabled_systems: HashMap<String, Property<'static, bool>>,
#[cfg(feature="stats_events")]
send_enabled_systems: HashMap<String, bool>,
#[cfg(feature="dynamic_systems")]
dynamic_systems: DynamicSystemsLoader,
}
#[cfg(feature="multithreaded")]
pub struct SendSystems<'a>{
systems: &'a [(Option<String>, SyncSystem)],
#[cfg(feature="stats_events")]
enabled_systems: &'a HashMap<String, bool>,
#[cfg(feature="stats_events")]
sender: crossbeam::channel::Sender<(String, time::Duration)>,
}
#[cfg(feature="multithreaded")]
impl<'a> SendSystems<'a>{
pub fn run_send_system(&self, idx: usize, entities: Entities, resources: Resources) {
let (_name, system_w) = &self.systems[idx];
let system_w = unsafe{ system_w.borrow_mut() };
#[cfg(feature="stats_events")]
{
if let Some(ref name) = _name {
match self.enabled_systems.get(name).map(|e| *e) {
Some(true) => {
let then = time::Instant::now();
system_w.run(entities, resources);
let now = time::Instant::now();
self.sender.send((name.clone(), now - then)).is_ok();
}
Some(false) => (),
None => system_w.run(entities, resources),
}
}else{
system_w.run(entities, resources);
}
}
#[cfg(not(feature="stats_events"))]
{
system_w.run(entities, resources);
}
}
}
#[cfg(feature="multithreaded")]
pub struct ThreadLocalSystems<'a>{
systems: &'a mut [(Option<String>, Box<for<'b> SystemThreadLocal<'b>>)],
#[cfg(feature="stats_events")]
enabled_systems: &'a HashMap<String, bool>,
#[cfg(feature="stats_events")]
stats: &'a mut Vec<(String, time::Duration)>,
#[cfg(feature="stats_events")]
receiver: crossbeam::channel::Receiver<(String, time::Duration)>,
}
#[cfg(feature="multithreaded")]
impl<'a> ThreadLocalSystems<'a>{
pub fn run_thread_local_system(&mut self, idx: usize, entities: EntitiesThreadLocal, resources: ResourcesThreadLocal) {
let (_name, system_w) = &mut self.systems[idx];
#[cfg(feature="stats_events")]
{
if let Some(name) = _name {
match self.enabled_systems.get(name).map(|e| *e) {
Some(true) => {
let then = time::Instant::now();
system_w.run(entities, resources);
let now = time::Instant::now();
self.stats.push((name.clone(), now - then));
}
Some(false) => (),
None => system_w.run(entities, resources),
}
}else{
system_w.run(entities, resources);
}
}
#[cfg(not(feature="stats_events"))]
system_w.run(entities, resources);
}
}
#[cfg(feature="stats_events")]
#[cfg(feature="multithreaded")]
impl<'a> Drop for ThreadLocalSystems<'a>{
fn drop(&mut self){
self.stats.extend(self.receiver.try_iter())
}
}
impl Systems{
#[cfg(feature="stats_events")]
pub fn reset_stats(&mut self){
self.send_enabled_systems.clear();
let enabled_systems = self.enabled_systems.iter().map(|(n, e)| (n.to_owned(), **e));
self.send_enabled_systems.extend(enabled_systems);
self.stats.clear();
#[cfg(feature="glin")]
self.gpu_stats.clear();
#[cfg(feature = "debug_parameters")]
let debug_systems = self.systems_debug.len();
#[cfg(not(feature = "debug_parameters"))]
let debug_systems = 0;
self.stats.reserve(
self.systems.len() +
self.systems_thread_local.len() +
self.systems_creation.len() +
debug_systems);
}
#[cfg(feature="multithreaded")]
pub fn send_and_tl_systems(&mut self) -> (SendSystems, ThreadLocalSystems){
#[cfg(feature="stats_events")]
let (sender, receiver) = crossbeam::channel::bounded(self.systems.len());
let send = SendSystems{
systems: &self.systems,
#[cfg(feature="stats_events")]
enabled_systems: &self.send_enabled_systems,
#[cfg(feature="stats_events")]
sender,
};
let tl = ThreadLocalSystems{
systems: &mut self.systems_thread_local,
#[cfg(feature="stats_events")]
enabled_systems: &self.send_enabled_systems,
#[cfg(feature="stats_events")]
stats: &mut self.stats,
#[cfg(feature="stats_events")]
receiver,
};
(send, tl)
}
pub fn run_send_system(&mut self, idx: usize, entities: Entities, resources: Resources){
let (_name, system_w) = &mut self.systems[idx];
let system_w = unsafe{ system_w.borrow_mut() };
#[cfg(feature="stats_events")]
{
if let Some(name) = _name {
match self.enabled_systems.get(name).map(|e| **e) {
Some(true) => {
let then = time::Instant::now();
system_w.run(entities, resources);
let now = time::Instant::now();
self.stats.push((name.clone(), now - then));
}
Some(false) => (),
None => system_w.run(entities, resources),
}
}else{
system_w.run(entities, resources);
}
}
#[cfg(not(feature="stats_events"))]
system_w.run(entities, resources);
}
pub fn run_thread_local_system(&mut self, idx: usize, entities: EntitiesThreadLocal, resources: ResourcesThreadLocal){
let (_name, system_w) = &mut self.systems_thread_local[idx];
#[cfg(feature="stats_events")]
{
if let Some(name) = _name {
match self.enabled_systems.get(name).map(|e| **e) {
Some(true) => {
#[cfg(feature="glin")]
{
if let Some(mut counter) = self.gpu_stats_counters.get_mut(name){
if let Some(duration) = counter.result() {
self.gpu_stats.push((name.clone(), duration));
}
counter.begin();
}
}
let then = time::Instant::now();
system_w.run(entities, resources);
let now = time::Instant::now();
#[cfg(feature="glin")]
{
if let Some(mut counter) = self.gpu_stats_counters.get_mut(name){
counter.end();
}
}
self.stats.push((name.clone(), now - then));
}
Some(false) => (),
None => system_w.run(entities, resources),
}
}else{
system_w.run(entities, resources);
}
}
#[cfg(not(feature="stats_events"))]
system_w.run(entities, resources);
}
pub fn run_creation_system(&mut self, idx: usize, entities: CreationProxy, resources: ResourcesThreadLocal){
let (_name, system_w) = &mut self.systems_creation[idx];
#[cfg(feature="stats_events")]
{
if let Some(name) = _name {
match self.enabled_systems.get(name).map(|e| **e) {
Some(true) => {
#[cfg(feature="glin")]
{
if let Some(mut counter) = self.gpu_stats_counters.get_mut(name){
if let Some(duration) = counter.result() {
self.gpu_stats.push((name.clone(), duration));
}
counter.begin();
}
}
let then = time::Instant::now();
system_w.run(entities, resources);
let now = time::Instant::now();
#[cfg(feature="glin")]
{
if let Some(mut counter) = self.gpu_stats_counters.get_mut(name){
counter.end();
}
}
self.stats.push((name.clone(), now - then));
}
Some(false) => (),
None => system_w.run(entities, resources),
}
}else{
system_w.run(entities, resources);
}
}
#[cfg(not(feature="stats_events"))]
system_w.run(entities, resources);
}
#[cfg(feature = "debug_parameters")]
pub fn run_debug_system(&mut self, idx: usize, entities: EntitiesDebug, resources: ResourcesThreadLocal){
let (_name, system_w) = &mut self.systems_debug[idx];
#[cfg(feature="stats_events")]
{
if let Some(name) = _name {
match self.enabled_systems.get(name).map(|e| **e) {
Some(true) => {
let then = time::Instant::now();
system_w.run(entities, resources);
let now = time::Instant::now();
self.stats.push((name.clone(), now - then));
}
Some(false) => (),
None => system_w.run(entities, resources),
}
}else{
system_w.run(entities, resources);
}
}
#[cfg(not(feature="stats_events"))]
system_w.run(entities, resources);
}
pub fn add_system<S, TraitObject>(&mut self, system: S, stat: Option<StatsType>) -> Priority
where S: AnySystem<TraitObject> + 'static
{
let priority = S::priority(S::collection(self).len());
#[cfg(feature="debug_concurrency")]
let name = unsafe{
Some(stat.map(|stat| stat.name().to_owned())
.unwrap_or_else(|| type_name::<S>().to_owned()))
};
#[cfg(not(feature="debug_concurrency"))]
let name = stat.map(|stat| stat.name().to_owned());
S::collection(self).push((name, system.into_trait_object()));
#[cfg(feature="stats_events")]
{
if let Some(stat) = stat {
self.stats_events.insert(stat.name().to_owned(), SenderRc::new());
if let StatsType::Gpu(name) = stat{
self.gpu_stats_events.insert(name.to_owned(), SenderRc::new());
}
self.enabled_systems.insert(stat.name().to_owned(), Property::new(true));
}
}
priority
}
#[cfg(feature="stats_events")]
pub fn stats(&mut self) -> impl Iterator<Item = (&str, Property<'static, time::Duration>)>{
self.stats_events.iter_mut()
.map(|(name, sender)| (name.as_str(), sender.stream().to_property(time::Duration::new(0, 0))))
}
#[cfg(all(feature="stats_events", feature="glin"))]
pub fn gpu_stats<C: glin::CreationContext>(&mut self, gl: &C) -> impl Iterator<Item = (&str, Property<'static, time::Duration>)>{
for stat in self.gpu_stats_events.keys(){
if !self.gpu_stats_counters.contains_key(stat){
self.gpu_stats_counters.insert(stat.clone(), gl.new_duration_query());
}
}
self.gpu_stats_events.iter_mut()
.map(|(name, sender)| (name.as_str(), sender.stream().to_property(time::Duration::new(0, 0))))
}
#[cfg(feature="stats_events")]
pub fn enabled_systems(&mut self) -> impl Iterator<Item = (&str, Property<'static, bool>)>{
self.enabled_systems.iter()
.map(|(name, enabled)| (name.as_str(), enabled.clone()))
}
#[cfg(feature="debug_concurrency")]
pub fn send_system_name(&self, i: usize) -> Option<&String>{
self.systems[i].0.as_ref()
}
#[cfg(feature="debug_concurrency")]
pub fn thread_local_system_name(&self, i: usize) -> Option<&String>{
self.systems_thread_local[i].0.as_ref()
}
#[cfg(feature="debug_concurrency")]
pub fn creation_system_name(&self, i: usize) -> Option<&String>{
self.systems_creation[i].0.as_ref()
}
#[cfg(any(feature="debug_parameters", feature="debug_concurrency"))]
pub fn debug_system_name(&self, i: usize) -> Option<&String>{
self.systems_debug[i].0.as_ref()
}
#[cfg(feature="stats_events")]
pub fn send_stats(&self){
for stat in self.stats.iter() {
if let Some(sender) = self.stats_events.get(&stat.0){
sender.send(stat.1)
}
}
for stat in self.gpu_stats.iter() {
if let Some(sender) = self.gpu_stats_events.get(&stat.0){
sender.send(stat.1)
}
}
}
}
pub struct SyncSystem(UnsafeCell<Box<for<'a> ::system::System<'a>>>);
impl SyncSystem{
fn new<S: for<'a> ::system::System<'a> + 'static>(s: S) -> SyncSystem{
SyncSystem(UnsafeCell::new(Box::new(s)))
}
unsafe fn borrow_mut(&self) -> &mut for<'a> ::system::System<'a>{
&mut **self.0.get()
}
fn _borrow(&self) -> &for<'a> ::system::System<'a>{
unsafe{ &**self.0.get() }
}
}
unsafe impl Send for SyncSystem{}
unsafe impl Sync for SyncSystem{}
#[derive(Clone, Copy, Debug)]
pub enum Priority{
Send(usize),
ThreadLocal(usize),
Creation(usize),
#[cfg(feature="debug_parameters")]
Debug(usize),
Barrier
}
#[derive(Copy,Clone,Debug)]
pub enum StatsType<'a>{
Cpu(&'a str),
Gpu(&'a str),
}
impl<'a> StatsType<'a>{
fn name(&self) -> &str{
match self{
StatsType::Cpu(name) | StatsType::Gpu(name) => name,
}
}
}
pub trait AnySystem<TraitObject>{
fn collection(systems: &mut Systems) -> &mut Vec<(Option<String>, TraitObject)>;
fn priority(p: usize) -> Priority;
fn into_trait_object(self) -> TraitObject;
}
impl<S: for<'a> System<'a> + 'static> AnySystem<SyncSystem> for S{
fn collection(systems: &mut Systems) -> &mut Vec<(Option<String>, SyncSystem)>{
&mut systems.systems
}
fn priority(p: usize) -> Priority{
Priority::Send(p)
}
fn into_trait_object(self) -> SyncSystem{
SyncSystem::new(self)
}
}
impl<S: for<'a> SystemThreadLocal<'a> + 'static> AnySystem<Box<for<'a> SystemThreadLocal<'a>>> for S{
fn collection(systems: &mut Systems) -> &mut Vec<(Option<String>, Box<for<'a> SystemThreadLocal<'a>>)>{
&mut systems.systems_thread_local
}
fn priority(p: usize) -> Priority{
Priority::ThreadLocal(p)
}
fn into_trait_object(self) -> Box<for<'a> SystemThreadLocal<'a>>{
Box::new(self)
}
}
impl<S: for<'a> CreationSystem<'a> + 'static> AnySystem<Box<for<'a> CreationSystem<'a>>> for S{
fn collection(systems: &mut Systems) -> &mut Vec<(Option<String>, Box<for<'a> CreationSystem<'a>>)>{
&mut systems.systems_creation
}
fn priority(p: usize) -> Priority{
Priority::Creation(p)
}
fn into_trait_object(self) -> Box<for<'a> CreationSystem<'a>>{
Box::new(self)
}
}
#[cfg(feature = "debug_parameters")]
impl<S: for<'a> SystemDebug<'a> + 'static> AnySystem<Box<for<'a> SystemDebug<'a>>> for S{
fn collection(systems: &mut Systems) -> &mut Vec<(Option<String>, Box<for<'a> SystemDebug<'a>>)>{
&mut systems.systems_debug
}
fn priority(p: usize) -> Priority{
Priority::Debug(p)
}
fn into_trait_object(self) -> Box<for<'a> SystemDebug<'a>>{
Box::new(self)
}
}