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 impl Error
{ {
/// Into the `ErrorKind`
pub fn into_inner(self) -> ErrorKind pub fn into_inner(self) -> ErrorKind
{ {
*self.internal *self.internal
@ -61,7 +62,6 @@ impl Error
&self.context &self.context
} }
/// Create a new error with a constant string /// Create a new error with a constant string
pub fn new_static(err: ErrorKind, ctx: Context, message: &'static str) -> Self pub fn new_static(err: ErrorKind, ctx: Context, message: &'static str) -> Self
{ {
@ -89,6 +89,15 @@ impl Error
message: Message::from_other(message), 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 impl fmt::Display for Error
@ -122,10 +131,38 @@ impl error::Error for Error
($fmt:literal $($tt:tt)*) => ($crate::context!(format!($fmt $($tt)*))); ($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 { #[macro_export] macro_rules! error {
($kind:expr, $lit:literal) => ($crate::error::Error::new_static($kind, $crate::context!(), $lit)); (@ $msg:expr) => {
($lit:literal) => ($crate::error!(Default::default(), $lit));
($kind:expr, $msg:expr) => {
{ {
pub struct DisplayError<D>(D) where D: fmt::Display; pub struct DisplayError<D>(D) where D: fmt::Display;
impl<D> fmt::Debug for DisplayError<D> impl<D> fmt::Debug for DisplayError<D>
@ -147,14 +184,26 @@ impl error::Error for Error
impl<D> error::Error for DisplayError<D> impl<D> error::Error for DisplayError<D>
where D: fmt::Display{} 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)*))); (impl $lit:literal) => ($crate::error!(@ $lit));
($kind:expr, $lit:literal $($tt:tt)*) => ($crate::error!($kind, format!($lit $($tt)*))); (impl $expr:expr) => ($crate::error!(@ $expr));
(yield $lit:literal $($tt:tt)*) => ($crate::error!(yield Default::default(), $lit $($tt)*)); (impl yield $lit:literal $($tt:tt)*) => ($crate::error!(@ lazy_format::lazy_format!($lit $($tt)*)));
($lit:literal $($tt:tt)*) => ($crate::error!(Default::default(), $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)] #[derive(Debug)]
@ -185,6 +234,7 @@ impl fmt::Display for ErrorKind
match self { match self {
Self::IO(io) => write!(f, "i/o error: {}", io), Self::IO(io) => write!(f, "i/o error: {}", io),
Self::Wrap(wrap) => write!(f, "{}", wrap), Self::Wrap(wrap) => write!(f, "{}", wrap),
Self::Any(any) => write!(f, "{}", any),
Self::None => Ok(()), Self::None => Ok(()),
_ => write!(f, "unknown error"), _ => write!(f, "unknown error"),
} }
@ -198,6 +248,7 @@ impl error::Error for ErrorKind
Some(match &self { Some(match &self {
Self::IO(io) => io, Self::IO(io) => io,
Self::Wrap(wrap) => return wrap.source(), Self::Wrap(wrap) => return wrap.source(),
Self::Any(any) => any.as_ref(),
_ => return None, _ => return None,
}) })
} }
@ -239,9 +290,8 @@ mod test
#[test] #[test]
fn test() -> ReportedResult<()> fn test() -> ReportedResult<()>
{ {
color_eyre::install()?;
fn testt() -> Result<()> { 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) Err(err)
.wrap_err_with(|| context!("with string")) .wrap_err_with(|| context!("with string"))
.wrap_err_with(|| context!(yield "with another string and some stuffs {}", 1))?; .wrap_err_with(|| context!(yield "with another string and some stuffs {}", 1))?;
@ -275,8 +325,16 @@ mod test
Ok(one() Ok(one()
.aggregate_with(|_| testt())
.aggregate_with(|_| two()) .aggregate_with(|_| two())
.aggregate_with(|_| works()) .aggregate_with(|_| works())
.aggregate_with(|_| three())?) .aggregate_with(|_| three())?)
} }
#[test]
fn strings() -> ReportedResult<()>
{
Err(error!(yield "literal format {}", 1))?;
Ok(())
}
} }

Loading…
Cancel
Save