correct dirty-checking on AsyncDerived

This commit is contained in:
Greg Johnston 2024-05-29 07:18:32 -04:00
parent 02f76dec35
commit e13b1561d8
3 changed files with 39 additions and 3 deletions

View file

@ -7,6 +7,7 @@ use crate::owner::Sandboxed;
use crate::{
channel::channel,
computed::suspense::SuspenseContext,
diagnostics::SpecialNonReactiveFuture,
graph::{
AnySource, AnySubscriber, ReactiveNode, Source, SourceSet, Subscriber,
SubscriberSet, ToAnySource, ToAnySubscriber,
@ -146,6 +147,7 @@ macro_rules! spawn_derived {
}
// notify reactive subscribers that we're now loading
inner.write().or_poisoned().dirty = true;
for sub in (&inner.read().or_poisoned().subscribers).into_iter() {
sub.mark_check();
}
@ -153,6 +155,7 @@ macro_rules! spawn_derived {
// generate and assign new value
let new_value = fut.await;
*value.write().or_poisoned() = AsyncState::Complete(new_value);
inner.write().or_poisoned().dirty = true;
ready_tx.send(());
// notify reactive subscribers that we're not loading any more
@ -244,7 +247,7 @@ impl<T: Send + Sync + 'static> ReadUntracked for ArcAsyncDerived<T> {
if matches!(&*self.value.read().or_poisoned(), AsyncState::Loading)
{
let handle = suspense_context.task_id();
let ready = self.ready();
let ready = SpecialNonReactiveFuture::new(self.ready());
Executor::spawn(async move {
ready.await;
drop(handle);

View file

@ -48,8 +48,8 @@ impl ReactiveNode for RwLock<ArcAsyncDerivedInner> {
guard.dirty = false;
return true;
}
drop(guard);
for source in sources.into_iter().flatten() {
if source.update_if_necessary() {
return true;

View file

@ -16,7 +16,13 @@ pub struct SpecialNonReactiveZone;
#[derive(Debug)]
pub struct SpecialNonReactiveZoneGuard;
use std::cell::Cell;
use pin_project_lite::pin_project;
use std::{
cell::Cell,
future::Future,
pin::Pin,
task::{Context, Poll},
};
thread_local! {
static IS_SPECIAL_ZONE: Cell<bool> = const { Cell::new(false) };
@ -46,6 +52,33 @@ impl Drop for SpecialNonReactiveZoneGuard {
}
}
pin_project! {
pub(crate) struct SpecialNonReactiveFuture<Fut> {
#[pin]
inner: Fut
}
}
impl<Fut> SpecialNonReactiveFuture<Fut> {
pub fn new(inner: Fut) -> Self {
Self { inner }
}
}
impl<Fut> Future for SpecialNonReactiveFuture<Fut>
where
Fut: Future,
{
type Output = Fut::Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
#[cfg(debug_assertions)]
let _rw = SpecialNonReactiveZone::enter();
let this = self.project();
this.inner.poll(cx)
}
}
thread_local! {
static SUPPRESS_RESOURCE_LOAD: Cell<bool> = const { Cell::new(false) };
}