# auto_invalidate
Automatic cache invalidation on mutable access using a guard pattern.
[](https://crates.io/crates/auto_invalidate)
[](https://docs.rs/auto_invalidate)
[](LICENSE-MIT)
## 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
```rust
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
```rust
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
```rust
#[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:
```rust
#[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:
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.