#![warn(missing_docs)]
#[macro_export]
macro_rules! quick_error {
( $(#[$meta:meta])*
pub enum $name:ident { $($chunks:tt)* }
) => {
quick_error!(SORT [pub enum $name $(#[$meta])* ]
items [] buf []
queue [ $($chunks)* ]);
};
( $(#[$meta:meta])*
enum $name:ident { $($chunks:tt)* }
) => {
quick_error!(SORT [enum $name $(#[$meta])* ]
items [] buf []
queue [ $($chunks)* ]);
};
( $(#[$meta:meta])*
pub enum $name:ident wraps $enum_name:ident { $($chunks:tt)* }
) => {
quick_error!(WRAPPER $enum_name [ pub struct ] $name $(#[$meta])*);
quick_error!(SORT [enum $enum_name $(#[$meta])* ]
items [] buf []
queue [ $($chunks)* ]);
};
( $(#[$meta:meta])*
pub enum $name:ident wraps pub $enum_name:ident { $($chunks:tt)* }
) => {
quick_error!(WRAPPER $enum_name [ pub struct ] $name $(#[$meta])*);
quick_error!(SORT [pub enum $enum_name $(#[$meta])* ]
items [] buf []
queue [ $($chunks)* ]);
};
( $(#[$meta:meta])*
enum $name:ident wraps $enum_name:ident { $($chunks:tt)* }
) => {
quick_error!(WRAPPER $enum_name [ struct ] $name $(#[$meta])*);
quick_error!(SORT [enum $enum_name $(#[$meta])* ]
items [] buf []
queue [ $($chunks)* ]);
};
( $(#[$meta:meta])*
enum $name:ident wraps pub $enum_name:ident { $($chunks:tt)* }
) => {
quick_error!(WRAPPER $enum_name [ struct ] $name $(#[$meta])*);
quick_error!(SORT [pub enum $enum_name $(#[$meta])* ]
items [] buf []
queue [ $($chunks)* ]);
};
(
WRAPPER $internal:ident [ $($strdef:tt)* ] $strname:ident
$(#[$meta:meta])*
) => {
$(#[$meta])*
$($strdef)* $strname ( $internal );
impl ::std::fmt::Display for $strname {
fn fmt(&self, f: &mut ::std::fmt::Formatter)
-> ::std::fmt::Result
{
::std::fmt::Display::fmt(&self.0, f)
}
}
impl From<$internal> for $strname {
fn from(err: $internal) -> Self {
$strname(err)
}
}
impl ::std::error::Error for $strname {
fn description(&self) -> &str {
self.0.description()
}
fn cause(&self) -> Option<&::std::error::Error> {
self.0.cause()
}
}
};
(SORT [enum $name:ident $( #[$meta:meta] )*]
items [$($( #[$imeta:meta] )*
=> $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
{$( $ifuncs:tt )*} )* ]
buf [ ]
queue [ ]
) => {
quick_error!(ENUM_DEFINITION [enum $name $( #[$meta] )*]
body []
queue [$($( #[$imeta] )*
=> $iitem: $imode [$( $ivar: $ityp ),*] )*]
);
quick_error!(IMPLEMENTATIONS $name {$(
$iitem: $imode [$(#[$imeta])*] [$( $ivar: $ityp ),*] {$( $ifuncs )*}
)*});
$(
quick_error!(ERROR_CHECK $imode $($ifuncs)*);
)*
};
(SORT [pub enum $name:ident $( #[$meta:meta] )*]
items [$($( #[$imeta:meta] )*
=> $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
{$( $ifuncs:tt )*} )* ]
buf [ ]
queue [ ]
) => {
quick_error!(ENUM_DEFINITION [pub enum $name $( #[$meta] )*]
body []
queue [$($( #[$imeta] )*
=> $iitem: $imode [$( $ivar: $ityp ),*] )*]
);
quick_error!(IMPLEMENTATIONS $name {$(
$iitem: $imode [$(#[$imeta])*] [$( $ivar: $ityp ),*] {$( $ifuncs )*}
)*});
$(
quick_error!(ERROR_CHECK $imode $($ifuncs)*);
)*
};
(SORT [$( $def:tt )*]
items [$($( #[$imeta:meta] )*
=> $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
{$( $ifuncs:tt )*} )* ]
buf [$( #[$bmeta:meta] )*]
queue [ #[$qmeta:meta] $( $tail:tt )*]
) => {
quick_error!(SORT [$( $def )*]
items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*]
buf [$( #[$bmeta] )* #[$qmeta] ]
queue [$( $tail )*]);
};
(SORT [$( $def:tt )*]
items [$($( #[$imeta:meta] )*
=> $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
{$( $ifuncs:tt )*} )* ]
buf [$( #[$bmeta:meta] )*]
queue [ $qitem:ident $( $tail:tt )*]
) => {
quick_error!(SORT [$( $def )*]
items [$( $(#[$imeta])*
=> $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*]
buf [$(#[$bmeta])* => $qitem : UNIT [ ] ]
queue [$( $tail )*]);
};
(SORT [$( $def:tt )*]
items [$($( #[$imeta:meta] )*
=> $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
{$( $ifuncs:tt )*} )* ]
buf [$( #[$bmeta:meta] )*
=> $bitem:ident: $bmode:tt [$( $bvar:ident: $btyp:ty ),*] ]
queue [ #[$qmeta:meta] $( $tail:tt )*]
) => {
quick_error!(SORT [$( $def )*]
enum [$( $(#[$emeta])* => $eitem $(( $($etyp),* ))* )*
$(#[$bmeta])* => $bitem: $bmode $(( $($btyp),* ))*]
items [$($( #[$imeta:meta] )*
=> $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*
$bitem: $bmode [$( $bvar:$btyp ),*] {} ]
buf [ #[$qmeta] ]
queue [$( $tail )*]);
};
(SORT [$( $def:tt )*]
items [$($( #[$imeta:meta] )*
=> $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
{$( $ifuncs:tt )*} )* ]
buf [$( #[$bmeta:meta] )* => $bitem:ident: UNIT [ ] ]
queue [($( $qvar:ident: $qtyp:ty ),+) $( $tail:tt )*]
) => {
quick_error!(SORT [$( $def )*]
items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*]
buf [$( #[$bmeta] )* => $bitem: TUPLE [$( $qvar:$qtyp ),*] ]
queue [$( $tail )*]
);
};
(SORT [$( $def:tt )*]
items [$($( #[$imeta:meta] )*
=> $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
{$( $ifuncs:tt )*} )* ]
buf [$( #[$bmeta:meta] )* => $bitem:ident: UNIT [ ] ]
queue [{ $( $qvar:ident: $qtyp:ty ),+} $( $tail:tt )*]
) => {
quick_error!(SORT [$( $def )*]
items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*]
buf [$( #[$bmeta] )* => $bitem: STRUCT [$( $qvar:$qtyp ),*] ]
queue [$( $tail )*]);
};
(SORT [$( $def:tt )*]
items [$($( #[$imeta:meta] )*
=> $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
{$( $ifuncs:tt )*} )* ]
buf [$( #[$bmeta:meta] )* => $bitem:ident: UNIT [ ] ]
queue [{$( $qvar:ident: $qtyp:ty ),+ ,} $( $tail:tt )*]
) => {
quick_error!(SORT [$( $def )*]
items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*]
buf [$( #[$bmeta] )* => $bitem: STRUCT [$( $qvar:$qtyp ),*] ]
queue [$( $tail )*]);
};
(SORT [$( $def:tt )*]
items [$($( #[$imeta:meta] )*
=> $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
{$( $ifuncs:tt )*} )* ]
buf [$( #[$bmeta:meta] )*
=> $bitem:ident: $bmode:tt [$( $bvar:ident: $btyp:ty ),*] ]
queue [ {$( $qfuncs:tt )*} $( $tail:tt )*]
) => {
quick_error!(SORT [$( $def )*]
items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*
$(#[$bmeta])* => $bitem: $bmode [$( $bvar:$btyp ),*] {$( $qfuncs )*} ]
buf [ ]
queue [$( $tail )*]);
};
(SORT [$( $def:tt )*]
items [$($( #[$imeta:meta] )*
=> $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
{$( $ifuncs:tt )*} )* ]
buf [$( #[$bmeta:meta] )*
=> $bitem:ident: $bmode:tt [$( $bvar:ident: $btyp:ty ),*] ]
queue [ $qitem:ident $( $tail:tt )*]
) => {
quick_error!(SORT [$( $def )*]
items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*
$(#[$bmeta])* => $bitem: $bmode [$( $bvar:$btyp ),*] {} ]
buf [ => $qitem : UNIT [ ] ]
queue [$( $tail )*]);
};
(SORT [$( $def:tt )*]
items [$($( #[$imeta:meta] )*
=> $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
{$( $ifuncs:tt )*} )* ]
buf [$( #[$bmeta:meta] )*
=> $bitem:ident: $bmode:tt [$( $bvar:ident: $btyp:ty ),*] ]
queue [ ]
) => {
quick_error!(SORT [$( $def )*]
items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*
$(#[$bmeta])* => $bitem: $bmode [$( $bvar:$btyp ),*] {} ]
buf [ ]
queue [ ]);
};
(ENUM_DEFINITION [pub enum $name:ident $( #[$meta:meta] )*]
body [$($( #[$imeta:meta] )*
=> $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ]
queue [ ]
) => {
#[allow(unknown_lints)] #[allow(renamed_and_removed_lints)]
#[allow(unused_doc_comment)]
#[allow(unused_doc_comments)]
$(#[$meta])*
pub enum $name {
$(
$(#[$imeta])*
$iitem $(($( $ttyp ),*))* $({$( $svar: $styp ),*})*,
)*
}
};
(ENUM_DEFINITION [enum $name:ident $( #[$meta:meta] )*]
body [$($( #[$imeta:meta] )*
=> $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ]
queue [ ]
) => {
#[allow(unknown_lints)] #[allow(renamed_and_removed_lints)]
#[allow(unused_doc_comment)]
#[allow(unused_doc_comments)]
$(#[$meta])*
enum $name {
$(
$(#[$imeta])*
$iitem $(($( $ttyp ),*))* $({$( $svar: $styp ),*})*,
)*
}
};
(ENUM_DEFINITION [$( $def:tt )*]
body [$($( #[$imeta:meta] )*
=> $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ]
queue [$( #[$qmeta:meta] )*
=> $qitem:ident: UNIT [ ] $( $queue:tt )*]
) => {
quick_error!(ENUM_DEFINITION [ $($def)* ]
body [$($( #[$imeta] )* => $iitem ($(($( $ttyp ),+))*) {$({$( $svar: $styp ),*})*} )*
$( #[$qmeta] )* => $qitem () {} ]
queue [ $($queue)* ]
);
};
(ENUM_DEFINITION [$( $def:tt )*]
body [$($( #[$imeta:meta] )*
=> $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ]
queue [$( #[$qmeta:meta] )*
=> $qitem:ident: TUPLE [$( $qvar:ident: $qtyp:ty ),+] $( $queue:tt )*]
) => {
quick_error!(ENUM_DEFINITION [ $($def)* ]
body [$($( #[$imeta] )* => $iitem ($(($( $ttyp ),+))*) {$({$( $svar: $styp ),*})*} )*
$( #[$qmeta] )* => $qitem (($( $qtyp ),*)) {} ]
queue [ $($queue)* ]
);
};
(ENUM_DEFINITION [$( $def:tt )*]
body [$($( #[$imeta:meta] )*
=> $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ]
queue [$( #[$qmeta:meta] )*
=> $qitem:ident: STRUCT [$( $qvar:ident: $qtyp:ty ),*] $( $queue:tt )*]
) => {
quick_error!(ENUM_DEFINITION [ $($def)* ]
body [$($( #[$imeta] )* => $iitem ($(($( $ttyp ),+))*) {$({$( $svar: $styp ),*})*} )*
$( #[$qmeta] )* => $qitem () {{$( $qvar: $qtyp ),*}} ]
queue [ $($queue)* ]
);
};
(IMPLEMENTATIONS
$name:ident {$(
$item:ident: $imode:tt [$(#[$imeta:meta])*] [$( $var:ident: $typ:ty ),*] {$( $funcs:tt )*}
)*}
) => {
#[allow(unused)]
#[allow(unknown_lints)] #[allow(renamed_and_removed_lints)]
#[allow(unused_doc_comment)]
#[allow(unused_doc_comments)]
impl ::std::fmt::Display for $name {
fn fmt(&self, fmt: &mut ::std::fmt::Formatter)
-> ::std::fmt::Result
{
match *self {
$(
$(#[$imeta])*
quick_error!(ITEM_PATTERN
$name $item: $imode [$( ref $var ),*]
) => {
let display_fn = quick_error!(FIND_DISPLAY_IMPL
$name $item: $imode
{$( $funcs )*});
display_fn(self, fmt)
}
)*
}
}
}
#[allow(unused)]
#[allow(unknown_lints)] #[allow(renamed_and_removed_lints)]
#[allow(unused_doc_comment)]
#[allow(unused_doc_comments)]
impl ::std::error::Error for $name {
fn description(&self) -> &str {
match *self {
$(
$(#[$imeta])*
quick_error!(ITEM_PATTERN
$name $item: $imode [$( ref $var ),*]
) => {
quick_error!(FIND_DESCRIPTION_IMPL
$item: $imode self fmt [$( $var ),*]
{$( $funcs )*})
}
)*
}
}
fn cause(&self) -> Option<&::std::error::Error> {
match *self {
$(
$(#[$imeta])*
quick_error!(ITEM_PATTERN
$name $item: $imode [$( ref $var ),*]
) => {
quick_error!(FIND_CAUSE_IMPL
$item: $imode [$( $var ),*]
{$( $funcs )*})
}
)*
}
}
}
$(
quick_error!(FIND_FROM_IMPL
$name $item: $imode [$( $var:$typ ),*]
{$( $funcs )*});
)*
$(
quick_error!(FIND_CONTEXT_IMPL
$name $item: $imode [$( $var:$typ ),*]
{$( $funcs )*});
)*
};
(FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt
{ display($self_:tt) -> ($( $exprs:tt )*) $( $tail:tt )*}
) => {
|quick_error!(IDENT $self_): &$name, f: &mut ::std::fmt::Formatter| { write!(f, $( $exprs )*) }
};
(FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt
{ display($pattern:expr) $( $tail:tt )*}
) => {
|_, f: &mut ::std::fmt::Formatter| { write!(f, $pattern) }
};
(FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt
{ display($pattern:expr, $( $exprs:tt )*) $( $tail:tt )*}
) => {
|_, f: &mut ::std::fmt::Formatter| { write!(f, $pattern, $( $exprs )*) }
};
(FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt
{ $t:tt $( $tail:tt )*}
) => {
quick_error!(FIND_DISPLAY_IMPL
$name $item: $imode
{$( $tail )*})
};
(FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt
{ }
) => {
|self_: &$name, f: &mut ::std::fmt::Formatter| {
write!(f, "{}", ::std::error::Error::description(self_))
}
};
(FIND_DESCRIPTION_IMPL $item:ident: $imode:tt $me:ident $fmt:ident
[$( $var:ident ),*]
{ description($expr:expr) $( $tail:tt )*}
) => {
$expr
};
(FIND_DESCRIPTION_IMPL $item:ident: $imode:tt $me:ident $fmt:ident
[$( $var:ident ),*]
{ $t:tt $( $tail:tt )*}
) => {
quick_error!(FIND_DESCRIPTION_IMPL
$item: $imode $me $fmt [$( $var ),*]
{$( $tail )*})
};
(FIND_DESCRIPTION_IMPL $item:ident: $imode:tt $me:ident $fmt:ident
[$( $var:ident ),*]
{ }
) => {
stringify!($item)
};
(FIND_CAUSE_IMPL $item:ident: $imode:tt
[$( $var:ident ),*]
{ cause($expr:expr) $( $tail:tt )*}
) => {
Some($expr)
};
(FIND_CAUSE_IMPL $item:ident: $imode:tt
[$( $var:ident ),*]
{ $t:tt $( $tail:tt )*}
) => {
quick_error!(FIND_CAUSE_IMPL
$item: $imode [$( $var ),*]
{ $($tail)* })
};
(FIND_CAUSE_IMPL $item:ident: $imode:tt
[$( $var:ident ),*]
{ }
) => {
None
};
(FIND_FROM_IMPL $name:ident $item:ident: $imode:tt
[$( $var:ident: $typ:ty ),*]
{ from() $( $tail:tt )*}
) => {
$(
impl From<$typ> for $name {
fn from($var: $typ) -> $name {
$name::$item($var)
}
}
)*
quick_error!(FIND_FROM_IMPL
$name $item: $imode [$( $var:$typ ),*]
{$( $tail )*});
};
(FIND_FROM_IMPL $name:ident $item:ident: UNIT
[ ]
{ from($ftyp:ty) $( $tail:tt )*}
) => {
impl From<$ftyp> for $name {
fn from(_discarded_error: $ftyp) -> $name {
$name::$item
}
}
quick_error!(FIND_FROM_IMPL
$name $item: UNIT [ ]
{$( $tail )*});
};
(FIND_FROM_IMPL $name:ident $item:ident: TUPLE
[$( $var:ident: $typ:ty ),*]
{ from($fvar:ident: $ftyp:ty) -> ($( $texpr:expr ),*) $( $tail:tt )*}
) => {
impl From<$ftyp> for $name {
fn from($fvar: $ftyp) -> $name {
$name::$item($( $texpr ),*)
}
}
quick_error!(FIND_FROM_IMPL
$name $item: TUPLE [$( $var:$typ ),*]
{ $($tail)* });
};
(FIND_FROM_IMPL $name:ident $item:ident: STRUCT
[$( $var:ident: $typ:ty ),*]
{ from($fvar:ident: $ftyp:ty) -> {$( $tvar:ident: $texpr:expr ),*} $( $tail:tt )*}
) => {
impl From<$ftyp> for $name {
fn from($fvar: $ftyp) -> $name {
$name::$item {
$( $tvar: $texpr ),*
}
}
}
quick_error!(FIND_FROM_IMPL
$name $item: STRUCT [$( $var:$typ ),*]
{ $($tail)* });
};
(FIND_FROM_IMPL $name:ident $item:ident: $imode:tt
[$( $var:ident: $typ:ty ),*]
{ $t:tt $( $tail:tt )*}
) => {
quick_error!(FIND_FROM_IMPL
$name $item: $imode [$( $var:$typ ),*]
{$( $tail )*}
);
};
(FIND_FROM_IMPL $name:ident $item:ident: $imode:tt
[$( $var:ident: $typ:ty ),*]
{ }
) => {
};
(FIND_CONTEXT_IMPL $name:ident $item:ident: TUPLE
[$( $var:ident: $typ:ty ),*]
{ context($cvar:ident: AsRef<$ctyp:ty>, $fvar:ident: $ftyp:ty)
-> ($( $texpr:expr ),*) $( $tail:tt )* }
) => {
impl<T: AsRef<$ctyp>> From<$crate::Context<T, $ftyp>> for $name {
fn from(
$crate::Context($cvar, $fvar): $crate::Context<T, $ftyp>)
-> $name
{
$name::$item($( $texpr ),*)
}
}
quick_error!(FIND_CONTEXT_IMPL
$name $item: TUPLE [$( $var:$typ ),*]
{ $($tail)* });
};
(FIND_CONTEXT_IMPL $name:ident $item:ident: TUPLE
[$( $var:ident: $typ:ty ),*]
{ context($cvar:ident: $ctyp:ty, $fvar:ident: $ftyp:ty)
-> ($( $texpr:expr ),*) $( $tail:tt )* }
) => {
impl<'a> From<$crate::Context<$ctyp, $ftyp>> for $name {
fn from(
$crate::Context($cvar, $fvar): $crate::Context<$ctyp, $ftyp>)
-> $name
{
$name::$item($( $texpr ),*)
}
}
quick_error!(FIND_CONTEXT_IMPL
$name $item: TUPLE [$( $var:$typ ),*]
{ $($tail)* });
};
(FIND_CONTEXT_IMPL $name:ident $item:ident: STRUCT
[$( $var:ident: $typ:ty ),*]
{ context($cvar:ident: AsRef<$ctyp:ty>, $fvar:ident: $ftyp:ty)
-> {$( $tvar:ident: $texpr:expr ),*} $( $tail:tt )* }
) => {
impl<T: AsRef<$ctyp>> From<$crate::Context<T, $ftyp>> for $name {
fn from(
$crate::Context($cvar, $fvar): $crate::Context<$ctyp, $ftyp>)
-> $name
{
$name::$item {
$( $tvar: $texpr ),*
}
}
}
quick_error!(FIND_CONTEXT_IMPL
$name $item: STRUCT [$( $var:$typ ),*]
{ $($tail)* });
};
(FIND_CONTEXT_IMPL $name:ident $item:ident: STRUCT
[$( $var:ident: $typ:ty ),*]
{ context($cvar:ident: $ctyp:ty, $fvar:ident: $ftyp:ty)
-> {$( $tvar:ident: $texpr:expr ),*} $( $tail:tt )* }
) => {
impl<'a> From<$crate::Context<$ctyp, $ftyp>> for $name {
fn from(
$crate::Context($cvar, $fvar): $crate::Context<$ctyp, $ftyp>)
-> $name
{
$name::$item {
$( $tvar: $texpr ),*
}
}
}
quick_error!(FIND_CONTEXT_IMPL
$name $item: STRUCT [$( $var:$typ ),*]
{ $($tail)* });
};
(FIND_CONTEXT_IMPL $name:ident $item:ident: $imode:tt
[$( $var:ident: $typ:ty ),*]
{ $t:tt $( $tail:tt )*}
) => {
quick_error!(FIND_CONTEXT_IMPL
$name $item: $imode [$( $var:$typ ),*]
{$( $tail )*}
);
};
(FIND_CONTEXT_IMPL $name:ident $item:ident: $imode:tt
[$( $var:ident: $typ:ty ),*]
{ }
) => {
};
(ITEM_BODY $(#[$imeta:meta])* $item:ident: UNIT
) => { };
(ITEM_BODY $(#[$imeta:meta])* $item:ident: TUPLE
[$( $typ:ty ),*]
) => {
($( $typ ),*)
};
(ITEM_BODY $(#[$imeta:meta])* $item:ident: STRUCT
[$( $var:ident: $typ:ty ),*]
) => {
{$( $var:$typ ),*}
};
(ITEM_PATTERN $name:ident $item:ident: UNIT []
) => {
$name::$item
};
(ITEM_PATTERN $name:ident $item:ident: TUPLE
[$( ref $var:ident ),*]
) => {
$name::$item ($( ref $var ),*)
};
(ITEM_PATTERN $name:ident $item:ident: STRUCT
[$( ref $var:ident ),*]
) => {
$name::$item {$( ref $var ),*}
};
(ERROR_CHECK $imode:tt display($self_:tt) -> ($( $exprs:tt )*) $( $tail:tt )*)
=> { quick_error!(ERROR_CHECK $imode $($tail)*); };
(ERROR_CHECK $imode:tt display($pattern: expr) $( $tail:tt )*)
=> { quick_error!(ERROR_CHECK $imode $($tail)*); };
(ERROR_CHECK $imode:tt display($pattern: expr, $( $exprs:tt )*) $( $tail:tt )*)
=> { quick_error!(ERROR_CHECK $imode $($tail)*); };
(ERROR_CHECK $imode:tt description($expr:expr) $( $tail:tt )*)
=> { quick_error!(ERROR_CHECK $imode $($tail)*); };
(ERROR_CHECK $imode:tt cause($expr:expr) $($tail:tt)*)
=> { quick_error!(ERROR_CHECK $imode $($tail)*); };
(ERROR_CHECK $imode:tt from() $($tail:tt)*)
=> { quick_error!(ERROR_CHECK $imode $($tail)*); };
(ERROR_CHECK $imode:tt from($ftyp:ty) $($tail:tt)*)
=> { quick_error!(ERROR_CHECK $imode $($tail)*); };
(ERROR_CHECK TUPLE from($fvar:ident: $ftyp:ty) -> ($( $e:expr ),*) $( $tail:tt )*)
=> { quick_error!(ERROR_CHECK TUPLE $($tail)*); };
(ERROR_CHECK STRUCT from($fvar:ident: $ftyp:ty) -> {$( $v:ident: $e:expr ),*} $( $tail:tt )*)
=> { quick_error!(ERROR_CHECK STRUCT $($tail)*); };
(ERROR_CHECK TUPLE context($cvar:ident: $ctyp:ty, $fvar:ident: $ftyp:ty)
-> ($( $e:expr ),*) $( $tail:tt )*)
=> { quick_error!(ERROR_CHECK TUPLE $($tail)*); };
(ERROR_CHECK STRUCT context($cvar:ident: $ctyp:ty, $fvar:ident: $ftyp:ty)
-> {$( $v:ident: $e:expr ),*} $( $tail:tt )*)
=> { quick_error!(ERROR_CHECK STRUCT $($tail)*); };
(ERROR_CHECK $imode:tt ) => {};
(IDENT $ident:ident) => { $ident }
}
#[derive(Debug)]
pub struct Context<X, E>(pub X, pub E);
pub trait ResultExt<T, E> {
fn context<X>(self, x: X) -> Result<T, Context<X, E>>;
}
impl<T, E> ResultExt<T, E> for Result<T, E> {
fn context<X>(self, x: X) -> Result<T, Context<X, E>> {
self.map_err(|e| Context(x, e))
}
}
#[cfg(test)]
mod test {
use std::num::{ParseFloatError, ParseIntError};
use std::str::Utf8Error;
use std::string::FromUtf8Error;
use std::error::Error;
use std::path::{Path, PathBuf};
use super::ResultExt;
quick_error! {
#[derive(Debug)]
pub enum Bare {
One
Two
}
}
#[test]
fn bare_item_direct() {
assert_eq!(format!("{}", Bare::One), "One".to_string());
assert_eq!(format!("{:?}", Bare::One), "One".to_string());
assert_eq!(Bare::One.description(), "One".to_string());
assert!(Bare::One.cause().is_none());
}
#[test]
fn bare_item_trait() {
let err: &Error = &Bare::Two;
assert_eq!(format!("{}", err), "Two".to_string());
assert_eq!(format!("{:?}", err), "Two".to_string());
assert_eq!(err.description(), "Two".to_string());
assert!(err.cause().is_none());
}
quick_error! {
#[derive(Debug)]
pub enum Wrapper wraps Wrapped {
One
Two(s: String) {
display("two: {}", s)
from()
}
}
}
#[test]
fn wrapper() {
assert_eq!(format!("{}", Wrapper::from(Wrapped::One)),
"One".to_string());
assert_eq!(format!("{}",
Wrapper::from(Wrapped::from(String::from("hello")))),
"two: hello".to_string());
assert_eq!(format!("{:?}", Wrapper::from(Wrapped::One)),
"Wrapper(One)".to_string());
assert_eq!(Wrapper::from(Wrapped::One).description(),
"One".to_string());
}
quick_error! {
#[derive(Debug, PartialEq)]
pub enum TupleWrapper {
ParseFloatError(err: ParseFloatError) {
from()
description(err.description())
display("parse float error: {err}", err=err)
cause(err)
}
Other(descr: &'static str) {
description(descr)
display("Error: {}", descr)
}
FromUtf8Error(err: Utf8Error, source: Vec<u8>) {
cause(err)
display(me) -> ("{desc} at index {pos}: {err}", desc=me.description(), pos=err.valid_up_to(), err=err)
description("utf8 error")
from(err: FromUtf8Error) -> (err.utf8_error().clone(), err.into_bytes())
}
Discard {
from(&'static str)
}
Singleton {
display("Just a string")
}
}
}
#[test]
fn tuple_wrapper_err() {
let cause = "one and a half times pi".parse::<f32>().unwrap_err();
let err = TupleWrapper::ParseFloatError(cause.clone());
assert_eq!(format!("{}", err), format!("parse float error: {}", cause));
assert_eq!(format!("{:?}", err), format!("ParseFloatError({:?})", cause));
assert_eq!(err.description(), cause.description());
assert_eq!(format!("{:?}", err.cause().unwrap()), format!("{:?}", cause));
}
#[test]
fn tuple_wrapper_trait_str() {
let desc = "hello";
let err: &Error = &TupleWrapper::Other(desc);
assert_eq!(format!("{}", err), format!("Error: {}", desc));
assert_eq!(format!("{:?}", err), format!("Other({:?})", desc));
assert_eq!(err.description(), desc);
assert!(err.cause().is_none());
}
#[test]
fn tuple_wrapper_trait_two_fields() {
let invalid_utf8: Vec<u8> = vec![0, 159, 146, 150];
let cause = String::from_utf8(invalid_utf8.clone()).unwrap_err().utf8_error();
let err: &Error = &TupleWrapper::FromUtf8Error(cause.clone(), invalid_utf8.clone());
assert_eq!(format!("{}", err), format!("{desc} at index {pos}: {cause}", desc=err.description(), pos=cause.valid_up_to(), cause=cause));
assert_eq!(format!("{:?}", err), format!("FromUtf8Error({:?}, {:?})", cause, invalid_utf8));
assert_eq!(err.description(), "utf8 error");
assert_eq!(format!("{:?}", err.cause().unwrap()), format!("{:?}", cause));
}
#[test]
fn tuple_wrapper_from() {
let cause = "one and a half times pi".parse::<f32>().unwrap_err();
let err = TupleWrapper::ParseFloatError(cause.clone());
let err_from: TupleWrapper = From::from(cause);
assert_eq!(err_from, err);
}
#[test]
fn tuple_wrapper_custom_from() {
let invalid_utf8: Vec<u8> = vec![0, 159, 146, 150];
let cause = String::from_utf8(invalid_utf8.clone()).unwrap_err();
let err = TupleWrapper::FromUtf8Error(cause.utf8_error().clone(), invalid_utf8);
let err_from: TupleWrapper = From::from(cause);
assert_eq!(err_from, err);
}
#[test]
fn tuple_wrapper_discard() {
let err: TupleWrapper = From::from("hello");
assert_eq!(format!("{}", err), format!("Discard"));
assert_eq!(format!("{:?}", err), format!("Discard"));
assert_eq!(err.description(), "Discard");
assert!(err.cause().is_none());
}
#[test]
fn tuple_wrapper_singleton() {
let err: TupleWrapper = TupleWrapper::Singleton;
assert_eq!(format!("{}", err), format!("Just a string"));
assert_eq!(format!("{:?}", err), format!("Singleton"));
assert_eq!(err.description(), "Singleton");
assert!(err.cause().is_none());
}
quick_error! {
#[derive(Debug, PartialEq)]
pub enum StructWrapper {
Utf8Error{ err: Utf8Error, hint: Option<&'static str> } {
cause(err)
display(me) -> ("{desc} at index {pos}: {err}", desc=me.description(), pos=err.valid_up_to(), err=err)
description("utf8 error")
from(err: Utf8Error) -> { err: err, hint: None }
}
ExcessComma { descr: &'static str, } {
description(descr)
display("Error: {}", descr)
}
}
}
#[test]
fn struct_wrapper_err() {
let invalid_utf8: Vec<u8> = vec![0, 159, 146, 150];
let cause = String::from_utf8(invalid_utf8.clone()).unwrap_err().utf8_error();
let err: &Error = &StructWrapper::Utf8Error{ err: cause.clone(), hint: Some("nonsense") };
assert_eq!(format!("{}", err), format!("{desc} at index {pos}: {cause}", desc=err.description(), pos=cause.valid_up_to(), cause=cause));
assert_eq!(format!("{:?}", err), format!("Utf8Error {{ err: {:?}, hint: {:?} }}", cause, Some("nonsense")));
assert_eq!(err.description(), "utf8 error");
assert_eq!(format!("{:?}", err.cause().unwrap()), format!("{:?}", cause));
}
#[test]
fn struct_wrapper_struct_from() {
let invalid_utf8: Vec<u8> = vec![0, 159, 146, 150];
let cause = String::from_utf8(invalid_utf8.clone()).unwrap_err().utf8_error();
let err = StructWrapper::Utf8Error{ err: cause.clone(), hint: None };
let err_from: StructWrapper = From::from(cause);
assert_eq!(err_from, err);
}
#[test]
fn struct_wrapper_excess_comma() {
let descr = "hello";
let err = StructWrapper::ExcessComma { descr: descr };
assert_eq!(format!("{}", err), format!("Error: {}", descr));
assert_eq!(format!("{:?}", err), format!("ExcessComma {{ descr: {:?} }}", descr));
assert_eq!(err.description(), descr);
assert!(err.cause().is_none());
}
quick_error! {
#[derive(Debug)]
pub enum ContextErr {
Float(src: String, err: ParseFloatError) {
context(s: &'a str, e: ParseFloatError) -> (s.to_string(), e)
display("Float error {:?}: {}", src, err)
}
Int { src: String, err: ParseIntError } {
context(s: &'a str, e: ParseIntError)
-> {src: s.to_string(), err: e}
display("Int error {:?}: {}", src, err)
}
Utf8(path: PathBuf, err: Utf8Error) {
context(p: AsRef<Path>, e: Utf8Error)
-> (p.as_ref().to_path_buf(), e)
display("Path error at {:?}: {}", path, err)
}
Utf8Str(s: String, err: ::std::io::Error) {
context(s: AsRef<str>, e: ::std::io::Error)
-> (s.as_ref().to_string(), e)
display("Str error {:?}: {}", s, err)
}
}
}
#[test]
fn parse_float_error() {
fn parse_float(s: &str) -> Result<f32, ContextErr> {
Ok(try!(s.parse().context(s)))
}
assert_eq!(format!("{}", parse_float("12ab").unwrap_err()),
r#"Float error "12ab": invalid float literal"#);
}
#[test]
fn parse_int_error() {
fn parse_int(s: &str) -> Result<i32, ContextErr> {
Ok(try!(s.parse().context(s)))
}
assert_eq!(format!("{}", parse_int("12.5").unwrap_err()),
r#"Int error "12.5": invalid digit found in string"#);
}
#[test]
fn debug_context() {
fn parse_int(s: &str) -> i32 {
s.parse().context(s).unwrap()
}
assert_eq!(parse_int("12"), 12);
assert_eq!(format!("{:?}", "x".parse::<i32>().context("x")),
r#"Err(Context("x", ParseIntError { kind: InvalidDigit }))"#);
}
#[test]
fn path_context() {
fn parse_utf<P: AsRef<Path>>(s: &[u8], p: P)
-> Result<(), ContextErr>
{
try!(::std::str::from_utf8(s).context(p));
Ok(())
}
let etext = parse_utf(b"a\x80\x80", "/etc").unwrap_err().to_string();
assert!(etext.starts_with(
"Path error at \"/etc\": invalid utf-8"));
let etext = parse_utf(b"\x80\x80", PathBuf::from("/tmp")).unwrap_err()
.to_string();
assert!(etext.starts_with(
"Path error at \"/tmp\": invalid utf-8"));
}
#[test]
fn conditional_compilation() {
quick_error! {
#[allow(dead_code)]
#[derive(Debug)]
pub enum Test {
#[cfg(feature = "foo")]
Variant
}
}
}
}