odra_ir/module_item/
constructor.rs1use std::convert::TryFrom;
2
3use crate::attrs::{partition_attributes, OdraAttribute};
4use quote::{quote, ToTokens};
5
6use super::utils;
7
8pub struct Constructor {
21 pub attrs: Vec<OdraAttribute>,
22 pub impl_item: syn::ImplItemMethod,
23 pub ident: syn::Ident,
24 pub args: syn::punctuated::Punctuated<syn::PatType, syn::token::Comma>,
25 pub full_sig: syn::Signature
26}
27
28impl ToTokens for Constructor {
29 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
30 let is_non_reentrant = self.attrs.iter().any(OdraAttribute::is_non_reentrant);
31 let is_mut = utils::is_mut(&self.full_sig);
32 let name = &self.ident.to_string();
33 let args = &self
34 .args
35 .iter()
36 .flat_map(|arg| {
37 let name = &*arg.pat;
38 let (ty, is_slice) = utils::ty(arg);
39 let is_ref = utils::is_ref(arg);
40 let ty = quote!(<#ty as odra::types::CLTyped>::cl_type());
41 quote! {
42 odra::types::contract_def::Argument {
43 ident: odra::prelude::string::String::from(stringify!(#name)),
44 ty: #ty,
45 is_ref: #is_ref,
46 is_slice: #is_slice
47 },
48 }
49 })
50 .collect::<proc_macro2::TokenStream>();
51 let ep = quote! {
52 odra::types::contract_def::Entrypoint {
53 ident: odra::prelude::string::String::from(#name),
54 args: odra::prelude::vec![#args],
55 is_mut: #is_mut,
56 ret: odra::types::CLType::Unit,
57 ty: odra::types::contract_def::EntrypointType::Constructor { non_reentrant: #is_non_reentrant },
58 },
59 };
60
61 tokens.extend(ep)
62 }
63}
64
65impl TryFrom<syn::ImplItemMethod> for Constructor {
66 type Error = syn::Error;
67
68 fn try_from(method: syn::ImplItemMethod) -> Result<Self, Self::Error> {
69 let (odra_attrs, attrs) = partition_attributes(method.clone().attrs).unwrap();
70 let ident = method.sig.ident.to_owned();
71 let args = utils::extract_typed_inputs(&method.sig);
72 if let syn::ReturnType::Type(_, _) = method.sig.output {
73 return Err(syn::Error::new_spanned(
74 method.sig,
75 "Constructor must not return value."
76 ));
77 }
78 let full_sig = method.sig.clone();
79
80 Ok(Self {
81 attrs: odra_attrs,
82 impl_item: syn::ImplItemMethod { attrs, ..method },
83 ident,
84 args,
85 full_sig
86 })
87 }
88}
89
90#[cfg(test)]
91mod test {
92 use std::convert::TryFrom;
93
94 use super::Constructor;
95
96 #[test]
97 fn test_attrs() {
98 let item: syn::ImplItemMethod = syn::parse_quote! {
99 #[odra(init, non_reentrant)]
100 #[some(a)]
101 pub fn set_initial_value(&self, value: u32) {
102 self.set_value(value);
103 }
104 };
105 let constructor = Constructor::try_from(item).unwrap();
106 assert_eq!(constructor.attrs.len(), 1);
107 }
108}