error-rail
use *;
Why error-rail?
Most error handling libraries format context eagerly—even on success paths where the context is never used. error-rail uses lazy evaluation, deferring string formatting until an error actually occurs.
Benchmark Results (full details):
| Scenario | error-rail | Eager formatting | Speedup |
|---|---|---|---|
| Success path | 637 ns | 1,351 ns | 2.1x faster |
| Error path | 941 ns | 835 ns | 1.1x slower |
Since most operations succeed (95%+), lazy evaluation provides significant real-world performance gains.
Installation
30-Second Quick Start
use *;
// Add context to any Result with .ctx()
// Chain multiple contexts
New to error-rail? See the Quick Start Guide for step-by-step examples.
Key Features
1. Structured Error Context
Wrap any error in ComposableError and attach layered metadata.
use ;
let err = new
.with_context
.with_context
.set_code;
println!;
// Output: retry attempt 3 -> [database] at src/main.rs:7 (host=localhost:5432) -> connection failed (code: 500)
2. Error Pipeline
Chain context and transformations with a fluent builder API.
use ;
let result = new
.with_context
.with_context
.map_error // Transform error type
.finish_boxed;
if let Err = result
3. Validation Accumulation
Collect multiple errors instead of failing fast—ideal for form validation.
use Validation;
// Collect all validation results
let results: = vec!.into_iter.collect;
match results
// Output:
// Error: age must be between 0 and 150
// Error: name cannot be empty
4. Zero-Cost Lazy Context
The context! macro defers string formatting until an error actually occurs.
use ;
let payload = LargePayload ;
// format!() is NEVER called on success path
let result = new
.with_context
.finish_boxed;
Performance: In benchmarks, lazy context adds near-zero overhead on success. Eager formatting can be orders of magnitude slower.
5. Convenient Macros
| Macro | Purpose | Example |
|---|---|---|
context! |
Lazy formatted message | context!("user_id: {}", id) |
group! |
Structured context with multiple fields | group!(tag("db"), location(file!(), line!())) |
rail! |
Quick pipeline wrapper | rail!(fallible_fn()) |
use ;
// rail! is shorthand for ErrorPipeline::new(...).finish_boxed()
let result = rail!;
6. Type Aliases for Ergonomics
use ;
// Instead of Result<T, ComposableError<E>>
// Instead of Result<T, Box<ComposableError<E>>>
When to Use What?
Quick Reference
| Scenario | Recommended Type | Example |
|---|---|---|
| Simple error wrapping | ComposableError<E> |
Internal error handling |
| Function return type | BoxedComposableResult<T, E> |
Public API boundaries |
| Adding context to Result | ErrorPipeline |
Wrapping I/O operations |
| Form/input validation | Validation<E, T> |
Collecting all field errors |
| Error chaining | ErrorPipeline + finish_boxed() |
Multi-step operations |
Validation vs Result
| Feature | Result<T, E> |
Validation<E, T> |
|---|---|---|
| Short-circuit | ✅ Yes (stops at first error) | ❌ No (collects all) |
| Use case | Sequential operations | Parallel validation |
| Error count | Single | Multiple |
| Iterator support | ? operator |
.collect() |
Common Pitfalls
1. Forgetting to Box for Return Types
// ❌ Large stack size (48+ bytes per Result)
// ✅ Reduced stack size (8 bytes pointer)
2. Excessive Context Depth
// ❌ Adding context at every layer (O(n) performance)
db_call
.with_context
.and_then
.and_then
// ... 20 more layers
// ✅ Add context at boundaries only
let result = db_call
.and_then
.and_then;
new
.with_context
.finish_boxed
3. Eager vs Lazy Context
// ❌ Eager: format! runs even on success
.with_context
// ✅ Lazy: format! only runs on error
.with_context
Module Reference
| Module | Description |
|---|---|
prelude |
Start here! Common imports: ResultExt, BoxedResult, macros |
context |
Context attachment: with_context, accumulate_context, format_error_chain |
convert |
Conversions between Result, Validation, and ComposableError |
macros |
context!, group!, rail!, impl_error_context! |
traits |
ResultExt, BoxedResultExt, IntoErrorContext, ErrorOps, WithError |
types |
ComposableError, ErrorContext, ErrorPipeline, LazyContext |
validation |
Validation<E, A> type with collectors and iterators |
no_std Support
error-rail is no_std compatible by default. It requires only the alloc crate.
[]
= { = "0.4", = false }
Enable std features when needed:
[]
= { = "0.4", = ["std"] } # Enables backtrace! macro
Examples
Integration Guides
- Quick Start Guide - Step-by-step tutorial
License
Apache-2.0