okerrr 0.0.0

macros for concise Result and Option handling with caller-level control flow
Documentation
  • Coverage
  • 100%
    5 out of 5 items documented1 out of 5 items with examples
  • Size
  • Source code size: 35.21 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 92.96 kB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 1s Average build duration of successful builds.
  • all releases: 2s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • awill1988/okerrr
    0 0 0
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • awill1988
okerrr-0.0.0 has been yanked.

okerrr!

Small declarative macros for the Result and Option patterns that turn up at every call site. The triple r is for a little fun; the API stays simple.

Crates.io Documentation License

Why a macro?

When an error needs its payload and must return from the caller, a match is often the right tool:

fn process(input: Result<i32, &'static str>) -> Result<i32, &'static str> {
    let value = match input {
        Ok(value) => value,
        Err(error) => return Err(error),
    };
    Ok(value * 2)
}

okerrr! keeps the same control flow and error binding while removing the repeated pattern:

use okerrr::okerrr;

fn process(input: Result<i32, &'static str>) -> Result<i32, &'static str> {
    let value = okerrr!(input, error => return Err(error));
    Ok(value * 2)
}

if let is still useful when only one branch matters. let-else is good for early returns, but its else block cannot bind the Err payload. A closure such as unwrap_or_else can bind the error, but return, break, and continue inside it do not control the caller. A macro keeps those choices at the call site.

Forms

Use okerrr! for Result and okerrr_some! for Option in new code. okerr! and okerr_some! are supported convenience spellings.

use okerrr::{okerrr, okerrr_some};

fn double(input: Result<i32, &'static str>) -> Result<i32, String> {
    let value = okerrr!(input, error => return Err(format!("bad input: {}", error)));
    Ok(value * 2)
}

fn value_or_zero(input: Result<i32, &'static str>) -> i32 {
    okerrr!(input, 0) // also: okerrr!(input, else 0)
}

fn maybe_double(input: Option<i32>) -> Option<i32> {
    let value = okerrr_some!(input);
    Some(value * 2)
}

fn option_or_zero(input: Option<i32>) -> i32 {
    okerrr_some!(input, 0) // also: okerrr_some!(input, else 0)
}

okerrr!(result) returns Err(From::from(error)) from the caller on failure. An error handler can also break or continue an enclosing loop. The input expression runs once; fallback expressions run only for Err or None.

The default build has no dependencies and supports #![no_std].

Caller-side tracing

okerrr! does not log an Err or require its type to implement a formatting trait. If a caller decides an error deserves an event, put tracing::error! in the bound handler:

use okerrr::okerrr;

fn read(input: Result<i32, &'static str>) -> Result<i32, &'static str> {
    let value = okerrr!(input, error => {
        tracing::error!(error = ?error, "read failed");
        return Err(error);
    });
    Ok(value)
}

The Debug requirement above comes from the caller's ?error field. A caller can choose different fields or a different level. The application owns its subscriber and any tracing-to-OpenTelemetry pipeline; this crate has no exporter or tracing feature.

Contributor checks

Install the conventional commit linter and activate the tracked hooks:

npm ci
git config core.hooksPath .githooks

pre-commit checks formatting and strict Clippy for the crate and its downstream no_std fixture. commit-msg checks conventional commit format. Both stop invalid commits. Run cargo fmt --all and cargo fmt --manifest-path tests/fixtures/downstream/Cargo.toml, then restage reviewed changes before committing.

Squash merges use the pull request title as the final commit message. Mark breaking changes with ! in that title (for example, feat!: change macro syntax) so release notes retain the signal.

Releases

A version increase in Cargo.toml signals a release. A merge without a version increase runs CI and skips publishing. CI validates the proposed version against the previous main manifest and crates.io, then provides a release-notes preview on the pull request.

After the tests pass on main, the release job generates notes from conventional commits since the previous v* tag, publishes the manifest version to crates.io, and creates a matching GitHub release. Prerelease versions receive prerelease GitHub releases. Notes live in GitHub releases; there is no tracked changelog file.

Publishing uses the CARGO_REGISTRY_TOKEN secret in the production GitHub environment. For bootstrap, 0.0.0 is an unreleased baseline: the first version increase from it triggers publishing. Later increases require the previous version to be published. Run CI manually from GitHub Actions to check packaging and production secret access without publishing.

Use chore(release): bump version for a version-only commit; release notes omit that commit.

License

Dual-licensed under MIT or Apache 2.0.