Single Change Token

The SingleChangeToken behaves the same as the DefaultChangeToken with a single exception. It changes exactly once. Once SingleChangeToken::notify has been invoked, changed will always return true. Any registered callbacks will be invoked, at most, once. If a callback is registered after SingleChangeToken::notify has been called, it will never be invoked.

The design of a ChangeToken does not indicate whether it supports multiple notifications. As a result, consumers are likely to create new change tokens from producers often. SingleChangeToken tends to be the most commonly used change token. It guarantees at-most once execution and prevents change tokens from living longer than they need to.

use tokens::*;
use std::sync::{Arc, RwLock};

#[derive(Default)]
pub struct Counter {
    token: RwLock<SharedChangeToken<SingleChangeToken>>,
    value: RwLock<usize>,
}

impl Counter {
    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.value.read().unwrap())
    }
}

fn main() {
    let counter = Arc::new(Counter::default());
    let mut registration = counter.watch().register(
        Box::new(|state| {
            let printable = state.unwrap().downcast_ref::<Counter>().unwrap();
            println!("{}", printable.to_string());
        }),
        Some(counter.clone()));

    counter.increment(); // prints 'Value 1'
    counter.increment(); // doesn't print because token already fired

    registration = counter.watch().register(
        Box::new(|state| {
            let printable = state.unwrap().downcast_ref::<Counter>().unwrap();
            println!("{}", printable.to_string());
        }),
        Some(counter.clone()));

    counter.increment(); // prints 'Value 3'
}