fix: do not panic in automatic Track implementation if source is disposed (#2964)

This commit is contained in:
Greg Johnston 2024-09-12 09:22:46 -04:00 committed by GitHub
parent 4fa6660a3f
commit a083b57260
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 61 additions and 8 deletions

View file

@ -9,7 +9,7 @@ use reactive_graph::{
},
owner::use_context,
signal::guards::{AsyncPlain, ReadGuard},
traits::{DefinedAt, ReadUntracked},
traits::{DefinedAt, IsDisposed, ReadUntracked},
};
use send_wrapper::SendWrapper;
use std::{
@ -121,6 +121,13 @@ where
}
}
impl<T: 'static> IsDisposed for ArcLocalResource<T> {
#[inline(always)]
fn is_disposed(&self) -> bool {
false
}
}
impl<T: 'static> ToAnySource for ArcLocalResource<T> {
fn to_any_source(&self) -> AnySource {
self.data.to_any_source()
@ -292,6 +299,12 @@ where
}
}
impl<T: 'static> IsDisposed for LocalResource<T> {
fn is_disposed(&self) -> bool {
self.data.is_disposed()
}
}
impl<T: 'static> ToAnySource for LocalResource<T>
where
T: Send + Sync + 'static,

View file

@ -9,7 +9,7 @@ use crate::{
guards::{Mapped, Plain, ReadGuard},
ArcReadSignal, ArcRwSignal,
},
traits::{DefinedAt, Get, ReadUntracked},
traits::{DefinedAt, Get, IsDisposed, ReadUntracked},
};
use core::fmt::Debug;
use or_poisoned::OrPoisoned;
@ -260,6 +260,16 @@ where
}
}
impl<T: 'static, S> IsDisposed for ArcMemo<T, S>
where
S: Storage<T>,
{
#[inline(always)]
fn is_disposed(&self) -> bool {
false
}
}
impl<T: 'static, S> ToAnySource for ArcMemo<T, S>
where
S: Storage<T>,

View file

@ -18,7 +18,8 @@ use crate::{
ArcTrigger,
},
traits::{
DefinedAt, Notify, ReadUntracked, Track, UntrackableGuard, Writeable,
DefinedAt, IsDisposed, Notify, ReadUntracked, Track, UntrackableGuard,
Writeable,
},
transition::AsyncTransition,
};
@ -600,6 +601,13 @@ impl<T: 'static> Writeable for ArcAsyncDerived<T> {
}
}
impl<T: 'static> IsDisposed for ArcAsyncDerived<T> {
#[inline(always)]
fn is_disposed(&self) -> bool {
false
}
}
impl<T: 'static> ToAnySource for ArcAsyncDerived<T> {
fn to_any_source(&self) -> AnySource {
AnySource(

View file

@ -7,7 +7,8 @@ use crate::{
owner::{FromLocal, LocalStorage, Storage, StoredValue, SyncStorage},
signal::guards::{AsyncPlain, ReadGuard, WriteGuard},
traits::{
DefinedAt, Dispose, Notify, ReadUntracked, UntrackableGuard, Writeable,
DefinedAt, Dispose, IsDisposed, Notify, ReadUntracked,
UntrackableGuard, Writeable,
},
unwrap_signal,
};
@ -322,6 +323,16 @@ where
}
}
impl<T, S> IsDisposed for AsyncDerived<T, S>
where
T: 'static,
S: Storage<ArcAsyncDerived<T>>,
{
fn is_disposed(&self) -> bool {
self.inner.is_disposed()
}
}
impl<T, S> ToAnySource for AsyncDerived<T, S>
where
T: 'static,

View file

@ -1,10 +1,10 @@
use super::{node::ReactiveNode, AnySubscriber};
use crate::traits::DefinedAt;
use crate::traits::{DefinedAt, IsDisposed};
use core::{fmt::Debug, hash::Hash};
use std::{panic::Location, sync::Weak};
/// Abstracts over the type of any reactive source.
pub trait ToAnySource {
pub trait ToAnySource: IsDisposed {
/// Converts this type to its type-erased equivalent.
fn to_any_source(&self) -> AnySource;
}
@ -62,6 +62,13 @@ impl PartialEq for AnySource {
impl Eq for AnySource {}
impl IsDisposed for AnySource {
#[inline(always)]
fn is_disposed(&self) -> bool {
false
}
}
impl ToAnySource for AnySource {
fn to_any_source(&self) -> AnySource {
self.clone()

View file

@ -13,7 +13,7 @@ use crate::{
AnySource, AnySubscriber, ReactiveNode, Source, SubscriberSet,
ToAnySource,
},
traits::DefinedAt,
traits::{DefinedAt, IsDisposed},
unwrap_signal,
};
use or_poisoned::OrPoisoned;
@ -93,7 +93,7 @@ impl<T: AsSubscriberSet + DefinedAt> Source for T {
}
}
impl<T: AsSubscriberSet + DefinedAt> ToAnySource for T
impl<T: AsSubscriberSet + DefinedAt + IsDisposed> ToAnySource for T
where
T::Output: Borrow<Arc<RwLock<SubscriberSet>>>,
{

View file

@ -107,6 +107,10 @@ pub trait Track {
impl<T: Source + ToAnySource + DefinedAt> Track for T {
#[track_caller]
fn track(&self) {
if self.is_disposed() {
return;
}
if let Some(subscriber) = Observer::get() {
subscriber.add_source(self.to_any_source());
self.add_subscriber(subscriber);