Skip to content

Give the key of Table::entry() its own lifetime under experimental-api-5 - #1639

Merged
cberner merged 1 commit into
masterfrom
claude/sweet-hypatia-m4vct7-entry-key-lifetime
Nov 8, 2026
Merged

cberner merged 1 commit into
masterfrom
claude/sweet-hypatia-m4vct7-entry-key-lifetime

Conversation

@cberner

@cberner cberner commented Nov 8, 2026

Copy link
Copy Markdown
Owner

Under experimental-api-5, Table::entry() gives the key its own lifetime:

pub fn entry<'a, 'k>(&'a mut self, key: K::SelfType<'k>) -> Result<Entry<'a, 'k, K, V>>

Entry, OccupiedEntry and VacantEntry get the matching 'k parameter. key(), into_key(), remove_entry() and or_insert_with_key() hand the key back with that lifetime.

Why: today the key shares the table borrow's lifetime (entry<'a>(&'a mut self, key: K::SelfType<'a>)), which causes two problems:

  • The guard can't outlive the key. Returning table.entry(key.as_str())?.or_insert(..)? from a block where the key String lives fails with E0597.
  • Generic code is worse. K::SelfType<'k> is invariant in 'k, so the table must stay mutably borrowed for the key's entire lifetime. Calling entry() in a loop over keys of one lifetime fails, and so does calling it with a key whose lifetime isn't tied to the table borrow.

The key stays by value rather than impl Borrow: Entry has to own it, and a concrete parameter type keeps coercions working, such as entry(&string) on a &str table or entry(&vec) on a &[u8] table. A 'k: 'a bound can't replace the extra lifetime, because the compiler can't shorten K::SelfType<'k> to K::SelfType<'a>.

Gating, so that the 4.x API is unchanged:

  • The structs: OccupiedEntry and VacantEntry take 'k in both modes. Without the feature, lib.rs exports one-lifetime aliases OccupiedEntry<'a, K, V> = table::OccupiedEntry<'a, 'a, K, V>. That is fully compatible because their fields are private.
  • The enum: a type alias would break use redb::Entry::{Occupied, Vacant}, so without the feature the old Entry enum and its impl stay as a verbatim copy in mod entry_api4. Only two doc-link lines differ.
  • Table::entry has both signatures, each behind a cfg.

At flag removal, delete entry_api4, the two aliases and the old entry().

semver-checks note: cargo semver-checks --default-features reports struct_missing for OccupiedEntry and VacantEntry, because it doesn't treat a type alias as equivalent to a struct. I checked the uses that matter for structs with private fields: import by path, user trait impls, { .. } patterns, type-relative calls such as OccupiedEntry::key(&e), and elided lifetimes. All of them compile through the alias, so I believe it's a false positive. If you'd rather have that check clean for a 4.x release, the alternative is to also keep verbatim copies of the two structs and their impls, about 110 more lines, in entry_api4. With all features on, it reports the intended api-5 changes: the new lifetime, and redb::io from #1638.

Tests:

  • entry_guard_outlives_key and entry_in_generic_code (api-5 only). I checked that both fail to compile against the current signature: one with E0597, the other with a lifetime error.
  • I reworded two existing test comments that described the single-lifetime signature.

Checked:

  • cargo fmt.
  • clippy --all --all-targets, with and without --all-features.
  • clippy for thumbv7em (no_std).
  • cargo doc in both modes. Without the feature, Entry is still an enum whose variants link to the aliases.
  • cargo test --all-features, and cargo test with default features.

Generated by Claude Code

entry() tied the key to the lifetime of the table borrow, so the guard
an entry returned could not outlive the key. In generic code, where
K::SelfType<'k> is invariant, the table stayed mutably borrowed for the
key's whole lifetime, and entry() could not be called twice with keys
of one lifetime. Under experimental-api-5, Entry, OccupiedEntry and
VacantEntry take a second lifetime for the key.

Without the feature the 4.x API is unchanged: OccupiedEntry and
VacantEntry are aliases with one lifetime, and Entry keeps its 4.x
definition.

Assisted-by: Claude Code
Claude-Session: https://claude.ai/code/session_01ALhxet6NP69dCfAUv8TAhR
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 8, 2026 •

Copy link
Copy Markdown
Codex Review Summary: ✅ Completed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-08T23:13:37.000387Z ecc761d PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@cberner
cberner merged commit b15a899 into master Nov 8, 2026
5 checks passed
@cberner
cberner deleted the claude/sweet-hypatia-m4vct7-entry-key-lifetime branch November 8, 2026 23:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant