I think we need to have a discussion on the std::error::Error
trait (again?) Here is the definition for your reference…
pub trait Error: Debug + Display + Reflect {
fn description(&self) -> &str;
fn cause(&self) -> Option<&Error> { ... }
}
As the Error trait stands now it is difficult for someone to write an implementation for the description method without preallocating a String
or using an str
with a 'static
lifetime. For example you cannot use format!()
to return an informative error string if you want to go beyond static strings. Look at the following implementation to understand where I am coming from…
pub enum MyError<'a> {
...
ParseIntError {
error: ParseIntError,
iter: CharIndices<'a>,
err_msg: String,
},
}
impl<'a> Error for MyError<'a> {
fn description(&self) -> &str {
match *self {
// Note: the error message cannot be constructed here since we have
// an immutable reference to Self. All we can do is simply pass on
// what we have here.
MyError::ParseIntError { ref err_msg, .. } => err_msg,
...
}
}
}
impl<'a> From<(ParseIntError, CharIndices<'a>)> for MyError<'a> {
fn from(err: (ParseIntError, CharIndices<'a>)) -> MyError<'a> {
let error = err.0;
let iter = err.1;
// NOTE: The error message has to be allocated and constructed ahead
// of time. There is no guarantee that it will ever be used but we have
// to take a performance hit here anyway. This goes against Rust's pay
// as you go philosophy.
let err_msg;
if let Some((i, _)) = iter.clone().next() {
err_msg = format!("{} @ {}", error.description(), i);
} else {
err_msg = format!("{} @ UNKOWN", error.description());
}
MyError::ParseIntError {
error: error,
iter: iter,
err_msg: err_msg,
}
}
}
Playpen link to a more complete example.
IMO either of the following signatures will get rid of the preallocation / a priori construction problem…
pub trait Error: Debug + Display + Reflect {
fn description(&self, &mut String);
fn cause(&self) -> Option<&Error> { ... }
}
pub trait Error: Debug + Display + Reflect {
fn description(&mut self) -> &str;
fn cause(&self) -> Option<&Error> { ... }
}
I hope I am doing this the right way if not please do let me know.