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
#![recursion_limit = "128"]
extern crate proc_macro;

use proc_macro::TokenStream;

use near_bindgen_core::*;
use near_bindgen_promise::process_trait;
use proc_macro2::Span;
use quote::quote;
use syn::export::TokenStream2;
use syn::{File, ItemImpl, ItemStruct, ItemTrait};

#[proc_macro_attribute]
pub fn near_bindgen(attr: TokenStream, item: TokenStream) -> TokenStream {
    if let Ok(input) = syn::parse::<ItemStruct>(item.clone()) {
        let sys_file = rust_file(include_bytes!("../res/sys.rs"));
        let near_environment = rust_file(include_bytes!("../res/near_blockchain.rs"));
        return TokenStream::from(quote! {
            #input
            #sys_file
            #near_environment
        });
    } else if let Ok(input) = syn::parse::<ItemImpl>(item) {
        let generated_code = process_impl(&input, TokenStream2::from(attr));
        TokenStream::from(quote! {
            #input
            #generated_code
        })
    } else {
        TokenStream::from(
            syn::Error::new(
                Span::call_site(),
                "near_bindgen can only be used on type declarations and impl sections.",
            )
            .to_compile_error(),
        )
    }
}

fn rust_file(data: &[u8]) -> File {
    let data = std::str::from_utf8(data).unwrap();
    syn::parse_file(data).unwrap()
}

#[proc_macro_attribute]
pub fn ext_contract(attr: TokenStream, item: TokenStream) -> TokenStream {
    if let Ok(input) = syn::parse::<ItemTrait>(item.clone()) {
        let mut mod_name: Option<proc_macro2::Ident> = None;
        if !attr.is_empty() {
            mod_name = match syn::parse(attr) {
                Ok(x) => x,
                Err(err) => {
                    return TokenStream::from(
                        syn::Error::new(
                            Span::call_site(),
                            format!("Failed to parse mod name for ext_contract: {}", err),
                        )
                        .to_compile_error(),
                    )
                }
            };
        }
        match process_trait(&input, mod_name.map(|x| x.to_string())) {
            Ok(generated_code) => TokenStream::from(quote! {
                #input
                #generated_code
            }),
            Err(e) => TokenStream::from(e.to_compile_error()),
        }
    } else {
        TokenStream::from(
            syn::Error::new(Span::call_site(), "ext_contract can only be used on traits")
                .to_compile_error(),
        )
    }
}

/// `callback_args` is a marker attribute it does not generate code by itself.
#[proc_macro_attribute]
pub fn callback_args(_attr: TokenStream, item: TokenStream) -> TokenStream {
    item
}

/// `callback_args_vec` is a marker attribute it does not generate code by itself.
#[proc_macro_attribute]
pub fn callback_args_vec(_attr: TokenStream, item: TokenStream) -> TokenStream {
    item
}