improvement

work
Avril 4 years ago
parent cf6d97d69f
commit 878c58b49e
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -38,6 +38,7 @@ impl Default for ErrorKind
impl Error
{
/// Into the `ErrorKind`
pub fn into_inner(self) -> ErrorKind
{
*self.internal
@ -61,7 +62,6 @@ impl Error
&self.context
}
/// Create a new error with a constant string
pub fn new_static(err: ErrorKind, ctx: Context, message: &'static str) -> Self
{
@ -89,6 +89,15 @@ impl Error
message: Message::from_other(message),
}
}
/// Create a new error with no message
pub fn new_none(err: ErrorKind, ctx: Context) -> Self
{
Self {
internal: box err,
context: ctx,
message: Message::None,
}
}
}
impl fmt::Display for Error
@ -122,10 +131,38 @@ impl error::Error for Error
($fmt:literal $($tt:tt)*) => ($crate::context!(format!($fmt $($tt)*)));
}
/// Macro for instantiating errors and also ad-hoc error types
///
/// # Instantiating `Error`.
/// The primary use is to return errors of the `Error` struct, this is how it can work.
/// ## With `ErrorKind`
/// The kind should be prefixed with `;`:
/// ```
/// error!(ErrorKind::Unknown; "unknown error message");
/// error!(ErrorKind::IO(yield io_err; "I/O error opening {:?}", file));
/// ```
///
/// ## Without `ErrorKind`
/// With all except a single string literal, the message is boxed as the `ErrorKind`, and printed with a `None` message.
/// This means that the message given as an ad-hoc error type is counted as the source.
///
/// ```
/// error!("unknown error");
/// error!(yield "something went wrong: {}", message);
/// ```
///
/// # Defining errors
/// To create ad-hoc errors, use `error!(impl ...)`. It has the same syntax as the above cases, except with no error kind
/// ```
/// error!(impl "Error message");
/// error!(impl yield "lazy formatted string {}", string);
/// ```
///
/// # `yield`ing formatting
/// When format string are provided to `error!()`, they by default will use the eager `format!()` macro, which will immediately evaluate it's arguments and produce the string to put into the error.
/// To instead box the arguments and evaluate as-needed, we can use the `lazy_format` crate by prefixing the format string literals with `yield`. This works on both `Error` instantiations and ad-hoc error definitions.
#[macro_export] macro_rules! error {
($kind:expr, $lit:literal) => ($crate::error::Error::new_static($kind, $crate::context!(), $lit));
($lit:literal) => ($crate::error!(Default::default(), $lit));
($kind:expr, $msg:expr) => {
(@ $msg:expr) => {
{
pub struct DisplayError<D>(D) where D: fmt::Display;
impl<D> fmt::Debug for DisplayError<D>
@ -147,14 +184,26 @@ impl error::Error for Error
impl<D> error::Error for DisplayError<D>
where D: fmt::Display{}
$crate::error::Error::new($kind, $crate::context!(), DisplayError($msg))
DisplayError($msg)
}
};
($msg:expr) => ($crate::error!(Default::default(), $msg));
(yield $kind:expr, $lit:literal $($tt:tt)*) => ($crate::error!($kind, lazy_format::lazy_format!($lit $($tt)*)));
($kind:expr, $lit:literal $($tt:tt)*) => ($crate::error!($kind, format!($lit $($tt)*)));
(yield $lit:literal $($tt:tt)*) => ($crate::error!(yield Default::default(), $lit $($tt)*));
($lit:literal $($tt:tt)*) => ($crate::error!(Default::default(), $lit $($tt)*));
(impl $lit:literal) => ($crate::error!(@ $lit));
(impl $expr:expr) => ($crate::error!(@ $expr));
(impl yield $lit:literal $($tt:tt)*) => ($crate::error!(@ lazy_format::lazy_format!($lit $($tt)*)));
(impl $lit:literal $($tt:tt)*) => ($crate::error!(@ format!($lit $($tt)*)));
($kind:expr; $lit:literal) => ($crate::error::Error::new_static($kind, $crate::context!(), $lit));
($lit:literal) => ($crate::error!(Default::default(), $lit));
($kind:expr; $msg:expr) => ($crate::error::Error::new($kind, $crate::context!(), $msg));
($msg:expr) => ($crate::error::Error::new_none($crate::error::ErrorKind::Any(box $crate::error!(@ $msg)), $crate::context!()));
(yield $lit:literal $($tt:tt)*) => ($crate::error::Error::new_none($crate::error::ErrorKind::Any(box $crate::error!(@ lazy_format::lazy_format!($lit $($tt)*))), $crate::context!()));
($lit:literal $($tt:tt)*) => ($crate::error::Error::new_none($crate::error::ErrorKind::Any(box $crate::error!(@ format!($lit $($tt)*))), $crate::context!()));
(yield $kind:expr; $lit:literal $($tt:tt)*) => ($crate::error!($kind; lazy_format::lazy_format!($lit $($tt)*)));
($kind:expr; $lit:literal $($tt:tt)*) => ($crate::error::Error::new_string($kind, $crate::context!(), format!($lit $($tt)*)));
}
#[derive(Debug)]
@ -185,6 +234,7 @@ impl fmt::Display for ErrorKind
match self {
Self::IO(io) => write!(f, "i/o error: {}", io),
Self::Wrap(wrap) => write!(f, "{}", wrap),
Self::Any(any) => write!(f, "{}", any),
Self::None => Ok(()),
_ => write!(f, "unknown error"),
}
@ -198,6 +248,7 @@ impl error::Error for ErrorKind
Some(match &self {
Self::IO(io) => io,
Self::Wrap(wrap) => return wrap.source(),
Self::Any(any) => any.as_ref(),
_ => return None,
})
}
@ -239,9 +290,8 @@ mod test
#[test]
fn test() -> ReportedResult<()>
{
color_eyre::install()?;
fn testt() -> Result<()> {
let err= error!(yield one().unwrap_err().into_inner(), "hello world {} {}", 1, 2);
let err= error!(yield one().unwrap_err().into_inner(); "hello world {} {}", 1, 2);
Err(err)
.wrap_err_with(|| context!("with string"))
.wrap_err_with(|| context!(yield "with another string and some stuffs {}", 1))?;
@ -275,8 +325,16 @@ mod test
Ok(one()
.aggregate_with(|_| testt())
.aggregate_with(|_| two())
.aggregate_with(|_| works())
.aggregate_with(|_| three())?)
}
#[test]
fn strings() -> ReportedResult<()>
{
Err(error!(yield "literal format {}", 1))?;
Ok(())
}
}

Loading…
Cancel
Save