error_derive/
lib.rs

1/*!
2This crate provides macros for deriving some useful methods and traits for Error enums.
3
4All of these macros are designed to be used with the
5[`custom_derive`](https://crates.io/crates/custom_derive) crate, though they can be used independent of it.
6
7# Example
8
9Derive implementation of the standard `Error` trait.
10This also provides the requisite `Display` implementation.
11
12```rust
13#[macro_use] extern crate custom_derive;
14#[macro_use] extern crate error_derive;
15# use std::error::Error as StdError;
16# use std::io;
17# use std::str::{from_utf8, Utf8Error};
18
19custom_derive! {
20    #[derive(Debug,
21        ErrorFrom, ErrorDisplay, Error("very bad error"))]
22    pub enum Error {
23        Io(io::Error),
24        Utf8(Utf8Error),
25    }
26}
27
28# fn main() {
29let io_error = Error::Io(io::Error::last_os_error());
30let utf8_error = Error::Utf8(from_utf8(&[0, 142]).unwrap_err());
31
32assert_eq!("very bad error", io_error.description());
33assert_eq!("very bad error", utf8_error.description());
34
35assert!(io_error.cause().is_some());
36assert!(utf8_error.cause().is_some());
37# }
38```
39
40# Overview
41
42This crate allows to derive the following traits:
43
44- `ErrorFrom`, which creates `From` trait implementations from each enum variants that wraps an inner `Error`
45- `ErrorDisplay`, which creates a `Display` trait implementation showing the entire causal chain for an error
46- `Error`, which implements the standard `Error` trait with a given description
47
48`Error` and `ErrorDisplay` are typically derived together, though either can of course be implemented separately.
49
50# Usage without `custom_derive!`
51
52Although designed to be used with `custom_derive!`, all of the macros in this crate can be used without it.
53The following:
54
55```rust
56# #[macro_use] extern crate custom_derive;
57# #[macro_use] extern crate error_derive;
58# use std::io;
59custom_derive! {
60    #[derive(Debug, ErrorDisplay, Error("just I/O error"))]
61    pub enum JustIoError { ThisOne(io::Error) }
62}
63# fn main() {}
64```
65
66Can also be writtten as:
67
68```rust
69# #[macro_use] extern crate custom_derive;
70# #[macro_use] extern crate error_derive;
71# use std::io;
72#[derive(Debug)]
73pub enum JustIoError { ThisOne(io::Error) }
74ErrorDisplay! { () pub enum JustIoError { ThisOne(io::Error) } }
75Error! { ("just I/O error") pub enum JustIoError { ThisOne(io::Error) } }
76# fn main() {}
77```
78*/
79
80#![doc(html_root_uri = "https://xion.github.io/rust-error-derive")]
81
82#[macro_use] mod util;
83
84
85#[macro_export]
86macro_rules! ErrorFrom {
87    (@expand $name:ident ($($var_names:ident($var_tys:ty),)*)) => {
88        $(
89            impl ::std::convert::From<$var_tys> for $name {
90                fn from(v: $var_tys) -> $name {
91                    $name::$var_names(v)
92                }
93            }
94        )*
95    };
96
97    (() $(pub)* enum $name:ident { $($body:tt)* }) => {
98        enum_derive_util! {
99            @collect_unary_variants
100            (ErrorFrom { @expand $name }),
101            ($($body)*,) -> ()
102        }
103    };
104}
105
106
107#[macro_export]
108macro_rules! ErrorDisplay {
109    (@expand $name:ident ($($var_names:ident($var_tys:ty),)*)) => {
110        impl ::std::fmt::Display for $name {
111            fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
112                try!(write!(fmt, "{}", ::std::error::Error::description(self)));
113                if let Some(cause) = ::std::error::Error::cause(self) {
114                    try!(write!(fmt, "\n-- caused by {}", cause));
115                }
116                Ok(())
117            }
118        }
119    };
120
121    (() $(pub)* enum $name:ident { $($body:tt)* }) => {
122        enum_derive_util! {
123            @collect_unary_variants
124            (ErrorDisplay { @expand $name }),
125            ($($body)*,) -> ()
126        }
127    };
128}
129
130
131#[macro_export]
132macro_rules! Error {
133    (@expand $desc:expr, $name:ident ($($var_names:ident($var_tys:ty),)*)) => {
134        impl ::std::error::Error for $name {
135            fn description(&self) -> &str {
136               $desc
137            }
138
139            fn cause(&self) -> Option<&::std::error::Error> {
140                match *self {
141                    $(
142                        $name::$var_names(ref c) => Some(c),
143                    )*
144                }
145            }
146        }
147    };
148
149    (($desc:expr) $(pub)* enum $name:ident { $($body:tt)* }) => {
150        enum_derive_util! {
151            @collect_unary_variants
152            (Error { @expand $desc, $name }),
153            ($($body)*,) -> ()
154        }
155    };
156}