diff --git a/lib/ecs/src/lib.rs b/lib/ecs/src/lib.rs index 95493f9..08031f3 100644 --- a/lib/ecs/src/lib.rs +++ b/lib/ecs/src/lib.rs @@ -7,7 +7,12 @@ pub mod system; pub mod world; pub use component::Component as Component; +pub use component::Resource as Resource; pub use world::World as World; pub use world::ReadData as ReadData; +pub use world::ReadWriteData as ReadWriteData; +pub use world::ReadResource as ReadResource; +pub use world::ReadWriteResource as ReadWriteResource; pub use system::System as System; pub use system::Join as Join; +pub use system::Processor as Processor; diff --git a/lib/ecs/src/resourcemap.rs b/lib/ecs/src/resourcemap.rs index 26dbca8..8c8beb5 100644 --- a/lib/ecs/src/resourcemap.rs +++ b/lib/ecs/src/resourcemap.rs @@ -1,6 +1,6 @@ use std::cell::{Cell, UnsafeCell}; use std::collections::BTreeMap; -use std::ops::Deref; +use std::ops::{Deref, DerefMut}; use crate::component; use crate::borrow; @@ -45,9 +45,35 @@ impl ResourceMap { None => Err(AccessError::concurrent()), Some(b2) => { let val = val.as_ref(); - let val = unsafe { & *(val as *const (dyn component::Resource) as *const T) }; + let val = & *(val as *const (dyn component::Resource) as *const T); drop(b); - Ok(ResourceRef { val, borrow: b2 }) + Ok(ResourceRef { val, borrow: Some(b2) }) + }, + } + }, + None => Err(AccessError("resource absent from world".to_string())), + } + } + } + } + } + + pub fn get_mut<'a, T: component::Resource>(&'a self) -> Result, AccessError> { + match borrow::RefMut::new(&self.borrow) { + None => Err(AccessError::concurrent()), + Some(b) => { + let map = self.value.get(); + unsafe { + match (*map).get_mut(&component::resource_id::()) { + Some(entry) => { + let val = &mut entry.resource; + match borrow::RefMut::new(&entry.borrow) { + None => Err(AccessError::concurrent()), + Some(b2) => { + let val = val.as_mut(); + let val = &mut *(val as *mut (dyn component::Resource) as *mut T); + drop(b); + Ok(ResourceRefMut { val, borrow: Some(b2) }) }, } }, @@ -92,7 +118,7 @@ impl ResourceMap { pub struct ResourceRef<'a, T: component::Resource> { val: *const T, - borrow: borrow::Ref<'a>, + borrow: Option>, } impl<'a, T: component::Resource> Deref for ResourceRef<'a, T> { @@ -104,3 +130,37 @@ impl<'a, T: component::Resource> Deref for ResourceRef<'a, T> { } } } + +impl <'a, T: component::Resource> Drop for ResourceRef<'a, T> { + fn drop(&mut self) { + self.borrow = None; + } +} + +pub struct ResourceRefMut<'a, T: component::Resource> { + val: *mut T, + borrow: Option>, +} + +impl <'a, T: component::Resource> Drop for ResourceRefMut<'a, T> { + fn drop(&mut self) { + self.borrow = None; + } +} + +impl <'a, T: component::Resource> Deref for ResourceRefMut<'a, T> { + type Target = T; + fn deref(&self) -> &Self::Target { + unsafe { + &(*self.val) + } + } +} + +impl <'a, T: component::Resource> DerefMut for ResourceRefMut<'a, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { + &mut(*self.val) + } + } +} diff --git a/lib/ecs/src/system.rs b/lib/ecs/src/system.rs index f2dcf0d..5fdf3cf 100644 --- a/lib/ecs/src/system.rs +++ b/lib/ecs/src/system.rs @@ -6,7 +6,7 @@ use crate::{ world::{ ReadData, ReadDataIter, ReadWriteData, ReadWriteDataIter, - ReadResource, + ReadResource, ReadWriteResource, World, } }; @@ -75,6 +75,12 @@ impl<'a, T: component::Resource> Access<'a> for ReadResource<'a, T> { } } +impl<'a, T: component::Resource> Access<'a> for ReadWriteResource<'a, T> { + fn fetch(world: &'a World) -> Self { + world.resource_mut() + } +} + impl <'a, T: Access<'a>, U: Access<'a>, @@ -101,12 +107,34 @@ impl <'a, } } +impl <'a, + T: Access<'a>, + U: Access<'a>, + V: Access<'a>, + W: Access<'a>, +> Access<'a> for (T, U, V, W) { + fn fetch(world: &'a World) -> Self { + ( + T::fetch(world), + U::fetch(world), + V::fetch(world), + W::fetch(world), + ) + } +} + pub struct Processor<'a> { world: &'a World, runners: Vec>>, } impl<'a> Processor<'a> { + pub fn new(world: &'a World) -> Self { + Self { + world, + runners: Vec::new(), + } + } pub fn add_system + 'static>(&mut self, system: T) { self.runners.push(Box::new(system)); } @@ -172,13 +200,19 @@ mod test { component::Resource, system, system::Join, - world::{ReadData, ReadWriteData, ReadResource, World}, + world::{ReadData, ReadWriteData, ReadResource, ReadWriteResource, World}, }; #[derive(Clone,Debug,Default)] struct Delta(f32); impl Resource for Delta {} + #[derive(Clone,Debug)] + struct PhysicsStatus { + object_count: u64, + } + impl Resource for PhysicsStatus {} + #[derive(Clone,Debug)] struct Position { x: f32, @@ -199,15 +233,19 @@ mod test { impl<'a> system::System<'a> for Physics { type SystemData = ( ReadWriteData<'a, Position> , ReadData<'a, Velocity> - , ReadResource<'a, Delta>); + , ReadResource<'a, Delta> + , ReadWriteResource<'a, PhysicsStatus>); - fn run(&mut self, (pos, vel, delta): Self::SystemData) { + fn run(&mut self, (pos, vel, delta, status): Self::SystemData) { let d = delta.get(); + let mut count = 0u64; for (mut p, v) in (pos, vel).join_all() { p.x += v.x * d.0; p.y += v.y * d.0; p.z += v.z * d.0; + count += 1; } + status.get().object_count = count; } } @@ -217,6 +255,7 @@ mod test { world.new_entity().with(Velocity { x: 0.0, y: 0.0, z: 1.0 }).with(Position { x: 1.0, y: 2.0, z: 3.0 }).build(); world.new_entity().with(Velocity { x: 0.0, y: 0.0, z: 2.0 }).with(Position { x: 4.0, y: 5.0, z: 6.0 }).build(); world.set_resource(Delta(1.0)); + world.set_resource(PhysicsStatus { object_count: 0u64 }); let mut p = system::Processor { world: &world, @@ -231,5 +270,6 @@ mod test { world.set_resource(Delta(2.0)); p.run(); assert_eq!(vec![6.0, 12.0], positions.iter().map(|(_, el)| el.z).collect::>()); + assert_eq!(2, world.resource::().get().object_count); } } diff --git a/lib/ecs/src/world.rs b/lib/ecs/src/world.rs index 9237d4d..d9d99a4 100644 --- a/lib/ecs/src/world.rs +++ b/lib/ecs/src/world.rs @@ -1,7 +1,6 @@ use std::collections::BTreeMap; use std::marker::PhantomData; use std::iter::Iterator; -use std::cell::{Ref, RefMut, RefCell}; use crate::componentmap::{ ComponentMap, @@ -11,6 +10,7 @@ use crate::componentmap::{ use crate::resourcemap::{ ResourceMap, ResourceRef, + ResourceRefMut, }; use crate::entity; use crate::component; @@ -98,7 +98,18 @@ pub struct ReadResource<'a, T: component::Resource> { impl<'a, T: component::Resource> ReadResource<'a, T> { pub fn get(&self) -> ResourceRef<'a, T> { - self.world.resources.get::<'a, T>().unwrap() + self.world.resources.get::().unwrap() + } +} + +pub struct ReadWriteResource<'a, T: component::Resource> { + world: &'a World, + phantom: PhantomData<&'a T>, +} + +impl<'a, T: component::Resource> ReadWriteResource<'a, T> { + pub fn get(&self) -> ResourceRefMut<'a, T> { + self.world.resources.get_mut::().unwrap() } } @@ -154,6 +165,13 @@ impl World { } } + pub fn resource_mut<'a, T: component::Resource>(&'a self) -> ReadWriteResource<'a, T> { + ReadWriteResource { + world: self, + phantom: PhantomData, + } + } + pub fn set_resource(&self, r: T) { self.resources.set(r).unwrap(); }