Function moxie::cache_with [−][src]
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:
Context