diff options
author | HampusM <hampus@hampusmat.com> | 2025-01-05 22:03:34 +0100 |
---|---|---|
committer | HampusM <hampus@hampusmat.com> | 2025-01-05 22:03:34 +0100 |
commit | a44e663eb6d4aaf567dd35f2676014ba5aaa9e00 (patch) | |
tree | cd81d1f61b33e1905d6b3def851e5be18838556b /ecs | |
parent | cd385ddedc767c953f24109ec3ffe0a07d247ff5 (diff) |
feat(ecs): allow control over component mutability in query
Diffstat (limited to 'ecs')
-rw-r--r-- | ecs/examples/event_loop.rs | 6 | ||||
-rw-r--r-- | ecs/examples/extension.rs | 4 | ||||
-rw-r--r-- | ecs/examples/multiple_queries.rs | 4 | ||||
-rw-r--r-- | ecs/examples/optional_component.rs | 2 | ||||
-rw-r--r-- | ecs/examples/relationship.rs | 4 | ||||
-rw-r--r-- | ecs/examples/simple.rs | 2 | ||||
-rw-r--r-- | ecs/examples/with_local.rs | 4 | ||||
-rw-r--r-- | ecs/examples/with_sole.rs | 2 | ||||
-rw-r--r-- | ecs/src/component.rs | 143 | ||||
-rw-r--r-- | ecs/src/lib.rs | 11 | ||||
-rw-r--r-- | ecs/src/lock.rs | 11 | ||||
-rw-r--r-- | ecs/src/query.rs | 114 | ||||
-rw-r--r-- | ecs/src/relationship.rs | 41 | ||||
-rw-r--r-- | ecs/src/system.rs | 69 |
14 files changed, 222 insertions, 195 deletions
diff --git a/ecs/examples/event_loop.rs b/ecs/examples/event_loop.rs index c9f7757..2365eb0 100644 --- a/ecs/examples/event_loop.rs +++ b/ecs/examples/event_loop.rs @@ -21,7 +21,7 @@ struct Name name: &'static str, } -fn sheer(query: Query<(Wool, Name)>) +fn sheer(query: Query<(&mut Wool, &Name)>) { for (mut wool, name) in &query { if wool.remaining == 0 { @@ -37,7 +37,7 @@ fn sheer(query: Query<(Wool, Name)>) } } -fn feed(query: Query<(Health, Name)>) +fn feed(query: Query<(&mut Health, &Name)>) { for (mut health, name) in &query { health.health += 1; @@ -46,7 +46,7 @@ fn feed(query: Query<(Health, Name)>) } } -fn age(query: Query<(Health, Name)>, mut actions: Actions) +fn age(query: Query<(&mut Health, &Name)>, mut actions: Actions) { for (mut health, name) in &query { if health.health <= 2 { diff --git a/ecs/examples/extension.rs b/ecs/examples/extension.rs index ddde32c..f6282e1 100644 --- a/ecs/examples/extension.rs +++ b/ecs/examples/extension.rs @@ -20,8 +20,8 @@ enum EvilnessLevel } fn spawn_enemies( - spawner_query: Query<(EnemySpawnSource, Position)>, - enemies_query: Query<(EvilnessLevel,)>, + spawner_query: Query<(&EnemySpawnSource, &Position)>, + enemies_query: Query<(&EvilnessLevel,)>, mut actions: Actions, ) { diff --git a/ecs/examples/multiple_queries.rs b/ecs/examples/multiple_queries.rs index 1ae9d19..e0c957f 100644 --- a/ecs/examples/multiple_queries.rs +++ b/ecs/examples/multiple_queries.rs @@ -31,8 +31,8 @@ impl Display for EnemyName } fn do_attacks( - attacker_query: Query<(AttackStrength,)>, - enemy_query: Query<(Health, EnemyName)>, + attacker_query: Query<(&AttackStrength,)>, + enemy_query: Query<(&mut Health, &EnemyName)>, ) { for (attack_strength,) in &attacker_query { diff --git a/ecs/examples/optional_component.rs b/ecs/examples/optional_component.rs index bcc0c54..488dad2 100644 --- a/ecs/examples/optional_component.rs +++ b/ecs/examples/optional_component.rs @@ -21,7 +21,7 @@ pub struct CatName name: String, } -fn pet_cats(query: Query<(CatName, PettingCapacity, Option<Aggressivity>)>) +fn pet_cats(query: Query<(&CatName, &mut PettingCapacity, &Option<Aggressivity>)>) { for (cat_name, mut petting_capacity, aggressivity) in &query { let Some(aggressivity) = aggressivity else { diff --git a/ecs/examples/relationship.rs b/ecs/examples/relationship.rs index 1b3d1de..240884a 100644 --- a/ecs/examples/relationship.rs +++ b/ecs/examples/relationship.rs @@ -19,7 +19,9 @@ struct Health struct Holding; -fn print_player_stats(player_query: Query<(Player, Health, Relationship<Holding, Sword>)>) +fn print_player_stats( + player_query: Query<(&Player, &Health, &Relationship<Holding, Sword>)>, +) { for (_, health, sword_relationship) in &player_query { println!("Player health: {}", health.health); diff --git a/ecs/examples/simple.rs b/ecs/examples/simple.rs index 6429035..0169062 100644 --- a/ecs/examples/simple.rs +++ b/ecs/examples/simple.rs @@ -13,7 +13,7 @@ struct Greeting greeting: String, } -fn say_hello(query: Query<(SomeData, Greeting)>) +fn say_hello(query: Query<(&SomeData, &Greeting)>) { for (data, greeting) in &query { println!("{}: {}", greeting.greeting, data.num); diff --git a/ecs/examples/with_local.rs b/ecs/examples/with_local.rs index 0872dfc..4658fc0 100644 --- a/ecs/examples/with_local.rs +++ b/ecs/examples/with_local.rs @@ -21,7 +21,7 @@ struct SayHelloState cnt: usize, } -fn say_hello(query: Query<(SomeData,)>, mut state: Local<SayHelloState>) +fn say_hello(query: Query<(&SomeData,)>, mut state: Local<SayHelloState>) { for (data,) in &query { println!("Hello there. Count {}: {}", state.cnt, data.num); @@ -30,7 +30,7 @@ fn say_hello(query: Query<(SomeData,)>, mut state: Local<SayHelloState>) } } -fn say_whats_up(query: Query<(SomeData, Name)>, mut state: Local<SayHelloState>) +fn say_whats_up(query: Query<(&SomeData, &Name)>, mut state: Local<SayHelloState>) { for (data, name) in &query { println!( diff --git a/ecs/examples/with_sole.rs b/ecs/examples/with_sole.rs index 47aa0b3..689e562 100644 --- a/ecs/examples/with_sole.rs +++ b/ecs/examples/with_sole.rs @@ -15,7 +15,7 @@ struct AmmoCounter counter: u32, } -fn count_ammo(query: Query<(Ammo,)>, mut ammo_counter: Single<AmmoCounter>) +fn count_ammo(query: Query<(&Ammo,)>, mut ammo_counter: Single<AmmoCounter>) { for (ammo,) in &query { println!("Found {} ammo", ammo.ammo_left); diff --git a/ecs/src/component.rs b/ecs/src/component.rs index 1abb23c..4d37cb8 100644 --- a/ecs/src/component.rs +++ b/ecs/src/component.rs @@ -8,7 +8,7 @@ use crate::event::component::{ Kind as ComponentEventKind, Removed as ComponentRemovedEvent, }; -use crate::lock::{ReadGuard, WriteGuard}; +use crate::lock::{Error as LockError, Lock, ReadGuard, WriteGuard}; use crate::system::{ComponentRef, ComponentRefMut, Input as SystemInput}; use crate::type_name::TypeName; use crate::uid::Uid; @@ -26,11 +26,11 @@ pub trait Component: SystemInput + Any + TypeName where Self: Sized; - type RefMut<'component>: FromOptionalMut<'component> + type RefMut<'component>: FromOptionalMut<'component> + FromLockedOptional<'component> where Self: Sized; - type Ref<'component>: FromOptional<'component> + type Ref<'component>: FromOptional<'component> + FromLockedOptional<'component> where Self: Sized; @@ -163,14 +163,6 @@ impl<ComponentT> SystemInput for Option<ComponentT> where ComponentT: Component /// A sequence of components. pub trait Sequence { - type MutRefs<'component> - where - Self: 'component; - - type Refs<'component> - where - Self: 'component; - /// The number of components in this component sequence. const COUNT: usize; @@ -181,20 +173,43 @@ pub trait Sequence fn added_event_ids() -> Vec<Uid>; fn removed_event_ids() -> Vec<Uid>; +} - fn from_components_mut<'component>( - components: &'component [EntityComponent], - component_index_lookup: impl Fn(Uid) -> Option<usize>, - world: &'component World, - lock_component: fn(&EntityComponent) -> WriteGuard<'_, Box<dyn Component>>, - ) -> Self::MutRefs<'component>; +/// A sequence of references (immutable or mutable) to components. +pub trait RefSequence +{ + type Handles<'component>; + + fn metadata() -> impl Array<Metadata>; fn from_components<'component>( components: &'component [EntityComponent], component_index_lookup: impl Fn(Uid) -> Option<usize>, world: &'component World, - lock_component: fn(&EntityComponent) -> ReadGuard<'_, Box<dyn Component>>, - ) -> Self::Refs<'component>; + ) -> Self::Handles<'component>; +} + +/// A mutable or immutable reference to a component. +pub trait Ref +{ + type Component: Component; + type Handle<'component>: FromLockedOptional<'component>; +} + +impl<ComponentT> Ref for &ComponentT +where + ComponentT: Component, +{ + type Component = ComponentT; + type Handle<'component> = ComponentT::Ref<'component>; +} + +impl<ComponentT> Ref for &mut ComponentT +where + ComponentT: Component, +{ + type Component = ComponentT; + type Handle<'component> = ComponentT::RefMut<'component>; } /// [`Component`] metadata. @@ -261,6 +276,14 @@ pub trait FromOptional<'comp> ) -> Self; } +pub trait FromLockedOptional<'comp>: Sized +{ + fn from_locked_optional_component( + optional_component: Option<&'comp Lock<Box<dyn Component>>>, + world: &'comp World, + ) -> Result<Self, LockError>; +} + macro_rules! inner { ($c: tt) => { seq!(I in 0..=$c { @@ -269,12 +292,6 @@ macro_rules! inner { #(for<'comp> Comp~I::RefMut<'comp>: FromOptionalMut<'comp>,)* #(for<'comp> Comp~I::Ref<'comp>: FromOptional<'comp>,)* { - type MutRefs<'component> = (#(Comp~I::RefMut<'component>,)*) - where Self: 'component; - - type Refs<'component> = (#(Comp~I::Ref<'component>,)*) - where Self: 'component; - const COUNT: usize = $c + 1; fn into_vec(self) -> Vec<Box<dyn Component>> @@ -307,46 +324,40 @@ macro_rules! inner { #(ComponentRemovedEvent::<Comp~I>::id(),)* ] } + } - #[inline] - fn from_components_mut<'component>( - components: &'component [EntityComponent], - component_index_lookup: impl Fn(Uid) -> Option<usize>, - world: &'component World, - lock_component: - fn(&EntityComponent) -> WriteGuard<'_, Box<dyn Component>>, - ) -> Self::MutRefs<'component> + impl<#(CompRef~I: Ref,)*> RefSequence for (#(CompRef~I,)*) + { + type Handles<'component> = (#(CompRef~I::Handle<'component>,)*); + + fn metadata() -> impl Array<Metadata> { - (#( - Comp~I::RefMut::from_optional_mut_component( - component_index_lookup(Comp~I::Component::id()) - .and_then(|component_index| { - components.get(component_index) - .map(lock_component) - }), - world - ), - )*) + [#( + Metadata { + id: CompRef~I::Component::id(), + is_optional: CompRef~I::Component::is_optional(), + }, + )*] } - #[inline] fn from_components<'component>( components: &'component [EntityComponent], component_index_lookup: impl Fn(Uid) -> Option<usize>, world: &'component World, - lock_component: - fn(&EntityComponent) -> ReadGuard<'_, Box<dyn Component>>, - ) -> Self::Refs<'component> + ) -> Self::Handles<'component> { (#( - Comp~I::Ref::from_optional_component( - component_index_lookup(Comp~I::Component::id()) - .and_then(|component_index| { - components.get(component_index) - .map(lock_component) - }), - world - ), + CompRef~I::Handle::from_locked_optional_component( + component_index_lookup(CompRef~I::Component::id()) + .and_then(|component_index| components.get(component_index)) + .map(|component| &component.component), + world, + ).unwrap_or_else(|err| { + panic!( + "Taking component {} lock failed: {err}", + type_name::<CompRef~I::Component>() + ); + }), )*) } } @@ -360,9 +371,6 @@ seq!(C in 0..=16 { impl Sequence for () { - type MutRefs<'component> = (); - type Refs<'component> = (); - const COUNT: usize = 0; fn into_vec(self) -> Vec<Box<dyn Component>> @@ -384,25 +392,22 @@ impl Sequence for () { Vec::new() } +} - #[inline] - fn from_components_mut<'component>( - _components: &'component [EntityComponent], - _component_index_lookup: impl Fn(Uid) -> Option<usize>, - _world: &'component World, - _lock_component: fn(&EntityComponent) -> WriteGuard<'_, Box<dyn Component>>, - ) -> Self::MutRefs<'component> +impl RefSequence for () +{ + type Handles<'component> = (); + + fn metadata() -> impl Array<Metadata> { - () + [] } - #[inline] fn from_components<'component>( _components: &'component [EntityComponent], _component_index_lookup: impl Fn(Uid) -> Option<usize>, _world: &'component World, - _lock_component: fn(&EntityComponent) -> ReadGuard<'_, Box<dyn Component>>, - ) -> Self::Refs<'component> + ) -> Self::Handles<'component> { () } diff --git a/ecs/src/lib.rs b/ecs/src/lib.rs index ae5fd19..d217525 100644 --- a/ecs/src/lib.rs +++ b/ecs/src/lib.rs @@ -15,6 +15,7 @@ use crate::component::{ Component, IsOptional as ComponentIsOptional, Metadata as ComponentMetadata, + RefSequence as ComponentRefSequence, Sequence as ComponentSequence, }; use crate::entity::CREATE_STATIC_ENTITIES; @@ -175,7 +176,7 @@ impl World pub fn query<Comps, OptionsT>(&self) -> Query<Comps, OptionsT> where - Comps: ComponentSequence, + Comps: ComponentRefSequence, OptionsT: QueryOptions, { Query::new(self) @@ -236,7 +237,7 @@ impl World fn query_and_run_systems(&self, phase_euid: Uid) { let system_comps_query = - self.query::<(SystemComponent, Relationship<DependsOn, Phase>), ()>(); + self.query::<(&SystemComponent, &Relationship<DependsOn, Phase>), ()>(); let system_iter = system_comps_query.iter().filter(|(_, phase_rel)| { phase_rel @@ -254,7 +255,7 @@ impl World fn perform_child_phases(&self, parent_phase_euid: Uid) { - let phase_query = self.query::<(Phase, Relationship<ChildOf, Phase>), ()>(); + let phase_query = self.query::<(&Phase, &Relationship<ChildOf, Phase>), ()>(); for (index, (_, phase_rel)) in phase_query.iter().enumerate() { if !phase_rel @@ -277,7 +278,7 @@ impl World fn perform_phases(&self) { let phase_query = - self.query::<(Phase,), Not<With<Relationship<ChildOf, Phase>>>>(); + self.query::<(&Phase,), Not<With<Relationship<ChildOf, Phase>>>>(); for (index, (_,)) in phase_query.iter().enumerate() { let child_phase_euid = phase_query @@ -440,7 +441,7 @@ impl World fn emit_event_by_id(&self, event_id: Uid) { for (system,) in self - .query::<(SystemComponent,), ()>() + .query::<(&SystemComponent,), ()>() .iter_with_extra_comps([ComponentMetadata { id: event_id, is_optional: ComponentIsOptional::No, diff --git a/ecs/src/lock.rs b/ecs/src/lock.rs index fbc6842..135f654 100644 --- a/ecs/src/lock.rs +++ b/ecs/src/lock.rs @@ -28,7 +28,7 @@ where pub fn read_nonblock(&self) -> Result<ReadGuard<Value>, Error> { let guard = self.inner.try_read().or_else(|err| match err { - TryLockError::WouldBlock => Err(Error::Unavailable), + TryLockError::WouldBlock => Err(Error::ReadUnavailable), TryLockError::Poisoned(poison_err) => Ok(poison_err.into_inner()), })?; @@ -45,7 +45,7 @@ where pub fn write_nonblock(&self) -> Result<WriteGuard<Value>, Error> { let guard = self.inner.try_write().or_else(|err| match err { - TryLockError::WouldBlock => Err(Error::Unavailable), + TryLockError::WouldBlock => Err(Error::WriteUnavailable), TryLockError::Poisoned(poison_err) => Ok(poison_err.into_inner()), })?; @@ -69,8 +69,11 @@ where #[derive(Debug, thiserror::Error)] pub enum Error { - #[error("Lock is unavailable")] - Unavailable, + #[error("Lock is unavailable for reading")] + ReadUnavailable, + + #[error("Lock is unavailable for writing")] + WriteUnavailable, } #[derive(Debug)] diff --git a/ecs/src/query.rs b/ecs/src/query.rs index 68964eb..53d4b74 100644 --- a/ecs/src/query.rs +++ b/ecs/src/query.rs @@ -9,22 +9,21 @@ use crate::component::storage::{ Storage as ComponentStorage, }; use crate::component::{ - Component, Metadata as ComponentMetadata, - Sequence as ComponentSequence, + RefSequence as ComponentRefSequence, }; -use crate::lock::{ReadGuard, WriteGuard}; +use crate::lock::ReadGuard; use crate::query::options::Options; use crate::system::{Param as SystemParam, System}; use crate::uid::Uid; -use crate::{EntityComponent, World}; +use crate::World; pub mod options; #[derive(Debug)] pub struct Query<'world, Comps, OptionsT = ()> where - Comps: ComponentSequence, + Comps: ComponentRefSequence, { world: &'world World, component_storage: ReadGuard<'world, ComponentStorage>, @@ -33,38 +32,11 @@ where impl<'world, Comps, OptionsT> Query<'world, Comps, OptionsT> where - Comps: ComponentSequence, + Comps: ComponentRefSequence, OptionsT: Options, { /// Iterates over the entities matching this query. #[must_use] - pub fn iter_mut<'query>( - &'query self, - ) -> ComponentIterMut<'query, 'world, Comps, QueryEntityIter<'query>> - { - #[cfg(feature = "debug")] - tracing::debug!("Searching for {}", std::any::type_name::<Comps>()); - - #[allow(clippy::map_flatten)] - ComponentIterMut { - world: self.world, - entities: self - .component_storage - .iter_archetypes_with_comps(Comps::metadata()) - .map( - (|archetype| { - repeat_n(archetype, archetype.entity_cnt()) - .zip(archetype.entities()) - }) as ComponentIterMapFn, - ) - .flatten() - .filter(|(_, entity)| OptionsT::entity_filter(entity.components())), - comps_pd: PhantomData, - } - } - - /// Iterates over the entities matching this query. - #[must_use] pub fn iter<'query>( &'query self, ) -> ComponentIter<'query, 'world, Comps, QueryEntityIter<'query>> @@ -158,21 +130,21 @@ where impl<'query, 'world, Comps, OptionsT> IntoIterator for &'query Query<'world, Comps, OptionsT> where - Comps: ComponentSequence + 'world, + Comps: ComponentRefSequence + 'world, OptionsT: Options, { - type IntoIter = ComponentIterMut<'query, 'world, Comps, QueryEntityIter<'query>>; - type Item = Comps::MutRefs<'query>; + type IntoIter = ComponentIter<'query, 'world, Comps, QueryEntityIter<'query>>; + type Item = Comps::Handles<'query>; fn into_iter(self) -> Self::IntoIter { - self.iter_mut() + self.iter() } } impl<'world, Comps, OptionsT> SystemParam<'world> for Query<'world, Comps, OptionsT> where - Comps: ComponentSequence, + Comps: ComponentRefSequence, OptionsT: Options, { type Input = (); @@ -204,52 +176,6 @@ type QueryEntityIter<'query> = Filter< ComponentIterFilterFn, >; -pub struct ComponentIterMut<'query, 'world, Comps, EntityIter> -where - EntityIter: Iterator<Item = (&'query Archetype, &'query ArchetypeEntity)>, -{ - world: &'world World, - entities: EntityIter, - comps_pd: PhantomData<Comps>, -} - -impl<'query, 'world, Comps, EntityIter> Iterator - for ComponentIterMut<'query, 'world, Comps, EntityIter> -where - Comps: ComponentSequence + 'world, - EntityIter: Iterator<Item = (&'query Archetype, &'query ArchetypeEntity)>, - 'world: 'query, -{ - type Item = Comps::MutRefs<'query>; - - fn next(&mut self) -> Option<Self::Item> - { - let (archetype, entity) = self.entities.next()?; - - Some(Comps::from_components_mut( - entity.components(), - |component_uid| archetype.get_index_for_component(component_uid), - self.world, - lock_component_rw, - )) - } -} - -fn lock_component_rw( - entity_component: &EntityComponent, -) -> WriteGuard<'_, Box<dyn Component>> -{ - entity_component - .component - .write_nonblock() - .unwrap_or_else(|_| { - panic!( - "Failed to acquire read-write lock to component {}", - entity_component.name - ); - }) -} - pub struct ComponentIter<'query, 'world, Comps, EntityIter> where EntityIter: Iterator<Item = (&'query Archetype, &'query ArchetypeEntity)>, @@ -262,11 +188,11 @@ where impl<'query, 'world, Comps, EntityIter> Iterator for ComponentIter<'query, 'world, Comps, EntityIter> where - Comps: ComponentSequence + 'world, + Comps: ComponentRefSequence + 'world, EntityIter: Iterator<Item = (&'query Archetype, &'query ArchetypeEntity)>, 'world: 'query, { - type Item = Comps::Refs<'query>; + type Item = Comps::Handles<'query>; fn next(&mut self) -> Option<Self::Item> { @@ -276,22 +202,6 @@ where entity.components(), |component_uid| archetype.get_index_for_component(component_uid), self.world, - lock_component_ro, )) } } - -fn lock_component_ro( - entity_component: &EntityComponent, -) -> ReadGuard<'_, Box<dyn Component>> -{ - entity_component - .component - .read_nonblock() - .unwrap_or_else(|_| { - panic!( - "Failed to acquire read-write lock to component {}", - entity_component.name - ); - }) -} diff --git a/ecs/src/relationship.rs b/ecs/src/relationship.rs index 7088613..d136db4 100644 --- a/ecs/src/relationship.rs +++ b/ecs/src/relationship.rs @@ -6,10 +6,11 @@ use ecs_macros::Component; use crate::component::storage::Storage as ComponentStorage; use crate::component::{ Component, + FromLockedOptional as FromLockedOptionalComponent, FromOptional as FromOptionalComponent, FromOptionalMut as FromOptionalMutComponent, }; -use crate::lock::ReadGuard; +use crate::lock::{Error as LockError, Lock, ReadGuard}; use crate::system::{ComponentRef, ComponentRefMut}; use crate::uid::{Kind as UidKind, Uid}; use crate::World; @@ -103,6 +104,25 @@ where } } +impl<'rel_comp, Kind, ComponentT> FromLockedOptionalComponent<'rel_comp> + for RelationMut<'rel_comp, Kind, ComponentT> +where + ComponentT: Component, +{ + fn from_locked_optional_component( + optional_component: Option<&'rel_comp crate::lock::Lock<Box<dyn Component>>>, + world: &'rel_comp World, + ) -> Result<Self, LockError> + { + Ok(Self::from_optional_mut_component( + optional_component + .map(|lock| lock.write_nonblock()) + .transpose()?, + world, + )) + } +} + impl<'rel_comp, Kind, ComponentT> RelationMut<'rel_comp, Kind, ComponentT> where ComponentT: Component, @@ -307,6 +327,25 @@ where } } +impl<'rel_comp, Kind, ComponentT> FromLockedOptionalComponent<'rel_comp> + for Relation<'rel_comp, Kind, ComponentT> +where + ComponentT: Component, +{ + fn from_locked_optional_component( + optional_component: Option<&'rel_comp Lock<Box<dyn Component>>>, + world: &'rel_comp World, + ) -> Result<Self, LockError> + { + Ok(Self::from_optional_component( + optional_component + .map(|lock| lock.read_nonblock()) + .transpose()?, + world, + )) + } +} + impl<'rel_comp, Kind, ComponentT> Relation<'rel_comp, Kind, ComponentT> where ComponentT: Component, diff --git a/ecs/src/system.rs b/ecs/src/system.rs index 992fd69..a810741 100644 --- a/ecs/src/system.rs +++ b/ecs/src/system.rs @@ -10,10 +10,11 @@ use seq_macro::seq; use crate::component::{ Component, + FromLockedOptional as FromLockedOptionalComponent, FromOptional as FromOptionalComponent, FromOptionalMut as FromOptionalMutComponent, }; -use crate::lock::{ReadGuard, WriteGuard}; +use crate::lock::{Error as LockError, Lock, ReadGuard, WriteGuard}; use crate::tuple::{ReduceElement as TupleReduceElement, Tuple}; use crate::World; @@ -222,6 +223,23 @@ impl<'component, ComponentT: Component> FromOptionalMutComponent<'component> } } +impl<'component, ComponentT: Component> FromLockedOptionalComponent<'component> + for ComponentRefMut<'component, ComponentT> +{ + fn from_locked_optional_component( + optional_component: Option<&'component crate::lock::Lock<Box<dyn Component>>>, + world: &'component World, + ) -> Result<Self, LockError> + { + Ok(Self::from_optional_mut_component( + optional_component + .map(|lock| lock.write_nonblock()) + .transpose()?, + world, + )) + } +} + impl<'comp, ComponentT> FromOptionalMutComponent<'comp> for Option<ComponentRefMut<'comp, ComponentT>> where @@ -236,6 +254,22 @@ where } } +impl<'comp, ComponentT> FromLockedOptionalComponent<'comp> + for Option<ComponentRefMut<'comp, ComponentT>> +where + ComponentT: Component, +{ + fn from_locked_optional_component( + optional_component: Option<&'comp Lock<Box<dyn Component>>>, + _world: &'comp World, + ) -> Result<Self, LockError> + { + optional_component + .map(|lock| Ok(ComponentRefMut::new(lock.write_nonblock()?))) + .transpose() + } +} + impl<'a, ComponentT: Component> Deref for ComponentRefMut<'a, ComponentT> { type Target = ComponentT; @@ -289,6 +323,23 @@ impl<'component, ComponentT: Component> FromOptionalComponent<'component> } } +impl<'component, ComponentT: Component> FromLockedOptionalComponent<'component> + for ComponentRef<'component, ComponentT> +{ + fn from_locked_optional_component( + optional_component: Option<&'component crate::lock::Lock<Box<dyn Component>>>, + world: &'component World, + ) -> Result<Self, LockError> + { + Ok(Self::from_optional_component( + optional_component + .map(|lock| lock.read_nonblock()) + .transpose()?, + world, + )) + } +} + impl<'comp, ComponentT> FromOptionalComponent<'comp> for Option<ComponentRef<'comp, ComponentT>> where @@ -303,6 +354,22 @@ where } } +impl<'comp, ComponentT> FromLockedOptionalComponent<'comp> + for Option<ComponentRef<'comp, ComponentT>> +where + ComponentT: Component, +{ + fn from_locked_optional_component( + optional_component: Option<&'comp Lock<Box<dyn Component>>>, + _world: &'comp World, + ) -> Result<Self, LockError> + { + optional_component + .map(|lock| Ok(ComponentRef::new(lock.read_nonblock()?))) + .transpose() + } +} + impl<'a, ComponentT: Component> Deref for ComponentRef<'a, ComponentT> { type Target = ComponentT; |