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; | 
