Shared State Patterns
Rc RefCell Log
Share a Mutable Record
Rc<RefCell<T>> combines shared ownership with checked interior mutation for single-threaded state.
Program
Play the program to choose an event and append it through a cloned owner.
rc_refcell_log.rs
Replay: real traced execution (multi-file project)
use std::cell::RefCell;
use std::rc::Rc;
fn main() {
let event = "render";
let log = Rc::new(RefCell::new(Vec::new()));
let worker = Rc::clone(&log);
record(&log, "start");
record(&worker, event);
let joined = log.borrow().join(",");
println!("{} owners={}", joined, Rc::strong_count(&log));
}
fn record(log: &Rc<RefCell<Vec<&'static str>>>, event: &'static str) {
log.borrow_mut().push(event);
}
use std::cell::RefCell;
use std::rc::Rc;
fn main() {
let event = "trace";
let log = Rc::new(RefCell::new(Vec::new()));
let worker = Rc::clone(&log);
record(&log, "start");
record(&worker, event);
let joined = log.borrow().join(",");
println!("{} owners={}", joined, Rc::strong_count(&log));
}
fn record(log: &Rc<RefCell<Vec<&'static str>>>, event: &'static str) {
log.borrow_mut().push(event);
}
use std::cell::RefCell;
use std::rc::Rc;
fn main() {
let event = "publish";
let log = Rc::new(RefCell::new(Vec::new()));
let worker = Rc::clone(&log);
record(&log, "start");
record(&worker, event);
let joined = log.borrow().join(",");
println!("{} owners={}", joined, Rc::strong_count(&log));
}
fn record(log: &Rc<RefCell<Vec<&'static str>>>, event: &'static str) {
log.borrow_mut().push(event);
}
event ← "render", log ← RefCell { value: [] }, worker ← RefCell { value: [] }
4fn main() {5 let even→ "render"t = "render"; //@event="render", "trace", "publish"6 let lo→ RefCell { value: [] }g = Rc::new(RefCell::new(Vec::new()));7 let worke→ RefCell { value: [] }r = Rc::clone(&loRefCell { value: [] }g);8 record(&log, "start");fn record(log: &Rc<RefCell<Vec<&'static str>>>, event: &'static str)
pass 1 of 214fn record(log: &Rc<RefCell<Vec<&'static str>>>, event: &'static str) {15 log.borrow_mut().push(event);16}joined ← "start,render"
pass 2 of 29 record(&worker, event);10 let joine→ "start,render"d = log.borrow().join(",");11 println!("{} owners={}", joined, Rc::strong_count(&log));12}1314fn record(log: &Rc<RefCell<Vec<&'static str>>>, event: &'static str) {15 log.borrow_mut().push(event);16}outputstart,render owners=2
event ← "trace", log ← RefCell { value: [] }, worker ← RefCell { value: [] }
4fn main() {5 let even→ "trace"t = "trace";6 let lo→ RefCell { value: [] }g = Rc::new(RefCell::new(Vec::new()));7 let worke→ RefCell { value: [] }r = Rc::clone(&loRefCell { value: [] }g);8 record(&log, "start");fn record(log: &Rc<RefCell<Vec<&'static str>>>, event: &'static str)
pass 1 of 214fn record(log: &Rc<RefCell<Vec<&'static str>>>, event: &'static str) {15 log.borrow_mut().push(event);16}joined ← "start,trace"
pass 2 of 29 record(&worker, event);10 let joine→ "start,trace"d = log.borrow().join(",");11 println!("{} owners={}", joined, Rc::strong_count(&log));12}1314fn record(log: &Rc<RefCell<Vec<&'static str>>>, event: &'static str) {15 log.borrow_mut().push(event);16}outputstart,trace owners=2
event ← "publish", log ← RefCell { value: [] }, worker ← RefCell { value: [] }
4fn main() {5 let even→ "publish"t = "publish";6 let lo→ RefCell { value: [] }g = Rc::new(RefCell::new(Vec::new()));7 let worke→ RefCell { value: [] }r = Rc::clone(&loRefCell { value: [] }g);8 record(&log, "start");fn record(log: &Rc<RefCell<Vec<&'static str>>>, event: &'static str)
pass 1 of 214fn record(log: &Rc<RefCell<Vec<&'static str>>>, event: &'static str) {15 log.borrow_mut().push(event);16}joined ← "start,publish"
pass 2 of 29 record(&worker, event);10 let joine→ "start,publish"d = log.borrow().join(",");11 println!("{} owners={}", joined, Rc::strong_count(&log));12}1314fn record(log: &Rc<RefCell<Vec<&'static str>>>, event: &'static str) {15 log.borrow_mut().push(event);16}outputstart,publish owners=2
Rc
`Rc` gives multiple owners of the same single-threaded value.
RefCell
`RefCell` checks borrow rules at runtime so the log can be mutated through shared owners.
shared log
Both `log` and `worker` point to the same vector, so both records appear together.