predicate_macros/
lib.rs

1//! # predicate-macros
2//! Easy to implement [predicate](https://github.com/Spxg/predicate) traits.
3//!
4//! ## Macros
5//! * add_field
6//! * BitAnd
7//! * BitOr
8//! * OpUnitTrait
9
10use proc_macro::TokenStream;
11use quote::quote;
12use quote::ToTokens;
13use syn::parse_macro_input;
14use syn::Data;
15use syn::DataEnum;
16use syn::DeriveInput;
17use syn::Variant;
18
19/// Add field `Unit(OpUnitRcType<OpUnit<Self>>)` to this enum.
20/// 
21/// Only impl for enum, other types will panic.
22#[proc_macro_attribute]
23pub fn add_field(_attr: TokenStream, input: TokenStream) -> TokenStream {
24    let mut item = parse_macro_input!(input as DeriveInput);
25    let item_name = item.ident.clone();
26
27    let unit_field = format!("Unit(OpUnitRcType<OpUnit<{}>>)", item_name);
28    let unit_field: TokenStream = unit_field.parse().expect("parse error");
29    let unit = parse_macro_input!(unit_field as Variant);
30
31    match item.data {
32        Data::Enum(DataEnum {
33            ref mut variants, ..
34        }) => {
35            variants.push(unit);
36        }
37        _ => panic!("only impl for enum"),
38    }
39
40    let tokens: proc_macro2::TokenStream = item.into_token_stream();
41    quote!(
42        #tokens
43    )
44    .into()
45}
46
47/// Impl `OpUnitTrait`.
48#[proc_macro_derive(OpUnitTrait)]
49pub fn impl_op_unit_trait(input: TokenStream) -> TokenStream {
50    let item = parse_macro_input!(input as DeriveInput);
51    let item_name = &item.ident;
52
53    quote!(
54        impl OpUnitTrait for #item_name {
55            fn get_op_unit(self: &OpUnitRcType<Self>) -> OpUnitRcType<OpUnit<Self>> {
56                match self.as_ref() {
57                    #item_name::Unit(unit) => unit.clone(),
58                    _ => OpUnitRcType::new(OpUnit::new(Some(self.clone()), None, Operation::Single)),
59                }
60            }
61        }
62    )
63    .into()
64}
65
66/// Impl `BitAnd`
67#[proc_macro_derive(BitAnd)]
68pub fn impl_bit_and(input: TokenStream) -> TokenStream {
69    let item = parse_macro_input!(input as DeriveInput);
70    let item_name = &item.ident;
71
72    quote!(
73        impl std::ops::BitAnd for #item_name {
74            type Output = Self;
75
76            fn bitand(self, rhs: Self) -> Self::Output {
77                let node = OpUnit::new(
78                    Some(OpUnitRcType::new(self)),
79                    Some(OpUnitRcType::new(rhs)),
80                    Operation::And,
81                );
82                #item_name::Unit(OpUnitRcType::new(node))
83            }
84        }
85    )
86    .into()
87}
88
89/// Impl `BitOr`
90#[proc_macro_derive(BitOr)]
91pub fn impl_bit_or(input: TokenStream) -> TokenStream {
92    let item = parse_macro_input!(input as DeriveInput);
93    let item_name = &item.ident;
94
95    quote!(
96        impl std::ops::BitOr for #item_name {
97            type Output = Self;
98
99            fn bitor(self, rhs: Self) -> Self::Output {
100                let node = OpUnit::new(
101                    Some(OpUnitRcType::new(self)),
102                    Some(OpUnitRcType::new(rhs)),
103                    Operation::Or,
104                );
105                #item_name::Unit(OpUnitRcType::new(node))
106            }
107        }
108    )
109    .into()
110}