macro_rules! context {
() => { ... };
($($arg:tt)*) => { ... };
}_helpers only.Expand description
Helper utilities for building procedural macros Creates a closure that generates context strings for error handling with automatic file and line information.
This macro provides a convenient way to add context to errors when using the anyhow
crate’s .with_context() method. It automatically prepends the current file name and line number to your
context message, making error tracking much easier during debugging.
The macro supports the same syntax as the standard format! macro, allowing for formatted context messages
with placeholders and arguments. When no arguments are provided, it creates a simple context with just
file and line information.
§Syntax
context!() // Just file:line info
context!("message") // Static message with file:line
context!("format {}", arg) // Formatted message with file:line
context!("multiple {} {}", a, b) // Multiple format arguments
context!("multiple {a} {b}") // All things that format! supports are supported here too§Returns
Returns a closure of type impl FnOnce() -> String that can be passed directly to
anyhow’s .with_context() method or called manually to get the formatted context string.
§Output Format
The context macro produces strings in the following exact formats:
-
With no message:
"src/file.rs:line_number"
Example:"src/main.rs:42" -
With message:
"src/file.rs:line_number\r\nYour custom message here"
Example:"src/main.rs:42\r\nOperation failed"
The file path includes the src/ prefix and the line number is automatically determined
at compile time using the file! and line! macros. Messages are separated from
the location info with a carriage return + line feed (\r\n) sequence.
§Examples
§Basic Usage
use std::fs;
fn risky_operation() -> anyhow::Result<String> {
// This will show "src/examples.rs:line" if it fails
fs::read_to_string("missing_file.txt").with_context(context!())
}
let result = risky_operation();
assert!(result.is_err());
let error_msg = format!("{:?}", result.unwrap_err());
// Should contain file path and line
assert!(error_msg.contains(format!("src/examples.rs:{}", line!() - 8).as_str()));§With Custom Messages
use std::fs;
fn load_config(path: &str) -> anyhow::Result<String> {
fs::read_to_string(path).with_context(context!("Failed to load config file"))
}
let result = load_config("nonexistent.txt");
assert!(result.is_err());
let error_msg = format!("{:?}", result.unwrap_err());
assert!(
error_msg.contains(
format!(
"src/examples.rs:{}\r\nFailed to load config file",
line!() - 11
)
.as_str()
)
);§With Formatted Messages
use std::fs;
fn process_user_data(user_id: u64) -> anyhow::Result<()> {
let fetch_data = || -> anyhow::Result<String> {
fs::read_to_string("missing_data.txt")
.with_context(context!("Failed to fetch data for user {}", user_id))
};
let validate_data = |_data: &str| -> anyhow::Result<()> {
Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"invalid",
))
.with_context(context!("Data validation failed for user {}", user_id))
};
let data = fetch_data()?;
validate_data(&data)?;
Ok(())
}
let result = process_user_data(42);
assert!(result.is_err());
let error_msg = format!("{:?}", result.unwrap_err());
assert!(
error_msg.contains(
format!(
"src/examples.rs:{}\r\nFailed to fetch data for user 42",
line!() - 25
)
.as_str()
)
);§Chaining Multiple Context Levels
use std::fs;
fn outer_function() -> anyhow::Result<()> {
inner_function().with_context(context!("Failed in outer function"))
}
fn inner_function() -> anyhow::Result<()> {
let _ = fs::File::open("nonexistent.txt")
.with_context(context!("Failed to open configuration file"))?;
Ok(())
}
let result = outer_function();
assert!(result.is_err());
let error_msg = format!("{:?}", result.unwrap_err());
assert!(
error_msg.contains(
format!(
"src/examples.rs:{}\r\nFailed in outer function",
line!() - 17
)
.as_str()
)
);
assert!(
error_msg.contains(
format!(
//Spaces are added by anyhow for indentation
"src/examples.rs:{}\r\n Failed to open configuration file",
line!() - 22
)
.as_str()
),
);§Manual Context Generation
let ctx = context!("Operation failed with code {}", 500);
let result = ctx();
assert_eq!(
result,
format!(
"src/examples.rs:{}\r\nOperation failed with code 500",
line!() - 7
)
);§See Also
anyhow::Context- The trait that provides the.with_context()methodformat!- The standard formatting macro that this macro’s syntax is based onfile!andline!- The macros used internally to get location information