From 2d6f319e497f89665c92f78076adcfa5963db64b Mon Sep 17 00:00:00 2001 From: szagi3891 Date: Tue, 14 Apr 2026 09:38:09 +0200 Subject: [PATCH] Guard Value::set while graph is refreshing --- .../vertigo/src/computed/dependencies/mod.rs | 4 ++++ .../computed/dependencies/transaction_state.rs | 5 +++++ crates/vertigo/src/computed/value.rs | 18 ++++++++++++++++-- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/crates/vertigo/src/computed/dependencies/mod.rs b/crates/vertigo/src/computed/dependencies/mod.rs index 40c46324..6bb29d7a 100644 --- a/crates/vertigo/src/computed/dependencies/mod.rs +++ b/crates/vertigo/src/computed/dependencies/mod.rs @@ -40,6 +40,10 @@ pub fn get_dependencies() -> Rc { } impl Dependencies { + pub(crate) fn is_refreshing(&self) -> bool { + self.transaction_state.is_refreshing() + } + pub fn transaction R>(&self, func: F) -> R { self.transaction_state.up(); diff --git a/crates/vertigo/src/computed/dependencies/transaction_state.rs b/crates/vertigo/src/computed/dependencies/transaction_state.rs index 84e3b274..9d9bcb0d 100644 --- a/crates/vertigo/src/computed/dependencies/transaction_state.rs +++ b/crates/vertigo/src/computed/dependencies/transaction_state.rs @@ -25,6 +25,11 @@ impl TransactionState { } } + /// True while the graph is running client/computed refresh (after the outer transaction commits). + pub fn is_refreshing(&self) -> bool { + self.state.map(|state| matches!(state, State::Refreshing)) + } + pub fn up(&self) { let TransactionState { state } = self; diff --git a/crates/vertigo/src/computed/value.rs b/crates/vertigo/src/computed/value.rs index aab35356..afa3a418 100644 --- a/crates/vertigo/src/computed/value.rs +++ b/crates/vertigo/src/computed/value.rs @@ -108,7 +108,14 @@ impl Value { } pub fn change(&self, change_fn: impl FnOnce(&mut T)) { - get_dependencies().transaction(|ctx| { + let deps = get_dependencies(); + if deps.is_refreshing() { + log::error!( + "Ignoring Value::change while the dependency graph is refreshing; the change was not applied" + ); + return; + } + deps.transaction(|ctx| { let mut value = self.get(ctx); change_fn(&mut value); self.set(value); @@ -116,7 +123,14 @@ impl Value { } pub fn set(&self, value: T) { - get_dependencies().transaction(|_| { + let deps = get_dependencies(); + if deps.is_refreshing() { + log::error!( + "Ignoring Value::set while the dependency graph is refreshing (would corrupt scheduling); the write was not applied" + ); + return; + } + deps.transaction(|_| { let need_refresh = self.inner.set(value); if need_refresh { get_dependencies().report_set(self.inner.id);