Add cache_clear operation#200
Conversation
| // https://redis.io/commands/flushdb/ | ||
| let _: () = redis::cmd("FLUSHDB").query(&mut *conn)?; |
There was a problem hiding this comment.
Wouldn't this delete someone's entire redis db? I think a scan + delete would need to be done instead, using the self.namespace + self.prefix in the scan
There was a problem hiding this comment.
Oh I just assumed the Redis DB was already unique per cache. I can fix this.
There was a problem hiding this comment.
I took a shot at it but needing two connections seems weird. scan_match needs &mut self, though, so I can't do anything with the deserialized values without opening another connection or collecting them all into memory first.
https://docs.rs/redis/latest/redis/trait.Commands.html#method.scan_match
There was a problem hiding this comment.
Any plans to merge this?
There was a problem hiding this comment.
Took a while, but I reimplemented this with the scan + delete strategy. Should be ready now?
|
Hi all, is there any development regarding this feature? Was it possibly added in some other PR? I am looking for a way to clear the redis cache. |
228daae to
6cdcd56
Compare
6cdcd56 to
7d2342b
Compare
|
@LucaCappelletti94 I just fixed up the merge conflicts and fixed up the async Redis |
…ext major) Second tranche of the next major (after the redb DiskCache rewrite). Bundles a set of breaking and additive changes. Macros: - `ttl_millis` attribute for sub-second TTLs, mutually exclusive with `ttl` (#149) - `force_refresh` attribute to bypass the cache per call (#146) - `in_impl` attribute to cache methods inside `impl` blocks / `self` receivers (#16, #140) - reference arguments (`&T`, `Option<&T>`) form the default key without `convert` (#202, #203) - generated code resolves the crate path via `proc-macro-crate`, so a renamed or re-exported `cached` dependency works (#157) - macro-introduced bindings are hygienically named, so arguments named `key` / `cache` / `result` no longer collide with generated code (#230, #114) - clear compile error for generic functions used without `key` + `convert` (#80) Traits and stores: - `get_or_set_with` / `try_get_or_set_with` (and the async variants) now return `&V` instead of `&mut V`, with new `*_mut` variants preserving the old behavior (#179) - new additive `SerializeCached` / `SerializeCachedAsync` traits (`cache_set_ref`) for serialize-backed stores; the redis/disk macro paths use the borrowed setter to avoid an extra clone (#196, #195) - `RedisCache` / `AsyncRedisCache` gain `cache_clear` / `async_cache_clear` (#200) - `LruCache::set_max_size` / `try_set_max_size` for resizing a live cache (#180) Redis: - TLS features split so rustls is selectable; `redis_tokio` / `redis_smol` no longer imply native-tls (add `*_native_tls` or `*_rustls`) (#231) Docs and process: - document floats as the canonical `convert` case (#78); add cache-invalidation and struct-method examples (#21, #236) - release workflow tags and creates a GitHub release on publish (#245) - fix a doctest under `--no-default-features` (#260) See docs/migrations/2.0-to-unreleased.md and the CHANGELOG for migration details.
…ext major) Second tranche of the next major (after the redb DiskCache rewrite). Bundles a set of breaking and additive changes. Macros: - `ttl_millis` attribute for sub-second TTLs, mutually exclusive with `ttl` (#149) - `force_refresh` attribute to bypass the cache per call (#146) - `in_impl` attribute to cache methods inside `impl` blocks / `self` receivers (#16, #140) - reference arguments (`&T`, `Option<&T>`) form the default key without `convert` (#202, #203) - generated code resolves the crate path via `proc-macro-crate`, so a renamed or re-exported `cached` dependency works (#157) - macro-introduced bindings are hygienically named, so arguments named `key` / `cache` / `result` no longer collide with generated code (#230, #114) - clear compile error for generic functions used without `key` + `convert` (#80) Traits and stores: - `get_or_set_with` / `try_get_or_set_with` (and the async variants) now return `&V` instead of `&mut V`, with new `*_mut` variants preserving the old behavior (#179) - new additive `SerializeCached` / `SerializeCachedAsync` traits (`cache_set_ref`) for serialize-backed stores; the redis/disk macro paths use the borrowed setter to avoid an extra clone (#196, #195) - `RedisCache` / `AsyncRedisCache` gain `cache_clear` / `async_cache_clear` (#200) - `LruCache::set_max_size` / `try_set_max_size` for resizing a live cache (#180) Redis: - TLS features split so rustls is selectable; `redis_tokio` / `redis_smol` no longer imply native-tls (add `*_native_tls` or `*_rustls`) (#231) Docs and process: - document floats as the canonical `convert` case (#78); add cache-invalidation and struct-method examples (#21, #236) - release workflow tags and creates a GitHub release on publish (#245) - fix a doctest under `--no-default-features` (#260) See docs/migrations/2.0-to-unreleased.md and the CHANGELOG for migration details.
…ext major) Second tranche of the next major (after the redb DiskCache rewrite). Bundles a set of breaking and additive changes. Macros: - `ttl_millis` attribute for sub-second TTLs, mutually exclusive with `ttl` (#149) - `force_refresh` attribute to bypass the cache per call (#146) - `in_impl` attribute to cache methods inside `impl` blocks / `self` receivers (#16, #140) - reference arguments (`&T`, `Option<&T>`) form the default key without `convert` (#202, #203) - generated code resolves the crate path via `proc-macro-crate`, so a renamed or re-exported `cached` dependency works (#157) - macro-introduced bindings are hygienically named, so arguments named `key` / `cache` / `result` no longer collide with generated code (#230, #114) - clear compile error for generic functions used without `key` + `convert` (#80) Traits and stores: - `get_or_set_with` / `try_get_or_set_with` (and the async variants) now return `&V` instead of `&mut V`, with new `*_mut` variants preserving the old behavior (#179) - new additive `SerializeCached` / `SerializeCachedAsync` traits (`cache_set_ref`) for serialize-backed stores; the redis/disk macro paths use the borrowed setter to avoid an extra clone (#196, #195) - `RedisCache` / `AsyncRedisCache` gain `cache_clear` / `async_cache_clear` (#200) - `LruCache::set_max_size` / `try_set_max_size` for resizing a live cache (#180) Redis: - TLS features split so rustls is selectable; `redis_tokio` / `redis_smol` no longer imply native-tls (add `*_native_tls` or `*_rustls`) (#231) Docs and process: - document floats as the canonical `convert` case (#78); add cache-invalidation and struct-method examples (#21, #236) - release workflow tags and creates a GitHub release on publish (#245) - fix a doctest under `--no-default-features` (#260) See docs/migrations/2.0-to-unreleased.md and the CHANGELOG for migration details.
…ext major) Second tranche of the next major (after the redb DiskCache rewrite). Bundles a set of breaking and additive changes. Macros: - `ttl_millis` attribute for sub-second TTLs, mutually exclusive with `ttl` (#149) - `force_refresh` attribute to bypass the cache per call (#146) - `in_impl` attribute to cache methods inside `impl` blocks / `self` receivers (#16, #140) - reference arguments (`&T`, `Option<&T>`) form the default key without `convert` (#202, #203) - generated code resolves the crate path via `proc-macro-crate`, so a renamed or re-exported `cached` dependency works (#157) - macro-introduced bindings are hygienically named, so arguments named `key` / `cache` / `result` no longer collide with generated code (#230, #114) - clear compile error for generic functions used without `key` + `convert` (#80) Traits and stores: - `get_or_set_with` / `try_get_or_set_with` (and the async variants) now return `&V` instead of `&mut V`, with new `*_mut` variants preserving the old behavior (#179) - new additive `SerializeCached` / `SerializeCachedAsync` traits (`cache_set_ref`) for serialize-backed stores; the redis/disk macro paths use the borrowed setter to avoid an extra clone (#196, #195) - `RedisCache` / `AsyncRedisCache` gain `cache_clear` / `async_cache_clear` (#200) - `LruCache::set_max_size` / `try_set_max_size` for resizing a live cache (#180) Redis: - TLS features split so rustls is selectable; `redis_tokio` / `redis_smol` no longer imply native-tls (add `*_native_tls` or `*_rustls`) (#231) Docs and process: - document floats as the canonical `convert` case (#78); add cache-invalidation and struct-method examples (#21, #236) - release workflow tags and creates a GitHub release for each published workspace crate on publish, via `bin/tag-release.sh` (root `cached` -> `vX.Y.Z`, subcrates -> `<crate-name>-vX.Y.Z`) (#245) - fix a doctest under `--no-default-features` (#260) See docs/migrations/2.0-to-unreleased.md and the CHANGELOG for migration details.
…ext major) Second tranche of the next major (after the redb DiskCache rewrite). Bundles a set of breaking and additive changes. Macros: - `ttl_millis` attribute for sub-second TTLs, mutually exclusive with `ttl` (#149) - `force_refresh` attribute to bypass the cache per call (#146) - `in_impl` attribute to cache methods inside `impl` blocks / `self` receivers (#16, #140) - reference arguments (`&T`, `Option<&T>`) form the default key without `convert` (#202, #203) - generated code resolves the crate path via `proc-macro-crate`, so a renamed or re-exported `cached` dependency works (#157) - macro-introduced bindings are hygienically named, so arguments named `key` / `cache` / `result` no longer collide with generated code (#230, #114) - clear compile error for generic functions used without `key` + `convert` (#80) Traits and stores: - `get_or_set_with` / `try_get_or_set_with` (and the async variants) now return `&V` instead of `&mut V`, with new `*_mut` variants preserving the old behavior (#179) - new additive `SerializeCached` / `SerializeCachedAsync` traits (`cache_set_ref`) for serialize-backed stores; the redis/disk macro paths use the borrowed setter to avoid an extra clone (#196, #195) - `RedisCache` / `AsyncRedisCache` gain `cache_clear` / `async_cache_clear` (#200) - `LruCache::set_max_size` / `try_set_max_size` for resizing a live cache (#180) Redis: - TLS features split so rustls is selectable; `redis_tokio` / `redis_smol` no longer imply native-tls (add `*_native_tls` or `*_rustls`) (#231) Docs and process: - document floats as the canonical `convert` case (#78); add cache-invalidation and struct-method examples (#21, #236) - release workflow tags and creates a GitHub release for each published workspace crate on publish, via `bin/tag-release.sh` (root `cached` -> `vX.Y.Z`, subcrates -> `<crate-name>-vX.Y.Z`) (#245) - fix a doctest under `--no-default-features` (#260) See docs/migrations/2.0-to-unreleased.md and the CHANGELOG for migration details.
…ext major) Second tranche of the next major (after the redb DiskCache rewrite). Bundles a set of breaking and additive changes. Macros: - `ttl_millis` attribute for sub-second TTLs, mutually exclusive with `ttl` (#149) - `force_refresh` attribute to bypass the cache per call (#146) - `in_impl` attribute to cache methods inside `impl` blocks / `self` receivers (#16, #140) - reference arguments (`&T`, `Option<&T>`) form the default key without `convert` (#202, #203) - generated code resolves the crate path via `proc-macro-crate`, so a renamed or re-exported `cached` dependency works (#157) - macro-introduced bindings are hygienically named, so arguments named `key` / `cache` / `result` no longer collide with generated code (#230, #114) - clear compile error for generic functions used without `key` + `convert` (#80) Traits and stores: - `get_or_set_with` / `try_get_or_set_with` (and the async variants) now return `&V` instead of `&mut V`, with new `*_mut` variants preserving the old behavior (#179) - new additive `SerializeCached` / `SerializeCachedAsync` traits (`cache_set_ref`) for serialize-backed stores; `#[concurrent_cached]` routes its set through an autoref shim that uses the borrowed setter for any store implementing the trait (built-in redis/disk or a custom `ty`/`create` store), avoiding a value clone (#196, #195) - `RedisCache` / `AsyncRedisCache` gain `cache_clear` / `async_cache_clear` (#200) - `LruCache::set_max_size` / `try_set_max_size` for resizing a live cache (#180) Redis: - TLS features split so rustls is selectable; `redis_tokio` / `redis_smol` no longer imply native-tls (add `*_native_tls` or `*_rustls`) (#231) Docs and process: - document floats as the canonical `convert` case (#78); add cache-invalidation and struct-method examples (#21, #236) - release workflow tags and creates a GitHub release for each published workspace crate on publish, via `bin/tag-release.sh` (root `cached` -> `vX.Y.Z`, subcrates -> `<crate-name>-vX.Y.Z`) (#245) - fix a doctest under `--no-default-features` (#260) See docs/migrations/2.0-to-unreleased.md and the CHANGELOG for migration details.
…ext major) Next-major batch (after the redb DiskCache rewrite). Bundles a set of breaking and additive changes plus the doc/test follow-ups. Macros: - `ttl_millis` attribute for sub-second TTLs, mutually exclusive with `ttl` (#149) - `force_refresh` attribute to bypass the cache per call, on all three macros (`#[cached]` / `#[concurrent_cached]` / `#[once]`); on `#[once]` it overwrites the single shared value (no per-call key, so no key-exclusion caveat) (#146) - `in_impl` attribute to cache methods inside `impl` blocks / `self` receivers (#16, #140) - reference arguments (`&T`, `Option<&T>`) form the default key without `convert` (#202, #203) - generated code resolves the crate path via `proc-macro-crate`, so a renamed or re-exported `cached` dependency works (#157) - macro-introduced bindings are hygienically named, so arguments named `key` / `cache` / `result` no longer collide with generated code (#230, #114) - clear compile error for generic functions used without `key` + `convert` (#80) - the shared `force_refresh` guard builder is factored into one helper Traits and stores: - `get_or_set_with` / `try_get_or_set_with` (and the async variants) now return `&V` instead of `&mut V`, with new `*_mut` variants preserving the old behavior (#179) - new additive `SerializeCached` / `SerializeCachedAsync` traits (`cache_set_ref`) for serialize-backed stores; `#[concurrent_cached]` routes its set through an autoref shim that uses the borrowed setter for any store implementing the trait (built-in redis/disk or a custom `ty`/`create` store), avoiding a value clone (#196, #195) - `RedisCache` / `AsyncRedisCache` gain `cache_clear` / `async_cache_clear` (#200) - `LruCache::set_max_size` / `try_set_max_size` for resizing a live cache (#180) Redis: - TLS features split so rustls is selectable; `redis_tokio` / `redis_smol` no longer imply native-tls (add `*_native_tls` or `*_rustls`) (#231) Docs and process: - document floats as the canonical `convert` case (#78); add cache-invalidation and struct-method examples (#21, #236) - release workflow tags and creates a GitHub release for each published workspace crate on publish, via `bin/tag-release.sh` (root `cached` -> `vX.Y.Z`, subcrates -> `<crate-name>-vX.Y.Z`) (#245); the CI tag-release git identity is scoped to `--local` - fix a doctest under `--no-default-features` (#260) - exclude internal dev tooling (.agents, .claude, .github, bin, docs/dev, AGENTS.md, CLAUDE.md) from the published crate via Cargo `exclude` - documentation accuracy pass: `ttl_millis` is valid with `result_fallback` and (on the in-memory path) needs `time_stores`; `in_impl` emits a same-visibility `{fn}_no_cache` cache-bypass sibling; wasm is incompatible with `redis_connection_manager` / `redis_async_cache`; Redis whole-second `ttl_millis` rounding; the `in_impl` shared-cache footgun; the async `V: Sync` clone-elision asymmetry; `CachedAsync` shared-ref default Send bounds; migration-guide `&mut V` -> `&V` coercion caveat - added coverage: async clone-elision clone-count assertions; `#[concurrent_cached]` `result_fallback` + `force_refresh`; `#[once]` `force_refresh`; generic `in_impl` rejection golden; `TtlSortedCache` shared-ref get-or-set delegation See docs/migrations/2.0-to-unreleased.md and the CHANGELOG for migration details.
…ext major) Next-major batch (after the redb DiskCache rewrite). Bundles a set of breaking and additive changes plus the doc/test follow-ups. Macros: - `ttl_millis` attribute for sub-second TTLs, mutually exclusive with `ttl` (#149); rejected alongside a `create` block like the other store-builder attributes - `force_refresh` attribute to bypass the cache per call, on all three macros (`#[cached]` / `#[concurrent_cached]` / `#[once]`); on `#[once]` it overwrites the single shared value (no per-call key, so no key-exclusion caveat) (#146) - `in_impl` attribute to cache methods inside `impl` blocks; `self`-receiver methods require `in_impl` (a `convert` block alone cannot rescue them, since the cache static cannot live at `impl` scope) and emit a same-visibility `{fn}_no_cache` cache-bypass sibling (#16, #140) - reference arguments (`&T`, `Option<&T>`) form the default key without `convert` (#202, #203) - generated code resolves the crate path via `proc-macro-crate`, so a renamed or re-exported `cached` dependency works (#157) - macro-introduced bindings are hygienically named, so arguments named `key` / `cache` / `result` no longer collide with generated code (#230, #114) - clear compile error for generic functions used without `key` + `convert` (#80) - the shared `force_refresh` guard builder is factored into one helper Traits and stores: - `get_or_set_with` / `try_get_or_set_with` (and the async variants) now return `&V` instead of `&mut V`, with new `*_mut` variants preserving the old behavior (#179) - new additive `SerializeCached` / `SerializeCachedAsync` traits (`cache_set_ref`) for serialize-backed stores; `#[concurrent_cached]` routes its set through an autoref shim that uses the borrowed setter for any store implementing the trait (built-in redis/disk or a custom `ty`/`create` store), avoiding a value clone (#196, #195) - `RedisCache` / `AsyncRedisCache` gain `cache_clear` / `async_cache_clear` (#200) - `LruCache::set_max_size` / `try_set_max_size` for resizing a live cache (#180) Redis: - TLS features split so rustls is selectable; `redis_tokio` / `redis_smol` no longer imply native-tls (add `*_native_tls` or `*_rustls`) (#231) Docs and process: - document floats as the canonical `convert` case (#78); add cache-invalidation and struct-method examples (#21, #236) - release workflow tags and creates a GitHub release for each published workspace crate on publish, via `bin/tag-release.sh` (root `cached` -> `vX.Y.Z`, subcrates -> `<crate-name>-vX.Y.Z`) (#245); the CI tag-release git identity is scoped to `--local` - fix a doctest under `--no-default-features` (#260) - exclude internal dev tooling (.agents, .claude, .github, bin, docs/dev, AGENTS.md, CLAUDE.md) from the published crate via Cargo `exclude` - documentation accuracy pass: `ttl_millis` is valid with `result_fallback` and (on the in-memory path) needs `time_stores`; on `#[cached]` the "honored exactly" claim is scoped to the default in-memory store; Redis rounds `ttl_millis` up to the next whole second (500ms -> 1s, 1500ms -> 2s); `in_impl` emits a same-visibility `{fn}_no_cache` sibling (documented on all three macros); `#[concurrent_cached]` `force_refresh` documents the `result_fallback` interaction; wasm is incompatible with `redis_connection_manager` / `redis_async_cache`; the `in_impl` shared-cache footgun; the async `V: Sync` clone-elision asymmetry, including how a `Send + !Sync + !Clone` value surfaces at the generated set site; `CachedAsync` shared-ref default Send bounds; `Cached::cache_get_or_set_with` / `cache_try_get_or_set_with` flagged as provided defaults; migration-guide `&mut V` -> `&V` coercion caveat - added coverage: async clone-elision clone-count assertions; `#[concurrent_cached]` `result_fallback` + `force_refresh`; `#[once]` `force_refresh`; `force_refresh` + `in_impl`; generic `in_impl` rejection golden; compile-fail goldens for `force_refresh`-unparseable on `#[once]` / `#[concurrent_cached]`, generic `#[concurrent_cached]` without `convert`, and `ttl_millis` + `create` conflict; `TtlSortedCache` shared-ref get-or-set delegation - macro-output polish: no dead `#[doc]` on the function-local `in_impl` cache static; documented rationale for `#[allow(dead_code)]` on the generated prime companion and for the `crate_path()` `::cached` fallback See docs/migrations/2.0-to-unreleased.md and the CHANGELOG for migration details.
…ext major) Next-major batch (after the redb DiskCache rewrite). Bundles a set of breaking and additive changes plus the doc/test follow-ups. Macros: - `ttl_millis` attribute for sub-second TTLs, mutually exclusive with `ttl` (#149); rejected alongside a `create` block like the other store-builder attributes - `force_refresh` attribute to bypass the cache per call, on all three macros (`#[cached]` / `#[concurrent_cached]` / `#[once]`); on `#[once]` it overwrites the single shared value (no per-call key, so no key-exclusion caveat). Combined with `result_fallback`, a force-refreshed `Err` still serves the previously cached `Ok`, and capturing that fallback leaves no read side effects on the bypassed entry (no TTL renewal, recency update, or hit-counter change) on both `#[cached]` and `#[concurrent_cached]` (#146) - `in_impl` attribute to cache methods inside `impl` blocks; `self`-receiver methods require `in_impl` (a `convert` block alone cannot rescue them, since the cache static cannot live at `impl` scope) and emit a `{fn}_no_cache` cache-bypass sibling, hidden from rustdoc via `#[doc(hidden)]` (#16, #140) - reference arguments (`&T`, `Option<&T>`) form the default key without `convert` (#202, #203) - generated code resolves the crate path via `proc-macro-crate`, so a renamed or re-exported `cached` dependency works (#157) - macro-introduced bindings are hygienically named, so arguments named `key` / `cache` / `result` no longer collide with generated code (#230, #114) - clear compile error for generic functions used without `key` + `convert` (#80) - the shared `force_refresh` guard builder is factored into one helper Traits and stores: - `get_or_set_with` / `try_get_or_set_with` (and the async variants) now return `&V` instead of `&mut V`, with new `*_mut` variants preserving the old behavior (#179) - new additive `SerializeCached` / `SerializeCachedAsync` traits (`cache_set_ref`) for serialize-backed stores; `#[concurrent_cached]` routes its set through an autoref shim that uses the borrowed setter for any store implementing the trait (built-in redis/disk or a custom `ty`/`create` store), avoiding a value clone (#196, #195) - `RedisCache` / `AsyncRedisCache` gain `cache_clear` / `async_cache_clear`, with `cache_reset` delegating to `cache_clear`; `RedisCacheBuilder` / `AsyncRedisCacheBuilder` `build()` reject an empty namespace+prefix scope (`EmptyScope`) so `cache_clear` cannot `SCAN MATCH *` the whole database (#200) - `RedbCacheBuilder::build()` validates `cache_name` as a filename component, returning `InvalidCacheName` for a path separator (`/` or `\`) or a path-traversal component (`.` / `..`) - `LruCache::set_max_size` / `try_set_max_size` for resizing a live cache, with matching methods on `LruTtlCache` and `ExpiringLruCache` (#180) - `ConcurrentCloneCached` gains a non-renewing `cache_peek_with_expiry_status` (used to capture a `result_fallback` stale value without read side effects) Redis: - TLS features split so rustls is selectable; `redis_tokio` / `redis_smol` no longer imply native-tls (add `*_native_tls` or `*_rustls`) (#231) Docs and process: - document floats as the canonical `convert` case (#78); add cache-invalidation and struct-method examples (#21, #236), the latter demonstrating `in_impl` - release workflow tags and creates a GitHub release for each published workspace crate on publish, via `bin/tag-release.sh` (root `cached` -> `vX.Y.Z`, subcrates -> `<crate-name>-vX.Y.Z`) (#245); the CI tag-release git identity is scoped to `--local` - fix a doctest under `--no-default-features` (#260) - exclude internal dev tooling (.agents, .claude, .github, bin, docs/dev, AGENTS.md, CLAUDE.md) from the published crate via Cargo `exclude` - dev tooling: pr-review shards reviewers across model-sized, randomized chunks (multiple of each type); pr-cycle fans fix application across disjoint sub-agents; AGENTS.md states README is generated from src/lib.rs via cargo-readme - documentation accuracy pass: `ttl_millis` is valid with `result_fallback` and (on the in-memory path) needs `time_stores`; on `#[cached]` the "honored exactly" claim is scoped to the default in-memory store; Redis rounds `ttl_millis` up to the next whole second (500ms -> 1s, 1500ms -> 2s); `in_impl` emits a `#[doc(hidden)]` `{fn}_no_cache` sibling (documented on all three macros); `#[concurrent_cached]` `force_refresh` documents the `result_fallback` interaction; the `#[concurrent_cached]` attribute table reaches parity with `#[cached]` (ttl_millis / force_refresh / in_impl rows); wasm is incompatible with `redis_connection_manager` / `redis_async_cache`; the `in_impl` shared-cache footgun; the async `V: Sync` clone-elision asymmetry, including how a `Send + !Sync + !Clone` value surfaces at the generated set site; `CachedAsync` shared-ref default Send bounds; `Cached::cache_get_or_set_with` / `cache_try_get_or_set_with` flagged as provided defaults; migration-guide `&mut V` -> `&V` coercion caveat - added coverage: async clone-elision clone-count assertions; `#[concurrent_cached]` `result_fallback` + `force_refresh` (including the no-read-side-effects bypass); `#[once]` `force_refresh`; `force_refresh` + `in_impl`; generic `in_impl` rejection goldens for `#[cached]` (free fn) and `#[concurrent_cached]` (in_impl method); compile-fail goldens for `force_refresh`-unparseable on `#[once]` / `#[concurrent_cached]`, generic `#[concurrent_cached]` without `convert`, and `ttl_millis` + `create` conflict; `_mut` trait coverage on `ExpiringCache` / `TtlSortedCache`; redis `cache_clear` / `cache_set_ref` and redb `cache_set_ref` round-trips; `TtlSortedCache` shared-ref get-or-set delegation - macro-output polish: ASCII-only macro diagnostics; no dead `#[doc]` on the function-local `in_impl` cache static; documented rationale for `#[allow(dead_code)]` on the generated prime companion and for the `crate_path()` `::cached` fallback See docs/migrations/2.0-to-unreleased.md and the CHANGELOG for migration details.
…ext major) Next-major batch (after the redb DiskCache rewrite). Bundles a set of breaking and additive changes plus the doc/test follow-ups. Macros: - `ttl_millis` attribute for sub-second TTLs, mutually exclusive with `ttl` (#149); rejected alongside a `create` block like the other store-builder attributes - `force_refresh` attribute to bypass the cache per call, on all three macros (`#[cached]` / `#[concurrent_cached]` / `#[once]`); on `#[once]` it overwrites the single shared value (no per-call key, so no key-exclusion caveat). Combined with `result_fallback`, a force-refreshed `Err` still serves the previously cached `Ok`, and capturing that fallback leaves no read side effects on the bypassed entry (no TTL renewal, recency update, or hit-counter change) on both `#[cached]` and `#[concurrent_cached]` (#146) - `in_impl` attribute to cache methods inside `impl` blocks; `self`-receiver methods require `in_impl` (a `convert` block alone cannot rescue them, since the cache static cannot live at `impl` scope) and emit a `{fn}_no_cache` cache-bypass sibling, hidden from rustdoc via `#[doc(hidden)]` (#16, #140) - reference arguments (`&T`, `Option<&T>`) form the default key without `convert` (#202, #203) - generated code resolves the crate path via `proc-macro-crate`, so a renamed or re-exported `cached` dependency works (#157) - macro-introduced bindings are hygienically named, so arguments named `key` / `cache` / `result` no longer collide with generated code (#230, #114) - clear compile error for generic functions used without `key` + `convert` (#80) - the shared `force_refresh` guard builder is factored into one helper Traits and stores: - `get_or_set_with` / `try_get_or_set_with` (and the async variants) now return `&V` instead of `&mut V`, with new `*_mut` variants preserving the old behavior (#179) - new additive `SerializeCached` / `SerializeCachedAsync` traits (`cache_set_ref`) for serialize-backed stores; `#[concurrent_cached]` routes its set through an autoref shim that uses the borrowed setter for any store implementing the trait (built-in redis/disk or a custom `ty`/`create` store), avoiding a value clone (#196, #195) - `RedisCache` / `AsyncRedisCache` gain `cache_clear` / `async_cache_clear`, with `cache_reset` delegating to `cache_clear`; `RedisCacheBuilder` / `AsyncRedisCacheBuilder` `build()` reject an empty namespace+prefix scope (`EmptyScope`) so `cache_clear` cannot `SCAN MATCH *` the whole database (#200) - `RedbCacheBuilder::build()` validates `cache_name` as a filename component, returning `InvalidCacheName` for a path separator (`/` or `\`) or a path-traversal component (`.` / `..`) - `LruCache::set_max_size` / `try_set_max_size` for resizing a live cache, with matching methods on `LruTtlCache` and `ExpiringLruCache` (#180) - `ConcurrentCloneCached` gains a non-renewing `cache_peek_with_expiry_status` (used to capture a `result_fallback` stale value without read side effects) Redis: - TLS features split so rustls is selectable; `redis_tokio` / `redis_smol` no longer imply native-tls (add `*_native_tls` or `*_rustls`) (#231) Docs and process: - document floats as the canonical `convert` case (#78); add cache-invalidation and struct-method examples (#21, #236), the latter demonstrating `in_impl` - release workflow tags and creates a GitHub release for each published workspace crate on publish, via `bin/tag-release.sh` (root `cached` -> `vX.Y.Z`, subcrates -> `<crate-name>-vX.Y.Z`) (#245); the CI tag-release git identity is scoped to `--local` - fix a doctest under `--no-default-features` (#260) - exclude internal dev tooling (.agents, .claude, .github, bin, docs/dev, AGENTS.md, CLAUDE.md) from the published crate via Cargo `exclude` - dev tooling: pr-review shards reviewers across model-sized, randomized chunks (multiple of each type); pr-cycle fans fix application across disjoint sub-agents; AGENTS.md states README is generated from src/lib.rs via cargo-readme - documentation accuracy pass: `ttl_millis` is valid with `result_fallback` and (on the in-memory path) needs `time_stores`; on `#[cached]` the "honored exactly" claim is scoped to the default in-memory store; Redis rounds `ttl_millis` up to the next whole second (500ms -> 1s, 1500ms -> 2s); `in_impl` emits a `#[doc(hidden)]` `{fn}_no_cache` sibling (documented on all three macros); `#[concurrent_cached]` `force_refresh` documents the `result_fallback` interaction; the `#[concurrent_cached]` attribute table reaches parity with `#[cached]` (ttl_millis / force_refresh / in_impl rows); wasm is incompatible with `redis_connection_manager` / `redis_async_cache`; the `in_impl` shared-cache footgun; the async `V: Sync` clone-elision asymmetry, including how a `Send + !Sync + !Clone` value surfaces at the generated set site; `CachedAsync` shared-ref default Send bounds; `Cached::cache_get_or_set_with` / `cache_try_get_or_set_with` flagged as provided defaults; migration-guide `&mut V` -> `&V` coercion caveat - added coverage: async clone-elision clone-count assertions; `#[concurrent_cached]` `result_fallback` + `force_refresh` (including the no-read-side-effects bypass); `#[once]` `force_refresh`; `force_refresh` + `in_impl`; generic `in_impl` rejection goldens for `#[cached]` (free fn) and `#[concurrent_cached]` (in_impl method); compile-fail goldens for `force_refresh`-unparseable on `#[once]` / `#[concurrent_cached]`, generic `#[concurrent_cached]` without `convert`, and `ttl_millis` + `create` conflict; `_mut` trait coverage on `ExpiringCache` / `TtlSortedCache`; redis `cache_clear` / `cache_set_ref` and redb `cache_set_ref` round-trips; `TtlSortedCache` shared-ref get-or-set delegation - macro-output polish: ASCII-only macro diagnostics; no dead `#[doc]` on the function-local `in_impl` cache static; documented rationale for `#[allow(dead_code)]` on the generated prime companion and for the `crate_path()` `::cached` fallback See docs/migrations/2.0-to-unreleased.md and the CHANGELOG for migration details.
…ext major) Next-major batch (after the redb DiskCache rewrite). Bundles a set of breaking and additive changes plus the doc/test follow-ups. Macros: - `ttl_millis` attribute for sub-second TTLs, mutually exclusive with `ttl` (#149); rejected alongside a `create` block like the other store-builder attributes - `force_refresh` attribute to bypass the cache per call, on all three macros (`#[cached]` / `#[concurrent_cached]` / `#[once]`); on `#[once]` it overwrites the single shared value (no per-call key, so no key-exclusion caveat). Combined with `result_fallback`, a force-refreshed `Err` still serves the previously cached `Ok`, and capturing that fallback leaves no read side effects on the bypassed entry (no TTL renewal, recency update, or hit-counter change) on both `#[cached]` and `#[concurrent_cached]` (#146) - `in_impl` attribute to cache methods inside `impl` blocks; `self`-receiver methods require `in_impl` (a `convert` block alone cannot rescue them, since the cache static cannot live at `impl` scope) and emit a `{fn}_no_cache` cache-bypass sibling, hidden from rustdoc via `#[doc(hidden)]` (#16, #140) - reference arguments (`&T`, `Option<&T>`) form the default key without `convert` (#202, #203) - generated code resolves the crate path via `proc-macro-crate`, so a renamed or re-exported `cached` dependency works (#157) - macro-introduced bindings are hygienically named, so arguments named `key` / `cache` / `result` no longer collide with generated code (#230, #114) - clear compile error for generic functions used without `key` + `convert` (#80) - the shared `force_refresh` guard builder is factored into one helper Traits and stores: - `get_or_set_with` / `try_get_or_set_with` (and the async variants) now return `&V` instead of `&mut V`, with new `*_mut` variants preserving the old behavior (#179) - new additive `SerializeCached` / `SerializeCachedAsync` traits (`cache_set_ref`) for serialize-backed stores; `#[concurrent_cached]` routes its set through an autoref shim that uses the borrowed setter for any store implementing the trait (built-in redis/disk or a custom `ty`/`create` store), avoiding a value clone (#196, #195) - `RedisCache` / `AsyncRedisCache` gain `cache_clear` / `async_cache_clear`, with `cache_reset` delegating to `cache_clear`; `RedisCacheBuilder` / `AsyncRedisCacheBuilder` `build()` reject an empty namespace+prefix scope (`EmptyScope`) so `cache_clear` cannot `SCAN MATCH *` the whole database (#200) - `RedbCacheBuilder::build()` validates `cache_name` as a filename component, returning `InvalidCacheName` for a path separator (`/` or `\`) or a path-traversal component (`.` / `..`) - `LruCache::set_max_size` / `try_set_max_size` for resizing a live cache, with matching methods on `LruTtlCache` and `ExpiringLruCache` (#180) - `ConcurrentCloneCached` gains a non-renewing `cache_peek_with_expiry_status` (used to capture a `result_fallback` stale value without read side effects) Redis: - TLS features split so rustls is selectable; `redis_tokio` / `redis_smol` no longer imply native-tls (add `*_native_tls` or `*_rustls`) (#231) Docs and process: - document floats as the canonical `convert` case (#78); add cache-invalidation and struct-method examples (#21, #236), the latter demonstrating `in_impl` - release workflow tags and creates a GitHub release for each published workspace crate on publish, via `bin/tag-release.sh` (root `cached` -> `vX.Y.Z`, subcrates -> `<crate-name>-vX.Y.Z`) (#245); the CI tag-release git identity is scoped to `--local` - fix a doctest under `--no-default-features` (#260) - exclude internal dev tooling (.agents, .claude, .github, bin, docs/dev, AGENTS.md, CLAUDE.md) from the published crate via Cargo `exclude` - dev tooling: pr-review shards reviewers across model-sized, randomized chunks (multiple of each type); pr-cycle fans fix application across disjoint sub-agents; AGENTS.md states README is generated from src/lib.rs via cargo-readme - documentation accuracy pass: `ttl_millis` is valid with `result_fallback` and (on the in-memory path) needs `time_stores`; on `#[cached]` the "honored exactly" claim is scoped to the default in-memory store; Redis rounds `ttl_millis` up to the next whole second (500ms -> 1s, 1500ms -> 2s); `in_impl` emits a `#[doc(hidden)]` `{fn}_no_cache` sibling (documented on all three macros); `#[concurrent_cached]` `force_refresh` documents the `result_fallback` interaction; the `#[concurrent_cached]` attribute table reaches parity with `#[cached]` (ttl_millis / force_refresh / in_impl rows); wasm is incompatible with `redis_connection_manager` / `redis_async_cache`; the `in_impl` shared-cache footgun; the async `V: Sync` clone-elision asymmetry, including how a `Send + !Sync + !Clone` value surfaces at the generated set site; `CachedAsync` shared-ref default Send bounds; `Cached::cache_get_or_set_with` / `cache_try_get_or_set_with` flagged as provided defaults; migration-guide `&mut V` -> `&V` coercion caveat - added coverage: async clone-elision clone-count assertions; `#[concurrent_cached]` `result_fallback` + `force_refresh` (including the no-read-side-effects bypass); `#[once]` `force_refresh`; `force_refresh` + `in_impl`; generic `in_impl` rejection goldens for `#[cached]` (free fn) and `#[concurrent_cached]` (in_impl method); compile-fail goldens for `force_refresh`-unparseable on `#[once]` / `#[concurrent_cached]`, generic `#[concurrent_cached]` without `convert`, and `ttl_millis` + `create` conflict; `_mut` trait coverage on `ExpiringCache` / `TtlSortedCache`; redis `cache_clear` / `cache_set_ref` and redb `cache_set_ref` round-trips; `TtlSortedCache` shared-ref get-or-set delegation - macro-output polish: ASCII-only macro diagnostics; no dead `#[doc]` on the function-local `in_impl` cache static; documented rationale for `#[allow(dead_code)]` on the generated prime companion and for the `crate_path()` `::cached` fallback See docs/migrations/2.0-to-unreleased.md and the CHANGELOG for migration details.
…ext major) Next-major batch (after the redb DiskCache rewrite). Bundles a set of breaking and additive changes plus the doc/test follow-ups. Macros: - `ttl_millis` attribute for sub-second TTLs, mutually exclusive with `ttl` (#149); rejected alongside a `create` block like the other store-builder attributes - `force_refresh` attribute to bypass the cache per call, on all three macros (`#[cached]` / `#[concurrent_cached]` / `#[once]`); on `#[once]` it overwrites the single shared value (no per-call key, so no key-exclusion caveat). Combined with `result_fallback`, a force-refreshed `Err` still serves the previously cached `Ok`, and capturing that fallback leaves no read side effects on the bypassed entry (no TTL renewal, recency update, or hit-counter change) on both `#[cached]` and `#[concurrent_cached]` (#146) - `in_impl` attribute to cache methods inside `impl` blocks; `self`-receiver methods require `in_impl` (a `convert` block alone cannot rescue them, since the cache static cannot live at `impl` scope) and emit a `{fn}_no_cache` cache-bypass sibling, hidden from rustdoc via `#[doc(hidden)]` (#16, #140) - reference arguments (`&T`, `Option<&T>`) form the default key without `convert` (#202, #203) - generated code resolves the crate path via `proc-macro-crate`, so a renamed or re-exported `cached` dependency works (#157) - macro-introduced bindings are hygienically named, so arguments named `key` / `cache` / `result` no longer collide with generated code (#230, #114) - clear compile error for generic functions used without `key` + `convert` (#80) - the shared `force_refresh` guard builder is factored into one helper Traits and stores: - `get_or_set_with` / `try_get_or_set_with` (and the async variants) now return `&V` instead of `&mut V`, with new `*_mut` variants preserving the old behavior (#179) - new additive `SerializeCached` / `SerializeCachedAsync` traits (`cache_set_ref`) for serialize-backed stores; `#[concurrent_cached]` routes its set through an autoref shim that uses the borrowed setter for any store implementing the trait (built-in redis/disk or a custom `ty`/`create` store), avoiding a value clone (#196, #195) - `RedisCache` / `AsyncRedisCache` gain `cache_clear` / `async_cache_clear`, with `cache_reset` delegating to `cache_clear`; `RedisCacheBuilder` / `AsyncRedisCacheBuilder` `build()` reject an empty namespace+prefix scope (`EmptyScope`) so `cache_clear` cannot `SCAN MATCH *` the whole database (#200) - `RedbCacheBuilder::build()` validates `cache_name` as a filename component, returning `InvalidCacheName` for a path separator (`/` or `\`) or a path-traversal component (`.` / `..`) - `LruCache::set_max_size` / `try_set_max_size` for resizing a live cache, with matching methods on `LruTtlCache` and `ExpiringLruCache` (#180) - `ConcurrentCloneCached` gains a non-renewing `cache_peek_with_expiry_status` (used to capture a `result_fallback` stale value without read side effects) Redis: - TLS features split so rustls is selectable; `redis_tokio` / `redis_smol` no longer imply native-tls (add `*_native_tls` or `*_rustls`) (#231) Docs and process: - document floats as the canonical `convert` case (#78); add cache-invalidation and struct-method examples (#21, #236), the latter demonstrating `in_impl` - release workflow tags and creates a GitHub release for each published workspace crate on publish, via `bin/tag-release.sh` (root `cached` -> `vX.Y.Z`, subcrates -> `<crate-name>-vX.Y.Z`) (#245); the CI tag-release git identity is scoped to `--local` - fix a doctest under `--no-default-features` (#260) - exclude internal dev tooling (.agents, .claude, .github, bin, docs/dev, AGENTS.md, CLAUDE.md) from the published crate via Cargo `exclude` - dev tooling: pr-review shards reviewers across model-sized, randomized chunks (multiple of each type); pr-cycle fans fix application across disjoint sub-agents; AGENTS.md states README is generated from src/lib.rs via cargo-readme - documentation accuracy pass: `ttl_millis` is valid with `result_fallback` and (on the in-memory path) needs `time_stores`; on `#[cached]` the "honored exactly" claim is scoped to the default in-memory store; Redis rounds `ttl_millis` up to the next whole second (500ms -> 1s, 1500ms -> 2s); `in_impl` emits a `#[doc(hidden)]` `{fn}_no_cache` sibling (documented on all three macros); `#[concurrent_cached]` `force_refresh` documents the `result_fallback` interaction; the `#[concurrent_cached]` attribute table reaches parity with `#[cached]` (ttl_millis / force_refresh / in_impl rows); wasm is incompatible with `redis_connection_manager` / `redis_async_cache`; the `in_impl` shared-cache footgun; the async `V: Sync` clone-elision asymmetry, including how a `Send + !Sync + !Clone` value surfaces at the generated set site; `CachedAsync` shared-ref default Send bounds; `Cached::cache_get_or_set_with` / `cache_try_get_or_set_with` flagged as provided defaults; migration-guide `&mut V` -> `&V` coercion caveat - added coverage: async clone-elision clone-count assertions; `#[concurrent_cached]` `result_fallback` + `force_refresh` (including the no-read-side-effects bypass); `#[once]` `force_refresh`; `force_refresh` + `in_impl`; generic `in_impl` rejection goldens for `#[cached]` (free fn) and `#[concurrent_cached]` (in_impl method); compile-fail goldens for `force_refresh`-unparseable on `#[once]` / `#[concurrent_cached]`, generic `#[concurrent_cached]` without `convert`, and `ttl_millis` + `create` conflict; `_mut` trait coverage on `ExpiringCache` / `TtlSortedCache`; redis `cache_clear` / `cache_set_ref` and redb `cache_set_ref` round-trips; `TtlSortedCache` shared-ref get-or-set delegation - macro-output polish: ASCII-only macro diagnostics; no dead `#[doc]` on the function-local `in_impl` cache static; documented rationale for `#[allow(dead_code)]` on the generated prime companion and for the `crate_path()` `::cached` fallback See docs/migrations/2.0-to-unreleased.md and the CHANGELOG for migration details.
…or + ttl consistency Next-major batch (after the redb DiskCache rewrite). Bundles a set of breaking and additive changes plus the doc/test follow-ups, including a consumer-experience pass that made constructors and the ttl attribute consistent across the public surface. Macros: - `ttl` attribute now takes a `Duration` expression (`ttl = "core::time::Duration::from_secs(60)"`); the old whole-seconds integer form (`ttl = 60`) is removed and emits a migration error pointing at `ttl_secs`/`ttl_millis` - `ttl_secs` attribute for whole-second TTLs and `ttl_millis` for sub-second TTLs; `ttl` / `ttl_secs` / `ttl_millis` are three-way mutually exclusive, and each is mutually exclusive with `expires` (#149) - `force_refresh` attribute to bypass the cache per call, on all three macros (`#[cached]` / `#[concurrent_cached]` / `#[once]`); on `#[once]` it overwrites the single shared value (no per-call key, so no key-exclusion caveat). Combined with `result_fallback`, a force-refreshed `Err` still serves the previously cached `Ok`, and capturing that fallback leaves no read side effects on the bypassed entry (no TTL renewal, recency update, or hit-counter change) on both `#[cached]` and `#[concurrent_cached]` (#146) - `in_impl` attribute to cache methods inside `impl` blocks; `self`-receiver methods require `in_impl` (a `convert` block alone cannot rescue them, since the cache static cannot live at `impl` scope) and emit a `{fn}_no_cache` cache-bypass sibling, hidden from rustdoc via `#[doc(hidden)]` (#16, #140) - reference arguments (`&T`, `Option<&T>`) form the default key without `convert` (#202, #203) - generated code resolves the crate path via `proc-macro-crate`, so a renamed or re-exported `cached` dependency works (#157) - macro-introduced bindings are hygienically named, so arguments named `key` / `cache` / `result` no longer collide with generated code (#230, #114) - clear compile error for generic functions used without `key` + `convert` (#80) - `refresh` is rejected alongside the other store-builder attributes when a `create` block is supplied, mirroring `#[concurrent_cached]` - the shared `force_refresh` guard builder is factored into one helper Traits and stores: - every in-memory and sharded store gains a `new()` that returns a ready-to-use cache (zero-config stores take no args; required-field stores take them positionally - `LruCache::new(max_size)`, `TtlCache::new(ttl)`, `LruTtlCache::new(max_size, ttl)`, the `Sharded*` variants, etc.), all `#[must_use]`. `RedbCache` / `RedisCache` / `AsyncRedisCache` drop `new()` (it returned a builder, not a cache); use `builder(...)`. `new()` now consistently returns a usable cache everywhere it exists - every TTL builder (non-sharded, sharded, Redis, Redb) gains `ttl_secs` / `ttl_millis` convenience setters alongside `ttl(Duration)`; last-writer-wins - `get_or_set_with` / `try_get_or_set_with` (and the async variants) now return `&V` instead of `&mut V`, with new `*_mut` variants preserving the old behavior (#179) - new additive `SerializeCached` / `SerializeCachedAsync` traits (`cache_set_ref`) for serialize-backed stores; `#[concurrent_cached]` routes its set through an autoref shim that uses the borrowed setter for any store implementing the trait (built-in redis/disk or a custom `ty`/`create` store), avoiding a value clone (#196, #195) - `RedisCache` / `AsyncRedisCache` gain `cache_clear` / `async_cache_clear`, with `cache_reset` delegating to `cache_clear`; `RedisCacheBuilder` / `AsyncRedisCacheBuilder` `build()` reject an empty namespace+prefix scope (`EmptyScope`) so `cache_clear` cannot `SCAN MATCH *` the whole database (#200) - `RedbCacheBuilder::build()` validates `cache_name` as a filename component, returning `InvalidCacheName` for a path separator (`/` or `\`) or a path-traversal component (`.` / `..`) - `LruCache::set_max_size` / `try_set_max_size` for resizing a live cache, with matching methods on `LruTtlCache` and `ExpiringLruCache` (#180) - `ConcurrentCloneCached` gains a non-renewing `cache_peek_with_expiry_status` (used to capture a `result_fallback` stale value without read side effects) Redis: - TLS features split so rustls is selectable; `redis_tokio` / `redis_smol` no longer imply native-tls (add `*_native_tls` or `*_rustls`) (#231) Docs and process: - docs and examples now prefer the short alias method API (`get`/`set`/`remove`/`clear`/`len`/...) over the `cache_*`-prefixed forms, with a note (in the crate docs and on the `Cached` trait) on when to use the `cache_*` names - a collision with another in-scope trait's method. Both forms remain; no method was removed - document floats as the canonical `convert` case (#78); add cache-invalidation and struct-method examples (#21, #236), the latter demonstrating `in_impl` and noting the in_impl cache is not externally invalidatable and its shared-id staleness footgun - release workflow tags and creates a GitHub release for each published workspace crate on publish, via `bin/tag-release.sh` (root `cached` -> `vX.Y.Z`, subcrates -> `<crate-name>-vX.Y.Z`) (#245); it retries a missing release when the tag already exists on the remote; the CI tag-release git identity is scoped to `--local` - fix a doctest under `--no-default-features` (#260) - exclude internal dev tooling (.agents, .claude, .github, bin, docs/dev, AGENTS.md, CLAUDE.md) from the published crate via Cargo `exclude` - README is generated from src/lib.rs via cargo-readme (regenerated here); dev tooling: pr-review shards reviewers across model-sized randomized chunks; pr-cycle fans fix application across disjoint sub-agents - documentation accuracy pass: `ttl_millis` / `ttl_secs` are valid with `result_fallback` and (on the in-memory path) need `time_stores`; on `#[cached]` the "honored exactly" claim is scoped to the default in-memory store; Redis rounds `ttl_millis` up to the next whole second (500ms -> 1s, 1500ms -> 2s); `in_impl` emits a `#[doc(hidden)]` `{fn}_no_cache` sibling (all three macros); `#[concurrent_cached]` `force_refresh` documents the `result_fallback` interaction; the `#[concurrent_cached]` attribute table reaches parity with `#[cached]`; wasm is incompatible with `redis_connection_manager` / `redis_async_cache`; the async `V: Sync` clone-elision asymmetry and how a `Send + !Sync + !Clone` value surfaces at the generated set site; `CachedAsync` shared-ref default Send bounds; `Cached::cache_get_or_set_with` / `cache_try_get_or_set_with` flagged as provided defaults; migration-guide `&mut V` -> `&V` coercion caveat; redis `build()` lists `InvalidTtl` before `EmptyScope` to match validation order - macro-output polish: ASCII-only macro diagnostics; no dead `#[doc]` on the function-local `in_impl` cache static; documented rationale for `#[allow(dead_code)]` on the generated prime companion and for the `crate_path()` `::cached` fallback Tests: - positive macro coverage for all three ttl spellings (`ttl` Duration expr / `ttl_secs` / `ttl_millis`) across `#[cached]` / `#[once]` / `#[concurrent_cached]`, and compile-fail UI goldens for the three-way exclusivity and the `ttl = <int>` migration error - inline store coverage for every new `new()` constructor and the `ttl_secs` / `ttl_millis` builder setters (including override semantics) - async clone-elision clone-count assertions; `#[concurrent_cached]` `result_fallback` + `force_refresh` (including the no-read-side-effects bypass); `#[once]` `force_refresh`; `force_refresh` + `in_impl`; generic-rejection goldens; `_mut` trait coverage on `ExpiringCache` / `TtlSortedCache`; redis `cache_clear` / `cache_set_ref` and redb `cache_set_ref` round-trips; deferred attribute/store combinations (max_size+ttl_millis, in_impl+ttl_millis, ttl_millis+force_refresh, result_fallback+ttl_millis, async once in_impl) and store(0) counter resets; sharded peek does not renew TTL under refresh_on_hit See docs/migrations/2.0-to-unreleased.md and the CHANGELOG for migration details.
…or + ttl consistency Next-major batch (after the redb DiskCache rewrite). Bundles a set of breaking and additive changes plus the doc/test follow-ups, including a consumer-experience pass that made constructors and the ttl attribute consistent across the public surface. Macros: - `ttl` attribute now takes a `Duration` expression (`ttl = "core::time::Duration::from_secs(60)"`); the old whole-seconds integer form (`ttl = 60`) is removed and emits a migration error pointing at `ttl_secs`/`ttl_millis` - `ttl_secs` attribute for whole-second TTLs and `ttl_millis` for sub-second TTLs; `ttl` / `ttl_secs` / `ttl_millis` are three-way mutually exclusive, and each is mutually exclusive with `expires` (#149) - `force_refresh` attribute to bypass the cache per call, on all three macros (`#[cached]` / `#[concurrent_cached]` / `#[once]`); on `#[once]` it overwrites the single shared value (no per-call key, so no key-exclusion caveat). Combined with `result_fallback`, a force-refreshed `Err` still serves the previously cached `Ok`, and capturing that fallback leaves no read side effects on the bypassed entry (no TTL renewal, recency update, or hit-counter change) on both `#[cached]` and `#[concurrent_cached]` (#146) - `in_impl` attribute to cache methods inside `impl` blocks; `self`-receiver methods require `in_impl` (a `convert` block alone cannot rescue them, since the cache static cannot live at `impl` scope) and emit a `{fn}_no_cache` cache-bypass sibling, hidden from rustdoc via `#[doc(hidden)]` (#16, #140) - reference arguments (`&T`, `Option<&T>`) form the default key without `convert` (#202, #203) - generated code resolves the crate path via `proc-macro-crate`, so a renamed or re-exported `cached` dependency works (#157) - macro-introduced bindings are hygienically named, so arguments named `key` / `cache` / `result` no longer collide with generated code (#230, #114) - clear compile error for generic functions used without `key` + `convert` (#80) - `refresh` is rejected alongside the other store-builder attributes when a `create` block is supplied, mirroring `#[concurrent_cached]` - the shared `force_refresh` guard builder is factored into one helper Traits and stores: - every in-memory and sharded store gains a `new()` that returns a ready-to-use cache (zero-config stores take no args; required-field stores take them positionally - `LruCache::new(max_size)`, `TtlCache::new(ttl)`, `LruTtlCache::new(max_size, ttl)`, the `Sharded*` variants, etc.), all `#[must_use]`. `RedbCache` / `RedisCache` / `AsyncRedisCache` drop `new()` (it returned a builder, not a cache); use `builder(...)`. `new()` now consistently returns a usable cache everywhere it exists - `new()` / `builder()` on each sharded `*Base` type are now defined only on the default-hasher specialization (`*Base<K, V, DefaultShardHasher>`, the named alias). They previously sat on the generic `*Base<K, V, H>` impl but always returned a `DefaultShardHasher` builder, so a `*Base::<_, _, CustomHasher>:: builder()` / `::new()` turbofish compiled yet silently dropped the custom hasher; that turbofish now fails to compile (E0599). A custom hasher is specified via `ShardedX::builder().hasher(h)`, which switches the builder's hasher type; alias-based construction and the `.hasher()` path are unchanged - every TTL builder (non-sharded, sharded, Redis, Redb) gains `ttl_secs` / `ttl_millis` convenience setters alongside `ttl(Duration)`; last-writer-wins - `get_or_set_with` / `try_get_or_set_with` (and the async variants) now return `&V` instead of `&mut V`, with new `*_mut` variants preserving the old behavior (#179) - new additive `SerializeCached` / `SerializeCachedAsync` traits (`cache_set_ref`) for serialize-backed stores; `#[concurrent_cached]` routes its set through an autoref shim that uses the borrowed setter for any store implementing the trait (built-in redis/disk or a custom `ty`/`create` store), avoiding a value clone (#196, #195) - `RedisCache` / `AsyncRedisCache` gain `cache_clear` / `async_cache_clear`, with `cache_reset` delegating to `cache_clear`; `RedisCacheBuilder` / `AsyncRedisCacheBuilder` `build()` reject an empty namespace+prefix scope (`EmptyScope`) so `cache_clear` cannot `SCAN MATCH *` the whole database (#200) - `RedbCacheBuilder::build()` validates `cache_name` as a filename component, returning `InvalidCacheName` for a path separator (`/` or `\`) or a path-traversal component (`.` / `..`) - `LruCache::set_max_size` / `try_set_max_size` for resizing a live cache, with matching methods on `LruTtlCache` and `ExpiringLruCache` (#180) - `ConcurrentCloneCached` gains a non-renewing `cache_peek_with_expiry_status` (used to capture a `result_fallback` stale value without read side effects) Redis: - TLS features split so rustls is selectable; `redis_tokio` / `redis_smol` no longer imply native-tls (add `*_native_tls` or `*_rustls`) (#231) Docs and process: - docs and examples now prefer the short alias method API (`get`/`set`/`remove`/`clear`/`len`/...) over the `cache_*`-prefixed forms, with a note (in the crate docs and on the `Cached` trait) on when to use the `cache_*` names - a collision with another in-scope trait's method. Both forms remain; no method was removed - document floats as the canonical `convert` case (#78); add cache-invalidation and struct-method examples (#21, #236), the latter demonstrating `in_impl` and noting the in_impl cache is not externally invalidatable and its shared-id staleness footgun - release workflow tags and creates a GitHub release for each published workspace crate on publish, via `bin/tag-release.sh` (root `cached` -> `vX.Y.Z`, subcrates -> `<crate-name>-vX.Y.Z`) (#245); it retries a missing release when the tag already exists on the remote; the CI tag-release git identity is scoped to `--local` - fix a doctest under `--no-default-features` (#260) - exclude internal dev tooling (.agents, .claude, .github, bin, docs/dev, AGENTS.md, CLAUDE.md) from the published crate via Cargo `exclude` - README is generated from src/lib.rs via cargo-readme (regenerated here); dev tooling: pr-review shards reviewers across model-sized randomized chunks; pr-cycle fans fix application across disjoint sub-agents - documentation accuracy pass: `ttl_millis` / `ttl_secs` are valid with `result_fallback` and (on the in-memory path) need `time_stores`; on `#[cached]` the "honored exactly" claim is scoped to the default in-memory store; Redis rounds `ttl_millis` up to the next whole second (500ms -> 1s, 1500ms -> 2s); `in_impl` emits a `#[doc(hidden)]` `{fn}_no_cache` sibling (all three macros); `#[concurrent_cached]` `force_refresh` documents the `result_fallback` interaction; the `#[concurrent_cached]` attribute table reaches parity with `#[cached]`; wasm is incompatible with `redis_connection_manager` / `redis_async_cache`; the async `V: Sync` clone-elision asymmetry and how a `Send + !Sync + !Clone` value surfaces at the generated set site; `CachedAsync` shared-ref default Send bounds; `Cached::cache_get_or_set_with` / `cache_try_get_or_set_with` flagged as provided defaults; migration-guide `&mut V` -> `&V` coercion caveat; redis `build()` lists `InvalidTtl` before `EmptyScope` to match validation order - macro-output polish: ASCII-only macro diagnostics; no dead `#[doc]` on the function-local `in_impl` cache static; documented rationale for `#[allow(dead_code)]` on the generated prime companion and for the `crate_path()` `::cached` fallback - elevate all compiler warnings to errors workspace-wide via the Cargo `[lints]` table (`[workspace.lints.rust] warnings = "deny"`, opted into by the `cached` and `cached_proc_macro` packages), so `cargo build`/`test`/`clippy` deny warnings rather than only the Makefile clippy target; gate `validate_ttl` to `any(time_stores, disk_store, redis_store)` and an unused test `AtomicUsize` import to `proc_macro` to keep `--no-default-features` warning-clean Tests: - positive macro coverage for all three ttl spellings (`ttl` Duration expr / `ttl_secs` / `ttl_millis`) across `#[cached]` / `#[once]` / `#[concurrent_cached]`, and compile-fail UI goldens for the three-way exclusivity and the `ttl = <int>` migration error - inline store coverage for every new `new()` constructor and the `ttl_secs` / `ttl_millis` builder setters (including override semantics) - compile-fail UI golden asserting `*Base::<_, _, CustomHasher>::{new,builder}()` no longer compiles (the custom-hasher `.hasher()` path stays covered by the existing sharded `custom_hasher` unit test) - async clone-elision clone-count assertions; `#[concurrent_cached]` `result_fallback` + `force_refresh` (including the no-read-side-effects bypass); `#[once]` `force_refresh`; `force_refresh` + `in_impl`; generic-rejection goldens; `_mut` trait coverage on `ExpiringCache` / `TtlSortedCache`; redis `cache_clear` / `cache_set_ref` and redb `cache_set_ref` round-trips; deferred attribute/store combinations (max_size+ttl_millis, in_impl+ttl_millis, ttl_millis+force_refresh, result_fallback+ttl_millis, async once in_impl) and store(0) counter resets; sharded peek does not renew TTL under refresh_on_hit See docs/migrations/2.0-to-unreleased.md and the CHANGELOG for migration details.
…or + ttl consistency Next-major batch (after the redb DiskCache rewrite). Bundles a set of breaking and additive changes plus the doc/test follow-ups, including a consumer-experience pass that made constructors and the ttl attribute consistent across the public surface. Macros: - `ttl` attribute now takes a `Duration` expression (`ttl = "core::time::Duration::from_secs(60)"`); the old whole-seconds integer form (`ttl = 60`) is removed and emits a migration error pointing at `ttl_secs`/`ttl_millis` - `ttl_secs` attribute for whole-second TTLs and `ttl_millis` for sub-second TTLs; `ttl` / `ttl_secs` / `ttl_millis` are three-way mutually exclusive, and each is mutually exclusive with `expires` (#149) - `force_refresh` attribute to bypass the cache per call, on all three macros (`#[cached]` / `#[concurrent_cached]` / `#[once]`); on `#[once]` it overwrites the single shared value (no per-call key, so no key-exclusion caveat). Combined with `result_fallback`, a force-refreshed `Err` still serves the previously cached `Ok`, and capturing that fallback leaves no read side effects on the bypassed entry (no TTL renewal, recency update, or hit-counter change) on both `#[cached]` and `#[concurrent_cached]` (#146) - `in_impl` attribute to cache methods inside `impl` blocks; `self`-receiver methods require `in_impl` (a `convert` block alone cannot rescue them, since the cache static cannot live at `impl` scope) and emit a `{fn}_no_cache` cache-bypass sibling, hidden from rustdoc via `#[doc(hidden)]` (#16, #140) - reference arguments (`&T`, `Option<&T>`) form the default key without `convert` (#202, #203) - generated code resolves the crate path via `proc-macro-crate`, so a renamed or re-exported `cached` dependency works (#157) - macro-introduced bindings are hygienically named, so arguments named `key` / `cache` / `result` no longer collide with generated code (#230, #114) - clear compile error for generic functions used without `key` + `convert` (#80) - `refresh` is rejected alongside the other store-builder attributes when a `create` block is supplied, mirroring `#[concurrent_cached]` - the shared `force_refresh` guard builder is factored into one helper Traits and stores: - every in-memory and sharded store gains a `new()` that returns a ready-to-use cache (zero-config stores take no args; required-field stores take them positionally - `LruCache::new(max_size)`, `TtlCache::new(ttl)`, `LruTtlCache::new(max_size, ttl)`, the `Sharded*` variants, etc.), all `#[must_use]`. `RedbCache` / `RedisCache` / `AsyncRedisCache` drop `new()` (it returned a builder, not a cache); use `builder(...)`. `new()` now consistently returns a usable cache everywhere it exists - `new()` / `builder()` on each sharded `*Base` type are now defined only on the default-hasher specialization (`*Base<K, V, DefaultShardHasher>`, the named alias). They previously sat on the generic `*Base<K, V, H>` impl but always returned a `DefaultShardHasher` builder, so a `*Base::<_, _, CustomHasher>:: builder()` / `::new()` turbofish compiled yet silently dropped the custom hasher; that turbofish now fails to compile (E0599). A custom hasher is specified via `ShardedX::builder().hasher(h)`, which switches the builder's hasher type; alias-based construction and the `.hasher()` path are unchanged - every TTL builder (non-sharded, sharded, Redis, Redb) gains `ttl_secs` / `ttl_millis` convenience setters alongside `ttl(Duration)`; last-writer-wins - `get_or_set_with` / `try_get_or_set_with` (and the async variants) now return `&V` instead of `&mut V`, with new `*_mut` variants preserving the old behavior (#179) - new additive `SerializeCached` / `SerializeCachedAsync` traits (`cache_set_ref`) for serialize-backed stores; `#[concurrent_cached]` routes its set through an autoref shim that uses the borrowed setter for any store implementing the trait (built-in redis/disk or a custom `ty`/`create` store), avoiding a value clone (#196, #195) - `RedisCache` / `AsyncRedisCache` gain `cache_clear` / `async_cache_clear`, with `cache_reset` delegating to `cache_clear`; `RedisCacheBuilder` / `AsyncRedisCacheBuilder` `build()` reject an empty namespace+prefix scope (`EmptyScope`) so `cache_clear` cannot `SCAN MATCH *` the whole database (#200) - `RedbCacheBuilder::build()` validates `cache_name` as a filename component, returning `InvalidCacheName` for a path separator (`/` or `\`) or a path-traversal component (`.` / `..`) - `LruCache::set_max_size` / `try_set_max_size` for resizing a live cache, with matching methods on `LruTtlCache` and `ExpiringLruCache` (#180) - `ConcurrentCloneCached` gains a non-renewing `cache_peek_with_expiry_status` (used to capture a `result_fallback` stale value without read side effects) Redis: - TLS features split so rustls is selectable; `redis_tokio` / `redis_smol` no longer imply native-tls (add `*_native_tls` or `*_rustls`) (#231) Docs and process: - docs and examples now prefer the short alias method API (`get`/`set`/`remove`/`clear`/`len`/...) over the `cache_*`-prefixed forms, with a note (in the crate docs and on the `Cached` trait) on when to use the `cache_*` names - a collision with another in-scope trait's method. Both forms remain; no method was removed - document floats as the canonical `convert` case (#78); add cache-invalidation and struct-method examples (#21, #236), the latter demonstrating `in_impl` and noting the in_impl cache is not externally invalidatable and its shared-id staleness footgun - release workflow tags and creates a GitHub release for each published workspace crate on publish, via `bin/tag-release.sh` (root `cached` -> `vX.Y.Z`, subcrates -> `<crate-name>-vX.Y.Z`) (#245); it retries a missing release when the tag already exists on the remote; the CI tag-release git identity is scoped to `--local` - fix a doctest under `--no-default-features` (#260) - exclude internal dev tooling (.agents, .claude, .github, bin, docs/dev, AGENTS.md, CLAUDE.md) from the published crate via Cargo `exclude` - README is generated from src/lib.rs via cargo-readme (regenerated here); dev tooling: pr-review shards reviewers across model-sized randomized chunks; pr-cycle fans fix application across disjoint sub-agents - documentation accuracy pass: `ttl_millis` / `ttl_secs` are valid with `result_fallback` and (on the in-memory path) need `time_stores`; on `#[cached]` the "honored exactly" claim is scoped to the default in-memory store; Redis rounds `ttl_millis` up to the next whole second (500ms -> 1s, 1500ms -> 2s); `in_impl` emits a `#[doc(hidden)]` `{fn}_no_cache` sibling (all three macros); `#[concurrent_cached]` `force_refresh` documents the `result_fallback` interaction; the `#[concurrent_cached]` attribute table reaches parity with `#[cached]`; wasm is incompatible with `redis_connection_manager` / `redis_async_cache`; the async `V: Sync` clone-elision asymmetry and how a `Send + !Sync + !Clone` value surfaces at the generated set site; `CachedAsync` shared-ref default Send bounds; `Cached::cache_get_or_set_with` / `cache_try_get_or_set_with` flagged as provided defaults; migration-guide `&mut V` -> `&V` coercion caveat; redis `build()` lists `InvalidTtl` before `EmptyScope` to match validation order - macro-output polish: ASCII-only macro diagnostics; no dead `#[doc]` on the function-local `in_impl` cache static; documented rationale for `#[allow(dead_code)]` on the generated prime companion and for the `crate_path()` `::cached` fallback - elevate all compiler warnings to errors workspace-wide via the Cargo `[lints]` table (`[workspace.lints.rust] warnings = "deny"`, opted into by the `cached` and `cached_proc_macro` packages), so `cargo build`/`test`/`clippy` deny warnings rather than only the Makefile clippy target; gate `validate_ttl` to `any(time_stores, disk_store, redis_store)` and an unused test `AtomicUsize` import to `proc_macro` to keep `--no-default-features` warning-clean Tests: - positive macro coverage for all three ttl spellings (`ttl` Duration expr / `ttl_secs` / `ttl_millis`) across `#[cached]` / `#[once]` / `#[concurrent_cached]`, and compile-fail UI goldens for the three-way exclusivity and the `ttl = <int>` migration error - inline store coverage for every new `new()` constructor and the `ttl_secs` / `ttl_millis` builder setters (including override semantics) - compile-fail UI golden asserting `*Base::<_, _, CustomHasher>::{new,builder}()` no longer compiles (the custom-hasher `.hasher()` path stays covered by the existing sharded `custom_hasher` unit test) - async clone-elision clone-count assertions; `#[concurrent_cached]` `result_fallback` + `force_refresh` (including the no-read-side-effects bypass); `#[once]` `force_refresh`; `force_refresh` + `in_impl`; generic-rejection goldens; `_mut` trait coverage on `ExpiringCache` / `TtlSortedCache`; redis `cache_clear` / `cache_set_ref` and redb `cache_set_ref` round-trips; deferred attribute/store combinations (max_size+ttl_millis, in_impl+ttl_millis, ttl_millis+force_refresh, result_fallback+ttl_millis, async once in_impl) and store(0) counter resets; sharded peek does not renew TTL under refresh_on_hit See docs/migrations/2.0-to-unreleased.md and the CHANGELOG for migration details.
…sistency Make constructors and the ttl attribute consistent across the public surface, on top of the redb DiskCache rewrite. Breaking and additive changes with doc and test follow-ups: Macros: - `ttl` attribute now takes a `Duration` expression (`ttl = "core::time::Duration::from_secs(60)"`); the old whole-seconds integer form (`ttl = 60`) is removed and emits a migration error pointing at `ttl_secs`/`ttl_millis` - `ttl_secs` attribute for whole-second TTLs and `ttl_millis` for sub-second TTLs; `ttl` / `ttl_secs` / `ttl_millis` are three-way mutually exclusive, and each is mutually exclusive with `expires` (#149) - `force_refresh` attribute to bypass the cache per call, on all three macros (`#[cached]` / `#[concurrent_cached]` / `#[once]`); on `#[once]` it overwrites the single shared value (no per-call key, so no key-exclusion caveat). Combined with `result_fallback`, a force-refreshed `Err` still serves the previously cached `Ok`, and capturing that fallback leaves no read side effects on the bypassed entry (no TTL renewal, recency update, or hit-counter change) on both `#[cached]` and `#[concurrent_cached]` (#146) - `in_impl` attribute to cache methods inside `impl` blocks; `self`-receiver methods require `in_impl` (a `convert` block alone cannot rescue them, since the cache static cannot live at `impl` scope) and emit a `{fn}_no_cache` cache-bypass sibling, hidden from rustdoc via `#[doc(hidden)]` (#16, #140) - reference arguments (`&T`, `Option<&T>`) form the default key without `convert` (#202, #203) - generated code resolves the crate path via `proc-macro-crate`, so a renamed or re-exported `cached` dependency works (#157) - macro-introduced bindings are hygienically named, so arguments named `key` / `cache` / `result` no longer collide with generated code (#230, #114) - clear compile error for generic functions used without `key` + `convert` (#80) - `refresh` is rejected alongside the other store-builder attributes when a `create` block is supplied, mirroring `#[concurrent_cached]` - the shared `force_refresh` guard builder is factored into one helper Traits and stores: - every in-memory and sharded store gains a `new()` that returns a ready-to-use cache (zero-config stores take no args; required-field stores take them positionally - `LruCache::new(max_size)`, `TtlCache::new(ttl)`, `LruTtlCache::new(max_size, ttl)`, the `Sharded*` variants, etc.), all `#[must_use]`. `RedbCache` / `RedisCache` / `AsyncRedisCache` drop `new()` (it returned a builder, not a cache); use `builder(...)`. `new()` now consistently returns a usable cache everywhere it exists - `new()` / `builder()` on each sharded `*Base` type are now defined only on the default-hasher specialization (`*Base<K, V, DefaultShardHasher>`, the named alias). They previously sat on the generic `*Base<K, V, H>` impl but always returned a `DefaultShardHasher` builder, so a `*Base::<_, _, CustomHasher>:: builder()` / `::new()` turbofish compiled yet silently dropped the custom hasher; that turbofish now fails to compile (E0599). A custom hasher is specified via `ShardedX::builder().hasher(h)`, which switches the builder's hasher type; alias-based construction and the `.hasher()` path are unchanged - every TTL builder (non-sharded, sharded, Redis, Redb) gains `ttl_secs` / `ttl_millis` convenience setters alongside `ttl(Duration)`; last-writer-wins - `get_or_set_with` / `try_get_or_set_with` (and the async variants) now return `&V` instead of `&mut V`, with new `*_mut` variants preserving the old behavior (#179) - new additive `SerializeCached` / `SerializeCachedAsync` traits (`cache_set_ref`) for serialize-backed stores; `#[concurrent_cached]` routes its set through an autoref shim that uses the borrowed setter for any store implementing the trait (built-in redis/disk or a custom `ty`/`create` store), avoiding a value clone (#196, #195) - `RedisCache` / `AsyncRedisCache` gain `cache_clear` / `async_cache_clear`, with `cache_reset` delegating to `cache_clear`; `RedisCacheBuilder` / `AsyncRedisCacheBuilder` `build()` reject an empty namespace+prefix scope (`EmptyScope`) so `cache_clear` cannot `SCAN MATCH *` the whole database (#200) - `RedbCacheBuilder::build()` validates `cache_name` as a filename component, returning `InvalidCacheName` for a path separator (`/` or `\`) or a path-traversal component (`.` / `..`) - `LruCache::set_max_size` / `try_set_max_size` for resizing a live cache, with matching methods on `LruTtlCache` and `ExpiringLruCache` (#180) - `ConcurrentCloneCached` gains a non-renewing `cache_peek_with_expiry_status` (used to capture a `result_fallback` stale value without read side effects) Redis: - TLS features split so rustls is selectable; `redis_tokio` / `redis_smol` no longer imply native-tls (add `*_native_tls` or `*_rustls`) (#231) Docs and process: - docs and examples now prefer the short alias method API (`get`/`set`/`remove`/`clear`/`len`/...) over the `cache_*`-prefixed forms, with a note (in the crate docs and on the `Cached` trait) on when to use the `cache_*` names - a collision with another in-scope trait's method. Both forms remain; no method was removed - document floats as the canonical `convert` case (#78); add cache-invalidation and struct-method examples (#21, #236), the latter demonstrating `in_impl` and noting the in_impl cache is not externally invalidatable and its shared-id staleness footgun - release workflow tags and creates a GitHub release for each published workspace crate on publish, via `bin/tag-release.sh` (root `cached` -> `vX.Y.Z`, subcrates -> `<crate-name>-vX.Y.Z`) (#245); it retries a missing release when the tag already exists on the remote; the CI tag-release git identity is scoped to `--local` - fix a doctest under `--no-default-features` (#260) - exclude internal dev tooling (.agents, .claude, .github, bin, docs/dev, AGENTS.md, CLAUDE.md) from the published crate via Cargo `exclude` - README is generated from src/lib.rs via cargo-readme (regenerated here); dev tooling: pr-review shards reviewers across model-sized randomized chunks; pr-cycle fans fix application across disjoint sub-agents - documentation accuracy pass: `ttl_millis` / `ttl_secs` are valid with `result_fallback` and (on the in-memory path) need `time_stores`; on `#[cached]` the "honored exactly" claim is scoped to the default in-memory store; Redis rounds `ttl_millis` up to the next whole second (500ms -> 1s, 1500ms -> 2s); `in_impl` emits a `#[doc(hidden)]` `{fn}_no_cache` sibling (all three macros); `#[concurrent_cached]` `force_refresh` documents the `result_fallback` interaction; the `#[concurrent_cached]` attribute table reaches parity with `#[cached]`; wasm is incompatible with `redis_connection_manager` / `redis_async_cache`; the async `V: Sync` clone-elision asymmetry and how a `Send + !Sync + !Clone` value surfaces at the generated set site; `CachedAsync` shared-ref default Send bounds; `Cached::cache_get_or_set_with` / `cache_try_get_or_set_with` flagged as provided defaults; migration-guide `&mut V` -> `&V` coercion caveat; redis `build()` lists `InvalidTtl` before `EmptyScope` to match validation order - macro-output polish: ASCII-only macro diagnostics; no dead `#[doc]` on the function-local `in_impl` cache static; documented rationale for `#[allow(dead_code)]` on the generated prime companion and for the `crate_path()` `::cached` fallback - elevate all compiler warnings to errors workspace-wide via the Cargo `[lints]` table (`[workspace.lints.rust] warnings = "deny"`, opted into by the `cached` and `cached_proc_macro` packages), so `cargo build`/`test`/`clippy` deny warnings rather than only the Makefile clippy target; gate `validate_ttl` to `any(time_stores, disk_store, redis_store)` and an unused test `AtomicUsize` import to `proc_macro` to keep `--no-default-features` warning-clean Tests: - positive macro coverage for all three ttl spellings (`ttl` Duration expr / `ttl_secs` / `ttl_millis`) across `#[cached]` / `#[once]` / `#[concurrent_cached]`, and compile-fail UI goldens for the three-way exclusivity and the `ttl = <int>` migration error - inline store coverage for every new `new()` constructor and the `ttl_secs` / `ttl_millis` builder setters (including override semantics) - compile-fail UI golden asserting `*Base::<_, _, CustomHasher>::{new,builder}()` no longer compiles (the custom-hasher `.hasher()` path stays covered by the existing sharded `custom_hasher` unit test) - async clone-elision clone-count assertions; `#[concurrent_cached]` `result_fallback` + `force_refresh` (including the no-read-side-effects bypass); `#[once]` `force_refresh`; `force_refresh` + `in_impl`; generic-rejection goldens; `_mut` trait coverage on `ExpiringCache` / `TtlSortedCache`; redis `cache_clear` / `cache_set_ref` and redb `cache_set_ref` round-trips; deferred attribute/store combinations (max_size+ttl_millis, in_impl+ttl_millis, ttl_millis+force_refresh, result_fallback+ttl_millis, async once in_impl) and store(0) counter resets; sharded peek does not renew TTL under refresh_on_hit See docs/migrations/2.0-to-unreleased.md and the CHANGELOG for migration details.
Closes #197.