RFC 2504 добавит обязательный fn backtrace(&self) -> Option<&Backtrace>
ко всем std::error::Error
.Это еще не готово, поэтому на данный момент SNAFU , макрос помощника по ошибкам, заполняет это, связывая черту ErrorCompat
со всеми типами, сгенерированными макросом.Это позволяет поддерживать обратную трассировку до того, как она появится в Rust по ночам.
Однако эта черта ErrorCompat
реализована не для всех разработчиков std::error::Error
.Я хочу - в некотором родовом коде печати ошибок - иметь возможность отображать цепочку причин вместе с трассировкой стека, связанной с тем, где была создана ошибка SNAFU.К сожалению, функция source()
возвращает &(dyn Error + 'static)
.
use std::error::Error as StdError;
use snafu::{ResultExt, ErrorCompat};
fn main() {
let err: Result<(), _> = Err(std::io::Error::new(std::io::ErrorKind::Other, "oh no!"));
let err = err.with_context(|| parse_error::ReadInput {
filename: "hello"
});
let err = err.with_context(|| compile_error::ParseStage);
// some generic error handling code
if let Err(err) = err {
// `cause` is type &(dyn std::error::Error + 'static)
let cause = err.source().unwrap();
if let Some(err) = /* attempt to downcast cause into &dyn snafu::ErrorCompat trait object */ {
println!("{}", err.backtrace().unwrap());
}
}
}
pub mod compile_error {
use snafu::{Snafu, Backtrace};
#[derive(Debug, Snafu)]
#[snafu(visibility(pub(super)))]
pub enum Error {
#[snafu(display("Error parsing code: {}", source))]
ParseStage {
source: crate::parse_error::Error,
backtrace: Backtrace
},
}
}
pub mod parse_error {
use snafu::{Snafu, Backtrace};
#[derive(Debug, Snafu)]
#[snafu(visibility(pub(super)))]
pub enum Error {
#[snafu(display("Could not read input {:?}: {}", filename, source))]
ReadInput {
filename: std::path::PathBuf,
source: std::io::Error,
backtrace: Backtrace
},
}
}
Я смотрел на std::any::Any::downcast_ref
, но это для понижения в структуру, а не для понижения объекта черты доеще одна черта объекта.Я хотел бы избежать перечисления всех возможных ошибок SNAFU конкретного типа в моем коде обработки ошибок.
Я мог бы заморозить себя, пока RFC 2504 (полностью) не будет (полностью) реализован, но, безусловно, есть какой-то способсделай это.