quickcheck_macros/
lib.rs

1extern crate proc_macro;
2extern crate proc_macro2;
3extern crate quote;
4extern crate syn;
5
6use std::mem;
7
8use proc_macro::TokenStream;
9use quote::quote;
10use syn::{
11    parse::{Parse, Parser},
12    parse_quote,
13    spanned::Spanned,
14};
15
16#[proc_macro_attribute]
17pub fn quickcheck(_args: TokenStream, input: TokenStream) -> TokenStream {
18    let output = match syn::Item::parse.parse(input.clone()) {
19        Ok(syn::Item::Fn(mut item_fn)) => {
20            let mut inputs = syn::punctuated::Punctuated::new();
21            let mut errors = Vec::new();
22
23            item_fn.sig.inputs.iter().for_each(|input| match *input {
24                syn::FnArg::Typed(syn::PatType { ref ty, .. }) => {
25                    inputs.push(parse_quote!(_: #ty));
26                }
27                _ => errors.push(syn::parse::Error::new(
28                    input.span(),
29                    "unsupported kind of function argument",
30                )),
31            });
32
33            if errors.is_empty() {
34                let attrs = mem::replace(&mut item_fn.attrs, Vec::new());
35                let name = &item_fn.sig.ident;
36                let fn_type = syn::TypeBareFn {
37                    lifetimes: None,
38                    unsafety: item_fn.sig.unsafety.clone(),
39                    abi: item_fn.sig.abi.clone(),
40                    fn_token: <syn::Token![fn]>::default(),
41                    paren_token: syn::token::Paren::default(),
42                    inputs,
43                    variadic: item_fn.sig.variadic.clone(),
44                    output: item_fn.sig.output.clone(),
45                };
46
47                quote! {
48                    #[test]
49                    #(#attrs)*
50                    fn #name() {
51                        #item_fn
52                       ::quickcheck::quickcheck(#name as #fn_type)
53                    }
54                }
55            } else {
56                errors
57                    .iter()
58                    .map(syn::parse::Error::to_compile_error)
59                    .collect()
60            }
61        }
62        Ok(syn::Item::Static(mut item_static)) => {
63            let attrs = mem::replace(&mut item_static.attrs, Vec::new());
64            let name = &item_static.ident;
65
66            quote! {
67                #[test]
68                #(#attrs)*
69                fn #name() {
70                    #item_static
71                    ::quickcheck::quickcheck(#name)
72                }
73            }
74        }
75        _ => {
76            let span = proc_macro2::TokenStream::from(input).span();
77            let msg =
78                "#[quickcheck] is only supported on statics and functions";
79
80            syn::parse::Error::new(span, msg).to_compile_error()
81        }
82    };
83
84    output.into()
85}