rustdv_methodology/shared.rs
1//! `RustdvShared<T>`: state two components can both see (D88).
2//!
3//! Analysis delivery has to be synchronous — the publisher calls `write` and
4//! every subscriber's handler runs before control comes back, with no
5//! `await` and no simulation time passing. But a subscriber's handler needs
6//! `&mut subscriber` while the publisher's `run` holds `&mut publisher`, and
7//! siblings in the tree cannot reach each other.
8//!
9//! The way out is to share the **state**, not the component. A subscriber
10//! keeps its tally in a `RustdvShared<T>`, hands a second handle to its port,
11//! and both see the same data. Delivery then mutates the tally without ever
12//! touching the component.
13//!
14//! The name is deliberate. This is not a general Rust facility — someone who
15//! goes looking for `Shared<T>` in the standard library will not find it — so
16//! it wears the framework's name and says where it comes from.
17
18use std::cell::{Ref, RefCell, RefMut};
19use std::fmt;
20use std::rc::Rc;
21
22/// A handle to state shared between a component and its analysis port.
23///
24/// Cloning gives another handle to the *same* state, the way `Rc` does — it
25/// does not copy the data.
26pub struct RustdvShared<T> {
27 inner: Rc<RefCell<T>>,
28}
29
30impl<T> RustdvShared<T> {
31 pub fn new(value: T) -> RustdvShared<T> {
32 RustdvShared { inner: Rc::new(RefCell::new(value)) }
33 }
34
35 /// Read the shared state.
36 ///
37 /// The guard borrows at run time, so holding one across a call that also
38 /// reads is fine and holding one across a call that *writes* panics. Keep
39 /// the guard short — usually one line, as in
40 /// `let seen = self.tally.get();`.
41 pub fn get(&self) -> Ref<'_, T> {
42 self.inner.borrow()
43 }
44
45 /// Modify the shared state.
46 pub fn get_mut(&self) -> RefMut<'_, T> {
47 self.inner.borrow_mut()
48 }
49
50 /// How many handles point at this state — the component's, the port's,
51 /// and any others.
52 pub fn handle_count(&self) -> usize {
53 Rc::strong_count(&self.inner)
54 }
55}
56
57impl<T> Clone for RustdvShared<T> {
58 fn clone(&self) -> Self {
59 RustdvShared { inner: self.inner.clone() }
60 }
61}
62
63impl<T: Default> Default for RustdvShared<T> {
64 fn default() -> Self {
65 RustdvShared::new(T::default())
66 }
67}
68
69impl<T: fmt::Debug> fmt::Debug for RustdvShared<T> {
70 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71 write!(f, "RustdvShared({:?})", self.inner.borrow())
72 }
73}