#[memoize]
Expand description
Memoize a function.
This attribute can be applied to free-standing functions as well as methods in inherent and trait impls.
§Kinds of arguments
Memoized functions can take three different kinds of arguments:
-
Hashed: This is the default. These arguments are hashed into a high-quality 128-bit hash, which is used as a cache key.
-
Immutably tracked: The argument is of the form
Tracked<T>
. These arguments enjoy fine-grained access tracking. This allows cache hits to occur even if the value ofT
is different than previously as long as the difference isn’t observed. -
Mutably tracked: The argument is of the form
TrackedMut<T>
. Through this type, you can safely mutate an argument from within a memoized function. If there is a cache hit, comemo will replay all mutations. Mutable tracked methods can also have return values that are tracked just like immutable methods.
§Restrictions
The following restrictions apply to memoized functions:
-
For the memoization to be correct, the
Hash
implementations of your arguments must feed all the information they expose to the hasher. Otherwise, memoized results might get reused invalidly. -
The only obversable impurity memoized functions may exhibit are mutations through
TrackedMut<T>
arguments. Comemo stops you from using basic mutable arguments, but it cannot determine all sources of impurity, so this is your responsibility. -
The output of a memoized function must be
Send
andSync
because it is stored in the global cache.
Furthermore, memoized functions cannot use destructuring patterns in their arguments.
§Example
/// Evaluate a `.calc` script.
#[comemo::memoize]
fn evaluate(script: &str, files: comemo::Tracked<Files>) -> i32 {
script
.split('+')
.map(str::trim)
.map(|part| match part.strip_prefix("eval ") {
Some(path) => evaluate(&files.read(path), files),
None => part.parse::<i32>().unwrap(),
})
.sum()
}