multiversx_sc_derive/generate/
proxy_callback_gen.rs

1use super::snippets;
2use crate::model::{
3    ArgPaymentMetadata, CallbackMetadata, ContractTrait, Method, MethodArgument, PublicRole,
4};
5
6/// Excludes the `#[call_result]` and the payment args.
7pub fn cb_proxy_arg_declarations(method_args: &[MethodArgument]) -> Vec<proc_macro2::TokenStream> {
8    method_args
9        .iter()
10        .filter_map(|arg| {
11            if arg.metadata.payment.is_payment_arg() || arg.metadata.callback_call_result {
12                None
13            } else {
14                let pat = &arg.pat;
15                let ty = &arg.ty;
16                Some(quote! {#pat : #ty })
17            }
18        })
19        .collect()
20}
21
22fn generate_callback_proxy_method(
23    m: &Method,
24    callback: &CallbackMetadata,
25) -> proc_macro2::TokenStream {
26    let arg_decl = cb_proxy_arg_declarations(&m.method_args);
27    let cb_name_literal = callback.callback_name.to_string();
28
29    let cb_arg_push_snippets: Vec<proc_macro2::TokenStream> = m
30        .method_args
31        .iter()
32        .map(|arg| {
33            if let ArgPaymentMetadata::NotPayment = arg.metadata.payment {
34                if arg.metadata.callback_call_result {
35                    quote! {}
36                } else {
37                    let pat = &arg.pat;
38                    quote! {
39                        ___callback_call___.push_endpoint_arg(&#pat);
40                    }
41                }
42            } else {
43                quote! {}
44            }
45        })
46        .collect();
47    let method_name = &m.name;
48    quote! {
49        #[allow(clippy::too_many_arguments)]
50        #[allow(clippy::type_complexity)]
51        fn #method_name(
52            self,
53            #(#arg_decl),*
54        ) -> multiversx_sc::types::CallbackClosure<Self::Api> {
55            let mut ___callback_call___ =
56                multiversx_sc::types::new_callback_call::<Self::Api>(#cb_name_literal);
57            #(#cb_arg_push_snippets)*
58            ___callback_call___
59        }
60    }
61}
62
63pub fn generate_callback_proxies_object(methods: &[Method]) -> proc_macro2::TokenStream {
64    let proxy_methods: Vec<proc_macro2::TokenStream> = methods
65        .iter()
66        .filter_map(|m| {
67            if let PublicRole::Callback(callback) | PublicRole::CallbackPromise(callback) =
68                &m.public_role
69            {
70                Some(generate_callback_proxy_method(m, callback))
71            } else {
72                None
73            }
74        })
75        .collect();
76
77    let callback_proxy_object_def = snippets::callback_proxy_object_def();
78
79    quote! {
80        #callback_proxy_object_def
81
82        pub trait CallbackProxy: multiversx_sc::contract_base::CallbackProxyObjBase + Sized {
83            #(#proxy_methods)*
84        }
85
86        impl<A> self::CallbackProxy for CallbackProxyObj<A> where A: multiversx_sc::api::VMApi + 'static {}
87    }
88}
89
90pub fn generate_callback_proxies(
91    contract: &ContractTrait,
92) -> (
93    proc_macro2::TokenStream,
94    proc_macro2::TokenStream,
95    proc_macro2::TokenStream,
96) {
97    if contract.callback_count() == 0 {
98        (quote! {}, quote! {}, quote! {})
99    } else {
100        (
101            quote! {
102                fn callbacks(&self) -> self::CallbackProxyObj<Self::Api>;
103            },
104            quote! {
105                fn callbacks(&self) -> self::CallbackProxyObj<Self::Api> {
106                    <self::CallbackProxyObj::<Self::Api> as multiversx_sc::contract_base::CallbackProxyObjBase>::new_cb_proxy_obj()
107                }
108            },
109            generate_callback_proxies_object(contract.methods.as_slice()),
110        )
111    }
112}