Allow source errors to expose their own context?
NightEule5 opened this issue · 1 comments
NightEule5 commented
It would be useful if error types could expose context to Anyhow. Say you're writing a library with an error like this:
#[derive(Copy, Debug)]
enum Context {
Copy,
Read,
Write,
Flush,
// ...
}
impl fmt::Display for Context {
// ...
}
#[derive(Debug, thiserror::Error)]
#[error("IO operation failed")]
struct Error {
#[source]
source: std::io::Error,
context: Context
}
impl Error {
fn context(&self) -> Context {
self.context
}
}
With Anyhow, the user could add the context manually like this, assuming they know the error type:
fn something() -> Result<(), Error> {
// ...
}
fn main() -> anyhow::Result<()> {
match something() {
Ok(_) => Ok(()),
Err(error) => Err(
anyhow::Error::from(error)
.context(error.context())
)
}
}
It'd be useful for error types to add context like this seamlessly. Maybe using the std Error
trait's provide
method could help here, but I didn't look too far into it. Adding a specialized trait could work:
// in anyhow
use std::{convert, error, fmt};
pub trait ContextError {
type Context: fmt::Display;
fn context(&self) -> Option<Self::Context>;
}
default impl<T: error::Error> ContextError for T {
type Context = convert::Infallible;
fn context(&self) -> Option<Self::Context> { None }
}
// usage
impl ContextError for Error {
type Context = Context;
fn context(&self) -> Option<Self::Context> {
Some(self.context)
}
}
Since specialization is unstable, it'd have to be feature-gated though. Thoughts?
dtolnay commented
Thanks for the suggestion!
This is not something that I would want to build into this crate, but I would be interested to see it explored further by someone in a different crate.