qcheck_macros/
lib.rs

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