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}