1extern crate proc_macro;
2
3use proc_macro::TokenStream;
4use ::quote::quote;
5use syn::{
6 spanned::Spanned,
7 parse_macro_input,
8 DeriveInput,
9 Result,
10 Error,
11};
12
13#[proc_macro_derive(Condition)]
14pub fn condition_derive(input: TokenStream) -> TokenStream {
15 let ast = parse_macro_input!(input as DeriveInput);
16 conditional(&ast)
17 .unwrap_or_else(|err| err.to_compile_error())
18 .into()
19}
20
21fn conditional (ast: &syn::DeriveInput) -> Result<proc_macro2::TokenStream> {
22 let name = &ast.ident;
23 let data = match &ast.data {
24 syn::Data::Enum(ref data) => &data.variants,
25 _ => return Err(Error::new(ast.span(), "Only enums may derive a Condition"))
26 };
27 if data.len() != 2 {
28 return Err(Error::new(ast.span(), "Condition enums must have exactly two fields"));
29 }
30 let falsehood = data.first().unwrap();
34 let truth = data.last().unwrap();
35
36 let gen = quote! {
37 impl Condition for #name {
38 #[inline]
39 fn is (&self, value: bool) -> bool {
40 match self {
41 Self::#falsehood => value == false,
42 Self::#truth => value == true,
43 }
44 }
45 }
46 };
47 Ok(gen.into())
48}