Function moxie::cache_state[][src]

pub fn cache_state<Arg, Input, Output>(
    arg: &Arg,
    init: impl FnOnce(&Input) -> Output
) -> (Commit<Output>, Key<Output>) where
    Arg: PartialEq<Input> + ToOwned<Owned = Input> + ?Sized,
    Input: Borrow<Arg> + 'static,
    Output: 'static, 
Expand description

Root a state variable at this callsite, returning a Key to the state variable. Re-initializes the state variable if the capture arg changes.

Example

use moxie::{cache_state, runtime::RunLoop, testing::BoolWaker};
use std::sync::atomic::{AtomicU64, Ordering};

let epoch = AtomicU64::new(0);

// this runtime holds a single state variable
// which is reinitialized whenever we change `epoch` above
let mut rt = RunLoop::new(|| cache_state(&epoch.load(Ordering::Relaxed), |e| *e));

let track_wakes = BoolWaker::new();
rt.set_state_change_waker(futures::task::waker(track_wakes.clone()));

let (first_commit, first_key) = rt.run_once();
assert_eq!(*first_commit, 0, "no updates yet");
assert!(!track_wakes.is_woken(), "no updates yet");

first_key.set(0); // this is a no-op
assert_eq!(*first_key, 0, "no updates yet");
assert!(!track_wakes.is_woken(), "no updates yet");

first_key.set(1);
assert_eq!(*first_key, 0, "update only enqueued, not yet committed");
assert!(track_wakes.is_woken());

let (second_commit, second_key) = rt.run_once(); // this commits the pending update
assert_eq!(*second_key, 1);
assert_eq!(*second_commit, 1);
assert_eq!(*first_commit, 0, "previous value still held by previous pointer");
assert!(!track_wakes.is_woken(), "wakes only come from updating state vars");
assert_eq!(first_key, second_key, "same state variable");

// start the whole thing over again
epoch.store(2, Ordering::Relaxed);

let (third_commit, third_key) = rt.run_once();
assert_ne!(third_key, second_key, "different state variable");

// the rest is repeated from above with slight modifications
assert_eq!(*third_commit, 2);
assert!(!track_wakes.is_woken());

third_key.set(2);
assert_eq!(*third_key, 2);
assert!(!track_wakes.is_woken());

third_key.set(3);
assert_eq!(*third_key, 2);
assert!(track_wakes.is_woken());

let (fourth_commit, fourth_key) = rt.run_once();
assert_eq!(*fourth_key, 3);
assert_eq!(*fourth_commit, 3);
assert_eq!(*third_commit, 2);
assert!(!track_wakes.is_woken());
assert_eq!(third_key, fourth_key);

Environment Expectations

This function requires the following types to be visible to illicit::get and will panic otherwise:

  • Context