Skip to content

Add try_get and document the remaining public-API panics#29

Merged
akesson merged 1 commit into
mainfrom
henrik/remove-public-panics
Jun 3, 2026
Merged

Add try_get and document the remaining public-API panics#29
akesson merged 1 commit into
mainfrom
henrik/remove-public-panics

Conversation

@akesson

@akesson akesson commented Jun 3, 2026

Copy link
Copy Markdown
Member

The last road-to-1.0 item (#4 of 4): get the public API's panics out of the "looks like sloppiness" category. This one is additive, not breaking — no existing call needs to change.

What & why

I sorted every remaining panic by who can trigger it:

Panic site Can user input reach it? Decision
L10nLanguageVec::get(impl AsRef<str>) Yes — any string Add try_get -> Option; keep get, document its precondition
Generated load() / load_all() (single-file) No — embedded, build-validated .ftl Keep infallible; unwrap() → diagnostic expect()
Generated msg(..).unwrap() accessors No — ids/types generated from the same .ftl Leave as-is (documented invariant on L10nError)

Only the first is a genuine footgun: get accepts an arbitrary string and panics on a miss. So:

  • try_get(&self, lang) -> Option<&L10nBundle> — the non-panicking path for when the language id comes from outside the loaded set (a raw Accept-Language, a query param, user input).
  • get stays for the common case — you pass an L10n enum variant, and the generated L10n::langneg always returns one (it has a Default fallback), so the lookup is guaranteed to hit. It now documents the panic precondition and delegates to try_get. Matches the stdlib Index-panics / get-returns-Option idiom (names inverted here for back-compat).

The generated single-file load/load_all are infallible by construction — the .ftl is embedded and validated at build time — so they keep their non-Result signatures (forcing callers to handle an impossible error would be pure noise; compare the compressed load<D>, which genuinely returns Result because the user's decompressor can fail). The bare unwrap() is now an expect() that says it's a build-time bug worth reporting.

The generated message accessors are deliberately untouched: a failure there is the same generated-code-vs-embedded-.ftl drift invariant already documented on L10nError, and adding an expect string to every accessor would only bloat the output.

Verification

  • cargo fmt --check, clippy --all-targets --features build,langneg -D warnings, RUSTDOCFLAGS=-D warnings cargo doc — all clean
  • 101 unit tests (+1: try_get Some/None) + 1 integration (playground) test pass; benches build
  • Regenerated all 16 *_gen.rs fixtures + snapshots and the playground single_l10n.rs; the entire generated diff is only unwrap()expect(..) on load/load_all (gzip and multi-file outputs correctly unchanged)

0.7 cycle

#25 seal BuildOptions · ✅ #26 seal FtlOutputOptions · ✅ #28 typed L10nError · ✅ this — closes out the 0.7 road-to-1.0 work.

🤖 Generated with Claude Code

The last road-to-1.0 item: take the public API's panics out of the
"looks like sloppiness" category. This one is additive, not breaking.

- `L10nLanguageVec::try_get` returns `Option<&L10nBundle>` for the case the
  type system can't rule out: a language id from outside the loaded set (a
  header, a query param, user input). `get` stays for known `L10n` variants
  (the generated `L10n::langneg` always yields one) but now documents its
  panic precondition and delegates to `try_get`.
- The generated single-file `load`/`load_all` kept a bare `.unwrap()`. They
  are infallible by construction — the `.ftl` is embedded and validated at
  build time — so they stay non-`Result`, but the panic is now an `expect`
  that says it's a build-time bug worth reporting, not a runtime condition.

The generated message accessors (`msg(..).unwrap()` etc.) are deliberately
left as-is: their ids and arg types are generated from the same validated
`.ftl`, so a failure there is the same drift invariant already documented on
`L10nError`, and per-accessor `expect` strings would only bloat the output.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@akesson akesson merged commit 39af3f8 into main Jun 3, 2026
5 checks passed
@akesson akesson deleted the henrik/remove-public-panics branch June 3, 2026 07:11
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