| @@ -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 | |||
| } | |||
| } | |||