Browse Source

Implemented basic world, storage and component

master
Bergmann89 3 years ago
parent
commit
82fc3f92ea
18 changed files with 250 additions and 43 deletions
  1. +42
    -0
      async-ecs-derive/src/component.rs
  2. +10
    -0
      async-ecs-derive/src/lib.rs
  3. +2
    -1
      async-ecs-derive/src/system_data.rs
  4. +2
    -0
      async-ecs/Cargo.toml
  5. +7
    -0
      async-ecs/src/component/mod.rs
  6. +2
    -0
      async-ecs/src/entity/mod.rs
  7. +8
    -2
      async-ecs/src/lib.rs
  8. +11
    -8
      async-ecs/src/main.rs
  9. +22
    -22
      async-ecs/src/resource/cell.rs
  10. +41
    -0
      async-ecs/src/resource/entry.rs
  11. +16
    -7
      async-ecs/src/resource/mod.rs
  12. +17
    -0
      async-ecs/src/storage/masked.rs
  13. +7
    -0
      async-ecs/src/storage/mod.rs
  14. +13
    -0
      async-ecs/src/storage/vec.rs
  15. +1
    -1
      async-ecs/src/system/accessor.rs
  16. +1
    -1
      async-ecs/src/system/mod.rs
  17. +1
    -1
      async-ecs/src/system/system_data.rs
  18. +47
    -0
      async-ecs/src/world/mod.rs

+ 42
- 0
async-ecs-derive/src/component.rs View File

@@ -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()?,
})
}
}

+ 10
- 0
async-ecs-derive/src/lib.rs View File

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

+ 2
- 1
async-ecs-derive/src/system_data.rs View File

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


+ 2
- 0
async-ecs/Cargo.toml View File

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


+ 7
- 0
async-ecs/src/component/mod.rs View File

@@ -0,0 +1,7 @@
use std::any::Any;

use crate::storage::Storage;

pub trait Component: Any + Sized {
type Storage: Storage<Self> + Any + Send + Sync;
}

+ 2
- 0
async-ecs/src/entity/mod.rs View File

@@ -0,0 +1,2 @@
#[derive(Default)]
pub struct Entities;

+ 8
- 2
async-ecs/src/lib.rs View File

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

+ 11
- 8
async-ecs/src/main.rs View File

@@ -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>);



async-ecs/src/resources/cell.rs → async-ecs/src/resource/cell.rs View File

@@ -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);


+ 41
- 0
async-ecs/src/resource/entry.rs View File

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

async-ecs/src/resources/mod.rs → async-ecs/src/resource/mod.rs View File

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

+ 17
- 0
async-ecs/src/storage/masked.rs View File

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

+ 7
- 0
async-ecs/src/storage/mod.rs View File

@@ -0,0 +1,7 @@
mod masked;
mod vec;

pub use masked::MaskedStorage;
pub use vec::VecStorage;

pub trait Storage<T> {}

+ 13
- 0
async-ecs/src/storage/vec.rs View File

@@ -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
- 1
async-ecs/src/system/accessor.rs View File

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



+ 1
- 1
async-ecs/src/system/mod.rs View File

@@ -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
- 1
async-ecs/src/system/system_data.rs View File

@@ -1,6 +1,6 @@
use std::marker::PhantomData;

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

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



+ 47
- 0
async-ecs/src/world/mod.rs View File

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

Loading…
Cancel
Save