#[track]Expand description
Make a type trackable.
This attribute can be applied to an inherent implementation block or trait
definition. It implements the Track trait for the type or trait object.
Tracking immutably and mutably
This allows you to
-
call
track()on that type, producing aTracked<T>container. Used as an argument to a memoized function, these containers enjoy fine-grained access tracking instead of blunt hashing. -
call
track_mut()on that type, producing aTrackedMut<T>. For mutable arguments, tracking is the only option, so that comemo can replay the side effects when there is a cache hit.
If you attempt to track any mutable methods, your type must implement
[Clone] so that comemo can roll back attempted mutations which did not
result in a cache hit.
Restrictions
Tracked impl blocks or traits may not be generic and may only contain methods. Just like with memoized functions, certain restrictions apply to tracked methods:
-
The only obversable impurity tracked methods may exhibit are mutations through
&mut self. Comemo stops you from using basic mutable arguments and return values, but it cannot determine all sources of impurity, so this is your responsibility. Tracked methods also must not return mutable references or other types which allow untracked mutation. You are allowed to use interior mutability if it is not observable (even in immutable methods, as long as they stay idempotent). -
The return values of tracked methods must implement
Hashand must feed all the information they expose to the hasher. Otherwise, memoized results might get reused invalidly.
Furthermore:
- Tracked methods cannot be generic.
- They cannot be
unsafe,asyncorconst. - They must take an
&selfor&mut selfparameter. - Their arguments must implement
ToOwned. - Their return values must implement
Hash. - They cannot use destructuring patterns in their arguments.
Example
/// File storage.
struct Files(HashMap<PathBuf, String>);
#[comemo::track]
impl Files {
/// Load a file from storage.
fn read(&self, path: &str) -> String {
self.0.get(Path::new(path)).cloned().unwrap_or_default()
}
}
impl Files {
/// Write a file to storage.
fn write(&mut self, path: &str, text: &str) {
self.0.insert(path.into(), text.into());
}
}