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 {
33 inner: Rc::new(RefCell::new(value)),
34 }
35 }
36
37 /// Read the shared state.
38 ///
39 /// The guard borrows at run time, so holding one across a call that also
40 /// reads is fine and holding one across a call that *writes* panics. Keep
41 /// the guard short — usually one line, as in
42 /// `let seen = self.tally.get();`.
43 pub fn get(&self) -> Ref<'_, T> {
44 self.inner.borrow()
45 }
46
47 /// Modify the shared state.
48 pub fn get_mut(&self) -> RefMut<'_, T> {
49 self.inner.borrow_mut()
50 }
51
52 /// How many handles point at this state — the component's, the port's,
53 /// and any others.
54 pub fn handle_count(&self) -> usize {
55 Rc::strong_count(&self.inner)
56 }
57}
58
59impl<T> Clone for RustdvShared<T> {
60 fn clone(&self) -> Self {
61 RustdvShared {
62 inner: self.inner.clone(),
63 }
64 }
65}
66
67impl<T: Default> Default for RustdvShared<T> {
68 fn default() -> Self {
69 RustdvShared::new(T::default())
70 }
71}
72
73impl<T: fmt::Debug> fmt::Debug for RustdvShared<T> {
74 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75 write!(f, "RustdvShared({:?})", self.inner.borrow())
76 }
77}