Skip to content

Nicolab/okerr

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

okerr - Ergonomic result / error handling

Crates.io Docs.rs License

okerr is a ergonomic result / error handling helpers built on anyhow and thiserror.

Most Rust projects handle errors with anyhow or eyre, and thiserror (for derive(Error)). Sometimes we have to juggle between.

okerr solves the problem, this crate makes this more convenient by providing consistency and an idiomatic API.

The okerr crate is mostly re-exported from anyhow, making it 100% compatible in both directions.

Thanks to okerr::from_boxed_error, it's easy to capture and convert eyre errors without including eyre as a dependency!

All of that in just a few lines of code (very lightweight, no overhead, no abstraction cost). Fully tested, of course!

Idiomatic aliases for clearer code:

anyerr!("Oops!"); // Instead of `anyhow!("Oops!")
err!("Oops!"); // Instead of `Err(anyhow!("Oops!")) or `Err(anyerr!("Oops!"))
fail!("Oops!"); // Instead of `bail!("Oops!")

// ---

use okerr::derive::Error;

#[derive(Error, Debug)]

// Instead of
use thiserror::Error;

#[derive(Error, Debug)]

// ---

// Convert from a boxed error (like eyre::Report)
let error = okerr::from_boxed_error(error.into())

// Create/convert from any std::error::Error
let error = okerr::anyerr!(error)

// Create/convert from a string
let error = okerr::anyerr!("Oops!")

// Wrap a Result into an okerr::Error
// Equivalent to result.map_err(okerr::Error::new)
let result = okerr::wrap_err(result)

It's very simple, very lightweight (just a few lines of code in the okerr crate), it provides consistency and a excellent DX. 100% compatible with anyhow and thiserror, convert easily error from a boxed error (like eyre::Report and others).

Related docs

Examples

Anyhow like

With okerr::Result, okerr::err!, okerr::fail! and okerr::anyerr!:

use okerr::{Result, err, fail, anyerr};

fn divide(a: i32, b: i32) -> Result<i32> {
    if b == 0 {
        err!("Cannot divide by zero")
    } else {
        Ok(a / b)
    }
}

fn maybe_fail(should_fail: bool) -> Result<String> {
  if should_fail {
    fail!("Oops!");
  }

  Ok("No error".to_string())
}

fn main() {
    let result = divide(10, 2);
    assert!(result.is_ok());
    assert_eq!(result.unwrap(), 5);

    let result = divide(10, 0);
    assert!(result.is_err());
    assert_eq!(result.unwrap_err().to_string(), "Cannot divide by zero");

    // fail! does early return
    let result = maybe_fail(true);
    assert!(result.is_err());
    assert_eq!(result.unwrap_err().to_string(), "Oops!");

    // No error
    let result = maybe_fail(false);
    assert!(result.is_ok());
    assert_eq!(result.unwrap(), "No error");

    // Same as anyhow!(...).
    // Creates an Error directly,
    // from a string or any std::error::Error
    let error = anyerr!("Oops!");
    assert_eq!(error.to_string(), "Oops!");
}

Thiserror like

NOTE: requieres the thiserror dependency to be added to your Cargo.toml (cargo add thiserror).

With okerr::derive::Error:

use okerr::{Result, err, derive::Error};

#[derive(Error, Debug)]
enum MyError {
    #[error("Cannot divide by zero")]
    DivideByZero,
    #[error("Cannot divide by {0}")]
    DivideBy(i32),
}

fn divide(a: i32, b: i32) -> Result<i32> {
    if b == 0 {
        err!(MyError::DivideByZero)
    } else if b < 0 {
        err!(MyError::DivideBy(b))
    } else {
        Ok(a / b)
    }
}

fn main() {
    let result = divide(10, 2);
    assert!(result.is_ok());
    assert_eq!(result.unwrap(), 5);

    let result = divide(10, 0);
    assert!(result.is_err());
    assert_eq!(result.unwrap_err().to_string(), "Cannot divide by zero");

    let result = divide(10, -2);
    assert!(result.is_err());
    assert_eq!(result.unwrap_err().to_string(), "Cannot divide by -2");
}

Tests

okerr is fully tested! Run all tests:

cargo test

Thanks

Thanks to @dtolnay, the author of anyhow and thiserror, for providing two great ways to handle errors in Rust. 👍

LICENSE

MIT (c) 2025, Nicolas Talle.

Author

Buy me a coffee ☕ via PayPal!

About

Ergonomic result / error handling helpers built on anyhow and thiserror.

Topics

Resources

License

Stars

Watchers

Forks

Languages