eosio_codegen/
contract.rs

1use std::collections::HashMap;
2
3use core::convert::TryFrom;
4use proc_macro2::TokenStream as TokenStream2;
5use quote::quote;
6use quote::quote_spanned;
7
8use syn::{
9    spanned::Spanned,
10    // token,
11};
12
13use proc_macro2::{
14    Ident,
15    // Span,
16};
17
18use crate::{
19    action::Action,
20    table::Table,
21    attrs,
22    // FixedString,
23    name::{
24        s2n,
25        is_name_valid,
26    },
27    format_err_spanned,
28    attrs::Attrs as _,
29};
30
31/// An contract definition consisting of the configuration and module.
32
33#[derive(Debug, PartialEq, Eq)]
34pub struct Contract {
35    attrs: Vec<syn::Attribute>,
36    vis: syn::Visibility,
37    ident: Ident,
38    main_struct: Option<syn::ItemStruct>,
39    sub_struct: Option<syn::ItemStruct>,
40    items: Vec<syn::Item>,
41    variants: Vec<syn::ItemEnum>,
42    actions: Vec<Action>,
43    structs: Vec<syn::ItemStruct>,
44    packers: Vec<syn::ItemStruct>,
45    tables: Vec<Table>,
46    others: Vec<syn::Item>,
47}
48
49impl TryFrom<syn::ItemMod> for Contract {
50    type Error = syn::Error;
51
52    fn try_from(module: syn::ItemMod) -> Result<Self, Self::Error> {
53        let _module_span = module.span();
54        let (_brace, items) = match module.content {
55            Some((brace, items)) => (brace, items),
56            None => {
57                return Err(format_err_spanned!(
58                    module,
59                    "out-of-line modules are not supported, use `#[chain::contract] mod name {{ ... }}`",
60                ))
61            }
62        };
63
64        let (_, other_attrs) = attrs::partition_attributes(module.attrs.clone())?;
65
66        let mut contract = Self {
67            attrs: other_attrs,
68            ident: module.ident,
69            vis: module.vis,
70            main_struct: None,
71            sub_struct: None,
72            items: items,
73            variants: Vec::new(),
74            actions: Vec::new(),
75            structs: Vec::new(),
76            packers: Vec::new(),
77            tables: Vec::new(),
78            others: Vec::new(),
79        };
80        contract.analyze_items()?;
81        return Ok(contract);
82    }
83}
84
85impl Contract {
86    /// Creates a new contract from the given configuration and module
87    pub fn new(
88        _config: TokenStream2,
89        module: TokenStream2,
90    ) -> Result<Self, syn::Error> {
91        let module = syn::parse2::<syn::ItemMod>(module)?;
92        return Contract::try_from(module);
93    }
94
95    /// Returns all non-chain attributes of the chain module.
96    pub fn attrs(&self) -> &[syn::Attribute] {
97        &self.attrs
98    }
99
100    /// Returns the visibility of the chain module.
101    pub fn vis(&self) -> &syn::Visibility {
102        &self.vis
103    }
104
105    pub fn has_main_struct(&self) -> bool {
106        return self.main_struct.is_some();
107    }
108
109    pub fn has_sub_struct(&self) -> bool {
110        return self.sub_struct.is_some();
111    }
112
113    fn verify_variant(item: &syn::ItemEnum) -> Result<(), syn::Error> {
114        for v in &item.variants {
115            match v.fields {
116                syn::Fields::Unnamed(_) => {}
117                _ => {
118                    return Err(format_err_spanned!(
119                        v.fields,
120                        "invalid variant field"
121                    ));
122                }
123            }
124        }
125        Ok(())
126    }
127
128    fn check_struct_name(item: &syn::ItemStruct) -> Result<(), syn::Error> {
129        if let Some(_) = item.ident.to_string().find("_") {
130            println!("++++++++item.ident:{}", item.ident);
131            return Err(format_err_spanned!(
132                item,
133                "structs with `_` in name are not supported by contract"
134            ));
135        }
136        return Ok(());
137    }
138    
139    pub fn has_apply_func(&self) -> bool {
140        for item in &self.items {
141            match item {
142                syn::Item::Fn(x) => {
143                    if x.sig.ident.to_string() == "apply" {
144                        return true;
145                    }
146                }
147                _ => {}
148            }
149        }
150        false
151    }
152
153    pub fn has_trait(&self, s: &str, trait_: &str) -> bool {
154        for item in &self.items {
155            match item {
156                syn::Item::Impl(x) => {
157                    if let Some((_, trait_path, _)) = &x.trait_ {
158                        if let Some(segment) = trait_path.segments.last() {
159                            if trait_ == segment.ident.to_string() {
160                                if let syn::Type::Path(ty) = &*x.self_ty {
161                                    if let Some(segment) = ty.path.segments.last() {
162                                        if segment.ident.to_string() == s {
163                                            return true;
164                                        }
165                                    }
166                                }
167                            }
168                        }
169                    }
170                }
171                _ => {}
172            }
173        }
174        return false;
175    }
176
177    pub fn has_primary_value_interface_trait(&self, s: &str) -> bool {
178        return self.has_trait(s, "PrimaryValueInterface");
179    }
180
181    pub fn has_secondary_value_interface_trait(&self, s: &str) -> bool {
182        return self.has_trait(s, "SecondaryValueInterface");
183    }
184
185    pub fn analyze_items(&mut self) -> Result<(), syn::Error> {
186        let mut arg_types: HashMap<String, String> = HashMap::new();
187        for item in &mut self.items {
188            match item {
189                syn::Item::Struct(ref mut x) => {
190                    Self::check_struct_name(&x)?;
191                    let (chain_attrs, other_attrs) = attrs::partition_attributes(x.attrs.clone())?;
192                    let x_backup = x.clone();
193                    x.attrs = other_attrs;
194                    for field in &mut x.fields {
195                        let (_, other_attrs) = attrs::partition_attributes(field.attrs.clone())?;
196                        field.attrs = other_attrs;
197                    }
198
199                    if chain_attrs.len() == 0 {
200                        continue;
201                    }
202
203                    if chain_attrs.len() > 1 {
204                        return Err(format_err_spanned!(
205                            x,
206                            "more than one chain attribute specified to struct {}", x.ident
207                        ));
208                    }
209
210                    let attr = &chain_attrs[0];
211                    if attr.args().len() < 1 {
212                        return Err(format_err_spanned!(
213                            x,
214                            "wrong chain attribute in {}", x.ident
215                        ));
216                    }
217
218                    let arg = &attr.args().next().unwrap().arg;
219                    match arg {
220                        attrs::AttributeArg::MainStruct => {
221                            self.main_struct = Some(x.clone())
222                        }
223                        attrs::AttributeArg::SubStruct => {
224                            self.sub_struct = Some(x.clone())
225                        }
226                        attrs::AttributeArg::Packer | attrs::AttributeArg::Table(_) => {
227                            let length = x.fields.len();
228                            for (i, field) in &mut x.fields.iter_mut().enumerate() {
229                                if Self::is_binary_extension_type(&field.ty) {
230                                    if i + 1 != length {
231                                        return Err(format_err_spanned!(
232                                            field,
233                                            "BinaryExtension type can only appear at the last field of a struct",
234                                        ));
235                                    }
236                                }
237                            }
238                            self.packers.push(x.clone());
239                            for field in &x.fields {
240                                let (type_name, _) = Self::extract_type(&field.ty)?;
241                                arg_types.insert(type_name.clone(), type_name);
242                            };
243                        }
244                        _ => {
245                            return Err(format_err_spanned!(
246                                x,
247                                "only packer or table attribute is supported by struct {}", x.ident
248                            ));
249                        }
250                    }
251
252                    match &arg {
253                        attrs::AttributeArg::Table(_) => {
254                            if let Some(name) = attr.table_name() {
255                                if !is_name_valid(&name.str()) || name.length == 0 {
256                                    return Err(format_err_spanned!(
257                                        attr.args().next().unwrap().ast,
258                                        "table name is empty or contains invalid character(s). valid charaters are a-z & 1-5: {}", name.str()
259                                    ));
260                                }
261                                if self.tables.iter().any(|table| {
262                                    table.table_name == name
263                                }) {
264                                    return Err(format_err_spanned!(
265                                        attr.args().next().unwrap().ast,
266                                        "dumplicated table name: {}", name.str()
267                                    ));
268                                }
269                                self.tables.push(
270                                    Table {
271                                        item: x_backup,
272                                        table_name: name,
273                                        singleton: attr.is_singleton(),
274                                    }
275                                )
276                            }
277                        }
278                        _ => {}
279                    }
280                }
281                syn::Item::Impl(x) => {
282                    for impl_item in &mut x.items {
283                        match impl_item {
284                            syn::ImplItem::Method(method_item) => {
285                                let (chain_attrs, other_attrs) = attrs::partition_attributes(method_item.attrs.clone())?;
286                                method_item.attrs = other_attrs;
287                                if chain_attrs.len() <= 0 {
288                                    continue;
289                                }
290                                if chain_attrs.len() > 1 {
291                                    return Err(format_err_spanned!(
292                                        chain_attrs[1].args().next().unwrap().ast,
293                                        "only one chain attribute supported"
294                                    ));
295                                }
296                                let attr = &chain_attrs[0];
297                                if let Some(name) = attr.action_name() {
298                                    if !is_name_valid(&name.str()) || name.length == 0 {
299                                        return Err(format_err_spanned!(
300                                            attr.args().next().unwrap().ast,
301                                            "action name is empty or contains invalid character(s). valid characters are a-z and 1-5.: {}", name.str()
302                                        ));
303                                    }
304                                    if self.actions.iter().any(|action| {
305                                        action.action_name == name
306                                    }) {
307                                        return Err(format_err_spanned!(
308                                            attr.args().next().unwrap().ast,
309                                            "dumplicated action name: {}", name.str()
310                                        ));
311                                    }
312
313                                    let length = method_item.sig.inputs.len();
314                                    for (i, arg) in method_item.sig.inputs.iter().enumerate() {
315                                        match arg {
316                                            syn::FnArg::Receiver(_) => {}
317                                            syn::FnArg::Typed(x) => {
318                                                if Self::is_binary_extension_type(&x.ty) {
319                                                    if i + 1 != length {
320                                                        return Err(format_err_spanned!(
321                                                            x,
322                                                            "BinaryExtension type can only appear at the last argument of a method",
323                                                        ));
324                                                    }
325                                                }
326                                                let (type_name, _) = Self::extract_type(&x.ty)?;
327                                                arg_types.insert(type_name.clone(), type_name);
328                                            }
329                                        }
330                                    };
331
332                                    self.actions.push(
333                                        Action{
334                                            item: method_item.clone(),
335                                            is_notify: attr.is_notify(),
336                                            action_name: name,
337                                        }
338                                    )
339                                }
340                            }
341                            _ => {
342                                // contract.others.push(item.clone());
343                            }
344                        }
345                    }
346                }
347
348                syn::Item::Enum(x) => {
349                    let (chain_attrs, other_attrs) = attrs::partition_attributes(x.attrs.clone())?;
350                    if chain_attrs.len() == 0 {
351                        continue;
352                    }
353
354                    if chain_attrs.len() > 1 {
355                        return Err(format_err_spanned!(
356                            x,
357                            "more than one chain attribute specified to struct {}", x.ident
358                        ));
359                    }
360
361                    let attr = &chain_attrs[0];
362                    if attr.args().len() < 1 {
363                        return Err(format_err_spanned!(
364                            x,
365                            "wrong chain attribute in {}", x.ident
366                        ));
367                    }
368
369                    x.attrs = other_attrs;
370                    let arg = &attr.args().next().unwrap().arg;
371                    if attrs::AttributeArg::Variant == *arg {
372                        Self::verify_variant(x)?;
373                        self.variants.push(x.clone());
374                    } else {
375                        return Err(format_err_spanned!(
376                            x,
377                            "only variant attribute is supported by contract"
378                        ));
379                    }
380                }
381                _ => {}
382            }
383        };
384
385        for (ty, _) in arg_types {
386            self.add_packer(&ty)?;
387        }
388        return Ok(())
389        
390    }
391    
392    fn is_primitive_type(name: &str) -> bool {
393        match name {
394            "bool" | "i8" | "u8" | "i16" | "u16" | "i32" | "u32" | "i64" | "u64" | "f32" | "f64" | "i128" | "u128" |
395            "String" |
396            "Varint32" | "VarUint32" | "Float128" | "TimePoint" | "TimePointSec" |
397            "BlockTimeStampType" | "Name" | "Checksum160" | "Checksum256" | "Uint256" |
398            "Checksum512" | "PublicKey" | "Signature" | "Symbol" | "SymbolCode" | "Asset" |
399            "ExtendedAsset" => {
400                return true;
401            }
402            _ => {
403                return false;
404            }
405        }
406    }
407
408    pub fn get_type_name(field: &syn::Field) -> Result<String, syn::Error> {
409        if let syn::Type::Path(type_path) = &field.ty {
410            if type_path.path.segments.len() != 1 {
411                return Err(format_err_spanned!(
412                    field,
413                    "type with multiple segments does not support by contract!"
414                ));
415            }
416            let path_seg = type_path.path.segments.last().unwrap();
417            return Ok(path_seg.ident.to_string());
418        } else {
419            return Err(format_err_spanned!(
420                field,
421                "Invalid contract type!"
422            ));
423        }
424    }
425
426    pub fn add_packer(&mut self, name: &str) -> Result<(), syn::Error> {
427        if Self::is_primitive_type(name) {
428            return Ok(());
429        }
430
431        let mut names: HashMap<String, bool> = HashMap::new();
432        for item in &self.items {
433            match item {
434                syn::Item::Struct(x) => {
435                    if x.ident.to_string() != name {
436                        continue;
437                    }
438                    if !self.packers.iter().any(|packer| {
439                        x.ident == packer.ident
440                    }) {
441                        self.packers.push(x.clone());
442                    }
443
444                    let length = x.fields.len();
445                    for (i, field) in x.fields.iter().enumerate() {
446                        if Self::is_binary_extension_type(&field.ty) {
447                            if i + 1 != length {
448                                return Err(format_err_spanned!(
449                                    field,
450                                    "BinaryExtension type can only appear at the last field of a struct",
451                                ));
452                            }
453                        }
454                    }
455
456                    for field in &x.fields {
457                        let name = Self::get_type_name(field)?;
458                        names.insert(name, true);
459                    }
460                    break;
461                }
462                syn::Item::Enum(x) => {
463                    if x.ident.to_string() != name {
464                        continue;
465                    }
466                    if !self.variants.iter().any(|v| {
467                        v.ident == x.ident
468                    }) {
469                        self.variants.push(x.clone());
470                    }
471                    for v in &x.variants {
472                        match &v.fields {
473                            syn::Fields::Unnamed(x) => {
474                                if x.unnamed.len() != 1 {
475                                    return Err(format_err_spanned!(
476                                        x,
477                                        "multiple fields in variant does not support by contract!"
478                                    ));
479                                }
480                                let field = x.unnamed.last().unwrap();
481                                let name = Self::get_type_name(field)?;
482                                names.insert(name, true);
483                            }
484                            _ => {
485                                return Err(format_err_spanned!(
486                                    v.fields,
487                                    "invalid variant field"
488                                ));
489                            }
490                        }
491                    }
492                    break;
493                }
494                _ => {}
495            }
496        }
497
498        for (name, _) in &names {
499            self.add_packer(name)?;
500        }
501        Ok(())
502    }
503
504    fn generate_code_for_packers(&self) -> TokenStream2 {
505        let packers_code = self.packers.iter().map(move |packer| {
506            let span = packer.span();
507            let ident = &packer.ident;
508            // let (_, other_attrs) = attrs::partition_attributes(packer.attrs.clone()).unwrap();
509
510            let serialize = packer.fields.iter().map(|packer_field| {
511                let span = packer_field.span();
512                let ident = &packer_field.ident;
513                quote_spanned!(span=>
514                    self.#ident.pack(enc);
515                )
516            });
517
518            let deserialize = packer.fields.iter().map(|packer_field| {
519                let span = packer_field.span();
520                let ident = &packer_field.ident;
521                let ty = &packer_field.ty;
522                quote_spanned!(span=>
523                    dec.unpack::<#ty>(&mut self.#ident);
524                )
525            });
526
527            let get_size = packer.fields.iter().map(|packer_field| {
528                let span = packer_field.span();
529                let ident = &packer_field.ident;
530                quote_spanned!(span=>
531                    _size += self.#ident.size();
532                )
533            });
534
535            let packed = quote_spanned!(span =>
536                impl ::rust_chain::serializer::Packer for #ident {
537                    fn size(&self) -> usize {
538                        let mut _size: usize = 0;
539                        #( #get_size )*
540                        return _size;
541                    }
542                
543                    fn pack(&self, enc: &mut Encoder) -> usize {
544                        let pos = enc.get_size();
545                        #( #serialize )*
546                        enc.get_size() - pos
547                    }
548                
549                    fn unpack(&mut self, data: &[u8]) -> usize {
550                        let mut dec = ::rust_chain::serializer::Decoder::new(data);
551                        #( #deserialize )*
552                        return dec.get_pos();
553                    }
554                }
555            );
556            quote_spanned!(span =>
557                #packed
558            )
559        });
560        quote! {
561            #( #packers_code )*
562        }
563    }
564
565    fn generate_action_structs(&self) -> TokenStream2 {
566        let action_structs_code = self.actions.iter().map(|action|{
567            let item = &action.item;
568            let span = item.span();
569            // let ident = &item.sig.ident;
570            let struct_name = action.action_name.str();
571            let struct_name_ident = proc_macro2::Ident::new(&struct_name, proc_macro2::Span::call_site());
572
573            let fields = item.sig.inputs.iter().filter(|arg| {
574                if let syn::FnArg::Typed(_) = arg {
575                    true
576                } else {
577                    false
578                }
579            }).map(|item|{
580                if let syn::FnArg::Typed(tp) = item {
581                    quote!{
582                        pub #tp
583                    }
584                } else {
585                    quote!{}
586                }
587            });
588
589            let serialize = item.sig.inputs.iter().map(|arg| {
590                if let syn::FnArg::Typed(pat_type) = arg {
591                    let span = arg.span();
592                    // let ty = &*pat_type.ty;
593                    if let syn::Pat::Ident(x) = &*pat_type.pat {
594                        quote_spanned!(span=>
595                            self.#x.pack(enc);
596                        )
597                    } else {
598                        quote!{}
599                    }
600                } else {
601                    quote!{}
602                }
603            });
604
605            let deserialize = item.sig.inputs.iter().map(|arg| {
606                if let syn::FnArg::Typed(pat_type) = arg {
607                    let span = arg.span();
608                    let ty = &*pat_type.ty;
609                    if let syn::Pat::Ident(x) = &*pat_type.pat {
610                        quote_spanned!(span=>
611                            dec.unpack::<#ty>(&mut self.#x);
612                        )
613                    } else {
614                        quote!{}
615                    }
616                } else {
617                    quote!{}
618                }
619            });
620
621            let get_size = item.sig.inputs.iter().map(|arg| {
622                if let syn::FnArg::Typed(pat_type) = arg {
623                    let span = arg.span();
624                    // let ty = &*pat_type.ty;
625                    if let syn::Pat::Ident(x) = &*pat_type.pat {
626                        quote_spanned!(span=>
627                            _size += self.#x.size();
628                        )
629                    } else {
630                        quote!{}
631                    }
632                } else {
633                    quote!{}
634                }
635            });
636
637            let error_name = struct_name_ident.to_string() + ".unpack: buffer overflow";
638            let error_lit = proc_macro2::Literal::string(&error_name);
639
640            let packed = quote_spanned!(span =>
641                impl ::rust_chain::serializer::Packer for #struct_name_ident {
642                    fn size(&self) -> usize {
643                        #[allow(unused_mut)]
644                        let mut _size: usize = 0;
645                        #( #get_size )*
646                        return _size;
647                    }
648
649                    fn pack(&self, enc: &mut Encoder) -> usize {
650                        let pos = enc.get_size();
651                        #( #serialize )*
652                        enc.get_size() - pos
653                    }
654
655                    fn unpack<'a>(&mut self, data: &'a [u8]) -> usize {
656                        rust_chain::check(data.len() >= self.size(), #error_lit);
657                        #[allow(unused_mut)]
658                        let mut dec = ::rust_chain::serializer::Decoder::new(data);
659                        #( #deserialize )*
660                        return dec.get_pos();
661                    }
662                }
663            );
664
665            quote! {
666                #[cfg_attr(feature = "std", derive(::rust_chain::eosio_scale_info::TypeInfo))]
667                #[cfg_attr(feature = "std", scale_info(crate = ::rust_chain::eosio_scale_info))]
668                #[derive(Default)]
669                pub struct #struct_name_ident {
670                    # ( #fields ), *
671                }
672                #packed
673            }
674        });
675        quote!{
676            #( #action_structs_code ) *
677        }
678    }
679
680    fn generate_tables_code(&self) -> Result<TokenStream2, syn::Error> {
681        let mut action_structs_code: Vec<TokenStream2> = Vec::new();
682        for table in &self.tables {
683            let item = &table.item;
684            let span = item.span();
685            let table_ident = &item.ident;
686            let mut primary_impl: Option<TokenStream2> = None;
687
688            for field in &item.fields {
689                let (chain_attrs, _) = attrs::partition_attributes(field.attrs.clone())?;
690                if chain_attrs.len() == 0 {
691                    continue;
692                }
693                let field_ident = field.ident.as_ref().expect(&format!("invalid field in {}", table_ident).to_string());
694                let attr = &chain_attrs[0];
695                
696                if attr.args().len() == 0 {
697                    return Err(format_err_spanned!(
698                        field,
699                        "no chain attribute specified for {}", field.ident.as_ref().unwrap(),
700                    ));
701                }
702
703                let first_attr = attr.args().next().unwrap();
704                match first_attr.arg {
705                    attrs::AttributeArg::Primary => {
706                        if primary_impl.is_some() {
707                            return Err(format_err_spanned!(
708                                field,
709                                "more than one primary field specified in {}", item.ident
710                            ));
711                        }
712
713                        primary_impl = Some(quote_spanned!(span =>
714                            impl ::rust_chain::db::PrimaryValueInterface for #table_ident {
715                                fn get_primary(&self) -> u64 {
716                                    return self.#field_ident.get_primary();
717                                }
718                            }
719                        ))
720                    }
721                    _ => {}
722                }
723            };
724
725            if table.singleton {
726                if primary_impl.is_some() {
727                    return Err(format_err_spanned!(
728                        item,
729                        "singelton table does not need a primary attribute in struct {}", item.ident
730                    ));
731                }
732            } else {
733                if primary_impl.is_none() {
734                    return Err(format_err_spanned!(
735                        item,
736                        "primary index does not specified in struct {}", item.ident
737                    ));
738                }
739            }
740
741            let mut secondary_fields: Vec<(attrs::AttributeArg, syn::Field)> = Vec::new();
742
743            for field in &item.fields {
744                let (chain_attrs, _) = attrs::partition_attributes(field.attrs.clone())?;
745                if chain_attrs.len() == 0 {
746                    continue;
747                }
748
749                let attr = &chain_attrs[0];
750                if attr.args().len() == 0 {
751                    return Err(format_err_spanned!(
752                        field,
753                        "no chain attribute specified",
754                    ));
755                }
756
757                let first_attr = attr.args().next().unwrap();
758                match first_attr.arg {
759                    attrs::AttributeArg::Primary => {},
760                    attrs::AttributeArg::Secondary => {
761                        if !Self::is_secondary_type(&field.ty) {
762                            return Err(format_err_spanned!(
763                                first_attr.ast,
764                                "invalid secondary type, only  \"u64\", \"u128\", \"Uint256\", \"f64\" or \"Float128\" supported"
765                            ));
766                        }
767                        secondary_fields.push((first_attr.arg.clone(), field.clone()));
768                    }
769                    _ => {
770                        return Err(format_err_spanned!(
771                            first_attr.ast,
772                            "invalid attribute argument"
773                        ));
774                    }
775                }
776            };
777
778            let secondary_impls;
779            if !self.has_secondary_value_interface_trait(&item.ident.to_string()) {
780                let secondary_getter_impls = secondary_fields.iter()
781                .enumerate()
782                .map(|(index, (_, field))|{
783                    let field_ident = field.ident.as_ref().unwrap();
784                    return quote! {
785                        if i == #index {
786                            return self.#field_ident.into();
787                        }
788                    }
789                });
790    
791                let secondary_setter_impls = secondary_fields.iter()
792                .enumerate()
793                .map(|(index, (_attr_arg, field))|{
794                    let field_ident = field.ident.as_ref().unwrap();
795                    return quote!{
796                        if i == #index {
797                            self.#field_ident = value.into();
798                        }
799                    }
800                });
801    
802                secondary_impls = quote_spanned!(span =>
803                    impl ::rust_chain::db::SecondaryValueInterface for #table_ident {
804                        #[allow(unused_variables, unused_mut)]
805                        fn get_secondary_value(&self, i: usize) -> rust_chain::db::SecondaryValue {
806                            #( #secondary_getter_impls )*
807                            return rust_chain::db::SecondaryValue::None;
808                        }
809        
810                        #[allow(unused_variables, unused_mut)]
811                        fn set_secondary_value(&mut self, i: usize, value: rust_chain::db::SecondaryValue) {
812                            #( #secondary_setter_impls )*
813                        }
814                    }
815                );
816            } else {
817                secondary_impls = quote!{};
818            }
819
820            let mi_impls = self.generate_mi_impls(table, &secondary_fields);
821
822            if !table.singleton {
823                if self.has_primary_value_interface_trait(&item.ident.to_string()) {
824                    primary_impl = None;
825                }
826
827                action_structs_code.push(quote_spanned!(span =>
828                    #primary_impl
829                    #secondary_impls
830                    #mi_impls
831                ));
832            } else {
833                let table_name = proc_macro2::Literal::string(&table.table_name.str());
834                action_structs_code.push(quote_spanned!(span =>
835                    impl ::rust_chain::db::PrimaryValueInterface for #table_ident {
836                        fn get_primary(&self) -> u64 {
837                            return rust_chain::name!(#table_name).value();
838                        }
839                    }
840
841                    #secondary_impls
842                    #mi_impls
843                ));
844            }
845        };
846
847        return Ok(quote!{
848            #( #action_structs_code ) *
849        });
850    }
851
852    fn generate_mi_impls(&self, table: &Table, secondary_fields: &Vec<(attrs::AttributeArg, syn::Field)>) -> TokenStream2 {
853        let table_name = table.table_name.str();
854
855        let span = table.item.span();
856        let table_ident = &table.item.ident;
857
858
859        let len_secondary = secondary_fields.len();
860
861        let secondary_types = secondary_fields
862            .iter()
863            .map(|(_, field)| {
864                let secondary_type_name = Self::to_secondary_type(&field.ty);
865                match secondary_type_name {
866                    Some("Idx64") => {
867                        return quote! {
868                            rust_chain::db::SecondaryType::Idx64
869                        }
870                    }
871                    Some("Idx128") => {
872                        return quote! {
873                            rust_chain::db::SecondaryType::Idx128
874                        }
875                    }
876                    Some("Idx256") => {
877                        return quote! {
878                            rust_chain::db::SecondaryType::Idx256
879                        }
880                    }
881                    Some("IdxF64") => {
882                        return quote! {
883                            rust_chain::db::SecondaryType::IdxF64
884                        }
885                    }
886                    Some("IdxF128") => {
887                        return quote! {
888                            rust_chain::db::SecondaryType::IdxF128
889                        }
890                    }
891                    _ => {
892                        quote!{}
893                    }
894                }
895            });
896
897            let get_idx_db_funcs = secondary_fields
898                .iter()
899                .enumerate()
900                .map(|(i, (_, field))| {
901                    let idx_type: usize;
902                    let secondary_type = Self::to_secondary_type(&field.ty);
903                    match secondary_type {
904                        Some("Idx64") => { idx_type = 0; }
905                        Some("Idx128") => { idx_type = 1; }
906                        Some("Idx256") => { idx_type = 2; }
907                        Some("IdxF64") => { idx_type = 3; }
908                        Some("IdxF128") => { idx_type = 4; }
909                        _ => {
910                            return quote!()
911                        }
912                    }
913
914                    match secondary_type {
915                        Some("Idx64") | Some("Idx128") | Some("Idx256") | Some("IdxF64") | Some("IdxF128") => {
916                            let span = field.span();
917                            let ty = &field.ty;
918                            let get_idx_method_name = String::from("get_idx_by_") + &field.ident.as_ref().unwrap().to_string();
919                            let get_idx_method_ident = syn::Ident::new(&get_idx_method_name, span);
920
921                            let update_idx_method_name = String::from("update_") + &field.ident.as_ref().unwrap().to_string();
922                            let update_idx_method_ident = syn::Ident::new(&update_idx_method_name, span);
923
924                            let error_message = String::from("invalid db index on update: ") + &field.ident.as_ref().unwrap().to_string();
925
926                            return quote_spanned!(span =>
927                                #[allow(dead_code)]
928                                fn #get_idx_method_ident(&self) -> ::rust_chain::db::IdxTableProxy<#ty, #idx_type> {
929                                    return ::rust_chain::db::IdxTableProxy::<#ty, #idx_type>::new(self.mi.get_idx_db(#i));
930                                }
931
932                                #[allow(dead_code)]
933                                fn #update_idx_method_ident(&self, it: &::rust_chain::db::SecondaryIterator, value: #ty, payer: rust_chain::Name) {
934                                    rust_chain::check(it.db_index == #i, #error_message);
935                                    self.mi.idx_update(it, value.into(), payer);
936                                }
937                            )
938                        }
939                        _ => return quote!(),
940                    };
941                });
942
943            let mi_name = table_ident.to_string() + "MultiIndex";
944            let mi_ident = syn::Ident::new(&mi_name, span);
945            if table.singleton {
946                return quote_spanned!(span =>
947                    pub struct #mi_ident {
948                        mi: ::rust_chain::mi::MultiIndex<#table_ident>
949                    }
950                
951                    #[allow(dead_code)]
952                    impl #mi_ident {
953                        ///
954                        pub fn new(code: rust_chain::Name, scope: rust_chain::Name, table: rust_chain::Name) -> Self {
955                            Self {
956                                mi: ::rust_chain::mi::MultiIndex::<#table_ident>::new(code, scope, table, &[rust_chain::db::SecondaryType::Idx64; 0]),
957                            }
958                        }
959
960                        pub fn new_table(code: rust_chain::Name, scope: rust_chain::Name, table: rust_chain::Name) -> Self {
961                            Self {
962                                mi: ::rust_chain::mi::MultiIndex::<#table_ident>::new(code, scope, table, &[rust_chain::db::SecondaryType::Idx64; 0]),
963                            }
964                        }
965
966                        fn get(&self) -> Option<#table_ident> {
967                            let it = self.mi.find(rust_chain::Name::new(#table_name).value());
968                            return self.mi.get(&it);
969                        }
970
971                        fn set(&self, value: &#table_ident, payer: rust_chain::Name) {
972                            let it = self.mi.find(rust_chain::Name::new(#table_name).value());
973                            if it.is_ok() {
974                                self.mi.update(&it, value, payer);
975                            } else {
976                                self.mi.store(value, payer);
977                            }
978                        }
979                    }
980
981                    impl #table_ident {
982                        #[allow(dead_code)]
983                        fn new_table_with_scope(code: rust_chain::Name, scope: rust_chain::Name) -> Box<#mi_ident> {
984                            return Box::new(#mi_ident::new(code, scope, rust_chain::Name::new(#table_name)));
985                        }
986
987                        #[allow(dead_code)]
988                        fn new_table(code: rust_chain::Name) -> Box<#mi_ident> {
989                            #table_ident::new_table_with_scope(code, rust_chain::Name{n: 0})
990                        }
991                    }
992                );
993            }
994    
995            return quote_spanned!(span =>
996
997                pub struct #mi_ident {
998                    mi: ::rust_chain::mi::MultiIndex<#table_ident>
999                }
1000            
1001                #[allow(dead_code)]
1002                impl #mi_ident {
1003
1004                    pub fn new(code: rust_chain::Name, scope: rust_chain::Name, table: rust_chain::Name, indices: &[rust_chain::db::SecondaryType]) -> Self {
1005                        Self {
1006                            mi: ::rust_chain::mi::MultiIndex::<#table_ident>::new(code, scope, table, indices),
1007                        }
1008                    }
1009
1010                    pub fn store(&self, value: &#table_ident, payer: rust_chain::Name) -> ::rust_chain::db::Iterator<#table_ident> {
1011                        return self.mi.store(value, payer);
1012                    }
1013                
1014                    pub fn update(&self, iterator: &::rust_chain::db::Iterator<#table_ident>, value: &#table_ident, payer: rust_chain::Name) {
1015                        return self.mi.update(iterator, value, payer);
1016                    }
1017                
1018                    pub fn remove(&self, iterator: &::rust_chain::db::Iterator<#table_ident>) {
1019                        return self.mi.remove(iterator);
1020                    }
1021                
1022                    pub fn get(&self, iterator: &::rust_chain::db::Iterator<#table_ident>) -> Option<#table_ident> {
1023                        return self.mi.get(iterator)
1024                    }
1025                
1026                    pub fn get_by_primary(&self, primary: u64) -> Option<#table_ident> {
1027                        return self.mi.get_by_primary(primary);
1028                    }
1029
1030                    pub fn next(&self, iterator: &::rust_chain::db::Iterator<#table_ident>) -> ::rust_chain::db::Iterator<#table_ident> {
1031                        return self.mi.next(iterator);
1032                    }
1033
1034                    pub fn previous(&self, iterator: &::rust_chain::db::Iterator<#table_ident>) -> ::rust_chain::db::Iterator<#table_ident> {
1035                        return self.mi.previous(iterator);
1036                    }
1037
1038                    pub fn find(&self, id: u64) -> ::rust_chain::db::Iterator<#table_ident> {
1039                        return self.mi.find(id);
1040                    }
1041                
1042                    pub fn lower_bound(&self, id: u64) -> ::rust_chain::db::Iterator<#table_ident> {
1043                        return self.mi.lower_bound(id);
1044                    }
1045                
1046                    pub fn upper_bound(&self, id: u64) -> ::rust_chain::db::Iterator<#table_ident> {
1047                        return self.mi.upper_bound(id);
1048                    }
1049                
1050                    pub fn end(&self) -> ::rust_chain::db::Iterator<#table_ident> {
1051                        return self.mi.end();
1052                    }
1053                
1054                    pub fn get_idx_db(&self, i: usize) -> &dyn ::rust_chain::db::IdxTable {
1055                        return self.mi.get_idx_db(i);
1056                    }
1057                
1058                    pub fn idx_update(&self, it: &::rust_chain::db::SecondaryIterator, value: ::rust_chain::db::SecondaryValue, payer: rust_chain::Name) {
1059                        self.mi.idx_update(it, value, payer);
1060                    }
1061
1062                    #( #get_idx_db_funcs )*
1063                }
1064
1065                impl #table_ident {
1066                    #[allow(dead_code)]
1067                    fn new_table_with_scope(code: rust_chain::Name, scope: rust_chain::Name) -> Box<#mi_ident> {
1068                        let indices: [rust_chain::db::SecondaryType; #len_secondary] = [#( #secondary_types ),*];
1069                        return Box::new(#mi_ident::new(code, scope, rust_chain::Name::new(#table_name), &indices));
1070                    }
1071
1072                    #[allow(dead_code)]
1073                    fn new_table(code: rust_chain::Name) -> Box<#mi_ident> {
1074                        #table_ident::new_table_with_scope(code, rust_chain::Name{n: 0})
1075                    }
1076                }
1077            );
1078    }
1079
1080    fn generate_action_handle_code(&self, notify: bool) -> TokenStream2 {
1081        let actions = self.actions.iter().filter(|action|{
1082            if notify {
1083                if action.is_notify {
1084                    return true;
1085                }
1086                return false;
1087            } else {
1088                if !action.is_notify {
1089                    return true;
1090                }
1091                return false;
1092            }
1093        });
1094
1095        let action_structs_code = actions.map(|action|{
1096            let item = &action.item;
1097            let ident = &item.sig.ident;
1098            let struct_name = action.action_name.str();
1099            let struct_name_ident = proc_macro2::Ident::new(&struct_name, proc_macro2::Span::call_site());
1100            let action_name_n = proc_macro2::Literal::u64_suffixed(s2n(&action.action_name.str()));
1101
1102            let args = item.sig.inputs.iter().filter(|arg|{
1103                if let syn::FnArg::Typed(_) = arg {
1104                    return true;
1105                }
1106                return false;
1107            });
1108
1109            let args = args.map(|arg| {
1110                if let syn::FnArg::Typed(pat_type) = arg {
1111                    let span = arg.span();
1112                    if let syn::Pat::Ident(x) = &*pat_type.pat {
1113                        quote_spanned!(span=>
1114                            action.#x
1115                        )
1116                    } else {
1117                        quote!{}
1118                    }
1119                } else {
1120                    quote!{}
1121                }
1122            });
1123
1124            quote! {
1125                #action_name_n => {
1126                    let mut action: #struct_name_ident = Default::default();
1127                    action.unpack(&::rust_chain::vmapi::eosio::read_action_data());
1128                    contract.#ident(#( #args ),*);
1129                }
1130            }
1131        });
1132        quote! {
1133            #( #action_structs_code ) *
1134        }
1135    }
1136
1137    #[allow(dead_code)]
1138    fn is_option_type(ty: &syn::Type) -> bool {
1139        if let syn::Type::Path(type_path) = ty {
1140            if type_path.path.segments.len() != 1 {
1141                return false;
1142            }
1143
1144            let path_seg = &type_path.path.segments[0];
1145            let name = path_seg.ident.to_string();
1146            if name == "Option" {
1147                return true;
1148            } else {
1149                return false;
1150            }
1151        }
1152        return false;
1153    }
1154
1155    fn extract_type(ty: &syn::Type) -> Result<(String, &syn::Type), syn::Error> {
1156        if let syn::Type::Path(type_path) = ty {
1157            if type_path.path.segments.len() != 1 {
1158                return Err(format_err_spanned!(
1159                    ty,
1160                    "can not parse type with multiple segments",
1161                ))
1162            }
1163
1164            let path_seg = &type_path.path.segments[0];
1165            let name = path_seg.ident.to_string();
1166            if name == "Option" || name == "Vec" || name == "BinaryExtension" {
1167                if let syn::PathArguments::AngleBracketed(x) = &path_seg.arguments {
1168                    if x.args.len() != 1 {
1169                        return Err(format_err_spanned!(
1170                            x,
1171                            "can not parse option type with multiple arguments",
1172                        ))      
1173                    }
1174
1175                    let arg = &x.args[0];
1176                    if let syn::GenericArgument::Type(ty) = arg {
1177                        if let syn::Type::Path(type_path) = ty {
1178                            if type_path.path.segments.len() != 1 {
1179                                return Err(format_err_spanned!(
1180                                    type_path,
1181                                    "can not parse type in option with multiple segments",
1182                                ))
1183                            }
1184                            let name = type_path.path.segments.last().unwrap().ident.to_string();
1185                            return Ok((name, ty));
1186                        }
1187                    }
1188                }
1189            } else {
1190                return Ok((name, ty));
1191            }
1192        }
1193
1194        Err(format_err_spanned!(
1195            ty,
1196            "unsupported type",
1197        ))
1198    }
1199
1200    fn is_binary_extension_type(ty: &syn::Type) -> bool {
1201        if let syn::Type::Path(type_path) = ty {
1202            if type_path.path.segments.len() != 1 {
1203                false;
1204            }
1205
1206            let path_seg = &type_path.path.segments[0];
1207            let name = path_seg.ident.to_string();
1208            if name == "BinaryExtension" {
1209                return true;
1210            } else {
1211                return false;
1212            }
1213        }
1214        return false;
1215    }
1216
1217    fn is_secondary_type(ty: &syn::Type) -> bool {
1218        if let syn::Type::Path(type_path) = ty {
1219            if type_path.path.segments.len() != 1 {
1220                return false;
1221            }
1222
1223            let path_seg = &type_path.path.segments[0];
1224            let name = path_seg.ident.to_string();
1225            if name == "u64" || name == "u128" || name == "Uint256" || name == "f64" || name == "Float128" {
1226                return true;
1227            } else {
1228                return false;
1229            }
1230        }
1231        return false;
1232    }
1233
1234    fn to_secondary_type(ty: &syn::Type) -> Option<&'static str> {
1235        if let syn::Type::Path(type_path) = ty {
1236            if type_path.path.segments.len() != 1 {
1237                return None;
1238            }
1239
1240            let path_seg = &type_path.path.segments[0];
1241            let name = path_seg.ident.to_string();
1242            if name == "u64" {
1243                return Some("Idx64");
1244            }  else if name == "u128" {
1245                return Some("Idx128");
1246            } else if name == "Uint256" {
1247                return Some("Idx256");
1248            } else if name == "f64" {
1249                return Some("IdxF64");
1250            } else if name == "Float128" {
1251                return Some("IdxF128");
1252            } else {
1253                return None;
1254            }
1255        }
1256        return None;
1257    }
1258
1259    fn add_abi_type<'a>(&'a self, tp_name: &str, abi_types: &mut HashMap<String, &'a syn::Type>) -> Result<(), syn::Error> {
1260        if Self::is_primitive_type(tp_name) {
1261            return Ok(());
1262        }
1263
1264        let mut ty_names: Vec<String> = Vec::new();
1265        for item in &self.items {
1266            match item {
1267                syn::Item::Struct(x) => {
1268                    if x.ident.to_string() != tp_name {
1269                        continue;
1270                    }
1271                    for field in &x.fields {
1272                        let (type_name, ty) = Self::extract_type(&field.ty)?;
1273                        if Self::is_primitive_type(&type_name) {
1274                            continue;
1275                        }
1276                        if abi_types.insert(type_name.clone(), ty).is_none() {
1277                            ty_names.push(type_name);
1278                        }
1279                    }
1280                    break;
1281                }
1282                syn::Item::Enum(x) => {
1283                    if x.ident.to_string() != tp_name {
1284                        continue;
1285                    }
1286
1287                    for field in &x.variants {
1288                        // let field_ident = &field.ident;
1289                        if let syn::Fields::Unnamed(unnamed_fields) = &field.fields {
1290                            let unnamed_field = unnamed_fields.unnamed.last().unwrap();
1291                            let (type_name, _) = Self::extract_type(&unnamed_field.ty)?;
1292                            if Self::is_primitive_type(&type_name) {
1293                                continue;
1294                            }
1295                            if abi_types.insert(type_name.clone(), &unnamed_field.ty).is_none() {
1296                                ty_names.push(type_name);
1297                            }
1298                        }
1299                        //DODO: return error
1300                    };
1301                    break;
1302                }
1303                _ => {}
1304            }
1305        }
1306
1307        for name in &ty_names {
1308            self.add_abi_type(name, abi_types)?;
1309        }
1310        Ok(())
1311    }
1312
1313    fn gather_scale_info(&self) -> Result<TokenStream2, syn::Error> {
1314        let mut abi_types: HashMap<String, &syn::Type> = HashMap::new();
1315
1316        for action in &self.actions {
1317            let item = &action.item;
1318            // let span = item.span();
1319            for arg in item.sig.inputs.iter() {
1320                if let syn::FnArg::Typed(pat_type) = arg {
1321                    let (type_name, ty) = Self::extract_type(&pat_type.ty)?;
1322                    if Self::is_primitive_type(&type_name) {
1323                        continue;
1324                    }
1325                    abi_types.insert(type_name.clone(), ty);
1326                    self.add_abi_type(&type_name, &mut abi_types)?;
1327                }
1328            }
1329        }
1330
1331        for table in &self.tables {
1332            for field in &table.item.fields {
1333                let (type_name, tp) = Self::extract_type(&field.ty)?;
1334                if Self::is_primitive_type(&type_name) {
1335                    continue;
1336                }
1337                abi_types.insert(type_name.clone(), tp);
1338                self.add_abi_type(&type_name, &mut abi_types)?;
1339            }
1340        }
1341
1342        let mut structs_code: Vec<TokenStream2> = Vec::new();
1343        for (_, tp) in abi_types {
1344            structs_code.push(
1345                quote!{
1346                    info.structs.push(#tp::type_info());
1347                }
1348            );
1349        }
1350
1351        self.actions
1352            .iter()
1353            .for_each(|action| {
1354                let struct_name_ident = proc_macro2::Ident::new(&action.action_name.str(), proc_macro2::Span::call_site());
1355                structs_code.push(
1356                    quote!{
1357                        info.structs.push(#struct_name_ident::type_info());
1358                    }
1359                );
1360            });
1361
1362        self.tables
1363            .iter()
1364            .for_each(|table| {
1365                let struct_name_ident = &table.item.ident;
1366                structs_code.push(
1367                    quote!{
1368                        info.structs.push(#struct_name_ident::type_info());
1369                    }
1370                );
1371            });
1372
1373        let table_scale_info_code = self.tables
1374            .iter()
1375            .map(|table| {
1376                let ident = &table.item.ident;
1377                let table_name_lit = proc_macro2::Literal::string(&table.table_name.str());
1378                quote!{
1379                    info.tables.push(
1380                        ::rust_chain::abi::TableInfo {
1381                            name: String::from(#table_name_lit),
1382                            info: #ident::type_info(),
1383                        });
1384                }
1385            });
1386
1387        let action_scale_info_code = self.actions
1388            .iter()
1389            .map(|action| {
1390                // let ident = &action.item.sig.ident;
1391                let struct_name = action.action_name.str();
1392                let action_name_lit = proc_macro2::Literal::string(&action.action_name.str());
1393
1394                let struct_name_ident = proc_macro2::Ident::new(&struct_name, proc_macro2::Span::call_site());
1395                quote!{
1396                    info.actions.push(
1397                        ::rust_chain::abi::ActionInfo {
1398                            name: String::from(#action_name_lit),
1399                            info: #struct_name_ident::type_info(),
1400                        });
1401                }
1402            });
1403
1404
1405        return Ok(quote!{
1406            #[cfg(feature = "std")]
1407            pub fn generate_abi() -> String {
1408                let mut info = ::rust_chain::abi::ABIInfo {
1409                    actions: Vec::new(),
1410                    tables: Vec::new(),
1411                    structs: Vec::new(),
1412                    variants: Vec::new(),
1413                };
1414                #( #structs_code ) *
1415                #( #action_scale_info_code ) *
1416                #( #table_scale_info_code ) *
1417                return ::rust_chain::abi::parse_abi_info(&mut info);
1418            }
1419        });
1420    }
1421
1422    fn generate_apply_code(&self) -> TokenStream2 {
1423        if self.main_struct.is_none() && self.sub_struct.is_none() {
1424            return quote!{};
1425        }
1426
1427        let ident;
1428        if self.main_struct.is_some() {
1429            ident = &self.main_struct.as_ref().unwrap().ident;
1430        } else if self.sub_struct.is_some() {
1431            ident = &self.sub_struct.as_ref().unwrap().ident;
1432        } else {
1433            panic!("invalid ident");
1434        }
1435
1436        let entry_code = match self.main_struct {
1437            Some(_) => {
1438                quote!{
1439                    #[cfg(not(feature = "std"))]
1440                    #[no_mangle]
1441                    pub fn apply(receiver: u64, first_receiver: u64, action: u64) {
1442                        contract_apply(receiver, first_receiver, action);
1443                    }        
1444                }
1445            }
1446            None => {
1447                quote!{}
1448            }
1449        };
1450        
1451        let notify_handle_code = self.generate_action_handle_code(true);
1452        let action_handle_code = self.generate_action_handle_code(false);
1453        quote!{
1454            pub fn contract_apply(receiver: u64, first_receiver: u64, action: u64) {
1455                let _receiver = rust_chain::Name{n: receiver};
1456                let _first_receiver = rust_chain::Name{n: first_receiver};
1457                let _action = rust_chain::Name{n: action};
1458                #[allow(unused_mut)]
1459                let mut contract: #ident = #ident::new(_receiver, _first_receiver, _action);
1460                if receiver == first_receiver {
1461                    match action {
1462                        #action_handle_code
1463                        _ => {}
1464                    }
1465                }
1466
1467                if receiver != first_receiver {
1468                    match action {
1469                        #notify_handle_code
1470                        _ => {}
1471                    }
1472                }
1473            }
1474
1475
1476            #entry_code
1477
1478            #[cfg(feature = "std")]
1479            use rust_chain::chaintester::interfaces::TApplySyncClient;
1480
1481            #[cfg(feature = "std")]
1482            pub fn native_apply(receiver: u64, first_receiver: u64, action: u64) {
1483                contract_apply(receiver, first_receiver, action);
1484            }
1485        }
1486    }
1487
1488    fn generate_variants_code(&self) -> Result<TokenStream2, syn::Error> {
1489        //
1490        let variants_code = self.variants.iter().map(|item| {
1491            let first_field = &item.variants.iter().next().unwrap().ident;
1492            let span = item.span();
1493            let variant_ident = &item.ident;
1494            let pack_code = item.variants
1495                .iter()
1496                .enumerate()
1497                .map(|(i, field)| {
1498                    let field_ident = &field.ident;
1499        
1500                    let index = syn::LitInt::new(&i.to_string(), proc_macro2::Span::call_site());
1501                    if let syn::Fields::Unnamed(_) = &field.fields {
1502                        // let ty = &x.unnamed.last().unwrap().ty;
1503                        return quote!{
1504                            #variant_ident::#field_ident(x) => {
1505                                let mut i: u8 = #index as u8;
1506                                i.pack(enc);
1507                                x.pack(enc);
1508                            }
1509                        }
1510                    } else {
1511                        quote!{}
1512                    }
1513            });
1514
1515            let unpack_code = item.variants
1516                .iter()
1517                .enumerate()
1518                .map(|(i,field)| {
1519                    let field_ident = &field.ident;
1520                    let index = syn::LitInt::new(&i.to_string(), proc_macro2::Span::call_site());
1521                    if let syn::Fields::Unnamed(x) = &field.fields {
1522                        let ty = &x.unnamed.last().unwrap().ty;
1523                        quote!{
1524                            #index => {
1525                                let mut v: #ty = Default::default();
1526                                dec.unpack(&mut v);
1527                                *self = #variant_ident::#field_ident(v);
1528                            }
1529                        }
1530                    } else {
1531                        quote!{}
1532                    }
1533            });
1534
1535            let getsize_code = item.variants
1536                .iter()
1537                .map(|field| {
1538                    let field_ident = &field.ident;
1539                    // let index = syn::LitInt::new(&i.to_string(), proc_macro2::Span::call_site());
1540                    quote!{
1541                        #variant_ident::#field_ident(x) => {
1542                            _size = 1 + x.size();
1543                        }
1544                    }
1545            });
1546
1547            quote_spanned!(span =>
1548                impl Default for #variant_ident {
1549                    ///
1550                    #[inline]
1551                    fn default() -> Self {
1552                        #variant_ident::#first_field(Default::default())
1553                    }
1554                }
1555
1556                impl ::rust_chain::serializer::Packer for #variant_ident {
1557                    fn size(&self) -> usize {
1558                        let mut _size: usize = 0;
1559                        match self {
1560                            #( #getsize_code )*
1561                        }
1562                        return _size;
1563                    }
1564                
1565                    fn pack(&self, enc: &mut Encoder) -> usize {
1566                        let pos = enc.get_size();
1567
1568                        match self {
1569                            #( #pack_code )*
1570                        }
1571
1572                        enc.get_size() - pos
1573                    }
1574                
1575                    fn unpack<'a>(&mut self, data: &'a [u8]) -> usize {
1576                        let mut dec = ::rust_chain::serializer::Decoder::new(data);
1577                        let mut variant_type_index: u8 = 0;
1578                        dec.unpack(&mut variant_type_index);
1579                        match variant_type_index {
1580                            #( #unpack_code )*
1581                            _ => {
1582                                ::rust_chain::vmapi::eosio::eosio_assert(false, "bad variant index!");
1583                            }
1584                        }
1585                        return dec.get_pos();
1586                    }
1587                }
1588            )
1589        });
1590        Ok(
1591            quote!{
1592                #( #variants_code ) *
1593            }
1594        )
1595    }
1596
1597    pub fn generate_code(&self) -> Result<TokenStream2, syn::Error> {
1598        let action_structs_code = self.generate_action_structs();
1599        let tables_code = self.generate_tables_code()?;
1600        let apply_code;
1601        if !self.has_apply_func() {
1602            apply_code = self.generate_apply_code();
1603        } else {
1604            apply_code = quote!{};
1605        }
1606
1607        let packers_code = self.generate_code_for_packers();
1608        let variants_code = self.generate_variants_code()?;
1609        let scale_info: Option<TokenStream2>;
1610
1611        if self.has_main_struct() || self.has_sub_struct() {
1612            scale_info = Some(self.gather_scale_info()?);
1613        } else {
1614            scale_info  = None;
1615        }
1616
1617        let items = self.items.iter().map(|item|{
1618            match item {
1619                syn::Item::Struct(x) => {
1620                    if self.packers.iter().any(|packer|{
1621                        packer.ident == x.ident
1622                    }) {
1623                        quote!{
1624                            #[cfg_attr(feature = "std", derive(rust_chain::eosio_scale_info::TypeInfo))]
1625                            #[cfg_attr(feature = "std", scale_info(crate = ::rust_chain::eosio_scale_info))]
1626                            #[derive(Default)]
1627                            #item
1628                        }
1629                    } else {
1630                        quote!{
1631                            #item
1632                        }
1633                    }
1634                }
1635                syn::Item::Enum(x) => {
1636                    if self.variants.iter().any(|variant|{
1637                        variant.ident == x.ident
1638                    }) {
1639                        quote!{
1640                            #[cfg_attr(feature = "std", derive(rust_chain::eosio_scale_info::TypeInfo))]
1641                            #[cfg_attr(feature = "std", scale_info(crate = ::rust_chain::eosio_scale_info))]
1642                            #item
1643                        }
1644                    } else {
1645                        quote!{
1646                            #item
1647                        }
1648                    }
1649                }
1650                _ => {
1651                    quote!{
1652                        #item
1653                    }
1654                }
1655            }
1656        });
1657        let ident = &self.ident;
1658        let attrs = self.attrs();
1659        let vis = self.vis();
1660        Ok(quote! {
1661            #( #attrs )*
1662            #vis mod #ident {
1663                use rust_chain::{
1664                    vec,
1665                    vec::Vec,
1666                    boxed::Box,
1667                    string::String,
1668                };
1669
1670                use rust_chain::{
1671                    serializer::{
1672                        Packer as _,
1673                        Encoder,
1674                    },
1675                    db::SecondaryType as _,
1676                    print::Printable as _,
1677                };
1678
1679                #[cfg(feature = "std")]
1680                use rust_chain::eosio_scale_info::TypeInfo as _;
1681    
1682                #[cfg(feature = "std")]
1683                use rust_chain::eosio_scale_info;
1684
1685                #( #items ) *
1686                #packers_code
1687                #variants_code
1688                #action_structs_code
1689                #tables_code
1690                #apply_code
1691                #scale_info
1692            }
1693
1694            #[cfg(feature = "std")]
1695            pub fn generate_abi() -> String {
1696                #ident::generate_abi()
1697            }
1698        })
1699    }
1700
1701    pub fn get_items(self) -> Vec<syn::Item> {
1702        return self.items;
1703    }
1704
1705    pub fn is_action_impl_block(
1706        item_impl: &syn::ItemImpl,
1707    ) -> Result<bool, syn::Error> {
1708        // Quick check in order to efficiently bail out in case where there are
1709        // no attributes:
1710        if !attrs::contains_chain_attributes(&item_impl.attrs)
1711            && item_impl
1712                .items
1713                .iter()
1714                .all(|item| !attrs::contains_chain_attributes(item.attrs()))
1715        {
1716            return Ok(false)
1717        }
1718
1719        // Check if any of the implementation block's methods either resembles
1720        // an contract constructor or an contract message:
1721        'repeat: for item in &item_impl.items {
1722            match item {
1723                syn::ImplItem::Method(method_item) => {
1724                    if !attrs::contains_chain_attributes(&method_item.attrs) {
1725                        continue 'repeat
1726                    }
1727                    let attr = attrs::first_chain_attribute(&method_item.attrs)?
1728                        .expect("missing expected contract attribute for struct");
1729                    match attr.first().kind() {
1730                        attrs::AttributeArg::Action(_) => {
1731                            return Ok(true)
1732                        }
1733                        _ => continue 'repeat,
1734                    }
1735                }
1736                _ => continue 'repeat,
1737            }
1738        }
1739        Ok(false)
1740    }
1741}