Support &T and Option<&T> in input#203
Open
BaxHugh wants to merge 2 commits into
Open
Conversation
Contributor
Author
|
Note: I think #196 seems relevant |
16d7d23 to
de3285c
Compare
- make_cache_key_type converts keys of Option<&T> to Option<T> - Use the __private ToFullyOwned trait in generated code impl
de3285c to
5b28035
Compare
jaemk
added a commit
that referenced
this pull request
Jun 9, 2026
…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.
jaemk
added a commit
that referenced
this pull request
Jun 9, 2026
…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.
jaemk
added a commit
that referenced
this pull request
Jun 9, 2026
…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.
jaemk
added a commit
that referenced
this pull request
Jun 9, 2026
…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.
jaemk
added a commit
that referenced
this pull request
Jun 10, 2026
…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.
jaemk
added a commit
that referenced
this pull request
Jun 10, 2026
…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.
jaemk
added a commit
that referenced
this pull request
Jun 10, 2026
…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.
jaemk
added a commit
that referenced
this pull request
Jun 10, 2026
…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.
jaemk
added a commit
that referenced
this pull request
Jun 11, 2026
…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.
jaemk
added a commit
that referenced
this pull request
Jun 11, 2026
…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.
jaemk
added a commit
that referenced
this pull request
Jun 11, 2026
…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.
jaemk
added a commit
that referenced
this pull request
Jun 11, 2026
…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.
jaemk
added a commit
that referenced
this pull request
Jun 13, 2026
…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.
jaemk
added a commit
that referenced
this pull request
Jun 14, 2026
…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.
jaemk
added a commit
that referenced
this pull request
Jun 20, 2026
…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.
jaemk
added a commit
that referenced
this pull request
Jun 20, 2026
…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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Changed some of the macro code so that
works, currently only inputs of owned types works.
Closes #202.
I've now implemented this but since then I've got some other thought. Which could affect whether we want this in the long run?
Cons to having this feature:
Why the feature is / might not be needed.
We're passing a reference with the expectation that it will be cloned within the body of the function. Instead why not just have users use functions which take owned data and omit any extra cloning in the impl body? If the input data needs keeping, then it would be cloned and passed to the function.
This would remove the need for additional logic to use
InputTas the key type when the input type is&InputT, and would defer dealing with refs and cloning to the library user.The alternative implementation we should/cloud instead provide.
Currently the implementation provided by the cache_proc macro calls clone() on the inputs to create the key.
for simple uses of the #[cached] macro (without complexity from other macro args) this clone is needless, as there is no later borrow, so the key could consume the inputs instead.
Removing the call to clone() I think only breaks the case when the with_cached_flag is used in the tests so in that case, an alternative impl could be provided, (a cleaner way of implementing the proc macro could help here)
Further refactoring elsewhere could make this simpler, i.e. if the cache_set method could take a
&Keyinstead of aKey, then we wouldn't need any extra logic to support ref inputs, i.e. they key type could be a ref type (maybe?)Conclusion given the short term
I think for now, given the current implementation, supporting the inputs being references is a good idea. If the user want to maintain ownership of the function's inputs, then passing a ref makes sense and it's one less clone that needs doing for each input (i.e.
fn foo(bar_arg = bar.clone()) { ... bar_arg.clone(); ... }is wasteful.Going forward, if there is every a refactor, it would be ideal to remove the need for cloning within the generated function body, this might look like something involving cache_set taking a
&Keyor by maybe just only supporting owned inputs which are consumed and not cloned more than they need to be. In the later case where the cache function must consume the inputs, then I think it would be best not to support ref inputs, and have the user clone() on their side where they need it.