@@ -0,0 +1,42 @@ | |||
use proc_macro2::TokenStream; | |||
use syn::{ | |||
parse::{Parse, ParseStream, Result}, | |||
DeriveInput, Path, | |||
}; | |||
pub fn execute(ast: &DeriveInput) -> TokenStream { | |||
let name = &ast.ident; | |||
let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl(); | |||
let storage = ast | |||
.attrs | |||
.iter() | |||
.find(|attr| attr.path.segments[0].ident == "storage") | |||
.map(|attr| { | |||
syn::parse2::<StorageAttribute>(attr.tokens.clone()) | |||
.unwrap() | |||
.storage | |||
}) | |||
.unwrap_or_else(|| parse_quote!(DenseVecStorage)); | |||
quote! { | |||
impl #impl_generics async_ecs::component::Component for #name #ty_generics #where_clause { | |||
type Storage = #storage<Self>; | |||
} | |||
} | |||
} | |||
struct StorageAttribute { | |||
storage: Path, | |||
} | |||
impl Parse for StorageAttribute { | |||
fn parse(input: ParseStream) -> Result<Self> { | |||
let content; | |||
let _parenthesized_token = parenthesized!(content in input); | |||
Ok(StorageAttribute { | |||
storage: content.parse()?, | |||
}) | |||
} | |||
} |
@@ -7,6 +7,7 @@ extern crate quote; | |||
#[macro_use] | |||
extern crate syn; | |||
mod component; | |||
mod system_data; | |||
use proc_macro::TokenStream; | |||
@@ -19,3 +20,12 @@ pub fn system_data(input: TokenStream) -> TokenStream { | |||
gen.into() | |||
} | |||
#[proc_macro_derive(Component, attributes(storage))] | |||
pub fn component(input: TokenStream) -> TokenStream { | |||
let ast = syn::parse(input).unwrap(); | |||
let gen = component::execute(&ast); | |||
gen.into() | |||
} |
@@ -73,7 +73,8 @@ fn gen_identifiers(fields: &Punctuated<Field, Comma>) -> Vec<Ident> { | |||
fn constrain_system_data_types(clause: &mut WhereClause, fetch_lt: &Lifetime, tys: &[Type]) { | |||
for ty in tys.iter() { | |||
let where_predicate: WherePredicate = parse_quote!(#ty : async_ecs::system::SystemData< #fetch_lt >); | |||
let where_predicate: WherePredicate = | |||
parse_quote!(#ty : async_ecs::system::SystemData< #fetch_lt >); | |||
clause.predicates.push(where_predicate); | |||
} | |||
} | |||
@@ -7,6 +7,8 @@ edition = "2018" | |||
[dependencies] | |||
async-ecs-derive = "0.1" | |||
env_logger = "0.8" | |||
hashbrown = "0.9" | |||
hibitset = "0.6" | |||
log = "0.4" | |||
mopa = "0.2" | |||
rand = "0.7" | |||
@@ -0,0 +1,7 @@ | |||
use std::any::Any; | |||
use crate::storage::Storage; | |||
pub trait Component: Any + Sized { | |||
type Storage: Storage<Self> + Any + Send + Sync; | |||
} |
@@ -0,0 +1,2 @@ | |||
#[derive(Default)] | |||
pub struct Entities; |
@@ -1,4 +1,10 @@ | |||
pub mod resources; | |||
pub mod component; | |||
pub mod entity; | |||
pub mod resource; | |||
pub mod storage; | |||
pub mod system; | |||
pub mod world; | |||
pub use resources::Resources; | |||
pub use resource::Resources; | |||
pub use storage::VecStorage; | |||
pub use world::World; |
@@ -1,10 +1,14 @@ | |||
use log::info; | |||
use async_ecs::{VecStorage, World}; | |||
use async_ecs_derive::Component; | |||
use rand::random; | |||
/* | |||
use std::time::{Duration, Instant}; | |||
use async_ecs::Resources; | |||
use rand::random; | |||
*/ | |||
fn main() { | |||
@@ -15,12 +19,12 @@ fn main() { | |||
info!("Application started!"); | |||
/* | |||
let mut resources = Resources::new(); | |||
resources.register::<Position>(); | |||
resources.register::<Velocity>(); | |||
resources.register::<Acceleration>(); | |||
let mut world = World::default(); | |||
world.register::<Position>(); | |||
world.register::<Velocity>(); | |||
world.register::<Acceleration>(); | |||
/* | |||
for _ in 0..ENTITY_COUNT { | |||
resources | |||
.create_entity() | |||
@@ -61,7 +65,6 @@ fn main() { | |||
*/ | |||
} | |||
/* | |||
const ENTITY_COUNT: usize = 3_000_000; | |||
const REPEAT_COUNT: u32 = 100; | |||
@@ -115,7 +118,7 @@ impl Acceleration { | |||
} | |||
} | |||
} | |||
/* | |||
impl<'a> System<'a> for Move { | |||
type SystemData = (WriteStorage<'a, Position>, ReadStorage<'a, Velocity>); | |||
@@ -4,7 +4,7 @@ use std::ops::{Deref, DerefMut}; | |||
use std::sync::atomic::{AtomicUsize, Ordering}; | |||
#[derive(Debug)] | |||
pub struct TrustCell<T> { | |||
pub struct Cell<T> { | |||
flag: AtomicUsize, | |||
inner: UnsafeCell<T>, | |||
} | |||
@@ -37,11 +37,11 @@ macro_rules! borrow_panic { | |||
}}; | |||
} | |||
/* TrustCell */ | |||
/* Cell */ | |||
impl<T> TrustCell<T> { | |||
impl<T> Cell<T> { | |||
pub fn new(inner: T) -> Self { | |||
TrustCell { | |||
Cell { | |||
flag: AtomicUsize::new(0), | |||
inner: UnsafeCell::new(inner), | |||
} | |||
@@ -236,7 +236,7 @@ mod tests { | |||
#[test] | |||
fn allow_multiple_reads() { | |||
let cell = TrustCell::new(5); | |||
let cell = Cell::new(5); | |||
let a = cell.borrow(); | |||
let b = cell.borrow(); | |||
@@ -246,7 +246,7 @@ mod tests { | |||
#[test] | |||
fn allow_clone_reads() { | |||
let cell = TrustCell::new(5); | |||
let cell = Cell::new(5); | |||
let a = cell.borrow(); | |||
let b = a.clone(); | |||
@@ -256,7 +256,7 @@ mod tests { | |||
#[test] | |||
fn allow_single_write() { | |||
let cell = TrustCell::new(5); | |||
let cell = Cell::new(5); | |||
{ | |||
let mut a = cell.borrow_mut(); | |||
@@ -270,7 +270,7 @@ mod tests { | |||
#[test] | |||
#[should_panic(expected = "but it was already borrowed mutably")] | |||
fn panic_write_and_read() { | |||
let cell = TrustCell::new(5); | |||
let cell = Cell::new(5); | |||
let mut a = cell.borrow_mut(); | |||
*a = 7; | |||
@@ -281,7 +281,7 @@ mod tests { | |||
#[test] | |||
#[should_panic(expected = "but it was already borrowed")] | |||
fn panic_write_and_write() { | |||
let cell = TrustCell::new(5); | |||
let cell = Cell::new(5); | |||
let mut a = cell.borrow_mut(); | |||
*a = 7; | |||
@@ -292,7 +292,7 @@ mod tests { | |||
#[test] | |||
#[should_panic(expected = "but it was already borrowed")] | |||
fn panic_read_and_write() { | |||
let cell = TrustCell::new(5); | |||
let cell = Cell::new(5); | |||
let _a = cell.borrow(); | |||
@@ -301,7 +301,7 @@ mod tests { | |||
#[test] | |||
fn try_write_and_read() { | |||
let cell = TrustCell::new(5); | |||
let cell = Cell::new(5); | |||
let mut a = cell.try_borrow_mut().unwrap(); | |||
*a = 7; | |||
@@ -313,7 +313,7 @@ mod tests { | |||
#[test] | |||
fn try_write_and_write() { | |||
let cell = TrustCell::new(5); | |||
let cell = Cell::new(5); | |||
let mut a = cell.try_borrow_mut().unwrap(); | |||
*a = 7; | |||
@@ -325,7 +325,7 @@ mod tests { | |||
#[test] | |||
fn try_read_and_write() { | |||
let cell = TrustCell::new(5); | |||
let cell = Cell::new(5); | |||
let _a = cell.try_borrow().unwrap(); | |||
@@ -334,7 +334,7 @@ mod tests { | |||
#[test] | |||
fn cloned_borrow_does_not_allow_write() { | |||
let cell = TrustCell::new(5); | |||
let cell = Cell::new(5); | |||
let a = cell.borrow(); | |||
let b = a.clone(); | |||
@@ -402,7 +402,7 @@ mod tests { | |||
#[test] | |||
fn ref_map_box() { | |||
let cell = TrustCell::new(Box::new(10)); | |||
let cell = Cell::new(Box::new(10)); | |||
let r: Ref<'_, Box<usize>> = cell.borrow(); | |||
assert_eq!(&**r, &10); | |||
@@ -413,7 +413,7 @@ mod tests { | |||
#[test] | |||
fn ref_map_preserves_flag() { | |||
let cell = TrustCell::new(Box::new(10)); | |||
let cell = Cell::new(Box::new(10)); | |||
let r: Ref<'_, Box<usize>> = cell.borrow(); | |||
assert_eq!(cell.flag.load(Ordering::SeqCst), 1); | |||
@@ -423,7 +423,7 @@ mod tests { | |||
#[test] | |||
fn ref_map_retains_borrow() { | |||
let cell = TrustCell::new(Box::new(10)); | |||
let cell = Cell::new(Box::new(10)); | |||
let _r: Ref<'_, usize> = cell.borrow().map(Box::as_ref); | |||
assert_eq!(cell.flag.load(Ordering::SeqCst), 1); | |||
@@ -434,7 +434,7 @@ mod tests { | |||
#[test] | |||
fn ref_map_drops_borrow() { | |||
let cell = TrustCell::new(Box::new(10)); | |||
let cell = Cell::new(Box::new(10)); | |||
let r: Ref<'_, usize> = cell.borrow().map(Box::as_ref); | |||
@@ -445,7 +445,7 @@ mod tests { | |||
#[test] | |||
fn ref_mut_map_box() { | |||
let cell = TrustCell::new(Box::new(10)); | |||
let cell = Cell::new(Box::new(10)); | |||
{ | |||
let mut r: RefMut<'_, Box<usize>> = cell.borrow_mut(); | |||
@@ -459,7 +459,7 @@ mod tests { | |||
#[test] | |||
fn ref_mut_map_preserves_flag() { | |||
let cell = TrustCell::new(Box::new(10)); | |||
let cell = Cell::new(Box::new(10)); | |||
let r: RefMut<'_, Box<usize>> = cell.borrow_mut(); | |||
assert_eq!(cell.flag.load(Ordering::SeqCst), std::usize::MAX); | |||
@@ -470,7 +470,7 @@ mod tests { | |||
#[test] | |||
#[should_panic(expected = "but it was already borrowed")] | |||
fn ref_mut_map_retains_mut_borrow() { | |||
let cell = TrustCell::new(Box::new(10)); | |||
let cell = Cell::new(Box::new(10)); | |||
let _rr: RefMut<'_, usize> = cell.borrow_mut().map(Box::as_mut); | |||
@@ -479,7 +479,7 @@ mod tests { | |||
#[test] | |||
fn ref_mut_map_drops_borrow() { | |||
let cell = TrustCell::new(Box::new(10)); | |||
let cell = Cell::new(Box::new(10)); | |||
let r: RefMut<'_, usize> = cell.borrow_mut().map(Box::as_mut); | |||
@@ -0,0 +1,41 @@ | |||
use std::marker::PhantomData; | |||
use hashbrown::hash_map::{DefaultHashBuilder, Entry as HbEntry}; | |||
use super::{cell::Cell, RefMut, Resource, ResourceId}; | |||
pub struct Entry<'a, T: 'a> { | |||
inner: Inner<'a>, | |||
marker: PhantomData<T>, | |||
} | |||
pub type Inner<'a> = HbEntry<'a, ResourceId, Cell<Box<dyn Resource>>, DefaultHashBuilder>; | |||
impl<'a, T> Entry<'a, T> | |||
where | |||
T: Resource + 'a, | |||
{ | |||
pub fn new(inner: Inner<'a>) -> Self { | |||
Self { | |||
inner, | |||
marker: PhantomData, | |||
} | |||
} | |||
pub fn or_insert(self, v: T) -> RefMut<'a, T> { | |||
self.or_insert_with(move || v) | |||
} | |||
pub fn or_insert_with<F>(self, f: F) -> RefMut<'a, T> | |||
where | |||
F: FnOnce() -> T, | |||
{ | |||
let inner = self.inner.or_insert_with(move || Cell::new(Box::new(f()))); | |||
let inner = inner.borrow_mut().map(Box::as_mut); | |||
RefMut { | |||
inner, | |||
phantom: PhantomData, | |||
} | |||
} | |||
} |
@@ -1,17 +1,19 @@ | |||
pub mod cell; | |||
pub mod entry; | |||
use std::any::TypeId; | |||
use std::collections::HashMap; | |||
use std::marker::PhantomData; | |||
use std::ops::{Deref, DerefMut}; | |||
use hashbrown::HashMap; | |||
use mopa::Any; | |||
use cell::{Ref as CellRef, RefMut as CellRefMut, TrustCell}; | |||
use cell::{Cell, Ref as CellRef, RefMut as CellRefMut}; | |||
use entry::Entry; | |||
#[derive(Default)] | |||
pub struct Resources { | |||
resources: HashMap<ResourceId, TrustCell<Box<dyn Resource>>>, | |||
resources: HashMap<ResourceId, Cell<Box<dyn Resource>>>, | |||
} | |||
#[derive(Debug, Hash, Eq, PartialEq)] | |||
@@ -47,12 +49,19 @@ macro_rules! fetch_panic { | |||
/* Resources */ | |||
impl Resources { | |||
pub fn entry<R>(&mut self) -> Entry<R> | |||
where | |||
R: Resource, | |||
{ | |||
Entry::new(self.resources.entry(ResourceId::new::<R>())) | |||
} | |||
pub fn insert<R>(&mut self, r: R) | |||
where | |||
R: Resource, | |||
{ | |||
self.resources | |||
.insert(ResourceId::new::<R>(), TrustCell::new(Box::new(r))); | |||
.insert(ResourceId::new::<R>(), Cell::new(Box::new(r))); | |||
} | |||
pub fn remove<R>(&mut self) -> Option<R> | |||
@@ -61,7 +70,7 @@ impl Resources { | |||
{ | |||
self.resources | |||
.remove(&ResourceId::new::<R>()) | |||
.map(TrustCell::into_inner) | |||
.map(Cell::into_inner) | |||
.map(|x: Box<dyn Resource>| x.downcast()) | |||
.map(|x: Result<Box<R>, _>| x.ok().unwrap()) | |||
.map(|x| *x) | |||
@@ -103,7 +112,7 @@ impl Resources { | |||
R: Resource, | |||
{ | |||
self.resources.get(&ResourceId::new::<R>()).map(|r| RefMut { | |||
inner: CellRefMut::map(r.borrow_mut(), Box::as_mut), | |||
inner: r.borrow_mut().map(Box::as_mut), | |||
phantom: PhantomData, | |||
}) | |||
} | |||
@@ -116,7 +125,7 @@ impl Resources { | |||
pub fn get_resource_mut(&mut self, id: ResourceId) -> Option<&mut dyn Resource> { | |||
self.resources | |||
.get_mut(&id) | |||
.map(TrustCell::get_mut) | |||
.map(Cell::get_mut) | |||
.map(Box::as_mut) | |||
} | |||
} |
@@ -0,0 +1,17 @@ | |||
use hibitset::BitSet; | |||
use crate::component::Component; | |||
pub struct MaskedStorage<T: Component> { | |||
mask: BitSet, | |||
inner: T::Storage, | |||
} | |||
impl<T: Component> MaskedStorage<T> { | |||
pub fn new(inner: T::Storage) -> Self { | |||
Self { | |||
mask: BitSet::new(), | |||
inner, | |||
} | |||
} | |||
} |
@@ -0,0 +1,7 @@ | |||
mod masked; | |||
mod vec; | |||
pub use masked::MaskedStorage; | |||
pub use vec::VecStorage; | |||
pub trait Storage<T> {} |
@@ -0,0 +1,13 @@ | |||
use std::mem::MaybeUninit; | |||
use super::Storage; | |||
pub struct VecStorage<T>(Vec<MaybeUninit<T>>); | |||
impl<T> Storage<T> for VecStorage<T> {} | |||
impl<T> Default for VecStorage<T> { | |||
fn default() -> Self { | |||
Self(Vec::new()) | |||
} | |||
} |
@@ -1,7 +1,7 @@ | |||
use std::marker::PhantomData; | |||
use std::ops::Deref; | |||
use crate::resources::ResourceId; | |||
use crate::resource::ResourceId; | |||
use super::{DynamicSystemData, System, SystemData}; | |||
@@ -4,7 +4,7 @@ mod system_data; | |||
pub use accessor::{Accessor, AccessorCow}; | |||
pub use system_data::{DynamicSystemData, SystemData}; | |||
use crate::resources::Resources; | |||
use crate::resource::Resources; | |||
use accessor::AccessorType; | |||
@@ -1,6 +1,6 @@ | |||
use std::marker::PhantomData; | |||
use crate::resources::{ResourceId, Resources}; | |||
use crate::resource::{ResourceId, Resources}; | |||
use super::accessor::{Accessor, StaticAccessor}; | |||
@@ -0,0 +1,47 @@ | |||
use std::ops::{Deref, DerefMut}; | |||
use crate::{component::Component, entity::Entities, resource::Resources, storage::MaskedStorage}; | |||
pub struct World(Resources); | |||
impl World { | |||
pub fn register<T: Component>(&mut self) | |||
where | |||
T::Storage: Default, | |||
{ | |||
self.register_with_storage::<T, _>(Default::default); | |||
} | |||
pub fn register_with_storage<T, F>(&mut self, storage: F) | |||
where | |||
T: Component, | |||
F: FnOnce() -> T::Storage, | |||
{ | |||
self.entry() | |||
.or_insert_with(move || MaskedStorage::<T>::new(storage())); | |||
} | |||
} | |||
impl Default for World { | |||
fn default() -> Self { | |||
let mut resources = Resources::default(); | |||
resources.insert(Entities::default()); | |||
Self(resources) | |||
} | |||
} | |||
impl Deref for World { | |||
type Target = Resources; | |||
fn deref(&self) -> &Self::Target { | |||
&self.0 | |||
} | |||
} | |||
impl DerefMut for World { | |||
fn deref_mut(&mut self) -> &mut Self::Target { | |||
&mut self.0 | |||
} | |||
} |