Bergmann89 преди 5 години
ревизия
b476810753
променени са 9 файла, в които са добавени 1183 реда и са изтрити 0 реда
  1. +2
    -0
      .gitignore
  2. +12
    -0
      Cargo.toml
  3. +4
    -0
      src/lib.rs
  4. +152
    -0
      src/main.rs
  5. +490
    -0
      src/resources/cell.rs
  6. +246
    -0
      src/resources/mod.rs
  7. +105
    -0
      src/system/accessor.rs
  8. +32
    -0
      src/system/mod.rs
  9. +140
    -0
      src/system/system_data.rs

+ 2
- 0
.gitignore Целия файл

@@ -0,0 +1,2 @@
/target
Cargo.lock

+ 12
- 0
Cargo.toml Целия файл

@@ -0,0 +1,12 @@
[package]
name = "async-ecs"
version = "0.1.0"
authors = ["Bergmann89 <info@bergmann89.de>"]
edition = "2018"

[dependencies]
env_logger = "0.8"
log = "0.4"
mopa = "0.2"
rand = "0.7"
thiserror = "1.0"

+ 4
- 0
src/lib.rs Целия файл

@@ -0,0 +1,4 @@
pub mod resources;
pub mod system;

pub use resources::Resources;

+ 152
- 0
src/main.rs Целия файл

@@ -0,0 +1,152 @@
use log::info;

/*
use std::time::{Duration, Instant};

use async_ecs::Resources;
use rand::random;
*/

fn main() {
env_logger::builder()
.filter_level(log::LevelFilter::Info)
.format_timestamp_nanos()
.init();

info!("Application started!");

/*
let mut resources = Resources::new();
resources.register::<Position>();
resources.register::<Velocity>();
resources.register::<Acceleration>();

for _ in 0..ENTITY_COUNT {
resources
.create_entity()
.with(Velocity::random())
.with(Position::random())
.with(Acceleration::random())
.build();
}

info!("World initialized!");

let mut dispatcher = DispatcherBuilder::new()
.with(Move, "move", &[])
.with(Accelerate, "accelerate", &["move"])
.build();
dispatcher.setup(&mut world);

info!("Setup done!");

let mut delta = Duration::from_secs(0);
for _ in 0..REPEAT_COUNT {
info!("Start iteration");

let start = Instant::now();

dispatcher.dispatch(&world);

let end = Instant::now();

info!("End iteration");

delta += end - start;
}

let delta = delta / REPEAT_COUNT;

info!("Average time per dispatch: {:?}", delta);
*/
}

/*
const ENTITY_COUNT: usize = 3_000_000;
const REPEAT_COUNT: u32 = 100;

#[derive(Debug, Component)]
#[storage(VecStorage)]
struct Position {
x: f64,
y: f64,
}

#[derive(Debug, Component)]
#[storage(VecStorage)]
struct Velocity {
x: f64,
y: f64,
}

#[derive(Debug, Component)]
#[storage(VecStorage)]
struct Acceleration {
x: f64,
y: f64,
}

struct Move;
struct Accelerate;

impl Position {
fn random() -> Self {
Self {
x: random::<f64>() - 0.5,
y: random::<f64>() - 0.5,
}
}
}

impl Velocity {
fn random() -> Self {
Self {
x: random::<f64>() - 0.5,
y: random::<f64>() - 0.5,
}
}
}

impl Acceleration {
fn random() -> Self {
Self {
x: random::<f64>() - 0.5,
y: random::<f64>() - 0.5,
}
}
}

impl<'a> System<'a> for Move {
type SystemData = (WriteStorage<'a, Position>, ReadStorage<'a, Velocity>);

fn run(&mut self, (mut position, velocity): Self::SystemData) {
/*
use specs::{prelude::ParallelIterator, ParJoin};

(&mut position, &velocity)
.par_join()
.for_each(|(position, velocity)| {
position.x += velocity.x;
position.y += velocity.y;
});
*/
}
}

impl<'a> System<'a> for Accelerate {
type SystemData = (WriteStorage<'a, Velocity>, ReadStorage<'a, Acceleration>);

fn run(&mut self, (mut velocity, acceleration): Self::SystemData) {
/*
use specs::{prelude::ParallelIterator, ParJoin};

(&mut velocity, &acceleration)
.par_join()
.for_each(|(velocity, acceleration)| {
velocity.x += acceleration.x;
velocity.y += acceleration.y;
});
*/
}
}
*/

+ 490
- 0
src/resources/cell.rs Целия файл

@@ -0,0 +1,490 @@
use std::cell::UnsafeCell;
use std::mem::forget;
use std::ops::{Deref, DerefMut};
use std::sync::atomic::{AtomicUsize, Ordering};

#[derive(Debug)]
pub struct TrustCell<T> {
flag: AtomicUsize,
inner: UnsafeCell<T>,
}

#[derive(Debug)]
pub struct Ref<'a, T>
where
T: ?Sized + 'a,
{
flag: &'a AtomicUsize,
value: &'a T,
}

#[derive(Debug)]
pub struct RefMut<'a, T>
where
T: ?Sized + 'a,
{
flag: &'a AtomicUsize,
value: &'a mut T,
}

macro_rules! borrow_panic {
($s:expr) => {{
panic!(
"Tried to fetch data of type {:?}, but it was already borrowed{}.",
::std::any::type_name::<T>(),
$s,
)
}};
}

/* TrustCell */

impl<T> TrustCell<T> {
pub fn new(inner: T) -> Self {
TrustCell {
flag: AtomicUsize::new(0),
inner: UnsafeCell::new(inner),
}
}

pub fn into_inner(self) -> T {
self.inner.into_inner()
}

pub fn borrow(&self) -> Ref<T> {
if !self.check_flag_read() {
borrow_panic!(" mutably");
}

Ref {
flag: &self.flag,
value: unsafe { &*self.inner.get() },
}
}

pub fn try_borrow(&self) -> Option<Ref<T>> {
if self.check_flag_read() {
Some(Ref {
flag: &self.flag,
value: unsafe { &*self.inner.get() },
})
} else {
None
}
}

pub fn borrow_mut(&self) -> RefMut<T> {
if !self.check_flag_write() {
borrow_panic!("");
}

RefMut {
flag: &self.flag,
value: unsafe { &mut *self.inner.get() },
}
}

pub fn try_borrow_mut(&self) -> Option<RefMut<T>> {
if self.check_flag_write() {
Some(RefMut {
flag: &self.flag,
value: unsafe { &mut *self.inner.get() },
})
} else {
None
}
}

pub fn get_mut(&mut self) -> &mut T {
unsafe { &mut *self.inner.get() }
}

fn check_flag_read(&self) -> bool {
loop {
let val = self.flag.load(Ordering::Acquire);

if val == usize::MAX {
return false;
}

if self.flag.compare_and_swap(val, val + 1, Ordering::AcqRel) == val {
return true;
}
}
}

fn check_flag_write(&self) -> bool {
match self.flag.compare_and_swap(0, usize::MAX, Ordering::AcqRel) {
0 => true,
_ => false,
}
}
}

/* Ref */

impl<'a, T> Ref<'a, T>
where
T: ?Sized,
{
pub fn map<U, F>(self, f: F) -> Ref<'a, U>
where
F: FnOnce(&T) -> &U,
U: ?Sized,
{
let flag = unsafe { &*(self.flag as *const _) };
let value = unsafe { &*(self.value as *const _) };

forget(self);

Ref {
flag,
value: f(value),
}
}
}

impl<'a, T> Deref for Ref<'a, T>
where
T: ?Sized,
{
type Target = T;

fn deref(&self) -> &T {
self.value
}
}

impl<'a, T> Drop for Ref<'a, T>
where
T: ?Sized,
{
fn drop(&mut self) {
self.flag.fetch_sub(1, Ordering::Release);
}
}

impl<'a, T> Clone for Ref<'a, T>
where
T: ?Sized,
{
fn clone(&self) -> Self {
self.flag.fetch_add(1, Ordering::Release);

Ref {
flag: self.flag,
value: self.value,
}
}
}

/* RefMut */

impl<'a, T> RefMut<'a, T>
where
T: ?Sized,
{
pub fn map<U, F>(self, f: F) -> RefMut<'a, U>
where
F: FnOnce(&mut T) -> &mut U,
U: ?Sized,
{
let flag = unsafe { &*(self.flag as *const _) };
let value = unsafe { &mut *(self.value as *mut _) };

forget(self);

RefMut {
flag,
value: f(value),
}
}
}

impl<'a, T> Deref for RefMut<'a, T>
where
T: ?Sized,
{
type Target = T;

fn deref(&self) -> &T {
self.value
}
}

impl<'a, T> DerefMut for RefMut<'a, T>
where
T: ?Sized,
{
fn deref_mut(&mut self) -> &mut T {
self.value
}
}

impl<'a, T> Drop for RefMut<'a, T>
where
T: ?Sized,
{
fn drop(&mut self) {
self.flag.store(0, Ordering::Release)
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn allow_multiple_reads() {
let cell = TrustCell::new(5);

let a = cell.borrow();
let b = cell.borrow();

assert_eq!(10, *a + *b);
}

#[test]
fn allow_clone_reads() {
let cell = TrustCell::new(5);

let a = cell.borrow();
let b = a.clone();

assert_eq!(10, *a + *b);
}

#[test]
fn allow_single_write() {
let cell = TrustCell::new(5);

{
let mut a = cell.borrow_mut();
*a += 2;
*a += 3;
}

assert_eq!(10, *cell.borrow());
}

#[test]
#[should_panic(expected = "but it was already borrowed mutably")]
fn panic_write_and_read() {
let cell = TrustCell::new(5);

let mut a = cell.borrow_mut();
*a = 7;

assert_eq!(7, *cell.borrow());
}

#[test]
#[should_panic(expected = "but it was already borrowed")]
fn panic_write_and_write() {
let cell = TrustCell::new(5);

let mut a = cell.borrow_mut();
*a = 7;

assert_eq!(7, *cell.borrow_mut());
}

#[test]
#[should_panic(expected = "but it was already borrowed")]
fn panic_read_and_write() {
let cell = TrustCell::new(5);

let _a = cell.borrow();

assert_eq!(7, *cell.borrow_mut());
}

#[test]
fn try_write_and_read() {
let cell = TrustCell::new(5);

let mut a = cell.try_borrow_mut().unwrap();
*a = 7;

assert!(cell.try_borrow().is_none());

*a = 8;
}

#[test]
fn try_write_and_write() {
let cell = TrustCell::new(5);

let mut a = cell.try_borrow_mut().unwrap();
*a = 7;

assert!(cell.try_borrow_mut().is_none());

*a = 8;
}

#[test]
fn try_read_and_write() {
let cell = TrustCell::new(5);

let _a = cell.try_borrow().unwrap();

assert!(cell.try_borrow_mut().is_none());
}

#[test]
fn cloned_borrow_does_not_allow_write() {
let cell = TrustCell::new(5);

let a = cell.borrow();
let b = a.clone();

drop(a);

assert!(cell.try_borrow_mut().is_none());
assert_eq!(5, *b);
}

#[test]
fn ref_with_non_sized() {
let r: Ref<'_, [i32]> = Ref {
flag: &AtomicUsize::new(1),
value: &[2, 3, 4, 5][..],
};

assert_eq!(&*r, &[2, 3, 4, 5][..]);
}

#[test]
fn ref_with_non_sized_clone() {
let r: Ref<'_, [i32]> = Ref {
flag: &AtomicUsize::new(1),
value: &[2, 3, 4, 5][..],
};
let rr = r.clone();

assert_eq!(&*r, &[2, 3, 4, 5][..]);
assert_eq!(r.flag.load(Ordering::SeqCst), 2);

assert_eq!(&*rr, &[2, 3, 4, 5][..]);
assert_eq!(rr.flag.load(Ordering::SeqCst), 2);
}

#[test]
fn ref_with_trait_obj() {
let ra: Ref<'_, dyn std::any::Any> = Ref {
flag: &AtomicUsize::new(1),
value: &2i32,
};

assert_eq!(ra.downcast_ref::<i32>().unwrap(), &2i32);
}

#[test]
fn ref_mut_with_non_sized() {
let mut r: RefMut<'_, [i32]> = RefMut {
flag: &AtomicUsize::new(1),
value: &mut [2, 3, 4, 5][..],
};

assert_eq!(&mut *r, &mut [2, 3, 4, 5][..]);
}

#[test]
fn ref_mut_with_trait_obj() {
let mut ra: RefMut<'_, dyn std::any::Any> = RefMut {
flag: &AtomicUsize::new(1),
value: &mut 2i32,
};

assert_eq!(ra.downcast_mut::<i32>().unwrap(), &mut 2i32);
}

#[test]
fn ref_map_box() {
let cell = TrustCell::new(Box::new(10));

let r: Ref<'_, Box<usize>> = cell.borrow();
assert_eq!(&**r, &10);

let rr: Ref<'_, usize> = cell.borrow().map(Box::as_ref);
assert_eq!(&*rr, &10);
}

#[test]
fn ref_map_preserves_flag() {
let cell = TrustCell::new(Box::new(10));

let r: Ref<'_, Box<usize>> = cell.borrow();
assert_eq!(cell.flag.load(Ordering::SeqCst), 1);
let _nr: Ref<'_, usize> = r.map(Box::as_ref);
assert_eq!(cell.flag.load(Ordering::SeqCst), 1);
}

#[test]
fn ref_map_retains_borrow() {
let cell = TrustCell::new(Box::new(10));

let _r: Ref<'_, usize> = cell.borrow().map(Box::as_ref);
assert_eq!(cell.flag.load(Ordering::SeqCst), 1);

let _rr: Ref<'_, usize> = cell.borrow().map(Box::as_ref);
assert_eq!(cell.flag.load(Ordering::SeqCst), 2);
}

#[test]
fn ref_map_drops_borrow() {
let cell = TrustCell::new(Box::new(10));

let r: Ref<'_, usize> = cell.borrow().map(Box::as_ref);

assert_eq!(cell.flag.load(Ordering::SeqCst), 1);
drop(r);
assert_eq!(cell.flag.load(Ordering::SeqCst), 0);
}

#[test]
fn ref_mut_map_box() {
let cell = TrustCell::new(Box::new(10));

{
let mut r: RefMut<'_, Box<usize>> = cell.borrow_mut();
assert_eq!(&mut **r, &mut 10);
}
{
let mut rr: RefMut<'_, usize> = cell.borrow_mut().map(Box::as_mut);
assert_eq!(&mut *rr, &mut 10);
}
}

#[test]
fn ref_mut_map_preserves_flag() {
let cell = TrustCell::new(Box::new(10));

let r: RefMut<'_, Box<usize>> = cell.borrow_mut();
assert_eq!(cell.flag.load(Ordering::SeqCst), std::usize::MAX);
let _nr: RefMut<'_, usize> = r.map(Box::as_mut);
assert_eq!(cell.flag.load(Ordering::SeqCst), std::usize::MAX);
}

#[test]
#[should_panic(expected = "but it was already borrowed")]
fn ref_mut_map_retains_mut_borrow() {
let cell = TrustCell::new(Box::new(10));

let _rr: RefMut<'_, usize> = cell.borrow_mut().map(Box::as_mut);

let _ = cell.borrow_mut();
}

#[test]
fn ref_mut_map_drops_borrow() {
let cell = TrustCell::new(Box::new(10));

let r: RefMut<'_, usize> = cell.borrow_mut().map(Box::as_mut);

assert_eq!(cell.flag.load(Ordering::SeqCst), std::usize::MAX);
drop(r);
assert_eq!(cell.flag.load(Ordering::SeqCst), 0);
}
}

+ 246
- 0
src/resources/mod.rs Целия файл

@@ -0,0 +1,246 @@
pub mod cell;

use std::any::TypeId;
use std::collections::HashMap;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};

use mopa::Any;

use cell::{Ref as CellRef, RefMut as CellRefMut, TrustCell};

#[derive(Default)]
pub struct Resources {
resources: HashMap<ResourceId, TrustCell<Box<dyn Resource>>>,
}

#[derive(Debug, Hash, Eq, PartialEq)]
pub struct ResourceId(TypeId);

pub trait Resource: Any + Send + Sync + 'static {}

pub struct Ref<'a, R: 'a> {
inner: CellRef<'a, dyn Resource>,
phantom: PhantomData<&'a R>,
}

pub struct RefMut<'a, R: 'a> {
inner: CellRefMut<'a, dyn Resource>,
phantom: PhantomData<&'a R>,
}

macro_rules! fetch_panic {
() => {{
panic!(
"\
Tried to fetch resource from the resources map, but the resource does not exist.\n\
\n\
Resource: `{resource_name_full}`\n\
\n\
You may ensure the resource exists!\
",
resource_name_full = std::any::type_name::<R>(),
)
}};
}

/* Resources */

impl Resources {
pub fn insert<R>(&mut self, r: R)
where
R: Resource,
{
self.resources
.insert(ResourceId::new::<R>(), TrustCell::new(Box::new(r)));
}

pub fn remove<R>(&mut self) -> Option<R>
where
R: Resource,
{
self.resources
.remove(&ResourceId::new::<R>())
.map(TrustCell::into_inner)
.map(|x: Box<dyn Resource>| x.downcast())
.map(|x: Result<Box<R>, _>| x.ok().unwrap())
.map(|x| *x)
}

pub fn contains<R>(&self) -> bool
where
R: Resource,
{
self.resources.contains_key(&ResourceId::new::<R>())
}

pub fn borrow<R>(&self) -> Ref<R>
where
R: Resource,
{
self.try_borrow().unwrap_or_else(|| fetch_panic!())
}

pub fn try_borrow<R>(&self) -> Option<Ref<R>>
where
R: Resource,
{
self.resources.get(&ResourceId::new::<R>()).map(|r| Ref {
inner: CellRef::map(r.borrow(), Box::as_ref),
phantom: PhantomData,
})
}

pub fn borrow_mut<R>(&self) -> RefMut<R>
where
R: Resource,
{
self.try_borrow_mut().unwrap_or_else(|| fetch_panic!())
}

pub fn try_borrow_mut<R>(&self) -> Option<RefMut<R>>
where
R: Resource,
{
self.resources.get(&ResourceId::new::<R>()).map(|r| RefMut {
inner: CellRefMut::map(r.borrow_mut(), Box::as_mut),
phantom: PhantomData,
})
}

pub fn get_mut<R: Resource>(&mut self) -> Option<&mut R> {
self.get_resource_mut(ResourceId::new::<R>())
.map(|res| res.downcast_mut().unwrap())
}

pub fn get_resource_mut(&mut self, id: ResourceId) -> Option<&mut dyn Resource> {
self.resources
.get_mut(&id)
.map(TrustCell::get_mut)
.map(Box::as_mut)
}
}

/* ResourceId */

impl ResourceId {
pub fn new<R>() -> Self
where
R: Resource,
{
Self(TypeId::of::<R>())
}
}

/* Resource */

impl<T> Resource for T where T: Any + Send + Sync {}

mod __resource_mopafy_scope {
#![allow(clippy::all)]

use mopa::mopafy;

use super::Resource;

mopafy!(Resource);
}

/* Ref */

impl<'a, R> Deref for Ref<'a, R>
where
R: Resource,
{
type Target = R;

fn deref(&self) -> &R {
unsafe { self.inner.downcast_ref_unchecked() }
}
}

impl<'a, R> Clone for Ref<'a, R> {
fn clone(&self) -> Self {
Ref {
inner: self.inner.clone(),
phantom: PhantomData,
}
}
}

/* RefMut */

impl<'a, R> Deref for RefMut<'a, R>
where
R: Resource,
{
type Target = R;

fn deref(&self) -> &R {
unsafe { self.inner.downcast_ref_unchecked() }
}
}

impl<'a, R> DerefMut for RefMut<'a, R>
where
R: Resource,
{
fn deref_mut(&mut self) -> &mut R {
unsafe { self.inner.downcast_mut_unchecked() }
}
}

#[cfg(test)]
mod tests {
use super::*;

#[derive(Default)]
struct Res;

#[test]
fn insert() {
struct Foo;

let mut resources = Resources::default();
resources.insert(Res);

assert!(resources.contains::<Res>());
assert!(!resources.contains::<Foo>());
}

#[test]
#[should_panic(expected = "but it was already borrowed")]
fn read_write_fails() {
let mut resources = Resources::default();
resources.insert(Res);

let _read = resources.borrow::<Res>();
let _write = resources.borrow_mut::<Res>();
}

#[test]
#[should_panic(expected = "but it was already borrowed mutably")]
fn write_read_fails() {
let mut resources = Resources::default();
resources.insert(Res);

let _write = resources.borrow_mut::<Res>();
let _read = resources.borrow::<Res>();
}

#[test]
fn remove_insert() {
let mut resources = Resources::default();
resources.insert(Res);

assert!(resources.contains::<Res>());

resources.remove::<Res>().unwrap();

assert!(!resources.contains::<Res>());

resources.insert(Res);

assert!(resources.contains::<Res>());
}
}

+ 105
- 0
src/system/accessor.rs Целия файл

@@ -0,0 +1,105 @@
use std::marker::PhantomData;
use std::ops::Deref;

use crate::resources::ResourceId;

use super::{DynamicSystemData, System, SystemData};

pub trait Accessor: Sized {
fn try_new() -> Option<Self>;

fn reads(&self) -> Vec<ResourceId>;

fn writes(&self) -> Vec<ResourceId>;
}

pub enum AccessorCow<'a, 'b, T>
where
AccessorType<'a, T>: 'b,
T: System<'a> + ?Sized,
'a: 'b,
{
/// A reference to an accessor.
Ref(&'b AccessorType<'a, T>),
/// An owned accessor.
Owned(AccessorType<'a, T>),
}

#[derive(Default)]
pub struct StaticAccessor<T> {
marker: PhantomData<fn() -> T>,
}

pub type AccessorType<'a, T> = <<T as System<'a>>::SystemData as DynamicSystemData<'a>>::Accessor;

/* Accessor */

impl Accessor for () {
fn try_new() -> Option<Self> {
None
}

fn reads(&self) -> Vec<ResourceId> {
Vec::new()
}

fn writes(&self) -> Vec<ResourceId> {
Vec::new()
}
}

impl<T> Accessor for PhantomData<T>
where
T: ?Sized,
{
fn try_new() -> Option<Self> {
None
}

fn reads(&self) -> Vec<ResourceId> {
Vec::new()
}

fn writes(&self) -> Vec<ResourceId> {
Vec::new()
}
}

/* AccessorCow */

impl<'a, 'b, T> Deref for AccessorCow<'a, 'b, T>
where
AccessorType<'a, T>: 'b,
T: System<'a> + ?Sized + 'b,
'a: 'b,
{
type Target = AccessorType<'a, T>;

fn deref(&self) -> &AccessorType<'a, T> {
match *self {
AccessorCow::Ref(r) => &*r,
AccessorCow::Owned(ref o) => o,
}
}
}

/* StaticAccessor */

impl<'a, T> Accessor for StaticAccessor<T>
where
T: SystemData<'a>,
{
fn try_new() -> Option<Self> {
Some(StaticAccessor {
marker: PhantomData,
})
}

fn reads(&self) -> Vec<ResourceId> {
T::reads()
}

fn writes(&self) -> Vec<ResourceId> {
T::writes()
}
}

+ 32
- 0
src/system/mod.rs Целия файл

@@ -0,0 +1,32 @@
mod accessor;
mod system_data;

pub use accessor::{Accessor, AccessorCow};
pub use system_data::{DynamicSystemData, SystemData};

use crate::resources::Resources;

use accessor::AccessorType;

pub trait System<'a> {
type SystemData: DynamicSystemData<'a>;

fn run(&mut self, data: Self::SystemData);

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, resources: &mut Resources) {
<Self::SystemData as DynamicSystemData>::setup(&self.accessor(), resources)
}

fn dispose(self, resources: &mut Resources)
where
Self: Sized,
{
let _ = resources;
}
}

+ 140
- 0
src/system/system_data.rs Целия файл

@@ -0,0 +1,140 @@
use std::marker::PhantomData;

use crate::resources::{ResourceId, Resources};

use super::accessor::{Accessor, StaticAccessor};

pub trait SystemData<'a> {
fn setup(world: &mut Resources);

fn fetch(world: &'a Resources) -> Self;

fn reads() -> Vec<ResourceId>;

fn writes() -> Vec<ResourceId>;
}

pub trait DynamicSystemData<'a> {
type Accessor: Accessor;

fn setup(accessor: &Self::Accessor, resources: &mut Resources);

fn fetch(access: &Self::Accessor, resources: &'a Resources) -> Self;
}

/* SystemData */

impl<'a, T> SystemData<'a> for PhantomData<T>
where
T: ?Sized,
{
fn setup(_: &mut Resources) {}

fn fetch(_: &Resources) -> Self {
PhantomData
}

fn reads() -> Vec<ResourceId> {
vec![]
}

fn writes() -> Vec<ResourceId> {
vec![]
}
}

/* DynamicSystemData */

impl<'a, T> DynamicSystemData<'a> for T
where
T: SystemData<'a>,
{
type Accessor = StaticAccessor<T>;

fn setup(_: &StaticAccessor<T>, resources: &mut Resources) {
T::setup(resources);
}

fn fetch(_: &StaticAccessor<T>, resources: &'a Resources) -> Self {
T::fetch(resources)
}
}

mod impl_system_data {
use super::*;

macro_rules! impl_system_data {
( $($ty:ident),* ) => {
impl<'a, $($ty),*> SystemData<'a> for ( $( $ty , )* )
where $( $ty : SystemData<'a> ),*
{
fn setup(resources: &mut Resources) {
#![allow(unused_variables)]

$(
<$ty as SystemData>::setup(&mut *resources);
)*
}

fn fetch(resources: &'a Resources) -> Self {
#![allow(unused_variables)]

( $( <$ty as SystemData<'a>>::fetch(resources), )* )
}

fn reads() -> Vec<ResourceId> {
#![allow(unused_mut)]

let mut r = Vec::new();

$( {
let mut reads = <$ty as SystemData>::reads();
r.append(&mut reads);
} )*

r
}

fn writes() -> Vec<ResourceId> {
#![allow(unused_mut)]

let mut r = Vec::new();

$( {
let mut writes = <$ty as SystemData>::writes();
r.append(&mut writes);
} )*

r
}
}
};
}

impl_system_data!(A);
impl_system_data!(A, B);
impl_system_data!(A, B, C);
impl_system_data!(A, B, C, D);
impl_system_data!(A, B, C, D, E);
impl_system_data!(A, B, C, D, E, F);
impl_system_data!(A, B, C, D, E, F, G);
impl_system_data!(A, B, C, D, E, F, G, H);
impl_system_data!(A, B, C, D, E, F, G, H, I);
impl_system_data!(A, B, C, D, E, F, G, H, I, J);
impl_system_data!(A, B, C, D, E, F, G, H, I, J, K);
impl_system_data!(A, B, C, D, E, F, G, H, I, J, K, L);
impl_system_data!(A, B, C, D, E, F, G, H, I, J, K, L, M);
impl_system_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
impl_system_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
impl_system_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
impl_system_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q);
impl_system_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R);
impl_system_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S);
impl_system_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T);
impl_system_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U);
impl_system_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V);
impl_system_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W);
impl_system_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X);
impl_system_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y);
impl_system_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z);
}

Зареждане…
Отказ
Запис