Skip to content

Commit

Permalink
Changelog + README
Browse files Browse the repository at this point in the history
  • Loading branch information
schneems committed Jan 25, 2025
1 parent ec3a282 commit b23f4a5
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 9 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
## Unreleased

- Add `#[cache_diff(custom = <function>)]` to containers (structs) to allow for customizing + deriving diffs. (https://github.com/heroku-buildpacks/cache_diff/pull/6)
- Add: Allow annotating ignored fields with `#[cache_diff(ignore = "<reason>")]`. Using `ignore = "custom"` requires the container (struct) to implement `custom = <function>`. (https://github.com/heroku-buildpacks/cache_diff/pull/6)

## 1.0.1

- Fix: Multiple `#[derive(CachDiff)]` calls in the same file now work (https://github.com/heroku-buildpacks/cache_diff/pull/4)

## 1.0.0
Expand Down
65 changes: 61 additions & 4 deletions cache_diff/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,16 @@ When it returns an empty list, the two structs are identical.

You can manually implement the trait, or you can use the `#[derive(CacheDiff)]` macro to automatically generate the implementation.

Attributes are:
Top level struct configuration (Container attributes):

- `cache_diff(rename = "<new name>")` Specify custom name for the field
- `cache_diff(ignore)` Ignores the given field
- `cache_diff(display = <function>)` Specify a function to call to display the field
- `#[cache_diff(custom = <function>)]` Specify a function that receives references to both current and old values and returns a Vec of strings if there are any differences. This function is only called once. It can be in combination with `#[cache_diff(custom)]` on fields to combine multiple related fields into one diff (for example OS distribution and version) or to split apart a monolithic field into multiple differences (for example an "inventory" struct that contains a version and CPU architecture information).

Attributes for fields are:

- `#[cache_diff(rename = "<new name>")]` Specify custom name for the field
- `#[cache_diff(ignore)]` or `#[cache_diff(ignore = "<reason>")]` Ignores the given field with an optional comment string.
If the field is ignored because you're using a custom diff function (see container attributes) you can use
`cache_diff(ignore = "custom")` which will check that the container implements a custom function.

### Why

Expand Down Expand Up @@ -189,6 +194,58 @@ let diff = now.diff(&Metadata { version: NoDisplay("3.3.0".to_string())});
assert_eq!(diff.join(" "), "version (`custom 3.3.0` to `custom 3.4.0`)");
```

### Customize one or more field differences

You can provide a custom implementation for a diffing a subset of fields without having to roll your own implementation.

#### Custom logic for one field example

Here's an example where someone wants to bust the cache after N cache calls. Everything else other than `cache_usage_count` can be derived. If you want to keep the existing derived difference checks, but add on a custom one you can do it like this:

```rust
use cache_diff::CacheDiff;
const MAX: f32 = 200.0;

#[derive(Debug, CacheDiff)]
#[cache_diff(custom = diff_cache_usage_count)]
pub(crate) struct Metadata {
#[cache_diff(ignore = "custom")]
cache_usage_count: f32,

binary_version: String,
target_arch: String,
os_distribution: String,
os_version: String,
}

fn diff_cache_usage_count(_old: &Metadata, now: &Metadata) -> Vec<String> {
let Metadata {
cache_usage_count,
binary_version: _,
target_arch: _,
os_distribution: _,
os_version: _,
} = now;

if cache_usage_count > &MAX {
vec![format!("Cache count ({}) exceeded limit {MAX}", cache_usage_count)]
} else {
Vec::new()
}
}
```

In this example, four fields are derived automatically, saving us time, while one field is custom
using the `#[cache_diff(custom = diff_cache_usage_count)]` attribute on the struct. This tells
[CacheDiff] to call this function and pass in the old and current values. It expects a vector
with some strings if there is a difference and an empty vector if there are none.

Don't forget to "ignore" any fields you're implementing yourself. You can also use this feature to
combine several fields into a single diff output, for example using the previous struct, if
you only wanted to have one output for a combined `os_distribution` and `os_version` in one output
like "OS (ubuntu-22 to ubuntu-24)". Alternatively, you can use <https://github.com/schneems/magic_migrate> to
re-arrange your struct to only have one field with a custom display.

<!-- cargo-rdme end -->

## Releasing
Expand Down
10 changes: 5 additions & 5 deletions cache_diff/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@
//!
//! Top level struct configuration (Container attributes):
//!
//! - `#[cache_diff(custom = <function>)]` Specify a function that receives references to both current and old values and returns a Vec of strings if there are any differences. This function is only called once. It can be in combination with `#[cache_diff(custom)]` on fields to combine multiple related fields into one diff (for example OS distribution and version) or to split apart a monolithic field into multiple differences (for example an "inventory" struct that contains a version and CPU architecture information).
//! - `#[cache_diff(custom = <function>)]` Specify a function that receives references to both current and old values and returns a Vec of strings if there are any differences. This function is only called once. It can be in combination with `#[cache_diff(custom)]` on fields to combine multiple related fields into one diff (for example OS distribution and version) or to split apart a monolithic field into multiple differences (for example an "inventory" struct that contains a version and CPU architecture information).
//!
//! Attributes for fields are:
//!
//! - `#[cache_diff(rename = "<new name>")]` Specify custom name for the field
//! - `#[cache_diff(ignore)]` or `#[cache_diff(ignore = "<reason>")]` Ignores the given field with an optional comment string.
//! If the field is ignored because you're using a custom diff function (see container attributes) you can use
//! `cache_diff(ignore = "custom")` which will check that the container implements a custom function.
//! - `#[cache_diff(rename = "<new name>")]` Specify custom name for the field
//! - `#[cache_diff(ignore)]` or `#[cache_diff(ignore = "<reason>")]` Ignores the given field with an optional comment string.
//! If the field is ignored because you're using a custom diff function (see container attributes) you can use
//! `cache_diff(ignore = "custom")` which will check that the container implements a custom function.
//!
//! ## Why
//!
Expand Down

0 comments on commit b23f4a5

Please sign in to comment.