pub trait FutureResultExt<T, E>: Future<Output = Result<T, E>> + Sized {
// Required method
fn with_ctx<F, C>(self, f: F) -> ContextFuture<Self, F> ⓘ
where F: FnOnce() -> C,
C: IntoErrorContext;
// Provided method
fn ctx<C>(self, context: C) -> ContextFuture<Self, impl FnOnce() -> C> ⓘ
where C: IntoErrorContext { ... }
}Expand description
Extension trait for attaching error context to async Result-returning futures.
This trait mirrors the sync ResultExt trait,
providing the same .ctx() and .with_ctx() ergonomics for async code.
§Design Principles
- Lazy attachment: Context is only attached when an error occurs
- Zero-cost success path: No allocation or context computation on success
- Familiar syntax: Same method names as sync counterparts
§Examples
§Basic Usage
use error_rail::prelude_async::*;
#[derive(Debug)]
struct User;
#[derive(Debug)]
struct ApiError;
async fn fetch_from_db(_id: u64) -> Result<User, ApiError> {
Err(ApiError)
}
async fn fetch_user(id: u64) -> BoxedResult<User, ApiError> {
fetch_from_db(id)
.ctx("fetching user")
.await
.map_err(Box::new)
}§With Lazy Context
use error_rail::prelude_async::*;
#[derive(Debug)]
struct Order;
#[derive(Debug)]
struct OrderError;
async fn validate_order(_order_id: u64) -> Result<Order, OrderError> {
Err(OrderError)
}
async fn process_order(order_id: u64) -> BoxedResult<Order, OrderError> {
validate_order(order_id)
.with_ctx(|| format!("validating order {}", order_id))
.await
.map_err(Box::new)
}Required Methods§
Sourcefn with_ctx<F, C>(self, f: F) -> ContextFuture<Self, F> ⓘwhere
F: FnOnce() -> C,
C: IntoErrorContext,
fn with_ctx<F, C>(self, f: F) -> ContextFuture<Self, F> ⓘwhere
F: FnOnce() -> C,
C: IntoErrorContext,
Attaches a lazily-evaluated context to the future’s error.
The closure is only called when the future resolves to an error, avoiding any computation on the success path.
Use this (or context!) when you want lazy string formatting.
§Arguments
f- A closure that produces the error context
§Examples
use error_rail::prelude_async::*;
#[derive(Debug)]
struct User;
#[derive(Debug)]
struct ApiError;
async fn fetch_from_db(_id: u64) -> Result<User, ApiError> {
Err(ApiError)
}
async fn fetch_user(id: u64) -> BoxedResult<User, ApiError> {
fetch_from_db(id)
.with_ctx(|| format!("fetching user {}", id))
.await
.map_err(Box::new)
}Provided Methods§
Sourcefn ctx<C>(self, context: C) -> ContextFuture<Self, impl FnOnce() -> C> ⓘwhere
C: IntoErrorContext,
fn ctx<C>(self, context: C) -> ContextFuture<Self, impl FnOnce() -> C> ⓘwhere
C: IntoErrorContext,
Attaches a static context to the future’s error.
The context is converted to an error context only when the future resolves to an error.
Note: if you pass an already-formatted String (e.g. format!(...)),
that formatting still happens eagerly before calling .ctx().
§Arguments
context- Any type implementingIntoErrorContext
§Examples
use error_rail::prelude_async::*;
async fn example() {
let result = async { Err::<(), _>("failed") }
.ctx("operation failed")
.await;
assert!(result.is_err());
}Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.