diff --git a/.travis.yml b/.travis.yml index 342c0ee..b31686a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,5 @@ language: rust rust: -- 1.3.0 - stable - beta - nightly diff --git a/README.rst b/README.rst index 287986f..fb7bd8f 100644 --- a/README.rst +++ b/README.rst @@ -28,7 +28,7 @@ Here is the comprehensive example: } Other(descr: &'static str) { description(descr) - display("Errorr {}", descr) + display("Error {}", descr) } IoAt(place: &'static str, err: io::Error) { cause(err) diff --git a/src/lib.rs b/src/lib.rs index a6dfa7e..aa3fec7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -203,6 +203,7 @@ //! Empty braces can be omitted as of quick_error 0.1.3. //! + /// Main macro that does all the work #[macro_export] macro_rules! quick_error { @@ -210,196 +211,257 @@ macro_rules! quick_error { pub enum $name:ident { $($chunks:tt)* } ) => { quick_error!(SORT [pub enum $name $(#[$meta])* ] - enum [] items [] buf [] + items [] buf [] queue [ $($chunks)* ]); }; ( $(#[$meta:meta])* enum $name:ident { $($chunks:tt)* } ) => { quick_error!(SORT [enum $name $(#[$meta])* ] - enum [] items [] buf [] + items [] buf [] queue [ $($chunks)* ]); }; // Queue is empty, can do the work - (SORT [enum $name:ident $(#[$meta:meta])* ] - enum [ $( $(#[$emeta:meta])* - => $eitem:ident $( ( $($etyp:ty),* ) )* )* ] - items [ $( $iitem:ident $(( $($ivar:ident : $ityp:ty),* ))* - { $($ifuncs:tt)* } )* ] + (SORT [enum $name:ident $( #[$meta:meta] )*] + items [$($( #[$imeta:imeta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] buf [ ] queue [ ] ) => { - $(#[$meta])* - enum $name { - $( - $(#[$emeta])* - $eitem $(( $($etyp),* ))*, - )* - } - quick_error!(IMPLEMENTATIONS $name { $( - $iitem $(( $($ivar: $ityp),* ))* { $($ifuncs)* } - )* }); + quick_error!(ENUM_DEFINITION [enum $name $( #[$meta] )*] + body [] + queue [$($( #[$imeta] )* + => $iitem: $imode [$( $ivar: $ityp ),*] )*] + ); + quick_error!(IMPLEMENTATIONS $name {$( + $iitem: $imode [$( $ivar: $ityp ),*] {$( $ifuncs )*} + )*}); $( - quick_error!(ERROR_CHECK $($ifuncs)*); + quick_error!(ERROR_CHECK $imode $($ifuncs)*); )* }; - (SORT [pub enum $name:ident $(#[$meta:meta])* ] - enum [ $( $(#[$emeta:meta])* - => $eitem:ident $( ( $($etyp:ty),* ) )* )* ] - items [ $( $iitem:ident $(( $($ivar:ident : $ityp:ty),* ))* - { $($ifuncs:tt)* } )* ] + (SORT [pub enum $name:ident $( #[$meta:meta] )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] buf [ ] queue [ ] ) => { - $(#[$meta])* - pub enum $name { - $( - $(#[$emeta])* - $eitem $(( $($etyp),* ))*, - )* - } - quick_error!(IMPLEMENTATIONS $name { $( - $iitem $(( $($ivar: $ityp),* ))* { $($ifuncs)* } - )* }); + quick_error!(ENUM_DEFINITION [pub enum $name $( #[$meta] )*] + body [] + queue [$($( #[$imeta] )* + => $iitem: $imode [$( $ivar: $ityp ),*] )*] + ); + quick_error!(IMPLEMENTATIONS $name {$( + $iitem: $imode [$( $ivar: $ityp ),*] {$( $ifuncs )*} + )*}); $( - quick_error!(ERROR_CHECK $($ifuncs)*); + quick_error!(ERROR_CHECK $imode $($ifuncs)*); )* }; // Add meta to buffer - (SORT [$($def:tt)*] - enum [ $( $(#[$emeta:meta])* - => $eitem:ident $(( $($etyp:ty),* ))* )* ] - items [ $( $iitem:ident $(( $($ivar:ident : $ityp:ty),* ))* - { $($ifuncs:tt)* } )* ] - buf [ $( #[$bmeta:meta] )* ] - queue [ #[$qmeta:meta] $($tail:tt)* ] - ) => { - quick_error!(SORT [$($def)* ] - enum [$( $(#[$emeta])* => $eitem $(( $($etyp),* ))* )*] - items [ $( $iitem $(( $($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 [ #[$qmeta:meta] $( $tail:tt )*] + ) => { + quick_error!(SORT [$( $def )*] + items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*] + buf [$( #[$bmeta] )* #[$qmeta] ] + queue [$( $tail )*]); }; // Add ident to buffer - (SORT [$($def:tt)*] - enum [ $( $(#[$emeta:meta])* - => $eitem:ident $(( $($etyp:ty),* ))* )* ] - items [ $( $iitem:ident $(( $($ivar:ident : $ityp:ty),* ))* - { $($ifuncs:tt)* } )* ] - buf [ $( #[$bmeta:meta] )* ] - queue [ $qitem:ident $($tail:tt)* ] - ) => { - quick_error!(SORT [$($def)* ] - enum [ $( $(#[$emeta])* => $eitem $(( $($etyp),* ))* )* ] - items [ $( $iitem $(( $($ivar:$ityp),* ))* { $($ifuncs)* } )* ] - buf [ $(#[$bmeta])* => $qitem ] - 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 )*]); }; // Flush buffer on meta after ident - (SORT [$($def:tt)*] - enum [ $( $(#[$emeta:meta])* - => $eitem:ident $(( $($etyp:ty),* ))* )* ] - items [ $( $iitem:ident $(( $($ivar:ident : $ityp:ty),* ))* - { $($ifuncs:tt)* } )* ] - buf [ $( #[$bmeta:meta] )* - => $bitem:ident $(( $($bvar:ident : $btyp:ty),* ))* ] - queue [ #[$qmeta:meta] $($tail:tt)* ] - ) => { - quick_error!(SORT [$($def)* ] + (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 $(( $($btyp),* ))*] - items [ $( $iitem $(( $($ivar:$ityp),* ))* { $($ifuncs)* } )* - $bitem $(( $($bvar:$btyp),* ))* {} ] + $(#[$bmeta])* => $bitem: $bmode $(( $($btyp),* ))*] + items [$($( #[$imeta:imeta] )* + => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )* + $bitem: $bmode [$( $bvar:$btyp ),*] {} ] buf [ #[$qmeta] ] - queue [ $($tail)* ]); - }; - // Add parenthesis - (SORT [$($def:tt)*] - enum [ $( $(#[$emeta:meta])* - => $eitem:ident $(( $($etyp:ty),* ))* )* ] - items [ $( $iitem:ident $(( $($ivar:ident : $ityp:ty),* ))* - { $($ifuncs:tt)* } )* ] - buf [ $( #[$bmeta:meta] )* => $bitem:ident ] - queue [ ( $( $qvar:ident : $qtyp:ty ),* ) $($tail:tt)* ] - ) => { - quick_error!(SORT [$($def)* ] - enum [$( $(#[$emeta])* => $eitem $(( $($etyp),* ))* )*] - items [ $( $iitem $(( $($ivar:$ityp),* ))* { $($ifuncs)* } )* ] - buf [ $( #[$bmeta] )* => $bitem ( $( $qvar:$qtyp ),* ) ] - queue [ $($tail)* ]); + queue [$( $tail )*]); + }; + // Add tuple enum-variant + (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 )*] + ); + }; + // Add struct enum-variant + (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 )*]); }; // Add braces and flush always on braces - (SORT [$($def:tt)*] - enum [ $( $(#[$emeta:meta])* - => $eitem:ident $(( $($etyp:ty),* ))* )* ] - items [ $( $iitem:ident $(( $($ivar:ident : $ityp:ty),* ))* - { $($ifuncs:tt)* } )* ] - buf [ $( #[$bmeta:meta] )* - => $bitem:ident $(( $($bvar:ident : $btyp:ty),* ))* ] - queue [ { $($qfuncs:tt)* } $($tail:tt)* ] - ) => { - quick_error!(SORT [$($def)* ] - enum [$( $(#[$emeta])* => $eitem $(( $($etyp),* ))* )* - $(#[$bmeta])* => $bitem $(( $($btyp),* ))* ] - items [ $( $iitem $(( $($ivar:$ityp),* ))* { $($ifuncs)* } )* - $bitem $(( $($bvar:$btyp),* ))* { $($qfuncs)* } ] + (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)* ]); + queue [$( $tail )*]); }; // Flush buffer on double ident - (SORT [$($def:tt)*] - enum [ $( $(#[$emeta:meta])* - => $eitem:ident $(( $($etyp:ty),* ))* )* ] - items [ $( $iitem:ident $(( $($ivar:ident : $ityp:ty),* ))* - { $($ifuncs:tt)* } )* ] - buf [ $( #[$bmeta:meta] )* - => $bitem:ident $(( $($bvar:ident : $btyp:ty),* ))* ] - queue [ $qitem:ident $($tail:tt)* ] - ) => { - quick_error!(SORT [$($def)* ] - enum [$( $(#[$emeta])* => $eitem $(( $($etyp),* ))* )* - $(#[$bmeta])* => $bitem $(( $($btyp),* ))*] - items [ $( $iitem $(( $($ivar:$ityp),* ))* { $($ifuncs)* } )* - $bitem $(( $($bvar:$btyp),* ))* {} ] - buf [ => $qitem ] - 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 )*]); }; // Flush buffer on end - (SORT [$($def:tt)*] - enum [ $( $(#[$emeta:meta])* - => $eitem:ident $(( $($etyp:ty),* ))* )* ] - items [ $( $iitem:ident $(( $($ivar:ident : $ityp:ty),* ))* - { $($ifuncs:tt)* } )* ] - buf [ $( #[$bmeta:meta] )* - => $bitem:ident $(( $($bvar:ident : $btyp:ty),* ))* ] + (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)* ] - enum [$( $(#[$emeta])* => $eitem $(( $($etyp),* ))* )* - $(#[$bmeta])* => $bitem $(( $($btyp),* ))* ] - items [ $( $iitem $(( $($ivar:$ityp),* ))* { $($ifuncs)* } )* - $bitem $(( $($bvar:$btyp),* ))* {} ] + quick_error!(SORT [$( $def )*] + items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )* + $(#[$bmeta])* => $bitem: $bmode [$( $bvar:$btyp ),*] {} ] buf [ ] queue [ ]); }; - (IMPLEMENTATIONS - $name:ident { + // Public enum (Queue Empty) + (ENUM_DEFINITION [pub enum $name:ident $( #[$meta:meta] )*] + body [$($( #[$imeta:meta] )* + => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ] + queue [ ] + ) => { + $(#[$meta])* + pub enum $name { $( - $item:ident $( ( $($var:ident : $typ:ty),* ) )* { $($funcs:tt)* } + $(#[$imeta])* + $iitem $(($( $ttyp ),*))* $({$( $svar: $styp ),*})*, )* } + }; + // Private enum (Queue Empty) + (ENUM_DEFINITION [enum $name:ident $( #[$meta:meta] )*] + body [$($( #[$imeta:meta] )* + => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ] + queue [ ] + ) => { + $(#[$meta])* + enum $name { + $( + $(#[$imeta])* + $iitem $(($( $ttyp ),*))* $({$( $svar: $styp ),*})*, + )* + } + }; + // Unit variant + (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)* ] + ); + }; + // Tuple variant + (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)* ] + ); + }; + // Struct variant + (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 [$( $var:ident: $typ:ty ),*] {$( $funcs:tt )*} + )*} ) => { #[allow(unused)] impl ::std::fmt::Display for $name { fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - match self { + match *self { $( - &$name::$item $( ( $(ref $var),* ) )* => { + quick_error!(ITEM_PATTERN + $name $item: $imode [$( ref $var ),*] + ) => { let display_fn = quick_error!(FIND_DISPLAY_IMPL - $name $item - { $($funcs)* }); + $name $item: $imode + {$( $funcs )*}); display_fn(self, fmt) } @@ -410,23 +472,27 @@ macro_rules! quick_error { #[allow(unused)] impl ::std::error::Error for $name { fn description(&self) -> &str { - match self { + match *self { $( - &$name::$item $( ( $(ref $var),* ) )* => { + quick_error!(ITEM_PATTERN + $name $item: $imode [$( ref $var ),*] + ) => { quick_error!(FIND_DESCRIPTION_IMPL - $item self fmt [ $( ( $($var)* ) )* ] - { $($funcs)* }) + $item: $imode self fmt [$( $var ),*] + {$( $funcs )*}) } )* } } fn cause(&self) -> Option<&::std::error::Error> { - match self { + match *self { $( - &$name::$item $( ( $(ref $var),* ) )* => { + quick_error!(ITEM_PATTERN + $name $item: $imode [$( ref $var ),*] + ) => { quick_error!(FIND_CAUSE_IMPL - $item [ $( ( $($var)* ) )* ] - { $($funcs)* }) + $item: $imode [$( $var ),*] + {$( $funcs )*}) } )* } @@ -434,97 +500,97 @@ macro_rules! quick_error { } $( quick_error!(FIND_FROM_IMPL - $name $item [ $( ( $($var:$typ)* ) )* ] - { $($funcs)* }); + $name $item: $imode [$( $var:$typ ),*] + {$( $funcs )*}); )* }; - (FIND_DISPLAY_IMPL $name:ident $item:ident - { display($self_:tt) -> ($($exprs:tt)*) $($tail:tt)* } + (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)*) } + |quick_error!(IDENT $self_): &$name, f: &mut ::std::fmt::Formatter| { write!(f, $( $exprs )*) } }; - (FIND_DISPLAY_IMPL $name:ident $item:ident - { display($pattern:expr) $($tail:tt)* } + (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 - { display($pattern:expr, $($exprs:tt)*) $($tail:tt)* } + (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)*) } + |_, f: &mut ::std::fmt::Formatter| { write!(f, $pattern, $( $exprs )*) } }; - (FIND_DISPLAY_IMPL $name:ident $item:ident - { $t:tt $($tail:tt)* } + (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt + { $t:tt $( $tail:tt )*} ) => { quick_error!(FIND_DISPLAY_IMPL - $name $item - { $($tail)* }) + $name $item: $imode + {$( $tail )*}) }; - (FIND_DISPLAY_IMPL $name:ident $item:ident + (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 $me:ident $fmt:ident - [ $( ( $($var:ident)* ) )* ] - { description($expr:expr) $($tail:tt)* } + (FIND_DESCRIPTION_IMPL $item:ident: $imode:tt $me:ident $fmt:ident + [$( $var:ident ),*] + { description($expr:expr) $( $tail:tt )*} ) => { $expr }; - (FIND_DESCRIPTION_IMPL $item:ident $me:ident $fmt:ident - [ $( ( $($var:ident)* ) )* ] - { $t:tt $($tail:tt)* } + (FIND_DESCRIPTION_IMPL $item:ident: $imode:tt $me:ident $fmt:ident + [$( $var:ident ),*] + { $t:tt $( $tail:tt )*} ) => { quick_error!(FIND_DESCRIPTION_IMPL - $item $me $fmt [ $( ( $($var)* ) )* ] - { $($tail)* }) + $item: $imode $me $fmt [$( $var ),*] + {$( $tail )*}) }; - (FIND_DESCRIPTION_IMPL $item:ident $me:ident $fmt:ident - [ $( ( $($var:ident)* ) )* ] + (FIND_DESCRIPTION_IMPL $item:ident: $imode:tt $me:ident $fmt:ident + [$( $var:ident ),*] { } ) => { stringify!($item) }; - (FIND_CAUSE_IMPL $item:ident - [ $( ( $($var:ident)* ) )* ] - { cause($expr:expr) $($tail:tt)* } + (FIND_CAUSE_IMPL $item:ident: $imode:tt + [$( $var:ident ),*] + { cause($expr:expr) $( $tail:tt )*} ) => { Some($expr) }; - (FIND_CAUSE_IMPL $item:ident - [ $( ( $($var:ident)* ) )* ] - { $t:tt $($tail:tt)* } + (FIND_CAUSE_IMPL $item:ident: $imode:tt + [$( $var:ident ),*] + { $t:tt $( $tail:tt )*} ) => { quick_error!(FIND_CAUSE_IMPL - $item [ $( ( $($var)* ) )* ] + $item: $imode [$( $var ),*] { $($tail)* }) }; - (FIND_CAUSE_IMPL $item:ident - [ $( ( $($var:ident)* ) )* ] + (FIND_CAUSE_IMPL $item:ident: $imode:tt + [$( $var:ident ),*] { } ) => { None }; - (FIND_FROM_IMPL $name:ident $item:ident - [ $( ( $($var:ident : $typ:ty)* ) )* ] - { from() $($tail:tt)* } + (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 [ $( ( $($var:$typ)* ) )* ] - { $($tail)* }); + $name $item: $imode [$( $var:$typ ),*] + {$( $tail )*}); }; - (FIND_FROM_IMPL $name:ident $item:ident + (FIND_FROM_IMPL $name:ident $item:ident: UNIT [ ] - { from($ftyp:ty) $($tail:tt)* } + { from($ftyp:ty) $( $tail:tt )*} ) => { impl From<$ftyp> for $name { fn from(_discarded_error: $ftyp) -> $name { @@ -532,63 +598,110 @@ macro_rules! quick_error { } } quick_error!(FIND_FROM_IMPL - $name $item [ ] - { $($tail)* }); + $name $item: UNIT [ ] + {$( $tail )*}); }; - (FIND_FROM_IMPL $name:ident $item:ident - [ $( ( $($var:ident : $typ:ty)* ) )* ] - { from($fvar:ident : $ftyp:ty) -> ($($expr:expr),*) $($tail:tt)* } + (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($($expr),*) + $name::$item($( $texpr ),*) } } quick_error!(FIND_FROM_IMPL - $name $item [ $( ( $($var:$typ)* ) )* ] + $name $item: TUPLE [$( $var:$typ ),*] { $($tail)* }); }; - (FIND_FROM_IMPL $name:ident $item:ident - [ $( ( $($var:ident : $typ:ty)* ) )* ] - { $t:tt $($tail:tt)* } + (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[ $( ( $($var:$typ)* ) )* ] + $name $item: STRUCT [$( $var:$typ ),*] { $($tail)* }); }; - (FIND_FROM_IMPL $name:ident $item:ident - [ $( ( $($var:ident : $typ:ty)* ) )* ] + (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 ),*] { } ) => { }; + (ITEM_BODY $(#[$imeta:imeta])* $item:ident: UNIT + ) => { }; + (ITEM_BODY $(#[$imeta:imeta])* $item:ident: TUPLE + [$( $typ:ty ),*] + ) => { + ($( $typ ),*) + }; + (ITEM_BODY $(#[$imeta:imeta])* $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 ),*} + }; // This one should match all allowed sequences in "funcs" but not match // anything else. // This is to contrast FIND_* clauses which just find stuff they need and // skip everything else completely - (ERROR_CHECK display($self_:tt) -> ($($exprs:tt)*) $($tail:tt)*) - => { quick_error!(ERROR_CHECK $($tail)*); }; - (ERROR_CHECK display($pattern: expr) $($tail:tt)*) - => { quick_error!(ERROR_CHECK $($tail)*); }; - (ERROR_CHECK display($pattern: expr, $($exprs:tt)*) $($tail:tt)*) - => { quick_error!(ERROR_CHECK $($tail)*); }; - (ERROR_CHECK description($expr:expr) $($tail:tt)*) - => { quick_error!(ERROR_CHECK $($tail)*); }; - (ERROR_CHECK cause($expr:expr) $($tail:tt)*) - => { quick_error!(ERROR_CHECK $($tail)*); }; - (ERROR_CHECK from() $($tail:tt)*) - => { quick_error!(ERROR_CHECK $($tail)*); }; - (ERROR_CHECK from($ftyp:ty) $($tail:tt)*) - => { quick_error!(ERROR_CHECK $($tail)*); }; - (ERROR_CHECK from($fvar:ident : $ftyp:ty) -> ($($e:expr),*) $($tail:tt)*) - => { quick_error!(ERROR_CHECK $($tail)*); }; - (ERROR_CHECK) => {}; + (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 $imode:tt ) => {}; // Utility functions - (IDENT $ident: ident) => { $ident } + (IDENT $ident:ident) => { $ident } } + #[cfg(test)] mod test { - use std::io; + use std::num::ParseFloatError; + use std::str::Utf8Error; + use std::string::FromUtf8Error; use std::error::Error; quick_error! { @@ -616,26 +729,32 @@ mod test { } quick_error! { - #[derive(Debug)] - pub enum IoWrapper { - /// I/O Error - Io(err: io::Error) { + #[derive(Debug, PartialEq)] + pub enum Wrapper { + /// ParseFloat Error + ParseFloatError(err: ParseFloatError) { from() description(err.description()) - display("I/O error: {err}", err=err) + display("parse float error: {err}", err=err) cause(err) } Other(descr: &'static str) { description(descr) display("Error: {}", descr) } - /// I/O error with some context - IoAt(place: &'static str, err: io::Error) { + /// FromUtf8 Error + TupleFromUtf8Error(err: Utf8Error, source: Vec) { cause(err) - display(self_) -> ("{} {}: {}", self_.description(), place, err) - description("io error at") - from(s: String) -> ("idea", - io::Error::new(io::ErrorKind::Other, s)) + 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()) + } + // Utf8 Error + StructUtf8Error{ 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 } } Discard { from(&'static str) @@ -647,72 +766,88 @@ mod test { } #[test] - fn io_wrapper_err() { - let io1 = IoWrapper::Io( - io::Error::new(io::ErrorKind::Other, "some error")); - assert_eq!(format!("{}", io1), "I/O error: some error".to_string()); - assert_eq!(format!("{:?}", io1), - "Io(Error { repr: Custom(Custom { kind: Other, \ - error: StringError(\"some error\") }) })".to_string()); - assert_eq!(io1.description(), "some error"); - assert_eq!(io1.cause().unwrap().description(), "some error"); + fn wrapper_err() { + let cause = "one and a half times pi".parse::().unwrap_err(); + let err = Wrapper::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 io_wrapper_trait_str() { - let err: &Error = &IoWrapper::Other("hello"); - assert_eq!(format!("{}", err), "Error: hello".to_string()); - assert_eq!(format!("{:?}", err), "Other(\"hello\")".to_string()); - assert_eq!(err.description(), "hello".to_string()); + fn wrapper_trait_str() { + let desc = "hello"; + let err: &Error = &Wrapper::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 io_wrapper_trait_two_fields() { - let io1 = IoWrapper::Io( - io::Error::new(io::ErrorKind::Other, "some error")); - let err: &Error = &IoWrapper::IoAt("file", - io::Error::new(io::ErrorKind::NotFound, io1)); - assert_eq!(format!("{}", err), - "io error at file: I/O error: some error".to_string()); - assert_eq!(format!("{:?}", err), "IoAt(\"file\", Error { \ - repr: Custom(Custom { kind: NotFound, \ - error: Io(Error { repr: Custom(Custom { \ - kind: Other, error: StringError(\"some error\") \ - }) }) }) })".to_string()); - assert_eq!(err.description(), "io error at"); - assert_eq!(err.cause().unwrap().description(), "some error"); + fn wrapper_trait_two_fields() { + let invalid_utf8: Vec = vec![0, 159, 146, 150]; + let cause = String::from_utf8(invalid_utf8.clone()).unwrap_err().utf8_error(); + let err: &Error = &Wrapper::TupleFromUtf8Error(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!("TupleFromUtf8Error({:?}, {:?})", cause, invalid_utf8)); + assert_eq!(err.description(), "utf8 error"); + assert_eq!(format!("{:?}", err.cause().unwrap()), format!("{:?}", cause)); } #[test] - fn io_wrapper_from() { - let io1: IoWrapper = From::from(io::Error::from_raw_os_error(2)); - assert_eq!(format!("{}", io1), - "I/O error: No such file or directory (os error 2)".to_string()); - let descr = io1.cause().unwrap().description(); - assert!(descr == "os error" // rust <= 1.6 - || descr == "entity not found" // rust 1.7 (probably, nightly) - ); + fn wrapper_struct() { + let invalid_utf8: Vec = vec![0, 159, 146, 150]; + let cause = String::from_utf8(invalid_utf8.clone()).unwrap_err().utf8_error(); + let err: &Error = &Wrapper::StructUtf8Error{ 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!("StructUtf8Error {{ err: {:?}, hint: {:?} }}", cause, Some("nonsense"))); + assert_eq!(err.description(), "utf8 error"); + assert_eq!(format!("{:?}", err.cause().unwrap()), format!("{:?}", cause)); } #[test] - fn io_wrapper_custom_from() { - let io1: IoWrapper = From::from("Stringy".to_string()); - assert_eq!(format!("{}", io1), "io error at idea: Stringy".to_string()); - assert_eq!(io1.cause().unwrap().description(), "Stringy"); + fn wrapper_from() { + let cause = "one and a half times pi".parse::().unwrap_err(); + let err = Wrapper::ParseFloatError(cause.clone()); + let err_from: Wrapper = From::from(cause); + assert_eq!(err_from, err); } #[test] - fn io_wrapper_discard() { - let io1: IoWrapper = From::from("hello"); - assert_eq!(format!("{}", io1), "Discard".to_string()); - assert!(io1.cause().is_none()); + fn wrapper_custom_from() { + let invalid_utf8: Vec = vec![0, 159, 146, 150]; + let cause = String::from_utf8(invalid_utf8.clone()).unwrap_err(); + let err = Wrapper::TupleFromUtf8Error(cause.utf8_error().clone(), invalid_utf8); + let err_from: Wrapper = From::from(cause); + assert_eq!(err_from, err); } #[test] - fn io_wrapper_signleton() { - let io1: IoWrapper = IoWrapper::Singleton; - assert_eq!(format!("{}", io1), "Just a string".to_string()); + fn wrapper_struct_from() { + let invalid_utf8: Vec = vec![0, 159, 146, 150]; + let cause = String::from_utf8(invalid_utf8.clone()).unwrap_err().utf8_error(); + let err = Wrapper::StructUtf8Error{ err: cause.clone(), hint: None }; + let err_from: Wrapper = From::from(cause); + assert_eq!(err_from, err); } + #[test] + fn wrapper_discard() { + let err: Wrapper = 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 wrapper_singleton() { + let err: Wrapper = Wrapper::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()); + } }