diff --git a/async-ecs/src/access/mod.rs b/async-ecs/src/access/mod.rs new file mode 100644 index 0000000..8ec7313 --- /dev/null +++ b/async-ecs/src/access/mod.rs @@ -0,0 +1,9 @@ +pub mod read; +pub mod read_storage; +pub mod write; +pub mod write_storage; + +pub use read::Read; +pub use read_storage::ReadStorage; +pub use write::Write; +pub use write_storage::WriteStorage; diff --git a/async-ecs/src/access/read.rs b/async-ecs/src/access/read.rs new file mode 100644 index 0000000..d48f220 --- /dev/null +++ b/async-ecs/src/access/read.rs @@ -0,0 +1,55 @@ +use std::marker::PhantomData; +use std::ops::Deref; + +use crate::{ + resource::{Ref, Resource, ResourceId}, + system::SystemData, + world::{DefaultSetupHandler, SetupHandler, World}, +}; + +pub struct Read<'a, T: 'a, F = DefaultSetupHandler> { + inner: Ref<'a, T>, + marker: PhantomData, +} + +impl<'a, T, F> Read<'a, T, F> { + pub fn new(inner: Ref<'a, T>) -> Self { + Self { + inner, + marker: PhantomData, + } + } +} + +impl<'a, T, F> Deref for Read<'a, T, F> +where + T: Resource, +{ + type Target = T; + + fn deref(&self) -> &T { + &*self.inner + } +} + +impl<'a, T, F> SystemData<'a> for Read<'a, T, F> +where + T: Resource, + F: SetupHandler, +{ + fn setup(world: &mut World) { + F::setup(world) + } + + fn fetch(world: &'a World) -> Self { + Self::new(world.borrow()) + } + + fn reads() -> Vec { + vec![ResourceId::new::()] + } + + fn writes() -> Vec { + vec![] + } +} diff --git a/async-ecs/src/access/read_storage.rs b/async-ecs/src/access/read_storage.rs new file mode 100644 index 0000000..1586412 --- /dev/null +++ b/async-ecs/src/access/read_storage.rs @@ -0,0 +1,35 @@ +use crate::{ + component::Component, + entity::Entities, + misc::TryDefault, + resource::{Ref, ResourceId}, + storage::{MaskedStorage, StorageWrapper}, + system::SystemData, + world::World, +}; + +pub type ReadStorage<'a, T> = StorageWrapper<'a, T, Ref<'a, MaskedStorage>>; + +impl<'a, T> SystemData<'a> for ReadStorage<'a, T> +where + T: Component, +{ + fn setup(world: &mut World) { + world.register_component_with_storage::(TryDefault::unwrap_default); + } + + fn fetch(world: &'a World) -> Self { + Self::new(world.borrow(), world.borrow()) + } + + fn reads() -> Vec { + vec![ + ResourceId::new::(), + ResourceId::new::>(), + ] + } + + fn writes() -> Vec { + vec![] + } +} diff --git a/async-ecs/src/access/write.rs b/async-ecs/src/access/write.rs new file mode 100644 index 0000000..4c0f840 --- /dev/null +++ b/async-ecs/src/access/write.rs @@ -0,0 +1,64 @@ +use std::marker::PhantomData; +use std::ops::{Deref, DerefMut}; + +use crate::{ + resource::{RefMut, Resource, ResourceId}, + system::SystemData, + world::{DefaultSetupHandler, SetupHandler, World}, +}; + +pub struct Write<'a, T: 'a, F = DefaultSetupHandler> { + inner: RefMut<'a, T>, + marker: PhantomData, +} + +impl<'a, T, F> Write<'a, T, F> { + pub fn new(inner: RefMut<'a, T>) -> Self { + Self { + inner, + marker: PhantomData, + } + } +} + +impl<'a, T, F> Deref for Write<'a, T, F> +where + T: Resource, +{ + type Target = T; + + fn deref(&self) -> &T { + &*self.inner + } +} + +impl<'a, T, F> DerefMut for Write<'a, T, F> +where + T: Resource, +{ + fn deref_mut(&mut self) -> &mut T { + &mut *self.inner + } +} + +impl<'a, T, F> SystemData<'a> for Write<'a, T, F> +where + T: Resource, + F: SetupHandler, +{ + fn setup(world: &mut World) { + F::setup(world) + } + + fn fetch(world: &'a World) -> Self { + Self::new(world.borrow_mut()) + } + + fn reads() -> Vec { + vec![] + } + + fn writes() -> Vec { + vec![ResourceId::new::()] + } +} diff --git a/async-ecs/src/access/write_storage.rs b/async-ecs/src/access/write_storage.rs new file mode 100644 index 0000000..b6d178c --- /dev/null +++ b/async-ecs/src/access/write_storage.rs @@ -0,0 +1,32 @@ +use crate::{ + component::Component, + entity::Entities, + misc::TryDefault, + resource::{RefMut, ResourceId}, + storage::{MaskedStorage, StorageWrapper}, + system::SystemData, + world::World, +}; + +pub type WriteStorage<'a, T> = StorageWrapper<'a, T, RefMut<'a, MaskedStorage>>; + +impl<'a, T> SystemData<'a> for WriteStorage<'a, T> +where + T: Component, +{ + fn setup(world: &mut World) { + world.register_component_with_storage::(TryDefault::unwrap_default); + } + + fn fetch(world: &'a World) -> Self { + Self::new(world.borrow_mut(), world.borrow()) + } + + fn reads() -> Vec { + vec![ResourceId::new::()] + } + + fn writes() -> Vec { + vec![ResourceId::new::>()] + } +} diff --git a/async-ecs/src/lib.rs b/async-ecs/src/lib.rs index 6d906bf..491084e 100644 --- a/async-ecs/src/lib.rs +++ b/async-ecs/src/lib.rs @@ -1,5 +1,7 @@ +pub mod access; pub mod component; pub mod entity; +pub mod misc; pub mod resource; pub mod storage; pub mod system; diff --git a/async-ecs/src/main.rs b/async-ecs/src/main.rs index ae5661d..9395631 100644 --- a/async-ecs/src/main.rs +++ b/async-ecs/src/main.rs @@ -20,13 +20,13 @@ fn main() { info!("Application started!"); let mut world = World::default(); - world.register::(); - world.register::(); - world.register::(); + world.register_component::(); + world.register_component::(); + world.register_component::(); /* for _ in 0..ENTITY_COUNT { - resources + world .create_entity() .with(Velocity::random()) .with(Position::random()) diff --git a/async-ecs/src/misc/mod.rs b/async-ecs/src/misc/mod.rs new file mode 100644 index 0000000..5df1510 --- /dev/null +++ b/async-ecs/src/misc/mod.rs @@ -0,0 +1,3 @@ +pub mod try_default; + +pub use try_default::TryDefault; diff --git a/async-ecs/src/misc/try_default.rs b/async-ecs/src/misc/try_default.rs new file mode 100644 index 0000000..d941e2c --- /dev/null +++ b/async-ecs/src/misc/try_default.rs @@ -0,0 +1,19 @@ +pub trait TryDefault: Sized { + fn try_default() -> Result; + + fn unwrap_default() -> Self { + match Self::try_default() { + Ok(x) => x, + Err(e) => panic!("Failed to create a default value for storage ({:?})", e), + } + } +} + +impl TryDefault for T +where + T: Default, +{ + fn try_default() -> Result { + Ok(T::default()) + } +} diff --git a/async-ecs/src/storage/masked.rs b/async-ecs/src/storage/masked_storage.rs similarity index 100% rename from async-ecs/src/storage/masked.rs rename to async-ecs/src/storage/masked_storage.rs diff --git a/async-ecs/src/storage/mod.rs b/async-ecs/src/storage/mod.rs index fa02898..7d684f5 100644 --- a/async-ecs/src/storage/mod.rs +++ b/async-ecs/src/storage/mod.rs @@ -1,7 +1,11 @@ -mod masked; -mod vec; +mod masked_storage; +mod storage_wrapper; +mod vec_storage; -pub use masked::MaskedStorage; -pub use vec::VecStorage; +pub use masked_storage::MaskedStorage; +pub use storage_wrapper::StorageWrapper; +pub use vec_storage::VecStorage; -pub trait Storage {} +use crate::misc::TryDefault; + +pub trait Storage: TryDefault {} diff --git a/async-ecs/src/storage/storage_wrapper.rs b/async-ecs/src/storage/storage_wrapper.rs new file mode 100644 index 0000000..98299ab --- /dev/null +++ b/async-ecs/src/storage/storage_wrapper.rs @@ -0,0 +1,19 @@ +use std::marker::PhantomData; + +use crate::{entity::Entities, resource::Ref}; + +pub struct StorageWrapper<'a, T, D> { + data: D, + entities: Ref<'a, Entities>, + phantom: PhantomData, +} + +impl<'a, T, D> StorageWrapper<'a, T, D> { + pub fn new(data: D, entities: Ref<'a, Entities>) -> Self { + Self { + data, + entities, + phantom: PhantomData, + } + } +} diff --git a/async-ecs/src/storage/vec.rs b/async-ecs/src/storage/vec_storage.rs similarity index 100% rename from async-ecs/src/storage/vec.rs rename to async-ecs/src/storage/vec_storage.rs diff --git a/async-ecs/src/system/mod.rs b/async-ecs/src/system/mod.rs index 3a999f0..d475f84 100644 --- a/async-ecs/src/system/mod.rs +++ b/async-ecs/src/system/mod.rs @@ -4,7 +4,7 @@ mod system_data; pub use accessor::{Accessor, AccessorCow}; pub use system_data::{DynamicSystemData, SystemData}; -use crate::resource::Resources; +use crate::world::World; use accessor::AccessorType; @@ -19,14 +19,14 @@ pub trait System<'a> { ) } - fn setup(&mut self, resources: &mut Resources) { - ::setup(&self.accessor(), resources) + fn setup(&mut self, world: &mut World) { + ::setup(&self.accessor(), world) } - fn dispose(self, resources: &mut Resources) + fn dispose(self, world: &mut World) where Self: Sized, { - let _ = resources; + let _ = world; } } diff --git a/async-ecs/src/system/system_data.rs b/async-ecs/src/system/system_data.rs index fc05d30..27fd1b9 100644 --- a/async-ecs/src/system/system_data.rs +++ b/async-ecs/src/system/system_data.rs @@ -1,13 +1,13 @@ use std::marker::PhantomData; -use crate::resource::{ResourceId, Resources}; +use crate::{resource::ResourceId, world::World}; use super::accessor::{Accessor, StaticAccessor}; pub trait SystemData<'a> { - fn setup(resources: &mut Resources); + fn setup(world: &mut World); - fn fetch(resources: &'a Resources) -> Self; + fn fetch(world: &'a World) -> Self; fn reads() -> Vec; @@ -17,9 +17,9 @@ pub trait SystemData<'a> { pub trait DynamicSystemData<'a> { type Accessor: Accessor; - fn setup(accessor: &Self::Accessor, resources: &mut Resources); + fn setup(accessor: &Self::Accessor, world: &mut World); - fn fetch(access: &Self::Accessor, resources: &'a Resources) -> Self; + fn fetch(access: &Self::Accessor, world: &'a World) -> Self; } /* SystemData */ @@ -28,9 +28,9 @@ impl<'a, T> SystemData<'a> for PhantomData where T: ?Sized, { - fn setup(_: &mut Resources) {} + fn setup(_: &mut World) {} - fn fetch(_: &Resources) -> Self { + fn fetch(_: &World) -> Self { PhantomData } @@ -51,12 +51,12 @@ where { type Accessor = StaticAccessor; - fn setup(_: &StaticAccessor, resources: &mut Resources) { - T::setup(resources); + fn setup(_: &StaticAccessor, world: &mut World) { + T::setup(world); } - fn fetch(_: &StaticAccessor, resources: &'a Resources) -> Self { - T::fetch(resources) + fn fetch(_: &StaticAccessor, world: &'a World) -> Self { + T::fetch(world) } } @@ -68,18 +68,18 @@ mod impl_system_data { impl<'a, $($ty),*> SystemData<'a> for ( $( $ty , )* ) where $( $ty : SystemData<'a> ),* { - fn setup(resources: &mut Resources) { + fn setup(world: &mut World) { #![allow(unused_variables)] $( - <$ty as SystemData>::setup(&mut *resources); + <$ty as SystemData>::setup(&mut *world); )* } - fn fetch(resources: &'a Resources) -> Self { + fn fetch(world: &'a World) -> Self { #![allow(unused_variables)] - ( $( <$ty as SystemData<'a>>::fetch(resources), )* ) + ( $( <$ty as SystemData<'a>>::fetch(world), )* ) } fn reads() -> Vec { diff --git a/async-ecs/src/world/mod.rs b/async-ecs/src/world/mod.rs index f9b6af8..2b329d6 100644 --- a/async-ecs/src/world/mod.rs +++ b/async-ecs/src/world/mod.rs @@ -1,18 +1,29 @@ +mod setup; + +pub use setup::{DefaultSetupHandler, SetupHandler}; + use std::ops::{Deref, DerefMut}; -use crate::{component::Component, entity::Entities, resource::Resources, storage::MaskedStorage}; +use crate::{ + access::{Read, ReadStorage, WriteStorage}, + component::Component, + entity::Entities, + resource::{Ref, RefMut, Resource, Resources}, + storage::MaskedStorage, + system::SystemData, +}; pub struct World(Resources); impl World { - pub fn register(&mut self) + pub fn register_component(&mut self) where T::Storage: Default, { - self.register_with_storage::(Default::default); + self.register_component_with_storage::(Default::default); } - pub fn register_with_storage(&mut self, storage: F) + pub fn register_component_with_storage(&mut self, storage: F) where T: Component, F: FnOnce() -> T::Storage, @@ -20,6 +31,34 @@ impl World { self.entry() .or_insert_with(move || MaskedStorage::::new(storage())); } + + pub fn register_resource(&mut self, res: T) { + self.0.insert(res); + } + + pub fn resource(&self) -> Ref { + self.0.borrow() + } + + pub fn resource_mut(&self) -> RefMut { + self.0.borrow_mut() + } + + pub fn entities(&self) -> Read { + Read::fetch(&self) + } + + pub fn entities_mut(&self) -> RefMut { + self.resource_mut() + } + + pub fn component(&self) -> ReadStorage { + ReadStorage::fetch(&self) + } + + pub fn component_mut(&self) -> WriteStorage { + WriteStorage::fetch(&self) + } } impl Default for World { diff --git a/async-ecs/src/world/setup.rs b/async-ecs/src/world/setup.rs new file mode 100644 index 0000000..ed3d61d --- /dev/null +++ b/async-ecs/src/world/setup.rs @@ -0,0 +1,18 @@ +use crate::resource::Resource; + +use super::World; + +pub trait SetupHandler: Sized { + fn setup(world: &mut World); +} + +pub struct DefaultSetupHandler; + +impl SetupHandler for DefaultSetupHandler +where + T: Default + Resource, +{ + fn setup(world: &mut World) { + world.entry().or_insert_with(T::default); + } +}