async-result-ext 0.1.1

Async extensions for Result<T, E> with async closures.
Documentation
  • Coverage
  • 90.91%
    10 out of 11 items documented5 out of 10 items with examples
  • Size
  • Source code size: 24.2 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 1.54 MB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 13s Average build duration of successful builds.
  • all releases: 13s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • tibrom/async-result-ext
    3 0 0
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • tibrom

async-result-ext

Async extensions for Rust’s [Result<T, E>].
This crate provides asynchronous counterparts of the standard Result methods (map, and_then, map_err, inspect), allowing you to use async closures seamlessly.


✨ Motivation

The standard library’s Result methods (map, and_then, etc.) only work with synchronous closures.
When writing async code, you often need to .await inside these transformations. This crate fills that gap.

Instead of:

let res: Result<i32, &str> = Ok(5);

let mapped = match res {
    Ok(v) => Ok(async { v * 2 }.await),
    Err(e) => Err(e),
};

You can just write:

use async_result_ext::AsyncResultExt;

let res: Result<i32, &str> = Ok(5);
let mapped = res.async_map(|v| async move { v * 2 }).await;

assert_eq!(mapped, Ok(10));

📦 Installation

Add this to your Cargo.toml:

[dependencies]
async-result-ext = "0.1.0"

🚀 Usage

use async_result_ext::AsyncResultExt;

#[tokio::main]
async fn main() {
    let r: Result<i32, &str> = Ok(2);

    // async_map: transform Ok values asynchronously
    let doubled = r.async_map(|v| async move { v * 2 }).await;
    assert_eq!(doubled, Ok(4));

    // async_and_then: chain async computations returning Result
    let chained = doubled.async_and_then(|v| async move { Ok(v + 3) }).await;
    assert_eq!(chained, Ok(7));

    // async_map_or: provide a default for Err cases
    let res = Err::<i32, &str>("fail");
    let fallback = res.async_map_or(100, |v| async move { v * 10 }).await;
    assert_eq!(fallback, 100);

    // async_map_err: transform errors asynchronously
    let err: Result<i32, &str> = Err("oops");
    let mapped_err = err.async_map_err(|e| async move { e.len() }).await;
    assert_eq!(mapped_err, Err(4));

    // async_inspect & async_inspect_err: peek into values without changing them
    let ok: Result<i32, &str> = Ok(42);
    ok.async_inspect(|v| async move {
        println!("Got value: {v}");
    }).await;

    let err: Result<i32, &str> = Err("fail");
    err.async_inspect_err(|e| async move {
        eprintln!("Error: {e}");
    }).await;

    // async_is_ok_and: check condition asynchronously on Ok values
    let r: Result<i32, &str> = Ok(10);
    let is_even = r.async_is_ok_and(|v| async move { v % 2 == 0 }).await;
    assert!(is_even);

    // async_is_err_and: check condition asynchronously on Err values
    let r: Result<i32, &str> = Err("boom!");
    let too_long = r.async_is_err_and(|e| async move { e.len() > 3 }).await;
    assert!(too_long);
}

📖 Provided Methods

  • async_map – async version of [Result::map]
  • async_and_then – async version of [Result::and_then]
  • async_map_or – async version of [Result::map_or]
  • async_map_or_else – async version of [Result::map_or_else]
  • async_map_err – async version of [Result::map_err]
  • async_inspect – async version of [Result::inspect]
  • async_inspect_err – async version of [Result::inspect_err]
  • async_is_ok_and - async version of [Result::is_ok_and]
  • async_is_err_and - async version of [Result::is_err_and]

⚡ Features

  • Minimal and lightweight
  • No dependencies (except your async runtime, e.g. Tokio or async-std)
  • Familiar API – mirrors the standard library’s Result methods

🔧 License

MIT License. See LICENSE for details.