diff options
| author | HampusM <hampus@hampusmat.com> | 2026-06-08 13:37:40 +0200 |
|---|---|---|
| committer | HampusM <hampus@hampusmat.com> | 2026-06-08 13:37:40 +0200 |
| commit | 661ef626dd8b78a199aa76c58f788349cbbcbe46 (patch) | |
| tree | 85e6b3ee0316c85166b1f211a26560f40964cb76 | |
| parent | 04bde94d9088f5a7c2a885d812495fa173cd67c0 (diff) | |
feat(engine-ecs): add support for dyn Any component handles
| -rw-r--r-- | engine-ecs/src/component.rs | 51 | ||||
| -rw-r--r-- | engine-ecs/src/entity.rs | 36 | ||||
| -rw-r--r-- | engine-ecs/src/lock.rs | 70 |
3 files changed, 135 insertions, 22 deletions
diff --git a/engine-ecs/src/component.rs b/engine-ecs/src/component.rs index 2734731..c163325 100644 --- a/engine-ecs/src/component.rs +++ b/engine-ecs/src/component.rs @@ -77,7 +77,7 @@ pub trait Sequence } #[derive(Debug)] -pub struct Handle<'a, DataT: 'static> +pub struct Handle<'a, DataT: ?Sized + 'static> { inner: MappedReadGuard<'a, DataT>, } @@ -111,7 +111,25 @@ impl<'comp, DataT: 'static> Handle<'comp, DataT> } } -impl<DataT: 'static> Deref for Handle<'_, DataT> +impl<'comp> Handle<'comp, dyn Any> +{ + pub fn new_any( + entity_component_ref: &EntityComponentRef<'comp>, + ) -> Result<Self, HandleError> + { + Ok(Self { + inner: ReadGuard::map( + entity_component_ref + .component() + .read_nonblock() + .map_err(AcquireLockError)?, + |component| &**component, + ), + }) + } +} + +impl<DataT: ?Sized + 'static> Deref for Handle<'_, DataT> { type Target = DataT; @@ -122,7 +140,7 @@ impl<DataT: 'static> Deref for Handle<'_, DataT> } #[derive(Debug)] -pub struct HandleMut<'a, DataT: 'static> +pub struct HandleMut<'a, DataT: ?Sized + 'static> { entity_component_ref: EntityComponentRef<'a>, inner: MappedWriteGuard<'a, DataT>, @@ -154,7 +172,30 @@ impl<'comp, DataT: 'static> HandleMut<'comp, DataT> event_submitter: world.event_submitter(), }) } +} + +impl<'comp> HandleMut<'comp, dyn Any> +{ + pub fn new_any( + entity_component_ref: &EntityComponentRef<'comp>, + world: &'comp World, + ) -> Result<Self, HandleError> + { + let inner = entity_component_ref + .component() + .write_nonblock() + .map_err(AcquireLockError)?; + + Ok(Self { + entity_component_ref: entity_component_ref.clone(), + inner: WriteGuard::map(inner, |component| &mut **component), + event_submitter: world.event_submitter(), + }) + } +} +impl<'comp, DataT: ?Sized + 'static> HandleMut<'comp, DataT> +{ pub fn set_changed(&self) { self.event_submitter.submit_event( @@ -167,7 +208,7 @@ impl<'comp, DataT: 'static> HandleMut<'comp, DataT> } } -impl<DataT: 'static> Deref for HandleMut<'_, DataT> +impl<DataT: ?Sized + 'static> Deref for HandleMut<'_, DataT> { type Target = DataT; @@ -177,7 +218,7 @@ impl<DataT: 'static> Deref for HandleMut<'_, DataT> } } -impl<DataT: 'static> DerefMut for HandleMut<'_, DataT> +impl<DataT: ?Sized + 'static> DerefMut for HandleMut<'_, DataT> { fn deref_mut(&mut self) -> &mut Self::Target { diff --git a/engine-ecs/src/entity.rs b/engine-ecs/src/entity.rs index f551de1..d7b63be 100644 --- a/engine-ecs/src/entity.rs +++ b/engine-ecs/src/entity.rs @@ -1,4 +1,4 @@ -use std::any::type_name; +use std::any::{type_name, Any}; use std::ops::Deref; use std::sync::LazyLock; @@ -122,6 +122,40 @@ impl<'a> Handle<'a> ) } + /// Returns a reference to the component with the ID `id` in this entity. + /// `None` is returned if the component isn't found. + /// + /// # Panics + /// Will panic if: + /// - The component is borrowed mutably elsewhere + #[must_use] + pub fn get_any_by_id(&self, id: Uid) -> Option<ComponentHandle<'a, dyn Any>> + { + let component = self.get_matching_components(id).next()?; + + Some(ComponentHandle::new_any(&component).unwrap_or_else(|err| { + panic!("Creating handle to component with id {id} failed: {err}"); + })) + } + + /// Returns a reference to the component with the ID `id` in this entity. + /// `None` is returned if the component isn't found. + /// + /// # Panics + /// Will panic if: + /// - The component is borrowed elsewhere + #[must_use] + pub fn get_any_by_id_mut(&self, id: Uid) -> Option<ComponentHandleMut<'a, dyn Any>> + { + let component = self.get_matching_components(id).next()?; + + Some( + ComponentHandleMut::new_any(&component, self.world).unwrap_or_else(|err| { + panic!("Creating handle to component with id {id} failed: {err}"); + }), + ) + } + /// Returns a mutable reference to the component with the ID `id` in this entity. /// `None` is returned if the component isn't found. /// diff --git a/engine-ecs/src/lock.rs b/engine-ecs/src/lock.rs index fe4e08b..3db29e8 100644 --- a/engine-ecs/src/lock.rs +++ b/engine-ecs/src/lock.rs @@ -82,14 +82,33 @@ pub enum Error } #[derive(Debug)] -pub struct ReadGuard<'guard, Value> +pub struct ReadGuard<'guard, Value: ?Sized> { inner: RwLockReadGuard<'guard, Value>, value_type_name: &'static str, } -impl<'guard, Value> ReadGuard<'guard, Value> +impl<'guard, Value: ?Sized> ReadGuard<'guard, Value> { + pub fn map<NewValue: ?Sized>( + this: Self, + func: impl FnOnce(&Value) -> &NewValue, + ) -> MappedReadGuard<'guard, NewValue> + { + let value_type_name = this.value_type_name; + + // The 'inner' field cannot be moved out of ReadGuard in a normal way since + // ReadGuard implements Drop + let inner = unsafe { std::ptr::read(&raw const this.inner) }; + + forget(this); + + MappedReadGuard { + inner: RwLockReadGuard::map(inner, func), + value_type_name: value_type_name, + } + } + pub fn try_map<NewValue>( this: Self, func: impl FnOnce(&Value) -> Option<&NewValue>, @@ -114,7 +133,7 @@ impl<'guard, Value> ReadGuard<'guard, Value> } } -impl<Value> Deref for ReadGuard<'_, Value> +impl<Value: ?Sized> Deref for ReadGuard<'_, Value> { type Target = Value; @@ -124,7 +143,7 @@ impl<Value> Deref for ReadGuard<'_, Value> } } -impl<Value> Drop for ReadGuard<'_, Value> +impl<Value: ?Sized> Drop for ReadGuard<'_, Value> { fn drop(&mut self) { @@ -133,13 +152,13 @@ impl<Value> Drop for ReadGuard<'_, Value> } #[derive(Debug)] -pub struct MappedReadGuard<'guard, Value> +pub struct MappedReadGuard<'guard, Value: ?Sized> { inner: MappedRwLockReadGuard<'guard, Value>, value_type_name: &'static str, } -impl<Value> Deref for MappedReadGuard<'_, Value> +impl<Value: ?Sized> Deref for MappedReadGuard<'_, Value> { type Target = Value; @@ -149,7 +168,7 @@ impl<Value> Deref for MappedReadGuard<'_, Value> } } -impl<Value> Drop for MappedReadGuard<'_, Value> +impl<Value: ?Sized> Drop for MappedReadGuard<'_, Value> { fn drop(&mut self) { @@ -161,14 +180,33 @@ impl<Value> Drop for MappedReadGuard<'_, Value> } #[derive(Debug)] -pub struct WriteGuard<'guard, Value> +pub struct WriteGuard<'guard, Value: ?Sized> { inner: RwLockWriteGuard<'guard, Value>, value_type_name: &'static str, } -impl<'guard, Value> WriteGuard<'guard, Value> +impl<'guard, Value: ?Sized> WriteGuard<'guard, Value> { + pub fn map<NewValue: ?Sized>( + this: Self, + func: impl FnOnce(&mut Value) -> &mut NewValue, + ) -> MappedWriteGuard<'guard, NewValue> + { + let value_type_name = this.value_type_name; + + // The 'inner' field cannot be moved out of ReadGuard in a normal way since + // ReadGuard implements Drop + let inner = unsafe { std::ptr::read(&raw const this.inner) }; + + forget(this); + + MappedWriteGuard { + inner: RwLockWriteGuard::map(inner, func), + value_type_name: value_type_name, + } + } + pub fn try_map<NewValue>( this: Self, func: impl FnOnce(&mut Value) -> Option<&mut NewValue>, @@ -193,7 +231,7 @@ impl<'guard, Value> WriteGuard<'guard, Value> } } -impl<Value> Deref for WriteGuard<'_, Value> +impl<Value: ?Sized> Deref for WriteGuard<'_, Value> { type Target = Value; @@ -203,7 +241,7 @@ impl<Value> Deref for WriteGuard<'_, Value> } } -impl<Value> DerefMut for WriteGuard<'_, Value> +impl<Value: ?Sized> DerefMut for WriteGuard<'_, Value> { fn deref_mut(&mut self) -> &mut Self::Target { @@ -211,7 +249,7 @@ impl<Value> DerefMut for WriteGuard<'_, Value> } } -impl<Value> Drop for WriteGuard<'_, Value> +impl<Value: ?Sized> Drop for WriteGuard<'_, Value> { fn drop(&mut self) { @@ -223,13 +261,13 @@ impl<Value> Drop for WriteGuard<'_, Value> } #[derive(Debug)] -pub struct MappedWriteGuard<'guard, Value> +pub struct MappedWriteGuard<'guard, Value: ?Sized> { inner: MappedRwLockWriteGuard<'guard, Value>, value_type_name: &'static str, } -impl<Value> Deref for MappedWriteGuard<'_, Value> +impl<Value: ?Sized> Deref for MappedWriteGuard<'_, Value> { type Target = Value; @@ -239,7 +277,7 @@ impl<Value> Deref for MappedWriteGuard<'_, Value> } } -impl<Value> DerefMut for MappedWriteGuard<'_, Value> +impl<Value: ?Sized> DerefMut for MappedWriteGuard<'_, Value> { fn deref_mut(&mut self) -> &mut Self::Target { @@ -247,7 +285,7 @@ impl<Value> DerefMut for MappedWriteGuard<'_, Value> } } -impl<Value> Drop for MappedWriteGuard<'_, Value> +impl<Value: ?Sized> Drop for MappedWriteGuard<'_, Value> { fn drop(&mut self) { |
