Skip to content

Replace runtime String errors with a typed L10nError#28

Merged
akesson merged 1 commit into
mainfrom
henrik/typed-runtime-errors
Jun 3, 2026
Merged

Replace runtime String errors with a typed L10nError#28
akesson merged 1 commit into
mainfrom
henrik/typed-runtime-errors

Conversation

@akesson

@akesson akesson commented Jun 3, 2026

Copy link
Copy Markdown
Member

Third of the batched 0.7 breaking changes on the road to 1.0 (road-to-1.0 item #3; version already at 0.7.0).

What & why

The runtime API returned Result<_, String> everywhere — impossible to match on, and a 1.0 wart. This introduces L10nError, a #[non_exhaustive] enum re-exported from the crate root and the prelude, and switches the whole runtime surface to it:

  • L10nBundle::{new, new_without_isolation, msg, attr, msg_segments}
  • L10nLanguageVec::{load, load_without_isolation}
  • the generated L10nLanguage::new
  • the generated compressed L10n::{load, load_all} accessors — the user's decompressor still returns Result<_, String>, and its error is wrapped in L10nError::Decompression

It mirrors the BuildError work already done on the build side. Crucially, the variants carry owned strings, not fluent-bundle's error types, so this public enum doesn't churn when that pre-1.0 dependency is bumped — the same decoupling the road-to-1.0 plan calls for.

This is breaking only for code that matched on / compared the error String. Code that unwrap/?-ed is unaffected — which is why the generated accessors (all .unwrap()) needed no body changes.

Notable mechanics

  • The committed *_gen.rs test modules are compiled, and their L10nLanguage::new does L10nBundle::new(...)? — so once new returns L10nError, the stale String versions wouldn't compile (no String: From<L10nError>), which would block the very test run that regenerates them. I pre-applied the exact signature change, then let the tests regenerate and confirmed the only content diff is the new() line.
  • Refreshed all insta snapshots (cargo insta accept); verified the aggregate diff across 15 snapshots is only the signature line.
  • Regenerated the playground outputs (incl. the compressed single_gzip_l10n.rs).
  • Strengthened the runtime test to assert L10nError::MessageNotFound { id } instead of just .is_err().

Verification (local, all green)

  • cargo test --features build,langneg — 100 unit + 1 playground integration test
  • cargo fmt --all --check, cargo clippy --all-targets --features build,langneg -- -D warnings
  • RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --features build,langneg
  • cargo build --benches --features bench-internals

Scope note

impl FromStr for L10n still uses type Err = String (a generated enum-parse on a generated type, distinct from the runtime error path) — left as-is to keep this focused.

Remaining 0.7 work

  1. Remove the public-API panics (L10nLanguageVec::get, generated load()/load_all() unwraps).

🤖 Generated with Claude Code

Introduce L10nError, a #[non_exhaustive] runtime error enum re-exported
from the crate root and the prelude. It carries owned strings rather than
fluent-bundle's own error types, so it stays stable across fluent-bundle
updates (the same decoupling goal as the road-to-1.0 work).

The runtime API now returns Result<_, L10nError> instead of
Result<_, String>:
  - L10nBundle::{new, new_without_isolation, msg, attr, msg_segments}
  - L10nLanguageVec::{load, load_without_isolation}
  - the generated L10nLanguage::new
  - the generated compressed L10n::{load, load_all} accessors, whose
    user decompressor error is wrapped in L10nError::Decompression

Generated code only `.unwrap()`/`?`-es these results, so message.rs needs
no change; the template and the compressed-accessor generator carry the
new signature. Regenerated every committed *_gen.rs fixture, refreshed the
insta snapshots (only the `new` signature line changed), and regenerated
the playground outputs. Strengthened the runtime test to match
L10nError::MessageNotFound rather than just asserting is_err().

Third of the batched 0.7 breaking changes; version already at 0.7.0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@akesson akesson merged commit e9afd25 into main Jun 3, 2026
5 checks passed
@akesson akesson deleted the henrik/typed-runtime-errors branch June 3, 2026 06:53
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