enum_display_derive/lib.rs
1//! # derive `Display` for simple enums
2//!
3//! You can derive the `Display` trait for simple enums.
4//!
5//! Actually, the most complex enum definition that this crate supports is like this one:
6//!
7//! ```rust,ignore
8//! #[derive(Display)]
9//! pub enum FooBar {
10//! Foo,
11//! Bar(),
12//! FooBar(i32), // some wrapped type which implements Display
13//! }
14//! ```
15//!
16//! The above code will be expanded (roughly, without the enum definition) into this code:
17//!
18//! ```rust,ignore
19//! impl Display for FooBar {
20//! fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::result::Result<(), ::std::fmt::Error> {
21//! match *self {
22//! FooBar::Foo => f.write_str("Foo"),
23//! FooBar::Bar => f.write_str("Bar()"),
24//! FooBar::FooBar(ref inner) => ::std::fmt::Display::fmt(inner, f),
25//! }
26//! }
27//! }
28//! ```
29//!
30//! ## Examples
31//!
32//! ```rust,ignore
33//! #[macro_use]
34//! extern crate enum_display_derive;
35//!
36//! use std::fmt::Display;
37//!
38//! #[derive(Display)]
39//! enum FizzBuzz {
40//! Fizz,
41//! Buzz,
42//! FizzBuzz,
43//! Number(u64),
44//! }
45//!
46//! fn fb(i: u64) {
47//! match (i % 3, i % 5) {
48//! (0, 0) => FizzBuzz::FizzBuzz,
49//! (0, _) => FizzBuzz::Fizz,
50//! (_, 0) => FizzBuzz::Buzz,
51//! (_, _) => FizzBuzz::Number(i),
52//! }
53//! }
54//!
55//! fn main() {
56//! for i in 0..100 {
57//! println!("{}", fb(i));
58//! }
59//! }
60//! ```
61//!
62
63extern crate proc_macro;
64extern crate proc_macro2;
65extern crate syn;
66#[macro_use]
67extern crate quote;
68
69use proc_macro::TokenStream;
70
71#[proc_macro_derive(Display)]
72#[doc(hidden)]
73pub fn display(input: TokenStream) -> TokenStream {
74 // Parse the string representation
75 let ast: syn::DeriveInput = syn::parse(input).unwrap();
76
77 match ast.data {
78 syn::Data::Enum(ref enum_data) => {
79 let name = &ast.ident;
80 impl_display(name, enum_data).into()
81 }
82 _ => panic!("#[derive(Display)] works only on enums"),
83 }
84}
85
86fn impl_display(name: &syn::Ident, data: &syn::DataEnum) -> proc_macro2::TokenStream {
87 let variants = data.variants.iter()
88 .map(|variant| impl_display_for_variant(name, variant));
89
90 quote! {
91 impl Display for #name {
92 fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::result::Result<(), ::std::fmt::Error> {
93 match *self {
94 #(#variants)*
95 }
96 }
97 }
98 }
99}
100
101fn impl_display_for_variant(name: &syn::Ident, variant: &syn::Variant) -> proc_macro2::TokenStream {
102 let id = &variant.ident;
103 match variant.fields {
104 syn::Fields::Unit => {
105 quote! {
106 #name::#id => {
107 f.write_str(stringify!(#id))
108 }
109 }
110 }
111 syn::Fields::Unnamed(ref fields) => {
112 match fields.unnamed.len() {
113 0 => {
114 quote! {
115 #name::#id() => {
116 f.write_str(stringify!(#id))?;
117 f.write_str("()")
118 }
119 }
120 }
121 1 => {
122 quote! {
123 #name::#id(ref inner) => {
124 ::std::fmt::Display::fmt(inner, f)
125 }
126 }
127 }
128 _ => {
129 panic!("#[derive(Display)] does not support tuple variants with more than one \
130 fields")
131 }
132 }
133 }
134 _ => panic!("#[derive(Display)] works only with unit and tuple variants"),
135 }
136}