odra_ir/module_item/
method.rs

1use quote::{quote, ToTokens};
2
3use crate::attrs::{partition_attributes, OdraAttribute};
4
5use super::utils;
6
7/// Odra method definition.
8///
9/// # Examples
10/// ```
11/// # <odra_ir::module::Method as TryFrom<syn::ImplItemMethod>>::try_from(syn::parse_quote! {
12/// pub fn set_value(&self, value: u32) {
13///    // logic goes here
14/// }
15/// # });
16/// ```
17pub struct Method {
18    pub attrs: Vec<OdraAttribute>,
19    pub impl_item: syn::ImplItemMethod,
20    pub ident: syn::Ident,
21    pub is_mut: bool,
22    pub args: syn::punctuated::Punctuated<syn::PatType, syn::token::Comma>,
23    pub ret: syn::ReturnType,
24    pub full_sig: syn::Signature,
25    pub visibility: syn::Visibility
26}
27
28impl Method {
29    pub fn is_public(&self) -> bool {
30        matches!(self.visibility, syn::Visibility::Public(_))
31    }
32
33    pub fn is_payable(&self) -> bool {
34        self.attrs.iter().any(|attr| attr.is_payable())
35    }
36}
37
38impl ToTokens for Method {
39    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
40        let is_non_reentrant = self.attrs.iter().any(OdraAttribute::is_non_reentrant);
41        let name = &self.ident.to_string();
42        let args = &self
43            .args
44            .iter()
45            .map(|arg| {
46                let name = &*arg.pat;
47
48                let (ty, is_slice) = utils::ty(arg);
49                let is_ref = utils::is_ref(arg);
50                let ty = quote!(<#ty as odra::types::CLTyped>::cl_type());
51                quote! {
52                    odra::types::contract_def::Argument {
53                        ident: odra::prelude::string::String::from(stringify!(#name)),
54                        ty: #ty,
55                        is_ref: #is_ref,
56                        is_slice: #is_slice
57                    },
58                }
59            })
60            .collect::<proc_macro2::TokenStream>();
61
62        let ret = match &self.ret {
63            syn::ReturnType::Default => quote!(odra::types::CLType::Unit),
64            syn::ReturnType::Type(_, ty) => {
65                quote!(<#ty as odra::types::CLTyped>::cl_type())
66            }
67        };
68
69        let ty = match self.attrs.iter().any(|attr| attr.is_payable()) {
70            true => {
71                quote!(odra::types::contract_def::EntrypointType::PublicPayable { non_reentrant: #is_non_reentrant })
72            }
73            false => {
74                quote!(odra::types::contract_def::EntrypointType::Public { non_reentrant: #is_non_reentrant })
75            }
76        };
77
78        let is_mut = self.is_mut;
79
80        let ep = quote! {
81            odra::types::contract_def::Entrypoint {
82                ident: odra::prelude::string::String::from(#name),
83                args: odra::prelude::vec![#args],
84                is_mut: #is_mut,
85                ret: #ret,
86                ty: #ty,
87            },
88        };
89
90        tokens.extend(ep)
91    }
92}
93
94impl TryFrom<syn::ImplItemMethod> for Method {
95    type Error = syn::Error;
96
97    fn try_from(method: syn::ImplItemMethod) -> Result<Self, Self::Error> {
98        let (odra_attrs, attrs) = partition_attributes(method.clone().attrs)?;
99        let ident = method.sig.ident.to_owned();
100        let args = utils::extract_typed_inputs(&method.sig);
101        let ret = method.clone().sig.output;
102        let full_sig = method.clone().sig;
103        let visibility = method.vis.clone();
104        let is_mut = utils::is_mut(&full_sig);
105
106        Ok(Self {
107            attrs: odra_attrs,
108            impl_item: syn::ImplItemMethod { attrs, ..method },
109            ident,
110            is_mut,
111            args,
112            ret,
113            full_sig,
114            visibility
115        })
116    }
117}