1use core::fmt::Debug;
2use std::cell::{Cell, RefCell};
3use std::rc::{Rc, Weak};
4
5#[cfg(test)]
6use test_log::test;
7
8use super::node::{ErasedNode, Incremental, Node, NodeId};
9use super::stabilisation_num::StabilisationNum;
10use super::state::IncrStatus;
11use super::state::State;
12use super::CellIncrement;
13use super::Incr;
14use crate::boxes::{new_unsized, SmallBox};
15use crate::incrsan::NotObserver;
16use crate::kind::KindTrait;
17use crate::Value;
18use crate::ValueInternal;
19
20pub(crate) type WeakVar = Weak<dyn ErasedVariable>;
24
25pub(crate) trait ErasedVariable: Debug + NotObserver + KindTrait {
26 fn set_var_stabilise_end(&self);
27 fn id(&self) -> NodeId;
28 fn break_rc_cycle(&self);
29 fn set_at(&self) -> StabilisationNum;
30}
31
32impl<T: Value> ErasedVariable for Var<T> {
33 fn set_var_stabilise_end(&self) {
34 let v_opt = self.value_set_during_stabilisation.borrow_mut().take();
35 if let Some(v) = v_opt {
38 self.set_var_while_not_stabilising(v);
39 }
40 }
41 fn id(&self) -> NodeId {
42 self.node_id.get()
43 }
44 fn break_rc_cycle(&self) {
45 self.node.take();
46 }
47 fn set_at(&self) -> StabilisationNum {
48 self.set_at.get()
49 }
50}
51
52impl<T: Value> KindTrait for Var<T> {
53 fn compute(&self) -> SmallBox<dyn ValueInternal> {
54 new_unsized!((*self.value.borrow()).clone())
55 }
56
57 fn children_len(&self) -> usize {
58 0
59 }
60
61 fn iter_children_packed(&self) -> Box<dyn Iterator<Item = crate::NodeRef> + '_> {
63 Box::new(std::iter::empty())
64 }
65
66 fn slow_get_child(&self, _index: usize) -> crate::NodeRef {
67 panic!()
68 }
69
70 fn debug_ty(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
71 write!(f, "Var<{}>", std::any::type_name::<T>())
72 }
73}
74
75pub struct Var<T: Value> {
76 pub(crate) state: Weak<State>,
77 pub(crate) value: RefCell<T>,
78 pub(crate) value_set_during_stabilisation: RefCell<Option<T>>,
79 pub(crate) set_at: Cell<StabilisationNum>,
80 pub(crate) node: RefCell<Option<Rc<Node>>>,
82 pub(crate) node_id: Cell<NodeId>,
84}
85
86impl<T: Value> Debug for Var<T> {
87 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
88 f.debug_struct("Var")
89 .field("set_at", &self.set_at.get())
90 .field("value", &self.value.borrow())
91 .finish()
92 }
93}
94
95impl<T: Value> Var<T> {
96 pub(crate) fn erased(self: &Rc<Self>) -> WeakVar {
97 Rc::downgrade(self) as WeakVar
98 }
99
100 pub(crate) fn get(&self) -> T {
101 self.value.borrow().clone()
102 }
103
104 pub(crate) fn was_changed_during_stabilisation(&self) -> bool {
105 self.value_set_during_stabilisation
106 .borrow()
107 .as_ref()
108 .map_or(false, |during| self.value.borrow().ne(during))
109 }
110
111 pub(crate) fn update(self: &Rc<Self>, f: impl FnOnce(T) -> T)
112 where
113 T: Default,
114 {
115 let t = self.state.upgrade().unwrap();
116 match t.status.get() {
117 IncrStatus::NotStabilising | IncrStatus::RunningOnUpdateHandlers => {
118 {
119 let mut value = self.value.borrow_mut();
120 let taken = std::mem::take(&mut *value);
122 *value = f(taken);
123 }
124 self.did_set_var_while_not_stabilising();
125 }
126 IncrStatus::Stabilising => {
127 let mut delayed_slot = self.value_set_during_stabilisation.borrow_mut();
128 if let Some(delayed) = &mut *delayed_slot {
129 let taken = std::mem::take(delayed);
131 *delayed = f(taken);
132 } else {
133 let mut stack = t.set_during_stabilisation.borrow_mut();
134 stack.push(self.erased());
135 let cloned = (*self.value.borrow()).clone();
138 delayed_slot.replace(f(cloned));
139 }
140 }
141 };
142 }
143
144 pub(crate) fn replace_with(self: &Rc<Self>, f: impl FnOnce(&mut T) -> T) -> T {
145 let t = self.state.upgrade().unwrap();
146 match t.status.get() {
147 IncrStatus::NotStabilising | IncrStatus::RunningOnUpdateHandlers => {
148 let old = {
149 let v = &mut *self.value.borrow_mut();
150 let new = f(v);
151 std::mem::replace(v, new)
152 };
153 self.did_set_var_while_not_stabilising();
154 old
155 }
156 IncrStatus::Stabilising => {
157 let mut delayed_slot = self.value_set_during_stabilisation.borrow_mut();
158 if let Some(delayed) = &mut *delayed_slot {
159 let new = f(delayed);
160 std::mem::replace(delayed, new)
161 } else {
162 let mut stack = t.set_during_stabilisation.borrow_mut();
163 stack.push(self.erased());
164 let mut cloned = (*self.value.borrow()).clone();
165 let new = f(&mut cloned);
166 let old = std::mem::replace(&mut cloned, new);
167 delayed_slot.replace(cloned);
168 old
169 }
170 }
171 }
172 }
173
174 pub(crate) fn modify(self: &Rc<Self>, f: impl FnOnce(&mut T)) {
175 let t = self.state.upgrade().unwrap();
176 match t.status.get() {
177 IncrStatus::NotStabilising | IncrStatus::RunningOnUpdateHandlers => {
178 {
179 let mut v = self.value.borrow_mut();
180 f(&mut v);
181 }
182 self.did_set_var_while_not_stabilising();
183 }
184 IncrStatus::Stabilising => {
185 let mut v = self.value_set_during_stabilisation.borrow_mut();
186 if let Some(v) = &mut *v {
187 f(v);
188 } else {
189 let mut stack = t.set_during_stabilisation.borrow_mut();
190 stack.push(self.erased());
191 let mut cloned = (*self.value.borrow()).clone();
192 f(&mut cloned);
193 v.replace(cloned);
194 }
195 }
196 };
197 }
198
199 pub(crate) fn set(self: &Rc<Self>, value: T) {
200 let t = self.state.upgrade().unwrap();
201 match t.status.get() {
202 IncrStatus::RunningOnUpdateHandlers | IncrStatus::NotStabilising => {
203 self.set_var_while_not_stabilising(value);
204 }
205 IncrStatus::Stabilising => {
206 let mut v = self.value_set_during_stabilisation.borrow_mut();
207 if v.is_none() {
208 let mut stack = t.set_during_stabilisation.borrow_mut();
209 stack.push(self.erased());
210 }
211 *v = Some(value);
212 }
213 }
214 }
215
216 fn set_var_while_not_stabilising(&self, value: T) {
217 {
218 let mut value_slot = self.value.borrow_mut();
219 *value_slot = value;
220 }
221 self.did_set_var_while_not_stabilising();
222 }
223
224 fn did_set_var_while_not_stabilising(&self) {
225 let Some(watch) = self.node.borrow().clone() else {
226 panic!(
227 "uninitialised var or abandoned watch node (had {:?})",
228 self.node_id
229 )
230 };
231 let t = self.state.upgrade().unwrap();
232 t.num_var_sets.increment();
233 if self.set_at.get() < t.stabilisation_num.get() {
234 tracing::info!(
235 "variable set at t={:?}, current revision is t={:?}",
236 self.set_at.get().0,
237 t.stabilisation_num.get().0
238 );
239 self.set_at.set(t.stabilisation_num.get());
240 debug_assert!(watch.is_stale());
241 if watch.is_necessary() && !watch.is_in_recompute_heap() {
242 tracing::info!(
243 "inserting var watch into recompute heap at height {:?}",
244 watch.height()
245 );
246 t.recompute_heap.insert(watch.packed());
247 }
248 }
249 }
250
251 pub(crate) fn watch(&self) -> Incr<T> {
252 Incr {
253 node: self
254 .node
255 .borrow()
256 .clone()
257 .expect("var was not initialised")
258 .as_input(),
259 }
260 }
261}
262
263#[cfg(test)]
264thread_local! {
265 static DID_DROP: Cell<u32> = Cell::new(0);
266}
267
268#[cfg(test)]
269impl<T: Value> Drop for Var<T> {
270 fn drop(&mut self) {
271 tracing::trace!("Dropping var with id {:?}", self.node_id);
272 DID_DROP.with(|cell| cell.set(cell.get() + 1));
273 }
274}
275
276#[test]
277fn var_drop() {
278 DID_DROP.with(|cell| cell.set(0));
279 {
280 let incr = crate::IncrState::new();
281 println!("before var created");
282 let v = incr.var(10);
283 println!("before watch created");
284 let w = v.watch();
285 drop(v);
286 println!("watch created, public::Var dropped");
287 let o = w.observe();
288 incr.stabilise();
289 assert_eq!(o.try_get_value(), Ok(10));
290 }
291 assert_eq!(DID_DROP.with(|cell| cell.get()), 1);
292}
293
294#[test]
295fn var_drop_delayed() {
296 DID_DROP.with(|cell| cell.set(0));
297 {
298 let incr = crate::IncrState::new();
299 let v = incr.var(10);
300 let w = v.watch();
301 let c = incr.constant(9).bind(move |_| {
302 v.set(99);
303 w.clone()
304 });
305 let o = c.observe();
306 incr.stabilise();
307 assert_eq!(o.try_get_value(), Ok(10));
308 incr.stabilise();
309 assert_eq!(o.try_get_value(), Ok(99));
310 }
311 assert_eq!(DID_DROP.with(|cell| cell.get()), 1);
312}