diff --git a/Cargo.toml b/Cargo.toml index ad5496b..291a7b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [workspace] resolver = "2" -members = ["ecs", "scene_update_macros"] +members = ["ecs", "update_macros"] [workspace.dependencies] anyhow = { version = "1.0.86", features = ["backtrace"] } diff --git a/ecs/Cargo.toml b/ecs/Cargo.toml index 2e54ab9..2901052 100644 --- a/ecs/Cargo.toml +++ b/ecs/Cargo.toml @@ -12,7 +12,7 @@ paste.workspace = true ron.workspace = true utilities.workspace = true -scene_update_macros = { path = "../scene_update_macros" } +update_macros = { path = "../update_macros" } [features] timings = [] diff --git a/ecs/src/entity.rs b/ecs/src/entity.rs index fdfdc35..f53dc33 100644 --- a/ecs/src/entity.rs +++ b/ecs/src/entity.rs @@ -7,7 +7,7 @@ use anyhow::Result; use indexmap::IndexMap; use serde::{Deserialize, Serialize}; -use crate::{ComponentDebug, ComponentNotFoundError, EntityComponent, MultiMut, TypeMap}; +use crate::{ComponentDebug, ComponentNotFoundError, EntityComponent, TypeMap}; #[derive(Debug)] pub struct EntityNotFoundError { @@ -89,10 +89,6 @@ impl EntityObject { self.gltf_file.as_ref() } - pub fn multi_mut(&mut self) -> MultiMut<'_> { - self.components.multi_mut() - } - pub fn insert_component( &mut self, component: T, diff --git a/ecs/src/lib.rs b/ecs/src/lib.rs index b74be15..8708cc1 100644 --- a/ecs/src/lib.rs +++ b/ecs/src/lib.rs @@ -9,9 +9,9 @@ mod world; pub use crate::entity::{Entity, EntityMultiMut, EntityNotFoundError, EntityObject}; pub use crate::events::Events; -pub use crate::resources::{ResourceMultiMut, Resources}; +pub use crate::resources::Resources; pub use crate::type_map::{ - ComponentCreateInfo, ComponentDebug, ComponentNotFoundError, EntityComponent, MultiMut, TypeMap, + ComponentCreateInfo, ComponentDebug, ComponentNotFoundError, EntityComponent, TypeMap, }; pub use crate::unsafe_component_store::UnsafeComponentStore; pub use crate::updates::*; diff --git a/ecs/src/resources.rs b/ecs/src/resources.rs index 44fbd15..1f7f662 100644 --- a/ecs/src/resources.rs +++ b/ecs/src/resources.rs @@ -1,7 +1,6 @@ use std::{ any::{Any, TypeId}, collections::HashMap, - mem::transmute, }; use utilities::prelude::{remove_life_time, remove_life_time_mut}; @@ -91,88 +90,7 @@ impl Resources { self.map.get_mut(&type_id).map(|any| any.as_mut()) } - pub fn multi_mut(&mut self) -> ResourceMultiMut<'_> { - ResourceMultiMut::new(&mut self.map) - } - pub fn contains(&self) -> bool { self.map.contains_key(&TypeId::of::()) } } - -// helper -impl Resources { - fn downcast_unchecked(boxed: Box) -> Box { - unsafe { Box::from_raw(Box::into_raw(boxed) as *mut T) } - } - - fn downcast_ref_unchecked(boxed_ref: &Box) -> &T { - unsafe { - let ptr_to_ptr: *const *const T = - transmute(destructure_traitobject::data(boxed_ref as *const _)); - - &**ptr_to_ptr - } - } - - fn downcast_mut_unchecked(boxed_ref: &mut Box) -> &mut T { - unsafe { - let ptr_to_ptr: *mut *mut T = - transmute(destructure_traitobject::data(boxed_ref as *mut _)); - - &mut **ptr_to_ptr - } - } -} - -/// Allows mutable access to multiple components at once -pub struct ResourceMultiMut<'a> { - map: &'a mut HashMap>, - buffer: Vec<*mut Box>, -} - -impl<'a> ResourceMultiMut<'a> { - fn new(map: &'a mut HashMap>) -> Self { - ResourceMultiMut { - map, - buffer: Vec::new(), - } - } - - /// Returns requested type on success - pub fn get(&mut self) -> &'a mut T { - self.get_by_type_id(&TypeId::of::()) - .map(|component| Resources::downcast_mut_unchecked(component)) - .unwrap() - } - - /// Returns requested type behind this type id on success - pub fn get_by_type_id( - &mut self, - type_id: &TypeId, - ) -> Option<&'a mut Box> { - self.map.get_mut(type_id).map(|v| { - let ptr = v as *mut _; - - match self.buffer.iter().find(|v| **v == ptr) { - Some(_) => { - panic!("This key has already been borrowed!"); - } - None => { - self.buffer.push(ptr); - } - } - - let t: Option<&'a mut Box> = unsafe { transmute(ptr) }; - - t.unwrap() - }) - } - - /// # Safety - /// - /// use this only when there are no references left - pub unsafe fn clear_all_usages(&mut self) { - self.buffer.clear(); - } -} diff --git a/ecs/src/type_map.rs b/ecs/src/type_map.rs index 9d85cdc..ce0a28d 100644 --- a/ecs/src/type_map.rs +++ b/ecs/src/type_map.rs @@ -1,4 +1,3 @@ -use std::mem::transmute; use std::{ any::{Any, TypeId}, collections::{ @@ -26,11 +25,16 @@ pub trait EntityComponent: Any + Send + Sync { } impl dyn EntityComponent { - pub fn downcast_ref(&self) -> Option<&T> { + pub fn downcast_owned(mut self: Box) -> Option { + self.downcast_mut() + .map(|raw| unsafe { *Box::from_raw(raw as *mut T) }) + } + + pub fn downcast_ref(&self) -> Option<&T> { (self as &dyn Any).downcast_ref() } - pub fn downcast_mut(&mut self) -> Option<&mut T> { + pub fn downcast_mut(&mut self) -> Option<&mut T> { (self as &mut dyn Any).downcast_mut() } } @@ -72,7 +76,8 @@ impl TypeMap { pub fn insert(&mut self, value: T) -> Option { self.map .insert(TypeId::of::(), Box::new(value)) - .map(|any| *Self::downcast_unchecked(any)) + .map(|any| any.downcast_owned()) + .flatten() } pub fn insert_type( @@ -85,7 +90,8 @@ impl TypeMap { pub fn remove(&mut self) -> Option { self.remove_by_type_id(&TypeId::of::()) - .map(|any| *Self::downcast_unchecked(any)) + .map(|any| any.downcast_owned()) + .flatten() } pub fn remove_by_type_id(&mut self, type_id: &TypeId) -> Option> { @@ -136,10 +142,6 @@ impl TypeMap { self.map.contains_key(type_id) } - pub fn multi_mut(&mut self) -> MultiMut<'_> { - MultiMut::new(&mut self.map) - } - pub fn iter(&self) -> Iter<'_, TypeId, Box> { self.map.iter() } @@ -147,41 +149,17 @@ impl TypeMap { pub fn iter_mut(&mut self) -> IterMut<'_, TypeId, Box> { self.map.iter_mut() } - - // fn downcast_unchecked(boxed: Box) -> Box { - // unsafe { Box::from_raw(Box::into_raw(boxed) as *mut T) } - // } - - // pub fn downcast_ref_unchecked(boxed_ref: &Box) -> &T { - // unsafe { - // let ptr_to_ptr: *const *const T = - // transmute(destructure_traitobject::data(boxed_ref as *const _)); - - // &**ptr_to_ptr - // } - // } - - // pub fn downcast_mut_unchecked( - // boxed_ref: &mut Box, - // ) -> &mut T { - // unsafe { - // let ptr_to_ptr: *mut *mut T = - // transmute(destructure_traitobject::data(boxed_ref as *mut _)); - - // &mut **ptr_to_ptr - // } - // } } -pub trait GetTypeMap { - fn get_mut(&mut self) -> std::result::Result<&mut T, ComponentNotFoundError>; +pub trait GetTypeMap<'a, T: 'a> { + fn get_mut(&'a mut self) -> std::result::Result; } -impl GetTypeMap for TypeMap +impl<'a, T> GetTypeMap<'a, &'a mut T> for TypeMap where T: EntityComponent + ComponentDebug, { - fn get_mut(&mut self) -> std::result::Result<&mut T, ComponentNotFoundError> { + fn get_mut(&'a mut self) -> std::result::Result<&'a mut T, ComponentNotFoundError> { self.map .get_mut(&TypeId::of::()) .map(|any| any.downcast_mut().unwrap()) @@ -190,75 +168,37 @@ where } macro_rules! impl_get_type_map { - ([$(t:ident,)+]) => { - impl<($(t,)+)> GetTypeMap<$(t,)+> for TypeMap { - fn get_mut(&mut self) -> std::result::Result<($(&mut t,)+), ComponentNotFoundError> { - self.map - .get_disjoint_mut( - [$(&TypeId::of::(),)]) - .map(|any| any.downcast_mut().unwrap()) - .ok_or_else(ComponentNotFoundError::component::) + (<$($t:ident$(,)?)+>) => { + impl<'a, $($t,)+> GetTypeMap<'a, ($(&'a mut $t,)+)> for TypeMap + where + $( + $t: EntityComponent + ComponentDebug + 'static, + )+ + { + fn get_mut(&'a mut self) -> std::result::Result<($(&'a mut $t,)+), ComponentNotFoundError> { + let mut types: std::collections::VecDeque<_> + = self.map.get_disjoint_mut([$(&TypeId::of::<$t>(),)+]).into_iter().collect(); + + Ok(($( + types + .pop_front() + .flatten() + .map(|any| any.downcast_mut().unwrap()) + .ok_or_else(ComponentNotFoundError::component::<$t>)?, + )+)) } } }; } -/// Allows mutable access to multiple components at once -pub struct MultiMut<'a> { - map: &'a mut HashMap>, - buffer: Vec<*mut Box>, -} - -impl<'a> MultiMut<'a> { - fn new(map: &'a mut HashMap>) -> Self { - MultiMut { - map, - buffer: Vec::new(), - } - } - - /// Returns requested type on success - pub fn get( - &mut self, - ) -> std::result::Result<&'a mut T, ComponentNotFoundError> { - self.get_by_type_id(&TypeId::of::()) - .map(|component| TypeMap::downcast_mut_unchecked(component)) - .map_err(|_| ComponentNotFoundError::component::()) - } - - /// Returns requested type behind this type id on success - pub fn get_by_type_id( - &mut self, - type_id: &TypeId, - ) -> std::result::Result<&'a mut Box, ComponentNotFoundError> { - match self.map.get_mut(type_id) { - Some(v) => { - let ptr = v as *mut _; - - match self.buffer.iter().find(|v| **v == ptr) { - Some(_) => { - panic!("This key has already been borrowed!"); - } - None => { - self.buffer.push(ptr); - } - } - - let t: Option<&'a mut Box> = unsafe { transmute(ptr) }; - - t.ok_or_else(|| ComponentNotFoundError::type_id(*type_id)) - } - None => Err(ComponentNotFoundError::type_id(*type_id)), - } - } - - /// # Safety - /// - /// use this only when there are no references left - pub unsafe fn clear_all_usages(&mut self) { - self.buffer.clear(); - } -} +impl_get_type_map!(); +impl_get_type_map!(); +impl_get_type_map!(); +impl_get_type_map!(); +impl_get_type_map!(); +impl_get_type_map!(); +impl_get_type_map!(); +impl_get_type_map!(); #[derive(Debug)] pub enum ComponentRequestType { @@ -319,21 +259,15 @@ impl PartialEq for Test { } #[test] -fn verify_multi_mut() { +fn verify_disjoint_get() { let mut map = TypeMap::default(); - map.insert(Test::default()); + let reference = Test { x: 5, y: 20, z: 30 }; - // test it multiple times, just for sanity - for _ in 0..10 { - let test = map.get::().unwrap().clone(); + map.insert(reference.clone()); + let old: &mut Test = map.get_mut().unwrap(); - let mut multi_mut = map.multi_mut(); - - let multi_mut_test = multi_mut.get::().unwrap().clone(); - - assert_eq!(test, multi_mut_test); - } + assert_eq!(*old, reference); } #[test] diff --git a/ecs/src/updates.rs b/ecs/src/updates.rs index 6a0e46d..f3d52f3 100644 --- a/ecs/src/updates.rs +++ b/ecs/src/updates.rs @@ -14,7 +14,7 @@ use indexmap::IndexMap; use super::super::timings::Timings; use crate::*; -use scene_update_macros::implement_pair_update; +use update_macros::implement_pair_update; macro_rules! impl_singleton_update { ( $name: ident, $([$var: ident]$(,)?)+ ) => { diff --git a/scene_update_macros/Cargo.toml b/update_macros/Cargo.toml similarity index 88% rename from scene_update_macros/Cargo.toml rename to update_macros/Cargo.toml index c6f9228..40fcede 100644 --- a/scene_update_macros/Cargo.toml +++ b/update_macros/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "scene_update_macros" +name = "update_macros" version = "0.1.0" authors = ["hodasemi "] edition = "2024" diff --git a/scene_update_macros/src/lib.rs b/update_macros/src/lib.rs similarity index 100% rename from scene_update_macros/src/lib.rs rename to update_macros/src/lib.rs