use log::error;
use thiserror::Error as ThisError;
pub use anyhow::Error;
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, Default, ThisError)]
#[error("{message}")]
pub struct AnnotatedReport {
message: String,
notes: Vec<String>,
}
impl AnnotatedReport {
pub fn set_message(&mut self, m: String) {
self.message = m;
}
pub fn add_note(&mut self, n: String) {
self.notes.push(n);
}
pub fn notes(&self) -> &[String] {
&self.notes[..]
}
}
#[doc(hidden)]
pub use anyhow::Context;
#[macro_export]
macro_rules! atry {
(@aa $ar:ident [ $($inner:tt)+ ] ) => {
$ar.set_message(format!($($inner)+));
};
(@aa $ar:ident ( note $($inner:tt)+ ) ) => {
$ar.add_note(format!($($inner)+));
};
($op:expr ; $( $annotation:tt )+) => {{
use $crate::errors::Context;
$op.with_context(|| {
let mut ar = $crate::errors::AnnotatedReport::default();
$(
atry!(@aa ar $annotation);
)+
ar
})?
}};
}
#[macro_export]
macro_rules! a_ok_or {
(@aa $ar:ident [ $($inner:tt)+ ] ) => {
$ar.set_message(format!($($inner)+));
};
(@aa $ar:ident ( note $($inner:tt)+ ) ) => {
$ar.add_note(format!($($inner)+));
};
($option:expr ; $( $annotation:tt )+) => {{
use $crate::atry;
$option.ok_or_else(|| {
let mut ar = $crate::errors::AnnotatedReport::default();
$(
atry!(@aa ar $annotation);
)+
ar
})?
}};
}
pub fn report(r: Result<i32>) -> i32 {
let err = match r {
Ok(c) => return c,
Err(e) => e,
};
let mut notes = Vec::new();
eprintln!();
error!("{}", err);
if let Some(ann) = err.downcast_ref::<AnnotatedReport>() {
notes.extend(ann.notes());
}
err.chain().skip(1).for_each(|cause| {
crate::logger::Logger::print_cause(cause);
if let Some(ann) = cause.downcast_ref::<AnnotatedReport>() {
notes.extend(ann.notes());
}
});
for note in ¬es {
eprintln!();
crate::logger::Logger::print_err_note(note);
}
1
}