[][src]Function moxie::cache_with

pub fn cache_with<Arg: ?Sized, Input, Output, Ret>(
    arg: &Arg,
    init: impl FnOnce(&Input) -> Output,
    with: impl FnOnce(&Output) -> Ret
) -> Ret where
    Arg: PartialEq<Input> + ToOwned<Owned = Input>,
    Input: Borrow<Arg> + 'static,
    Output: 'static,
    Ret: 'static, 

Cache the return of the init function.

If the cache has a stored (Input, Output) for the current topo::CallId and if arg is equal to the stored Input, marks the value as alive in the cache and returns the result of calling with on the stored Output.

Otherwise, calls arg.to_owned() to get an Input and calls init to get an Output. It calls with on the Output to get a Ret value, stores the (Input, Output) in the cache, and returns Ret.

Example

use moxie::{cache_with, runtime::RunLoop, testing::CountsClones};
use std::sync::atomic::{AtomicU64, Ordering};

let epoch = AtomicU64::new(0);
let num_created = AtomicU64::new(0);

// this runtime holds a single state variable
// which is reinitialized whenever we change `epoch` above
let mut rt = RunLoop::new(|| {
    let cached = cache_with(
        &epoch.load(Ordering::Relaxed),
        |_| {
            num_created.fetch_add(1, Ordering::Relaxed);
            CountsClones::default()
        },
        // this makes it equivalent to calling moxie::once(...)
        CountsClones::clone,
    );

    (num_created.load(Ordering::Relaxed), cached.clone_count())
});

for i in 1..1_000 {
    let (num_created, num_clones) = rt.run_once();
    assert_eq!(num_created, 1, "the first value is always cached");
    assert_eq!(num_clones, i, "cloned once per revision");
}

epoch.store(1, Ordering::Relaxed); // invalidates the cache

for i in 1..1_000 {
    let (num_created, num_clones) = rt.run_once();
    assert_eq!(num_created, 2, "reinitialized once after epoch changed");
    assert_eq!(num_clones, i, "cloned once per revision");
}

Environment Expectations

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