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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#[macro_use]
extern crate quote;

mod args;
mod dispatcher;
mod encoder;
mod fallible;
mod helper;
mod stub;

use args::MacroArgsRaw;
use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;

#[proc_macro_attribute]
pub fn serde_tc(args: TokenStream, input: TokenStream) -> TokenStream {
    match expand(TokenStream2::from(args), TokenStream2::from(input)) {
        Ok(x) => TokenStream::from(x),
        Err(x) => TokenStream::from(x),
    }
}

#[proc_macro_attribute]
pub fn serde_tc_full(_args: TokenStream, input: TokenStream) -> TokenStream {
    match expand(
        quote! {dispatcher, encoder, dict, tuple, async_methods, fallible = anyhow::Error, stub},
        TokenStream2::from(input),
    ) {
        Ok(x) => TokenStream::from(x),
        Err(x) => TokenStream::from(x),
    }
}

#[proc_macro_attribute]
pub fn serde_tc_debug(_args: TokenStream, input: TokenStream) -> TokenStream {
    match expand(
        quote! {dispatcher, encoder, dict, tuple, async_methods, fallible = anyhow::Error, stub},
        TokenStream2::from(input),
    ) {
        Ok(x) => println!("{}", x),
        Err(x) => println!("{}", x),
    }
    TokenStream::new()
}

fn expand(args: TokenStream2, input: TokenStream2) -> Result<TokenStream2, TokenStream2> {
    let args: MacroArgsRaw = syn::parse2(args).map_err(|e| e.to_compile_error())?;
    let args = args.fill_default_values();

    let source_trait = match syn::parse2::<syn::ItemTrait>(input.clone()) {
        Ok(x) => x,
        Err(_) => {
            return Err(
                syn::Error::new_spanned(input, "You can use #[serde_tc] only on a trait")
                    .to_compile_error(),
            )
        }
    };

    let dispatcher = dispatcher::generate_dispatcher(&source_trait, &args)?;
    let encoder = encoder::generate_encoder(&source_trait, &args)?;
    let fallible = fallible::generate_fallible_trait(&source_trait, &args)?;
    let stub = if args.stub {
        stub::generate_stub(
            &source_trait,
            &syn::parse2(fallible.clone()).unwrap(),
            &args,
        )?
    } else {
        quote! {}
    };
    let trait_ident = source_trait.ident.clone();
    if args.async_methods {
        Ok(quote! {
            #[async_trait::async_trait]
            #source_trait
            #[async_trait::async_trait]
            #fallible
            #dispatcher
            #encoder
            #stub
            impl HttpInterface for dyn #trait_ident {}
        })
    } else {
        Ok(quote! {
            #source_trait
            #[async_trait::async_trait]
            #fallible
            #dispatcher
            #encoder
            #stub
        })
    }
}