1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
use handler::{generate_handler, HandlerKind};
use quote::quote;
use syn::{meta, parse_macro_input, spanned::Spanned, Error, Item};

mod handler;

#[proc_macro_attribute]
pub fn handler(
    attr: proc_macro::TokenStream,
    input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
    // Extract information from the attribute
    let kind = {
        let mut kind = HandlerKind::Query;

        let attribute_parser = meta::parser(|meta| kind.parse(meta));

        parse_macro_input!(attr with attribute_parser);

        kind
    };

    // Attempt to match as a function
    syn::parse::<Item>(input)
        .and_then(|item| {
            if let Item::Fn(handler) = item {
                generate_handler(handler, kind)
            } else {
                Err(Error::new(item.span(), "handlers must be a method"))
            }
        })
        .unwrap_or_else(Error::into_compile_error)
        .into()
}

#[proc_macro_attribute]
pub fn exported_type(
    _attrs: proc_macro::TokenStream,
    input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
    let s = syn::parse::<Item>(input).unwrap();

    let (target_struct, fields) = match s {
        Item::Struct(ref s) => (
            s.ident.clone(),
            s.fields.iter().map(|field| field.ty.clone()),
        ),
        _ => unimplemented!(),
    };

    quote! {
        #[derive(TS)]
        #s

        impl qubit::TypeDependencies for #target_struct {
            fn get_deps(dependencies: &mut std::collections::BTreeMap<std::string::String, std::string::String>) {
                // Short circuit if this type has already been added
                if dependencies.contains_key(&Self::name()) {
                    return;
                }

                // Insert this type
                dependencies.insert(Self::name(), Self::inline());

                // Insert field types
                #(<#fields as qubit::TypeDependencies>::get_deps(dependencies);)*
            }
        }
    }
    .into()
}