18 releases (10 stable)
Uses new Rust 2024
| 1.4.0 | Mar 21, 2026 |
|---|---|
| 1.1.0 | Feb 16, 2026 |
| 0.9.0 | Feb 6, 2026 |
| 0.6.2 | Dec 29, 2025 |
#534 in Rust patterns
Used in 2 crates
18KB
113 lines
resext
Main crate providing error handling with context chains
This is the primary interface for ResExt. It re-exports the proc-macro as well as other helpers provided by ResExt.
Installation
[dependencies]
resext = "1.4.0"
Quick Example
use resext::resext;
use resext::ctx;
#[resext]
enum FileError {
Io(std::io::Error),
Parse(serde_json::Error),
}
fn load_data(path: &str) -> Res<Data> {
let content = std::fs::read_to_string(path)
.context(ctx!("Failed to read file: {}", path))?;
let data = serde_json::from_str(&content)
.context(ctx!("Failed to parse file: {}", path))?;
Ok(data)
}
Proc Macro
The proc macro provides clean syntax with full customization:
#[resext(
prefix = "ERROR: ",
suffix = "\n",
msg_prefix = " at: ",
msg_suffix = "",
delimiter = "\n",
source_prefix = "Caused by: ",
include_variant = true,
alias = MyResult,
alloc = true
)]
enum MyError {
Network(reqwest::Error),
Database { error: sqlx::Error },
}
Attribute Options
prefix- String prepended to entire error messagesuffix- String appended to entire error messagemsg_prefix- String prepended to each context messagemsg_suffix- String appended to each context messagedelimiter- Separator between context messages (default: "\n - ")source_prefix- String prepended to source error (default: "Error: ")include_variant- Include variant name in Display output (default: false)alias- Custom type alias name which is used for getting the names for other items generated by the proc-macro (default:Res)buf_size- Size for the context message byte buffer (default: 64)allocEnable heap-spilling if context exceedsbuf_size
.context() Method
Add static context to an error.
Accepts &str or ctx!() macro which outputs a lazily evaluated closure with usage similar to old format_args!() API
Example
std::fs::read("file.txt")
.context("Failed to read file")?;
ctx!() macro
Macro defined in resext crate that returns a lazily evaluated closure with similar usage to old format_args!() context API but with better performance
- This macro shoudln't be used alone and should be used with
.context()method instead
Example
let path: &str = "file.txt";
std::fs::read(path)
.context(ctx!("Failed to read file: {}", path))?;
Error Display Format
Errors are displayed with context chains:
Failed to load application
- Failed to read config file
- Failed to open file
Error: No such file or directory
With include_variant = true:
Failed to load application
- Failed to read config file
Error: Io: No such file or directory
Examples
Error Handling
use resext::ctx;
use resext::resext;
use std::io::{Error, ErrorKind};
#[resext]
enum AppError {
Io(Error),
Parse(std::num::ParseIntError),
}
fn read_config(path: &str) -> Res<String> {
let content: String = std::fs::read_to_string(path)
.context(ctx!("Failed to read file: {}", path))?;
if content.is_empty() {
return Err(ResErr::new(
"Content is is empty",
Error::new(ErrorKind::UnexpectedEof, "Data is empty"),
));
}
let value = content
.trim()
.parse::<i32>()
.context(ctx!("Failed to parse config value: {}", &content))?;
if value < 32 {
return Err(ResErr::from_args(
ctx!("Value: {} is less than 32", value),
Error::new(ErrorKind::InvalidData, "Data is less than 32"),
));
}
Ok(content)
}
Multiple Error Types
use resext::resext;
#[resext(alias = ApiResult)]
enum ApiError {
Network(reqwest::Error),
Database(sqlx::Error),
Json(serde_json::Error),
}
async fn fetch_user(id: u64) -> ApiResult<User> {
let response = reqwest::get(format!("/users/{}", id))
.await
.context("Failed to fetch user")?;
let user = response.json()
.await
.context("Failed to parse user data")?;
Ok(user)
}
Named Fields
use resext::resext;
#[resext]
enum DatabaseError {
Connection { error: sqlx::Error },
Query { error: sqlx::Error },
}
Contributing
See CONTRIBUTING.md for guidelines.
License
MIT - See LICENSE for details.
Dependencies
~62KB