Composite Change Token
Some applications may need to compose or aggregate multiple change tokens. This is the use case for a CompositeChangeToken
. The CompositeChangeToken
accepts a sequence of other ChangeToken
instances and mediates their change notifications. A consumer of a CompositeChangeToken
will be called back via CompositeChangeToken::notify
whenever the owner explicitly signals a change or when one of the mediated children signals a change.
use tokens::*;
use std::sync::{Arc, RwLock};
pub struct Counter {
id: usize,
token: RwLock<SharedChangeToken<SingleChangeToken>>,
value: RwLock<usize>,
}
impl Counter {
pub fn new(id: usize) -> Self {
Self {
id,
..Default::default()
}
}
pub fn increment(&self) {
*self.value.write().unwrap() += 1;
let token = std::mem.replace(
&mut *self.token.write().unwrap(),
Default::default());
token.notify();
}
pub fn watch(&self) -> impl ChangeToken {
self.token.clone()
}
}
impl ToString for Counter {
fn to_string(&self) -> String {
format!("[{}] Value: {}", self.id, *self.value.read().unwrap())
}
}
fn main() {
let counters = Arc::new(vec![Counter::new(1), Counter::new(2), Counter::new(3)]);
let token = CompositeChangeToken::new(counters.iter().map(|c| Box::new(c.watch())));
let mut registration = token.register(
Box::new(|state| {
let printables = state.unwrap().downcast_ref::<Vec<Counter>>().unwrap();
for printable in printables {
println!("{}", printable.to_string());
}
}),
Some(counters.clone()));
// prints '[1] Value 0'
// prints '[2] Value 0'
// prints '[3] Value 1'
counters[2].increment();
}