Skip to content

feat(error): add shared bail! and ensure! macros to ironrdp-error#1263

Open
Greg Lamberson (glamberson) wants to merge 1 commit into
Devolutions:masterfrom
lamco-admin:feat/ironrdp-error-bail-ensure-macros
Open

feat(error): add shared bail! and ensure! macros to ironrdp-error#1263
Greg Lamberson (glamberson) wants to merge 1 commit into
Devolutions:masterfrom
lamco-admin:feat/ironrdp-error-bail-ensure-macros

Conversation

@glamberson
Copy link
Copy Markdown
Contributor

Refs #1257.

Implements Change 3 from the proposal in #1257. Adds workspace-shared bail! and ensure! macros to ironrdp-error so call-site verbosity for typed errors matches anyhow::bail!/anyhow::ensure!.

What changes

  • bail!(kind) — empty context.
  • bail!(context, kind) — explicit &'static str context.
  • bail!(context, kind, source: source) — explicit context plus a chained source error.
  • ensure!(condition, kind) — empty context.
  • ensure!(condition, context, kind) — explicit context.

Both macros are #[macro_export]ed at the ironrdp-error crate root and use $crate::Error::new(...) for hygiene. The kind type is inferred from the enclosing function's return type (which must be Result<_, Error<Kind>> or any alias resolving to it).

Composition with #[track_caller]

Once Change 2 (#1262) lands and Error::new is annotated #[track_caller], these macros automatically capture the location at the macro use site (because the Error::new call expanded inside the macro is the caller of its own constructor, and #[track_caller] resolves to the macro's caller). This is the intended composition: Change 2 supplies the location, Change 3 supplies the call-site ergonomics, both compose without coordination.

No deprecation of per-crate macros

The existing per-crate constructor macros (decode_err!, encode_err!, pdu_other_err!, etc.) serve a different ergonomic pattern: they construct an error to be passed to ? or .map_err(...), rather than performing an early return. The shared bail!/ensure! are additive — they cover the early-return patterns that previously required hand-written return Err(Error::new(...)) boilerplate. The per-crate constructor macros remain useful for .map_err(decode_err!(...)) style and are not deprecated by this change.

Public API impact

Strictly additive. Two new exported macros at the ironrdp-error crate root. No changes to existing types, traits, or methods.

no_std verification

All three feature combinations of ironrdp-error build cleanly:

  • cargo check -p ironrdp-error --no-default-features
  • cargo check -p ironrdp-error --no-default-features --features alloc
  • cargo check -p ironrdp-error --features std

The macros use only fully-pathed std-free constructs (::core::result::Result::Err, $crate::Error::new), so they work identically across feature combinations.

xtask verification

  • cargo xtask check fmt: clean
  • cargo xtask check lints: clean
  • cargo xtask check locks: clean
  • cargo xtask check typos: clean
  • cargo xtask check tests: clean

Diff size

1 file changed, +56 lines, no deletions.

Refs Devolutions#1257.

Implements Change 3 from the proposal in Devolutions#1257. Adds workspace-shared
`bail!` and `ensure!` macros to ironrdp-error so call-site verbosity for
typed errors matches anyhow::bail!/anyhow::ensure!.

### What changes

- `bail!(kind)` — empty context.
- `bail!(context, kind)` — explicit `&'static str` context.
- `bail!(context, kind, source: source)` — explicit context plus a chained
  source error.
- `ensure!(condition, kind)` — empty context.
- `ensure!(condition, context, kind)` — explicit context.

Both macros are `#[macro_export]`ed at the ironrdp-error crate root and use
`$crate::Error::new(...)` for hygiene. The kind type is inferred from the
enclosing function's return type (which must be `Result<_, Error<Kind>>` or
any alias resolving to it).

### Composition with #[track_caller]

Once Change 2 (Devolutions#1262) lands and `Error::new` is annotated `#[track_caller]`,
these macros automatically capture the location at the macro use site
(because the `Error::new` call expanded inside the macro is the caller of
its own constructor, and `#[track_caller]` resolves to the macro's caller).
This is the intended composition: Change 2 supplies the location, Change 3
supplies the call-site ergonomics, both compose without coordination.

### No deprecation of per-crate macros

The existing per-crate constructor macros (`decode_err!`, `encode_err!`,
`pdu_other_err!`, etc.) serve a different ergonomic pattern: they construct
an error to be passed to `?` or `.map_err(...)`, rather than performing an
early return. The shared `bail!`/`ensure!` are additive — they cover the
early-return patterns that previously required hand-written
`return Err(Error::new(...))` boilerplate. The per-crate constructor
macros remain useful for `.map_err(decode_err!(...))` style and are not
deprecated by this change.

### Public API impact

Strictly additive. Two new exported macros at the ironrdp-error crate root.
No changes to existing types, traits, or methods.

### no_std verification

All three feature combinations of ironrdp-error build cleanly:
- `cargo check -p ironrdp-error --no-default-features`
- `cargo check -p ironrdp-error --no-default-features --features alloc`
- `cargo check -p ironrdp-error --features std`

The macros use only fully-pathed std-free constructs (`::core::result::Result::Err`,
`$crate::Error::new`), so they work identically across feature combinations.

### xtask verification

- `cargo xtask check fmt`: clean
- `cargo xtask check lints`: clean
- `cargo xtask check locks`: clean
- `cargo xtask check typos`: clean
- `cargo xtask check tests`: clean
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant