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 };
12
13use proc_macro2::{
14 Ident,
15 };
17
18use crate::{
19 action::Action,
20 table::Table,
21 attrs,
22 name::{
24 s2n,
25 is_name_valid,
26 },
27 format_err_spanned,
28 attrs::Attrs as _,
29};
30
31#[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 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 pub fn attrs(&self) -> &[syn::Attribute] {
97 &self.attrs
98 }
99
100 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 }
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 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 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 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 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 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 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 };
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 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 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 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 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 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 #[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 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 '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}