diff options
author | HampusM <hampus@hampusmat.com> | 2024-04-10 22:45:35 +0200 |
---|---|---|
committer | HampusM <hampus@hampusmat.com> | 2024-04-10 22:45:35 +0200 |
commit | e028d89e15fd219854cbd7122d63ebd2fa37d390 (patch) | |
tree | 90a87429e3851bde1678a5902e96f8e61ef85f9c /ecs/src/sole.rs | |
parent | 50fb3122a2a141f1b78a874c139b097459a09408 (diff) |
feat(ecs): add weak ref single
Diffstat (limited to 'ecs/src/sole.rs')
-rw-r--r-- | ecs/src/sole.rs | 94 |
1 files changed, 84 insertions, 10 deletions
diff --git a/ecs/src/sole.rs b/ecs/src/sole.rs index e5166e9..014ab7d 100644 --- a/ecs/src/sole.rs +++ b/ecs/src/sole.rs @@ -2,8 +2,9 @@ use std::any::{type_name, Any, TypeId}; use std::fmt::Debug; use std::marker::PhantomData; use std::ops::{Deref, DerefMut}; +use std::sync::{Arc, Weak}; -use crate::lock::WriteGuard; +use crate::lock::{Lock, WriteGuard}; use crate::system::{NoInitParamFlag, Param as SystemParam, System}; use crate::tuple::FilterExclude as TupleFilterExclude; use crate::type_name::TypeName; @@ -51,9 +52,41 @@ impl TypeName for Box<dyn Sole> pub struct Single<'world, SoleT: Sole> { sole: WriteGuard<'world, Box<dyn Sole>>, + sole_weak: Weak<Lock<Box<dyn Sole>>>, _ph: PhantomData<SoleT>, } +impl<'world, SoleT> Single<'world, SoleT> +where + SoleT: Sole, +{ + /// Returns a struct which holds a weak reference to the [`World`] that `Single` + /// references and that can be used to aquire a new `Single` if the referenced + /// [`World`] is still alive. + #[must_use] + pub fn to_weak_ref(&self) -> SingleWeakRef<SoleT> + { + SingleWeakRef { + sole: self.sole_weak.clone(), + _ph: PhantomData, + } + } + + fn new(sole: &'world Arc<Lock<Box<dyn Sole>>>) -> Self + { + Self { + sole: sole.write_nonblock().unwrap_or_else(|_| { + panic!( + "Failed to aquire read-write lock to single component {}", + type_name::<SoleT>() + ) + }), + sole_weak: Arc::downgrade(sole), + _ph: PhantomData, + } + } +} + unsafe impl<'world, SoleT> SystemParam<'world> for Single<'world, SoleT> where SoleT: Sole, @@ -76,16 +109,9 @@ where let sole = world_data .sole_storage .get::<SoleT>() - .expect("Sole was not found in world") - .write_nonblock() - .unwrap_or_else(|_| { - panic!( - "Failed to aquire read-write lock to single component {}", - type_name::<SoleT>() - ) - }); + .expect("Sole was not found in world"); - Self { sole, _ph: PhantomData } + Self::new(sole) } fn is_compatible<Other: SystemParam<'world>>() -> bool @@ -128,6 +154,54 @@ where } } +#[derive(Debug, Clone)] +pub struct SingleWeakRef<SoleT> +where + SoleT: Sole, +{ + sole: Weak<Lock<Box<dyn Sole>>>, + _ph: PhantomData<SoleT>, +} + +impl<SoleT> SingleWeakRef<SoleT> +where + SoleT: Sole, +{ + /// Returns a struct which can be used to retrieve a [`Single`]. + /// + /// Returns [`None`] if the referenced [`World`] has been dropped. + #[must_use] + pub fn access(&self) -> Option<SingleRef<'_, SoleT>> + { + Some(SingleRef { + sole: self.sole.upgrade()?, + _pd: PhantomData, + }) + } +} + +/// Intermediate between [`Single`] and [`SingleWeakRef`]. Contains a strong reference to +/// a world which is not allowed direct access to. +#[derive(Debug, Clone)] +pub struct SingleRef<'weak_ref, SoleT> +where + SoleT: Sole, +{ + sole: Arc<Lock<Box<dyn Sole>>>, + _pd: PhantomData<&'weak_ref SoleT>, +} + +impl<'weak_ref, SoleT> SingleRef<'weak_ref, SoleT> +where + SoleT: Sole, +{ + #[must_use] + pub fn to_single(&self) -> Single<'_, SoleT> + { + Single::new(&self.sole) + } +} + struct Comparable { sole_type_id: TypeId, |