condition_derive/
lib.rs

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  // TODO: Permit #[false] and #[true] fields so that the order doesn't really
31  // matter
32  // Unwrapping should be fine here, since we KNOW there are two fields.
33  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}