auto_invalidate 0.1.1

Automatic cache invalidation on mutable access using a guard pattern
Documentation
  • Coverage
  • 33.33%
    3 out of 9 items documented1 out of 9 items with examples
  • Size
  • Source code size: 29.7 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 1.96 MB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 15s Average build duration of successful builds.
  • all releases: 15s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • Repository
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • ericbreyer

auto_invalidate

Automatic cache invalidation on mutable access using a guard pattern.

Crates.io Documentation License

Overview

auto_invalidate provides a derive macro that wraps your structs with automatic cache invalidation. When you access the struct mutably through the as_mut() guard, all cache fields are automatically invalidated when the guard is dropped.

Usage

use auto_invalidate::cached;
use std::cell::OnceCell;

#[cached]
struct Squarer {
    value: i32,
    #[invalidate]
    cache: OnceCell<i32>,
}

impl Squarer {
    fn new(value: i32) -> Self {
        Self::build(value)
    }

    fn square(&self) -> i32 {
        *self.cache.get_or_init(|| self.value * self.value)
    }

    fn set(&mut self, value: i32) {
        // as_mut() returns a guard that invalidates on drop
        self.as_mut().value = value;
    }
}

fn main() {
    let mut squarer = Squarer::new(4);
    
    assert_eq!(squarer.square(), 16);  // Computed and cached
    assert_eq!(squarer.square(), 16);  // Retrieved from cache
    
    squarer.set(5);                    // Cache automatically invalidated
    
    assert_eq!(squarer.square(), 25);  // Recomputed
}

Features

Invalidation Modes

  • #[invalidate] or #[invalidate(take)] - Calls .take() on the field (works with Option, OnceCell, etc.)
  • #[invalidate(default)] - Replaces the field with Default::default()
  • #[invalidate(|c| expr)] - Custom invalidation logic
use std::cell::RefCell;
use std::collections::HashMap;

#[cached]
struct Cache {
    key: String,
    #[invalidate(|c| c.borrow_mut().clear())]
    data: RefCell<HashMap<String, i32>>,
}

Multiple Cache Fields

#[cached]
struct MultiCache {
    value: i32,
    #[invalidate]
    cache1: OnceCell<i32>,
    #[invalidate]
    cache2: OnceCell<i32>,
}

Generated build() Constructor

The macro always generates a build() constructor that takes non-cache fields as arguments and initializes cache fields to their defaults:

#[cached]
struct Example {
    value: i32,
    multiplier: f64,
    #[invalidate]
    cache: OnceCell<i32>,
}

// Generated: fn build(value: i32, multiplier: f64) -> Self
let e = Example::build(42, 2.0);

How It Works

The #[cached] macro transforms your struct:

  1. Renames your struct to {Name}Inner
  2. Creates a newtype wrapper {Name} that holds Cached<{Name}Inner>
  3. Implements Deref so you can access fields and methods transparently
  4. Provides as_mut() which returns a guard that invalidates caches on drop

License

Licensed under either of:

at your option.