Function moxie_dom::prelude::cache_with [−][src]
pub fn cache_with<Arg, Input, Output, Ret>(
arg: &Arg,
init: impl FnOnce(&Input) -> Output,
with: impl FnOnce(&Output) -> Ret
) -> Ret where
Arg: PartialEq<Input> + ToOwned<Owned = Input> + ?Sized,
Input: 'static + Borrow<Arg>,
Output: 'static,
Ret: 'static,
Expand description
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