incremental/
var.rs

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
20// For the delayed variable set list (set_during_stabilisation).
21// We use Weak to ensure we don't interfere with the manual
22// Rc-cycle-breaking on public::Var.
23pub(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 it's None, then we were simply pushed onto the
36        // value_set_during_stabilisation stack twice. So ignore.
37        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    // not used
62    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    // mutable for initialisation
81    pub(crate) node: RefCell<Option<Rc<Node>>>,
82    // mutable for initialisation
83    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                    // T: Default. So we can save a clone by writing e.g. an empty vec or map in there.
121                    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                    // T: Default. So we can save a clone by writing e.g. an empty vec or map in there.
130                    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                    // we have to clone, because we don't want to mem::take the value
136                    // that some nodes might still need to read during this stabilisation.
137                    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}