polymesh_api_codegen/
generate.rs

1#![allow(deprecated)]
2use std::collections::{BTreeMap, BTreeSet};
3
4use heck::ToSnakeCase;
5
6use indexmap::IndexMap;
7
8use proc_macro2::{Ident, TokenStream};
9use quote::{format_ident, quote, TokenStreamExt};
10
11use codec::Decode;
12use frame_metadata::{RuntimeMetadata, RuntimeMetadataPrefixed};
13
14fn segments_ident(segments: &[String], import_types: bool) -> TokenStream {
15  let idents: Vec<_> = segments.into_iter().map(|s| format_ident!("{s}")).collect();
16  if import_types && idents.len() > 1 {
17    quote! {
18      types::#(#idents)::*
19    }
20  } else {
21    quote! {
22      #(#idents)::*
23    }
24  }
25}
26
27struct ModuleCode {
28  name: String,
29  sub_modules: BTreeMap<String, ModuleCode>,
30  types: BTreeMap<String, TokenStream>,
31}
32
33impl ModuleCode {
34  fn new(name: String) -> Self {
35    Self {
36      name,
37      sub_modules: BTreeMap::new(),
38      types: BTreeMap::new(),
39    }
40  }
41
42  fn add_type(&mut self, segments: &[String], ident: String, code: TokenStream) {
43    if let Some((mod_name, segments)) = segments.split_first() {
44      let entry = self.sub_modules.entry(mod_name.into());
45      let sub = entry.or_insert_with(|| ModuleCode::new(mod_name.into()));
46      sub.add_type(segments, ident, code);
47    } else if self.name.len() > 0 {
48      self.types.insert(ident, code);
49    }
50  }
51
52  fn gen(self) -> TokenStream {
53    let mut code = TokenStream::new();
54    for (name, sub) in self.sub_modules {
55      let ident = format_ident!("{name}");
56      let sub_code = sub.gen();
57      code.append_all(quote! {
58        pub mod #ident {
59          use super::*;
60          #sub_code
61        }
62      });
63    }
64    for (_, ty_code) in self.types {
65      code.append_all(ty_code);
66    }
67    code
68  }
69}
70
71#[cfg(feature = "v14")]
72mod v14 {
73  use super::*;
74  use frame_metadata::v14::{
75    RuntimeMetadataV14, StorageEntryMetadata, StorageEntryModifier, StorageEntryType, StorageHasher,
76  };
77  use scale_info::{form::PortableForm, Field, Path, Type, TypeDef, Variant};
78
79  #[derive(Default)]
80  struct TypeParameters {
81    names: IndexMap<u32, String>,
82    used: BTreeSet<String>,
83    need_bounds: BTreeMap<u32, BTreeMap<String, TokenStream>>,
84  }
85
86  impl TypeParameters {
87    fn new(ty: &Type<PortableForm>) -> Self {
88      let mut names = IndexMap::new();
89
90      let ty_params = ty.type_params();
91      if ty_params.len() > 0 {
92        for p in ty_params {
93          if let Some(p_ty) = p.ty() {
94            let name = p.name();
95            names.insert(p_ty.id(), name.into());
96          }
97        }
98      }
99
100      Self {
101        names,
102        used: Default::default(),
103        need_bounds: Default::default(),
104      }
105    }
106
107    fn add_param_bounds(&mut self, id: u32, bound_name: &str, type_bound: TokenStream) -> bool {
108      if self.names.contains_key(&id) {
109        let bounds = self.need_bounds.entry(id).or_default();
110        bounds.insert(bound_name.to_string(), type_bound);
111        true
112      } else {
113        false
114      }
115    }
116
117    fn get_param(&mut self, id: u32) -> Option<TokenStream> {
118      self.names.get(&id).map(|name| {
119        self.used.insert(name.to_string());
120        let name = format_ident!("{name}");
121        quote! { #name }
122      })
123    }
124
125    fn get_type_params(&self) -> TokenStream {
126      if self.names.len() > 0 {
127        let params = self.names.iter().map(|(id, name)| {
128          let ident = format_ident!("{name}");
129          if let Some(with_bounds) = self.need_bounds.get(&id) {
130            let bounds: Vec<_> = with_bounds.values().collect();
131            quote!(#ident: #(#bounds) + *)
132          } else {
133            quote!(#ident)
134          }
135        });
136        quote!(<#(#params),*>)
137      } else {
138        TokenStream::new()
139      }
140    }
141
142    fn get_unused_params(&self) -> Option<TokenStream> {
143      if self.used.len() < self.names.len() {
144        let params = self
145          .names
146          .values()
147          .filter(|name| !self.used.contains(*name))
148          .map(|name| {
149            let ident = format_ident!("{name}");
150            quote!(#ident)
151          })
152          .collect::<Vec<_>>();
153        // Return a tuple type with the unused params.
154        if params.len() > 1 {
155          Some(quote! { core::marker::PhantomData<(#(#params),*)> })
156        } else {
157          Some(quote! { core::marker::PhantomData<#(#params),*> })
158        }
159      } else {
160        None
161      }
162    }
163  }
164
165  struct Generator {
166    md: RuntimeMetadataV14,
167    external_modules: BTreeSet<String>,
168    pallet_types: BTreeMap<u32, (String, String)>,
169    max_error_size: usize,
170    rename_types: BTreeMap<String, TokenStream>,
171    remap_namespaces: BTreeMap<String, String>,
172    ord_types: BTreeSet<String>,
173    custom_derives: BTreeMap<String, TokenStream>,
174    runtime_namespace: Vec<String>,
175    call: TokenStream,
176    event: TokenStream,
177    v2_weights: bool,
178    dispatch_event_info: bool,
179    api_interface: TokenStream,
180  }
181
182  impl Generator {
183    fn new(md: RuntimeMetadataV14) -> Self {
184      // Detect the chain runtime path.
185      let runtime_ty = md.types.resolve(md.ty.id()).unwrap();
186      let runtime_namespace = runtime_ty.path().namespace();
187      #[cfg(feature = "ink")]
188      let api_interface = quote!(::polymesh_api_ink);
189      #[cfg(not(feature = "ink"))]
190      let api_interface = quote!(::polymesh_api_client);
191
192      let call = quote! { runtime::RuntimeCall };
193      let event = quote! { runtime::RuntimeEvent };
194      let external_modules = BTreeSet::from_iter(
195        ["sp_version", "sp_weights", "bounded_collections"]
196          .iter()
197          .map(|t| t.to_string()),
198      );
199      let rename_types = BTreeMap::from_iter(
200        [
201          (
202            "sp_core::crypto::AccountId32",
203            quote!(#api_interface::AccountId),
204          ),
205          (
206            "polymesh_primitives::identity_id::IdentityId",
207            quote!(#api_interface::IdentityId),
208          ),
209          (
210            "polymesh_primitives::asset::AssetId",
211            quote!(#api_interface::AssetId),
212          ),
213          (
214            "sp_runtime::multiaddress::MultiAddress",
215            quote!(#api_interface::MultiAddress),
216          ),
217          (
218            "sp_runtime::MultiSignature",
219            quote!(#api_interface::MultiSignature),
220          ),
221          #[cfg(not(feature = "ink"))]
222          ("sp_runtime::generic::era::Era", quote!(#api_interface::Era)),
223          (
224            "sp_arithmetic::per_things::Perbill",
225            quote!(#api_interface::per_things::Perbill),
226          ),
227          (
228            "sp_arithmetic::per_things::Permill",
229            quote!(#api_interface::per_things::Permill),
230          ),
231          (
232            "sp_arithmetic::per_things::PerU16",
233            quote!(#api_interface::per_things::PerU16),
234          ),
235          (
236            "sp_arithmetic::per_things::Percent",
237            quote!(#api_interface::per_things::Percent),
238          ),
239          ("BTreeSet", quote!(::alloc::collections::BTreeSet)),
240          ("BTreeMap", quote!(::alloc::collections::BTreeMap)),
241          ("String", quote!(::alloc::string::String)),
242          ("Vec", quote!(::alloc::vec::Vec)),
243          ("Cow", quote!(::alloc::borrow::Cow)),
244          (
245            "bounded_collections::bounded_btree_map::BoundedBTreeMap",
246            quote!(::alloc::collections::BTreeMap),
247          ),
248          (
249            "bounded_collections::bounded_btree_set::BoundedBTreeSet",
250            quote!(::alloc::collections::BTreeSet),
251          ),
252          (
253            "bounded_collections::bounded_vec::BoundedVec",
254            quote!(::alloc::vec::Vec),
255          ),
256          (
257            "bounded_collections::weak_bounded_vec::WeakBoundedVec",
258            quote!(::alloc::vec::Vec),
259          ),
260          (
261            "types::frame_support::storage::weak_bounded_vec::WeakBoundedVec",
262            quote!(::alloc::vec::Vec),
263          ),
264          (
265            "types::frame_support::storage::bounded_vec::BoundedVec",
266            quote!(::alloc::vec::Vec),
267          ),
268          (
269            "types::frame_system::EventRecord",
270            quote!(#api_interface::EventRecord),
271          ),
272          ("sp_weights::OldWeight", quote!(#api_interface::OldWeight)),
273          (
274            "sp_weights::Weight",
275            quote!(#api_interface::sp_weights::Weight),
276          ),
277          (
278            "sp_weights::weight_v2::Weight",
279            quote!(#api_interface::sp_weights::Weight),
280          ),
281        ]
282        .into_iter()
283        .map(|(name, code)| (name.to_string(), code)),
284      );
285      let remap_namespaces = BTreeMap::from_iter(
286        [
287          (
288            "polymesh_common_utilities::traits::balances",
289            "pallet_balances",
290          ),
291          (
292            "polymesh_common_utilities::traits::checkpoint",
293            "polymesh_primitives::checkpoint",
294          ),
295          (
296            "polymesh_common_utilities::traits::identity",
297            "polymesh_primitives::identity",
298          ),
299          (
300            "polymesh_common_utilities::traits::group",
301            "polymesh_primitives::group",
302          ),
303        ]
304        .into_iter()
305        .map(|(old, new)| (old.to_string(), new.to_string())),
306      );
307      let ink_derives = quote! {
308        #[cfg_attr(all(feature = "ink", feature = "std"), derive(::ink::storage::traits::StorageLayout))]
309      };
310      let ink_enum_derives = quote! {
311        #[derive(Copy)]
312        #[cfg_attr(all(feature = "ink", feature = "std"), derive(::ink::storage::traits::StorageLayout))]
313      };
314      let ink_extra_derives = quote! {
315        #[derive(Default)]
316        #[cfg_attr(all(feature = "ink", feature = "std"), derive(::ink::storage::traits::StorageLayout))]
317      };
318      let ink_id_derives = quote! {
319        #[derive(Copy, Default)]
320        #[cfg_attr(all(feature = "ink", feature = "std"), derive(::ink::storage::traits::StorageLayout))]
321      };
322      let custom_derives = BTreeMap::from_iter(
323        [
324          // Asset types.
325          ("AssetName", &ink_extra_derives),
326          ("AssetType", &ink_enum_derives),
327          ("NonFungibleType", &ink_enum_derives),
328          ("AssetIdentifier", &ink_enum_derives),
329          ("CustomAssetTypeId", &ink_id_derives),
330          ("FundingRoundName", &ink_extra_derives),
331          ("Ticker", &ink_id_derives),
332          ("AssetId", &ink_id_derives),
333          ("AssetID", &ink_id_derives),
334          // Settlement leg and portfolio move types.
335          ("Fund", &ink_derives),
336          ("FundDescription", &ink_derives),
337          ("FungibleToken", &ink_derives),
338          ("NFTId", &ink_id_derives),
339          ("NFTs", &ink_derives),
340          ("Leg", &ink_derives),
341          ("FungibleLeg", &ink_derives),
342          ("NonFungibleLeg", &ink_derives),
343          ("OffChainLeg", &ink_derives),
344          // Portfolio
345          ("PortfolioId", &ink_enum_derives),
346          ("PortfolioKind", &ink_enum_derives),
347          ("PortfolioNumber", &ink_id_derives),
348          ("MovePortfolioItem", &ink_derives),
349          ("Memo", &ink_derives),
350          // Settlement types.
351          ("VenueId", &ink_id_derives),
352          ("VenueDetails", &ink_extra_derives),
353          ("VenueType", &ink_enum_derives),
354          ("LegId", &ink_id_derives),
355          ("InstructionId", &ink_id_derives),
356          ("AffirmationStatus", &ink_enum_derives),
357          ("InstructionStatus", &ink_enum_derives),
358          ("LegStatus", &ink_enum_derives),
359          ("SettlementType", &ink_enum_derives),
360          // Confidential Asset types.
361          ("LegParty", &ink_enum_derives),
362          ("TransactionStatus", &ink_enum_derives),
363          ("TransactionId", &ink_id_derives),
364          ("TransactionLegId", &ink_id_derives),
365          ("ConfidentialAccount", &ink_id_derives),
366          ("MediatorAccount", &ink_id_derives),
367          ("ConfidentialTransactionRole", &ink_enum_derives),
368          ("CompressedElgamalPublicKey", &ink_id_derives),
369        ]
370        .into_iter()
371        .map(|(name, code)| (name.to_string(), code.clone())),
372      );
373
374      let mut gen = Self {
375        runtime_namespace: runtime_namespace.iter().cloned().collect(),
376        md,
377        external_modules,
378        pallet_types: BTreeMap::new(),
379        max_error_size: 4,
380        rename_types,
381        remap_namespaces,
382        ord_types: Default::default(),
383        custom_derives,
384        call,
385        event,
386        v2_weights: false,
387        dispatch_event_info: false,
388        api_interface,
389      };
390
391      // Process namespace remappings.
392      gen.remap_namespaces();
393
394      // Manually enable `Ord` for `Ticker`.
395      gen.ord_types.insert("Ticker".into());
396      // Try a limited number of times to mark all types needing the `Ord` type.
397      let mut ord_type_ids = BTreeSet::new();
398      for _ in 0..10 {
399        if !gen.check_for_ord_types(&mut ord_type_ids) {
400          // Finished, no new ord types.
401          break;
402        }
403      }
404      // Convert ord type ids to full names.
405      for id in ord_type_ids {
406        match gen.id_to_full_name(id) {
407          Some(name) if name != "Option" => {
408            gen.ord_types.insert(name);
409          }
410          _ => (),
411        }
412      }
413
414      gen.detect_v2_weights();
415
416      // Rename pallet types.
417      gen.rename_pallet_types();
418
419      gen
420    }
421
422    fn remap_namespaces(&mut self) {
423      for ty in self.md.types.types() {
424        let path = ty.ty.path();
425        let ns = path.namespace().join("::");
426        if ns.is_empty() {
427          continue;
428        }
429        if let Some(new_ns) = self.remap_namespaces.get(&ns) {
430          let name = path
431            .ident()
432            .expect("Namespace wasn't empty, so there should be an ident.");
433          let mut new_segments = new_ns
434            .split("::")
435            .map(|s| s.to_string())
436            .collect::<Vec<_>>();
437          new_segments.push(name.clone());
438          let old_name = format!("{ns}::{name}");
439          let new_name = segments_ident(&new_segments, false);
440          self.rename_types.insert(old_name, new_name);
441        }
442      }
443    }
444
445    fn rename_pallet_type(&mut self, id: u32, p_name: &str, kind: &str) {
446      let ty = self.md.types.resolve(id).unwrap();
447      let path = ty.path();
448      let mut segments: Vec<_> = path.segments().into_iter().cloned().collect();
449      let old_name = segments.join("::");
450      // pop ident.
451      segments.pop();
452
453      // Check for remapped namespace
454      let ns = segments.join("::");
455      if let Some(new_ns) = self.remap_namespaces.get(&ns) {
456        segments = new_ns.split("::").map(|s| s.to_string()).collect();
457      }
458
459      // Build new name.
460      let new_name = format!("{}{}", p_name, kind);
461      segments.push(new_name.clone());
462
463      // Add mapping from old name to new name.
464      let new_ident = segments_ident(&segments, false);
465      self.rename_types.insert(old_name, new_ident);
466      self.pallet_types.insert(id, (p_name.to_string(), new_name));
467    }
468
469    // Rename pallet types Call/Event/Error.
470    fn rename_pallet_types(&mut self) {
471      // Collect pallet type ids.
472      let types: Vec<_> = self
473        .md
474        .pallets
475        .iter()
476        .map(|p| {
477          (
478            p.name.to_string(),
479            p.calls.clone(),
480            p.event.clone(),
481            p.error.clone(),
482          )
483        })
484        .collect();
485      for (p_name, call, event, error) in types {
486        if let Some(c) = call {
487          self.rename_pallet_type(c.ty.id(), &p_name, "Call");
488        }
489        if let Some(e) = event {
490          self.rename_pallet_type(e.ty.id(), &p_name, "Event");
491        }
492        if let Some(e) = error {
493          self.rename_pallet_type(e.ty.id(), &p_name, "Error");
494        }
495      }
496    }
497
498    // Detect if chain is using V2 Weights.
499    fn detect_v2_weights(&mut self) {
500      for ty in self.md.types.types() {
501        let id = ty.id();
502        let full_name = self.id_to_full_name(id).unwrap_or_default();
503        if full_name == "frame_support::dispatch::DispatchInfo" {
504          self.v2_weights = true;
505          return;
506        }
507        if full_name == "frame_system::DispatchEventInfo" {
508          self.dispatch_event_info = true;
509          return;
510        }
511      }
512    }
513
514    fn id_to_full_name(&self, id: u32) -> Option<String> {
515      let ty = self.md.types.resolve(id)?;
516      let segments = ty.path().segments();
517      if segments.len() > 0 {
518        Some(segments.join("::"))
519      } else {
520        None
521      }
522    }
523
524    fn check_for_ord_types(&self, ord_type_ids: &mut BTreeSet<u32>) -> bool {
525      let count = ord_type_ids.len();
526      for ty in self.md.types.types() {
527        let id = ty.id();
528        let ty = ty.ty();
529        let full_name = self.id_to_full_name(id).unwrap_or_default();
530        // Check for `BTreeSet` and `BTreeMap`.
531        match full_name.as_str() {
532          "BTreeSet" | "BTreeMap" => {
533            // Mark the first type parameter as needing `Ord`.
534            ty.type_params()
535              .first()
536              .and_then(|param| param.ty())
537              .map(|ty| {
538                ord_type_ids.insert(ty.id());
539              });
540            continue;
541          }
542          _ => (),
543        }
544        // Check if this type needs `Ord`.
545        if ord_type_ids.contains(&id) {
546          // Mark fields and used types as needing `Ord`.
547          match ty.type_def() {
548            TypeDef::Composite(struct_ty) => {
549              for field in struct_ty.fields() {
550                ord_type_ids.insert(field.ty().id());
551              }
552            }
553            TypeDef::Variant(enum_ty) => {
554              for variant in enum_ty.variants() {
555                for field in variant.fields() {
556                  ord_type_ids.insert(field.ty().id());
557                }
558              }
559            }
560            TypeDef::Sequence(ty) => {
561              ord_type_ids.insert(ty.type_param().id());
562            }
563            TypeDef::Array(ty) => {
564              ord_type_ids.insert(ty.type_param().id());
565            }
566            TypeDef::Tuple(ty) => {
567              for field in ty.fields() {
568                ord_type_ids.insert(field.id());
569              }
570            }
571            TypeDef::Primitive(_) => (),
572            TypeDef::Compact(ty) => {
573              ord_type_ids.insert(ty.type_param().id());
574            }
575            _ => {}
576          }
577        }
578      }
579      let new_count = ord_type_ids.len();
580      count != new_count
581    }
582
583    fn is_boxed(field: &Field<PortableForm>) -> bool {
584      if let Some(type_name) = field.type_name() {
585        type_name.contains("Box<")
586      } else {
587        false
588      }
589    }
590
591    fn need_field_attributes(&self, field: &Field<PortableForm>) -> TokenStream {
592      if let Some(ty) = self.md.types.resolve(field.ty().id()) {
593        match ty.type_def() {
594          TypeDef::Compact(_) => {
595            return quote! { #[codec(compact)] };
596          }
597          TypeDef::Array(ty) => {
598            let len = ty.len() as usize;
599            if len > 32 {
600              return quote! { #[cfg_attr(feature = "serde", serde(with = "::serde_big_array::BigArray"))] };
601            }
602          }
603          _ => (),
604        }
605      }
606      quote! {}
607    }
608
609    fn type_name(&self, id: u32, compact_wrap: bool, import_types: bool) -> Option<TokenStream> {
610      let mut scope = TypeParameters::default();
611      self.type_name_scoped(id, &mut scope, compact_wrap, import_types)
612    }
613
614    fn type_name_scoped(
615      &self,
616      id: u32,
617      scope: &mut TypeParameters,
618      compact_wrap: bool,
619      import_types: bool,
620    ) -> Option<TokenStream> {
621      if let Some(scope_type) = scope.get_param(id) {
622        return Some(scope_type);
623      }
624      let ty = self.md.types.resolve(id)?;
625      let path = ty.path();
626      let mut lifetime = quote!();
627      let (type_ident, is_btree) = match self.is_runtime_type(path) {
628        Some(name) => {
629          // Remap runtime types to namespace `runtime`.
630          let ident = format_ident!("{name}");
631          (quote!(runtime::#ident), false)
632        }
633        None => {
634          let segments = ty.path().segments();
635          let full_name = segments.join("::");
636          let is_btree = match full_name.as_str() {
637            "BTreeSet" | "BTreeMap" => true,
638            _ => false,
639          };
640          if full_name == "Cow" {
641            lifetime = quote!('static, );
642          }
643          let type_ident = self
644            .rename_types
645            .get(&full_name)
646            .cloned()
647            .unwrap_or_else(|| segments_ident(segments, import_types));
648          (type_ident, is_btree)
649        }
650      };
651
652      match ty.type_def() {
653        TypeDef::Sequence(ty) => {
654          return self
655            .type_name_scoped(ty.type_param().id(), scope, true, import_types)
656            .map(|elem_ty| {
657              quote! { ::alloc::vec::Vec<#elem_ty> }
658            });
659        }
660        TypeDef::Array(ty) => {
661          let len = ty.len() as usize;
662          return self
663            .type_name_scoped(ty.type_param().id(), scope, true, import_types)
664            .map(|elem_ty| {
665              quote! { [#elem_ty; #len] }
666            });
667        }
668        TypeDef::Tuple(ty) => {
669          let fields = ty
670            .fields()
671            .into_iter()
672            .filter_map(|field| self.type_name_scoped(field.id(), scope, true, import_types))
673            .collect::<Vec<_>>();
674          return Some(quote! { (#(#fields),*) });
675        }
676        TypeDef::Primitive(prim) => {
677          use scale_info::TypeDefPrimitive::*;
678          let name = format_ident!(
679            "{}",
680            match prim {
681              Bool => "bool",
682              Char => "char",
683              Str => return Some(quote!(::alloc::string::String)),
684              U8 => "u8",
685              U16 => "u16",
686              U32 => "u32",
687              U64 => "u64",
688              U128 => "u128",
689              U256 => "u256",
690              I8 => "i8",
691              I16 => "i16",
692              I32 => "i32",
693              I64 => "i64",
694              I128 => "i128",
695              I256 => "i256",
696            }
697          );
698          return Some(quote! { #name });
699        }
700        TypeDef::Compact(ty) => {
701          return self
702            .type_name_scoped(ty.type_param().id(), scope, true, import_types)
703            .map(|ty| {
704              if compact_wrap {
705                quote! { ::codec::Compact<#ty> }
706              } else {
707                ty
708              }
709            });
710        }
711        _ => {}
712      }
713
714      // Check if `BTreeSet` or `BTreeMap` use a scoped paramter for the key.
715      if is_btree {
716        ty.type_params()
717          .first()
718          .and_then(|param| param.ty())
719          .map(|ty| scope.add_param_bounds(ty.id(), "Ord", quote!(Ord)));
720      }
721
722      let type_params = ty
723        .type_params()
724        .iter()
725        .filter_map(|param| {
726          param
727            .ty()
728            .map(|ty| self.type_name_scoped(ty.id(), scope, true, import_types))
729        })
730        .collect::<Vec<_>>();
731
732      if type_params.len() > 0 {
733        Some(quote! {
734          #type_ident<#lifetime #(#type_params),*>
735        })
736      } else {
737        Some(type_ident)
738      }
739    }
740
741    fn gen_storage_func(
742      &self,
743      mod_prefix: &str,
744      md: &StorageEntryMetadata<PortableForm>,
745    ) -> TokenStream {
746      let storage_name = &md.name;
747      let storage_ident = format_ident!("{}", storage_name.to_snake_case());
748      let api_interface = &self.api_interface;
749      let mut key_prefix = Vec::with_capacity(512);
750      key_prefix.extend(sp_crypto_hashing::twox_128(mod_prefix.as_bytes()));
751      key_prefix.extend(sp_crypto_hashing::twox_128(storage_name.as_bytes()));
752
753      let (hashers, value_ty) = match &md.ty {
754        StorageEntryType::Plain(value) => (vec![], value.id()),
755        StorageEntryType::Map {
756          hashers,
757          key,
758          value,
759        } => match hashers.as_slice() {
760          [hasher] => {
761            // 1 key.
762            (vec![(key, hasher)], value.id())
763          }
764          hashers => {
765            // >=2 keys.
766            let keys_ty = self.md.types.resolve(key.id()).unwrap();
767            let key_hashers = if let TypeDef::Tuple(ty) = keys_ty.type_def() {
768              ty.fields().iter().zip(hashers).collect()
769            } else {
770              vec![]
771            };
772            (key_hashers, value.id())
773          }
774        },
775      };
776      let keys_len = hashers.len();
777      let mut keys = TokenStream::new();
778      let mut hashing = TokenStream::new();
779      for (idx, (key, hasher)) in hashers.into_iter().enumerate() {
780        let key_ident = format_ident!("key_{}", idx);
781        let type_name = self
782          .type_name(key.id(), false, true)
783          .expect("Missing Storage key type");
784        keys.append_all(quote! {#key_ident: #type_name,});
785        hashing.append_all(match hasher {
786          StorageHasher::Blake2_128 => quote! {
787            buf.extend(#api_interface::hashing::blake2_128(&#key_ident.encode()));
788          },
789          StorageHasher::Blake2_256 => quote! {
790            buf.extend(#api_interface::hashing::blake2_256(&#key_ident.encode()));
791          },
792          StorageHasher::Blake2_128Concat => quote! {
793            let key = #key_ident.encode();
794            buf.extend(#api_interface::hashing::blake2_128(&key));
795            buf.extend(key.into_iter());
796          },
797          StorageHasher::Twox128 => quote! {
798            buf.extend(#api_interface::hashing::twox_128(&#key_ident.encode()));
799          },
800          StorageHasher::Twox256 => quote! {
801            buf.extend(#api_interface::hashing::twox_256(&#key_ident.encode()));
802          },
803          StorageHasher::Twox64Concat => quote! {
804            let key = #key_ident.encode();
805            buf.extend(#api_interface::hashing::twox_64(&key));
806            buf.extend(key.into_iter());
807          },
808          StorageHasher::Identity => quote! {
809            buf.extend(#key_ident.encode());
810          },
811        });
812      }
813      let value_ty = if mod_prefix == "System" && storage_name == "Events" {
814        let event_ty = &self.event;
815        quote!(::alloc::vec::Vec<#api_interface::EventRecord<types::#event_ty>>)
816      } else {
817        self.type_name(value_ty, false, true).unwrap()
818      };
819
820      let (return_ty, return_value) = match md.modifier {
821        StorageEntryModifier::Optional => (quote! { Option<#value_ty>}, quote! { Ok(value) }),
822        StorageEntryModifier::Default => {
823          let default_value = &md.default;
824          (
825            quote! { #value_ty },
826            quote! {
827              Ok(value.unwrap_or_else(|| {
828                use ::codec::Decode;
829                const DEFAULT: &'static [u8] = &[#(#default_value,)*];
830                <#value_ty>::decode(&mut &DEFAULT[..]).unwrap()
831              }))
832            },
833          )
834        }
835      };
836
837      let docs = &md.docs;
838      if keys_len > 0 {
839        quote! {
840          #(#[doc = #docs])*
841          #[cfg(not(feature = "ink"))]
842          pub async fn #storage_ident(&self, #keys) -> ::polymesh_api_client::error::Result<#return_ty> {
843            use ::codec::Encode;
844            let mut buf = ::alloc::vec::Vec::with_capacity(512);
845            buf.extend([#(#key_prefix,)*]);
846            #hashing
847            let key = ::polymesh_api_client::StorageKey(buf);
848            let value = self.api.client.get_storage_by_key(key, self.at).await?;
849            #return_value
850          }
851
852          #(#[doc = #docs])*
853          #[cfg(feature = "ink")]
854          pub fn #storage_ident(&self, #keys) -> ::polymesh_api_ink::error::Result<#return_ty> {
855            use ::codec::Encode;
856            let mut buf = ::alloc::vec::Vec::with_capacity(512);
857            buf.extend([#(#key_prefix,)*]);
858            #hashing
859            let value = self.api.read_storage(buf)?;
860            #return_value
861          }
862        }
863      } else {
864        quote! {
865          #(#[doc = #docs])*
866          #[cfg(not(feature = "ink"))]
867          pub async fn #storage_ident(&self) -> ::polymesh_api_client::error::Result<#return_ty> {
868            let key = ::polymesh_api_client::StorageKey(::alloc::vec![#(#key_prefix,)*]);
869            let value = self.api.client.get_storage_by_key(key, self.at).await?;
870            #return_value
871          }
872
873          #(#[doc = #docs])*
874          #[cfg(feature = "ink")]
875          pub fn #storage_ident(&self) -> ::polymesh_api_ink::error::Result<#return_ty> {
876            let value = self.api.read_storage(::alloc::vec![#(#key_prefix,)*])?;
877            #return_value
878          }
879        }
880      }
881    }
882
883    fn gen_paged_storage_func(
884      &self,
885      mod_prefix: &str,
886      md: &StorageEntryMetadata<PortableForm>,
887    ) -> TokenStream {
888      let storage_name = &md.name;
889      let storage_ident = format_ident!("{}", storage_name.to_snake_case());
890      let api_interface = &self.api_interface;
891      let mut key_prefix = Vec::with_capacity(32);
892      key_prefix.extend(sp_crypto_hashing::twox_128(mod_prefix.as_bytes()));
893      key_prefix.extend(sp_crypto_hashing::twox_128(storage_name.as_bytes()));
894
895      let (mut hashers, value_ty) = match &md.ty {
896        StorageEntryType::Plain(value) => (vec![], value.id()),
897        StorageEntryType::Map {
898          hashers,
899          key,
900          value,
901        } => match hashers.as_slice() {
902          [hasher] => {
903            // 1 key.
904            (vec![(key, hasher)], value.id())
905          }
906          hashers => {
907            // >=2 keys.
908            let keys_ty = self.md.types.resolve(key.id()).unwrap();
909            let key_hashers = if let TypeDef::Tuple(ty) = keys_ty.type_def() {
910              ty.fields().iter().zip(hashers).collect()
911            } else {
912              vec![]
913            };
914            (key_hashers, value.id())
915          }
916        },
917      };
918      // Get the last key_hasher.
919      let (key_ty, key_hash_len) = if let Some((key, hasher)) = hashers.pop() {
920        let type_name = self
921          .type_name(key.id(), false, true)
922          .expect("Missing Storage key type");
923        let hash_len = match hasher {
924          StorageHasher::Blake2_128Concat => quote! { Some(16) },
925          StorageHasher::Twox64Concat => quote! { Some(8) },
926          StorageHasher::Identity => quote! { Some(0) },
927          _ => quote! { None },
928        };
929        (type_name, hash_len)
930      } else {
931        return quote! {};
932      };
933      let mut keys = TokenStream::new();
934      let mut hashing = TokenStream::new();
935      for (idx, (key, hasher)) in hashers.into_iter().enumerate() {
936        let key_ident = format_ident!("key_{}", idx);
937        let type_name = self
938          .type_name(key.id(), false, true)
939          .expect("Missing Storage key type");
940        keys.append_all(quote! {#key_ident: #type_name,});
941        hashing.append_all(match hasher {
942          StorageHasher::Blake2_128 => quote! {
943            buf.extend(#api_interface::hashing::blake2_128(&#key_ident.encode()));
944          },
945          StorageHasher::Blake2_256 => quote! {
946            buf.extend(#api_interface::hashing::blake2_256(&#key_ident.encode()));
947          },
948          StorageHasher::Blake2_128Concat => quote! {
949            let key = #key_ident.encode();
950            buf.extend(#api_interface::hashing::blake2_128(&key));
951            buf.extend(key.into_iter());
952          },
953          StorageHasher::Twox128 => quote! {
954            buf.extend(#api_interface::hashing::twox_128(&#key_ident.encode()));
955          },
956          StorageHasher::Twox256 => quote! {
957            buf.extend(#api_interface::hashing::twox_256(&#key_ident.encode()));
958          },
959          StorageHasher::Twox64Concat => quote! {
960            let key = #key_ident.encode();
961            buf.extend(#api_interface::hashing::twox_64(&key));
962            buf.extend(key.into_iter());
963          },
964          StorageHasher::Identity => quote! {
965            buf.extend(#key_ident.encode());
966          },
967        });
968      }
969      let value_ty = self.type_name(value_ty, false, true).unwrap();
970
971      let docs = &md.docs;
972      quote! {
973        #(#[doc = #docs])*
974        pub fn #storage_ident(&self, #keys) -> ::polymesh_api_client::StoragePaged<#key_ty, #value_ty> {
975          use ::codec::Encode;
976          let mut buf = ::alloc::vec::Vec::with_capacity(512);
977          buf.extend([#(#key_prefix,)*]);
978          #hashing
979          let prefix = ::polymesh_api_client::StorageKey(buf);
980          ::polymesh_api_client::StoragePaged::new(&self.api.client, prefix, #key_hash_len, self.at)
981        }
982      }
983    }
984
985    fn gen_func(
986      &self,
987      mod_name: &str,
988      mod_idx: u8,
989      mod_call_ty: u32,
990      md: &Variant<PortableForm>,
991    ) -> TokenStream {
992      let mod_call_ident = format_ident!("{mod_name}");
993      let mod_call = self.type_name(mod_call_ty, false, true).unwrap();
994      let func_name = md.name();
995      let func_idx = md.index();
996      let func_ident = format_ident!("{}", func_name.to_snake_case());
997
998      let mut fields = TokenStream::new();
999      let mut field_names = TokenStream::new();
1000      let mut fields_encode = TokenStream::new();
1001      for (idx, field) in md.fields().iter().enumerate() {
1002        let name = field
1003          .name()
1004          .map(|n| format_ident!("{n}"))
1005          .unwrap_or_else(|| format_ident!("param_{idx}"));
1006        let type_name = self
1007          .type_name(field.ty().id(), false, true)
1008          .expect("Missing Extrinsic param type");
1009        fields.append_all(quote! {#name: #type_name,});
1010        if Self::is_boxed(field) {
1011          field_names.append_all(quote! {#name: ::alloc::boxed::Box::new(#name),});
1012        } else {
1013          field_names.append_all(quote! {#name,});
1014        }
1015        fields_encode.append_all(quote! {
1016          #name.encode_to(&mut buf);
1017        });
1018      }
1019
1020      let docs = md.docs();
1021      let call_ty = &self.call;
1022      if md.fields().len() > 0 {
1023        quote! {
1024          #(#[doc = #docs])*
1025          #[cfg(not(feature = "ink"))]
1026          pub fn #func_ident(&self, #fields) -> ::polymesh_api_client::error::Result<super::super::WrappedCall> {
1027            self.api.wrap_call(#call_ty::#mod_call_ident(types::#mod_call::#func_ident { #field_names }))
1028          }
1029
1030          #(#[doc = #docs])*
1031          #[cfg(feature = "ink")]
1032          pub fn #func_ident(&self, #fields) -> super::super::WrappedCall {
1033            use ::codec::Encode;
1034            let mut buf = ::alloc::vec![#mod_idx, #func_idx];
1035            #fields_encode
1036            self.api.wrap_call(buf)
1037          }
1038        }
1039      } else {
1040        quote! {
1041          #(#[doc = #docs])*
1042          #[cfg(not(feature = "ink"))]
1043          pub fn #func_ident(&self) -> ::polymesh_api_client::error::Result<super::super::WrappedCall> {
1044            self.api.wrap_call(#call_ty::#mod_call_ident(types::#mod_call::#func_ident))
1045          }
1046
1047          #(#[doc = #docs])*
1048          #[cfg(feature = "ink")]
1049          pub fn #func_ident(&self) -> super::super::WrappedCall {
1050            self.api.wrap_call(::alloc::vec![#mod_idx, #func_idx])
1051          }
1052        }
1053      }
1054    }
1055
1056    fn gen_module(
1057      &self,
1058      md: &frame_metadata::v14::PalletMetadata<PortableForm>,
1059    ) -> (Ident, Ident, Ident, Ident, TokenStream) {
1060      let mod_idx = md.index;
1061      let mod_name = &md.name;
1062      let mod_call_api = format_ident!("{}CallApi", mod_name);
1063      let mod_query_api = format_ident!("{}QueryApi", mod_name);
1064      let mod_paged_query_api = format_ident!("{}PagedQueryApi", mod_name);
1065      let mod_ident = format_ident!("{}", mod_name.to_snake_case());
1066
1067      let mut call_fields = TokenStream::new();
1068      let mut query_fields = TokenStream::new();
1069      let mut paged_query_fields = TokenStream::new();
1070
1071      // Generate module functions.
1072      if let Some(calls) = &md.calls {
1073        let call_ty = self
1074          .md
1075          .types
1076          .resolve(calls.ty.id())
1077          .expect("Missing Pallet call type");
1078        match call_ty.type_def() {
1079          TypeDef::Variant(v) => {
1080            let mod_call_ty = calls.ty.id();
1081            for v in v.variants() {
1082              let code = self.gen_func(mod_name, mod_idx, mod_call_ty, v);
1083              call_fields.append_all(code);
1084            }
1085          }
1086          _ => {
1087            unimplemented!("Only Variant type supported for Pallet Call type.");
1088          }
1089        }
1090      }
1091
1092      // Generate module storage query functions.
1093      if let Some(storage) = &md.storage {
1094        let mod_prefix = &storage.prefix;
1095        for md in &storage.entries {
1096          query_fields.append_all(self.gen_storage_func(mod_prefix, md));
1097          paged_query_fields.append_all(self.gen_paged_storage_func(mod_prefix, md));
1098        }
1099      }
1100
1101      let code = quote! {
1102        pub mod #mod_ident {
1103          use super::*;
1104
1105          #[derive(Clone)]
1106          pub struct #mod_call_api<'api> {
1107            api: &'api super::super::Api,
1108          }
1109
1110          impl<'api> #mod_call_api<'api> {
1111            #call_fields
1112          }
1113
1114          impl<'api> From<&'api super::super::Api> for #mod_call_api<'api> {
1115            fn from(api: &'api super::super::Api) -> Self {
1116              Self { api }
1117            }
1118          }
1119
1120          #[derive(Clone)]
1121          pub struct #mod_query_api<'api> {
1122            pub(crate) api: &'api super::super::Api,
1123            #[cfg(not(feature = "ink"))]
1124            pub(crate) at: Option<::polymesh_api_client::BlockHash>,
1125          }
1126
1127          impl<'api> #mod_query_api<'api> {
1128            #query_fields
1129          }
1130
1131          #[derive(Clone)]
1132          #[cfg(not(feature = "ink"))]
1133          pub struct #mod_paged_query_api<'api> {
1134            pub(crate) api: &'api super::super::Api,
1135            pub(crate) at: Option<::polymesh_api_client::BlockHash>,
1136          }
1137
1138          #[cfg(not(feature = "ink"))]
1139          impl<'api> #mod_paged_query_api<'api> {
1140            #paged_query_fields
1141          }
1142        }
1143      };
1144      (
1145        mod_ident,
1146        mod_call_api,
1147        mod_query_api,
1148        mod_paged_query_api,
1149        code,
1150      )
1151    }
1152
1153    fn gen_struct_fields(
1154      &self,
1155      fields: &[Field<PortableForm>],
1156      scope: &mut TypeParameters,
1157    ) -> Option<(bool, TokenStream)> {
1158      let mut is_tuple = false;
1159      let mut named = Vec::new();
1160      let mut unnamed = Vec::new();
1161
1162      // Check for unit type (i.e. empty field list).
1163      if fields.len() == 0 {
1164        return Some((true, quote! {}));
1165      }
1166
1167      for field in fields {
1168        let mut field_ty = self.type_name_scoped(field.ty().id(), scope, false, false)?;
1169        if Self::is_boxed(field) {
1170          field_ty = quote!(::alloc::boxed::Box<#field_ty>);
1171        }
1172        let attr = self.need_field_attributes(field);
1173        unnamed.push(quote! { #attr pub #field_ty });
1174        if let Some(name) = field.name() {
1175          let docs = field.docs();
1176          let name = format_ident!("{name}");
1177          named.push(quote! {
1178              #(#[doc = #docs])*
1179              #attr
1180              pub #name: #field_ty
1181          });
1182        } else {
1183          // If there are any unnamed fields, then make it a tuple.
1184          is_tuple = true;
1185        }
1186      }
1187
1188      if is_tuple {
1189        Some((true, quote! { #(#unnamed),* }))
1190      } else {
1191        Some((
1192          false,
1193          quote! {
1194            #(#named),*
1195          },
1196        ))
1197      }
1198    }
1199
1200    fn gen_enum_match_fields(&self, fields: &[Field<PortableForm>]) -> TokenStream {
1201      let mut is_tuple = false;
1202      let mut unnamed = Vec::new();
1203
1204      // Check for unit type (i.e. empty field list).
1205      if fields.len() == 0 {
1206        return quote!();
1207      }
1208
1209      for field in fields {
1210        unnamed.push(quote!(_));
1211        if field.name().is_none() {
1212          // If there are any unnamed fields, then make it a tuple.
1213          is_tuple = true;
1214        }
1215      }
1216
1217      if is_tuple {
1218        quote! { (#(#unnamed),*) }
1219      } else {
1220        quote! {
1221          {
1222            ..
1223          }
1224        }
1225      }
1226    }
1227
1228    fn gen_enum_fields(
1229      &self,
1230      fields: &[Field<PortableForm>],
1231      scope: &mut TypeParameters,
1232    ) -> Option<(bool, Vec<TokenStream>)> {
1233      let mut is_tuple = false;
1234      let mut named = Vec::new();
1235      let mut unnamed = Vec::new();
1236
1237      // Check for unit type (i.e. empty field list).
1238      if fields.len() == 0 {
1239        return Some((true, unnamed));
1240      }
1241
1242      for field in fields {
1243        let mut field_ty = self.type_name_scoped(field.ty().id(), scope, false, false)?;
1244        if Self::is_boxed(field) {
1245          field_ty = quote!(::alloc::boxed::Box<#field_ty>);
1246        }
1247        let docs = field.docs();
1248        let attr = self.need_field_attributes(field);
1249        unnamed.push(quote! {
1250            #(#[doc = #docs])*
1251            #attr
1252            #field_ty
1253        });
1254        if let Some(name) = field.name() {
1255          let name = format_ident!("{name}");
1256          named.push(quote! {
1257              #(#[doc = #docs])*
1258              #attr
1259              #name: #field_ty
1260          });
1261        } else {
1262          // If there are any unnamed fields, then make it a tuple.
1263          is_tuple = true;
1264        }
1265      }
1266
1267      if is_tuple {
1268        Some((true, unnamed))
1269      } else {
1270        Some((false, named))
1271      }
1272    }
1273
1274    fn gen_enum_as_static_str(
1275      &self,
1276      ty_ident: &Ident,
1277      params: &TokenStream,
1278      ty: &Type<PortableForm>,
1279      prefix: Option<&String>,
1280    ) -> Option<TokenStream> {
1281      let mut as_str_arms = TokenStream::new();
1282      let mut as_docs_arms = TokenStream::new();
1283      match (prefix, ty.type_def()) {
1284        (None, TypeDef::Variant(enum_ty)) => {
1285          for variant in enum_ty.variants() {
1286            let top_name = variant.name();
1287            let top_ident = format_ident!("{}", top_name);
1288            let fields = variant.fields().len();
1289            match fields {
1290              0 => {
1291                as_str_arms.append_all(quote! {
1292                  Self::#top_ident => {
1293                    #top_name
1294                  },
1295                });
1296                as_docs_arms.append_all(quote! {
1297                  Self::#top_ident => {
1298                    &[""]
1299                  },
1300                });
1301              }
1302              1 => {
1303                as_str_arms.append_all(quote! {
1304                  Self::#top_ident(val) => {
1305                    val.as_static_str()
1306                  },
1307                });
1308                as_docs_arms.append_all(quote! {
1309                  Self::#top_ident(val) => {
1310                    val.as_docs()
1311                  },
1312                });
1313              }
1314              _ => {
1315                as_str_arms.append_all(quote! {
1316                  Self::#top_ident(_) => {
1317                    #top_name
1318                  },
1319                });
1320                as_docs_arms.append_all(quote! {
1321                  Self::#top_ident(_) => {
1322                    &[""]
1323                  },
1324                });
1325              }
1326            }
1327          }
1328        }
1329        (Some(prefix), TypeDef::Variant(enum_ty)) => {
1330          for variant in enum_ty.variants() {
1331            let var_name = variant.name();
1332            let var_ident = format_ident!("{}", var_name);
1333            let mut docs = variant.docs().to_vec();
1334            if docs.len() == 0 {
1335              docs.push("".to_string());
1336            }
1337            let as_str_name = format!("{}.{}", prefix, var_name);
1338            let match_fields = self.gen_enum_match_fields(variant.fields());
1339            as_str_arms.append_all(quote! {
1340              Self:: #var_ident #match_fields => {
1341                #as_str_name
1342              },
1343            });
1344            as_docs_arms.append_all(quote! {
1345              Self:: #var_ident #match_fields => {
1346                &[#(#docs,)*]
1347              },
1348            });
1349          }
1350        }
1351        _ => {
1352          return None;
1353        }
1354      };
1355      Some(quote! {
1356        impl #params #ty_ident #params {
1357          pub fn as_static_str(&self) -> &'static str {
1358            #[allow(unreachable_patterns)]
1359            match self {
1360              #as_str_arms
1361              _ => "Unknown",
1362            }
1363          }
1364        }
1365
1366        #[cfg(not(feature = "ink"))]
1367        impl #params ::polymesh_api_client::EnumInfo for #ty_ident #params {
1368          fn as_name(&self) -> &'static str {
1369            self.as_static_str()
1370          }
1371
1372          fn as_docs(&self) -> &'static [&'static str] {
1373            #[allow(unreachable_patterns)]
1374            match self {
1375              #as_docs_arms
1376              _ => &[""],
1377            }
1378          }
1379        }
1380
1381        impl #params From<#ty_ident #params> for &'static str {
1382          fn from(v: #ty_ident #params) -> Self {
1383            v.as_static_str()
1384          }
1385        }
1386
1387        impl #params From<&#ty_ident #params> for &'static str {
1388          fn from(v: &#ty_ident #params) -> Self {
1389            v.as_static_str()
1390          }
1391        }
1392      })
1393    }
1394
1395    fn is_runtime_type(&self, path: &Path<PortableForm>) -> Option<String> {
1396      if self.runtime_namespace == path.namespace() {
1397        let ident = path.ident();
1398        match ident.as_deref() {
1399          Some("Event") => Some("RuntimeEvent".into()),
1400          Some("Call") => Some("RuntimeCall".into()),
1401          Some(name) => Some(name.into()),
1402          _ => None,
1403        }
1404      } else {
1405        None
1406      }
1407    }
1408
1409    fn gen_module_error(
1410      &self,
1411      _id: u32,
1412      ty: &Type<PortableForm>,
1413      ident: &str,
1414    ) -> Option<TokenStream> {
1415      let ty_ident = format_ident!("{ident}");
1416      let mut scope = TypeParameters::new(ty);
1417
1418      let mut variants = TokenStream::new();
1419      let mut as_str_arms = TokenStream::new();
1420      let mut as_docs_arms = TokenStream::new();
1421      for p in &self.md.pallets {
1422        let idx = p.index;
1423        let mod_ident = format_ident!("{}", p.name);
1424        let error_ty = p.error.as_ref().and_then(|e| {
1425          self
1426            .type_name_scoped(e.ty.id(), &mut scope, false, false)
1427            .map(|ident| quote! { (#ident) })
1428        });
1429        if let Some(error_ty) = error_ty {
1430          variants.append_all(quote! {
1431            #[codec(index = #idx)]
1432            #mod_ident #error_ty,
1433          });
1434          as_str_arms.append_all(quote! {
1435            RuntimeError:: #mod_ident(err) => err.as_static_str(),
1436          });
1437          as_docs_arms.append_all(quote! {
1438            RuntimeError:: #mod_ident(err) => err.as_docs(),
1439          });
1440        }
1441      }
1442
1443      let docs = ty.docs();
1444      let max_error_size = self.max_error_size + 1;
1445      let code = quote! {
1446        #[derive(Clone, Debug, PartialEq, Eq)]
1447        #[derive(::codec::Encode, ::codec::Decode)]
1448        #[cfg_attr(all(feature = "std", feature = "type_info"), derive(::scale_info::TypeInfo))]
1449        #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
1450        pub enum RuntimeError {
1451          #variants
1452        }
1453
1454        impl RuntimeError {
1455          pub fn as_static_str(&self) -> &'static str {
1456            match self {
1457              #as_str_arms
1458            }
1459          }
1460        }
1461
1462        impl From<RuntimeError> for &'static str {
1463          fn from(v: RuntimeError) -> Self {
1464            v.as_static_str()
1465          }
1466        }
1467
1468        impl From<&RuntimeError> for &'static str {
1469          fn from(v: &RuntimeError) -> Self {
1470            v.as_static_str()
1471          }
1472        }
1473
1474        #[cfg(not(feature = "ink"))]
1475        impl ::polymesh_api_client::EnumInfo for RuntimeError {
1476          fn as_name(&self) -> &'static str {
1477            self.as_static_str()
1478          }
1479
1480          fn as_docs(&self) -> &'static [&'static str] {
1481            match self {
1482              #as_docs_arms
1483            }
1484          }
1485        }
1486
1487        #(#[doc = #docs])*
1488        #[derive(Clone, Debug, PartialEq, Eq)]
1489        #[cfg_attr(all(feature = "std", feature = "type_info"), derive(::scale_info::TypeInfo))]
1490        #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
1491        pub struct #ty_ident(pub RuntimeError);
1492
1493        impl ::codec::Encode for #ty_ident {
1494          fn encode_to<T: ::codec::Output + ?Sized>(&self, output: &mut T) {
1495            let mut raw = self.0.encode();
1496            raw.resize(#max_error_size, 0);
1497            output.write(raw.as_slice());
1498          }
1499        }
1500
1501        impl ::codec::Decode for #ty_ident {
1502          fn decode<I: ::codec::Input>(input: &mut I) -> Result<Self, ::codec::Error> {
1503            let raw: [u8; #max_error_size] = ::codec::Decode::decode(input)?;
1504            Ok(Self(RuntimeError::decode(&mut &raw[..])?))
1505          }
1506        }
1507
1508        impl #ty_ident {
1509          pub fn as_static_str(&self) -> &'static str {
1510            self.0.as_static_str()
1511          }
1512        }
1513
1514        impl From<#ty_ident> for &'static str {
1515          fn from(v: #ty_ident) -> Self {
1516            v.as_static_str()
1517          }
1518        }
1519
1520        impl From<&#ty_ident> for &'static str {
1521          fn from(v: &#ty_ident) -> Self {
1522            v.as_static_str()
1523          }
1524        }
1525
1526        #[cfg(not(feature = "ink"))]
1527        impl ::polymesh_api_client::EnumInfo for #ty_ident {
1528          fn as_name(&self) -> &'static str {
1529            self.as_static_str()
1530          }
1531
1532          fn as_docs(&self) -> &'static [&'static str] {
1533            self.0.as_docs()
1534          }
1535        }
1536      };
1537      Some(code)
1538    }
1539
1540    fn gen_dispatch_error(
1541      &self,
1542      _id: u32,
1543      ty: &Type<PortableForm>,
1544      ident: &str,
1545    ) -> Option<TokenStream> {
1546      let ty_ident = format_ident!("{ident}");
1547      let mut scope = TypeParameters::new(ty);
1548
1549      let mut variants = TokenStream::new();
1550      let mut as_str_arms = TokenStream::new();
1551      let mut as_docs_arms = TokenStream::new();
1552      for p in &self.md.pallets {
1553        let idx = p.index;
1554        let mod_ident = format_ident!("{}", p.name);
1555        let error_ty = p.error.as_ref().and_then(|e| {
1556          self
1557            .type_name_scoped(e.ty.id(), &mut scope, false, false)
1558            .map(|ident| quote! { (#ident) })
1559        });
1560        if let Some(error_ty) = error_ty {
1561          variants.append_all(quote! {
1562            #[codec(index = #idx)]
1563            #mod_ident #error_ty,
1564          });
1565          as_str_arms.append_all(quote! {
1566            RuntimeError:: #mod_ident(err) => err.as_static_str(),
1567          });
1568          as_docs_arms.append_all(quote! {
1569            RuntimeError:: #mod_ident(err) => err.as_docs(),
1570          });
1571        }
1572      }
1573
1574      let docs = ty.docs();
1575      let code = quote! {
1576        #(#[doc = #docs])*
1577        #[derive(Clone, Debug, PartialEq, Eq)]
1578        #[derive(::codec::Encode, ::codec::Decode)]
1579        #[cfg_attr(all(feature = "std", feature = "type_info"), derive(::scale_info::TypeInfo))]
1580        #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
1581        pub enum #ty_ident {
1582          Other,
1583          CannotLookup,
1584          BadOrigin,
1585          Module(ModuleError),
1586          ConsumerRemaining,
1587          NoProviders,
1588          TooManyConsumers,
1589          Token(sp_runtime::TokenError),
1590          Arithmetic(sp_arithmetic::ArithmeticError),
1591          Transactional(sp_runtime::TransactionalError),
1592          Exhausted,
1593          Corruption,
1594          Unavailable,
1595          RootNotAllowed,
1596        }
1597
1598        impl #ty_ident {
1599          pub fn as_static_str(&self) -> &'static str {
1600            match self {
1601              Self::Other => "Other",
1602              Self::CannotLookup => "CannotLookup",
1603              Self::BadOrigin => "BadOrigin",
1604              Self::Module(err) => err.as_static_str(),
1605              Self::ConsumerRemaining => "ConsumerRemaining",
1606              Self::NoProviders => "NoProviders",
1607              Self::TooManyConsumers => "TooManyConsumers",
1608              Self::Token(err) => err.as_static_str(),
1609              Self::Arithmetic(err) => err.as_static_str(),
1610              Self::Transactional(err) => err.as_static_str(),
1611              Self::Exhausted => "Exhausted",
1612              Self::Corruption => "Corruption",
1613              Self::Unavailable => "Unavailable",
1614              Self::RootNotAllowed => "RootNotAllowed",
1615            }
1616          }
1617        }
1618
1619        impl From<#ty_ident> for &'static str {
1620          fn from(v: #ty_ident) -> Self {
1621            v.as_static_str()
1622          }
1623        }
1624
1625        impl From<&#ty_ident> for &'static str {
1626          fn from(v: &#ty_ident) -> Self {
1627            v.as_static_str()
1628          }
1629        }
1630
1631        #[cfg(not(feature = "ink"))]
1632        impl ::polymesh_api_client::EnumInfo for #ty_ident {
1633          fn as_name(&self) -> &'static str {
1634            self.as_static_str()
1635          }
1636
1637          fn as_docs(&self) -> &'static [&'static str] {
1638            match self {
1639              Self::Other => &["Some error occurred."],
1640              Self::CannotLookup => &["Failed to lookup some data."],
1641              Self::BadOrigin => &["A bad origin."],
1642              Self::Module(err) => err.as_docs(),
1643              Self::ConsumerRemaining => &["At least one consumer is remaining so the account cannot be destroyed."],
1644              Self::NoProviders => &["There are no providers so the account cannot be created."],
1645              Self::TooManyConsumers => &["There are too many consumers so the account cannot be created."],
1646              Self::Token(err) => err.as_docs(),
1647              Self::Arithmetic(err) => err.as_docs(),
1648              Self::Transactional(err) => err.as_docs(),
1649              Self::Exhausted => &["Resources exhausted, e.g. attempt to read/write data which is too large to manipulate."],
1650              Self::Corruption => &["The state is corrupt; this is generally not going to fix itself."],
1651              Self::Unavailable => &["Some resource (e.g. a preimage) is unavailable right now. This might fix itself later."],
1652              Self::RootNotAllowed => &["Root origin is not allowed."],
1653            }
1654          }
1655        }
1656      };
1657      Some(code)
1658    }
1659
1660    fn gen_type(
1661      &self,
1662      id: u32,
1663      ty: &Type<PortableForm>,
1664      ident: &str,
1665      is_runtime_type: bool,
1666    ) -> Option<TokenStream> {
1667      let full_name = self.id_to_full_name(id)?;
1668      if full_name == "sp_runtime::ModuleError" {
1669        return self.gen_module_error(id, ty, ident);
1670      }
1671      if full_name == "sp_runtime::DispatchError" {
1672        return self.gen_dispatch_error(id, ty, ident);
1673      }
1674      let (pallet_name, ident) = match self.pallet_types.get(&id) {
1675        Some((pallet_name, ident)) => (Some(pallet_name), ident.as_str()),
1676        None => (None, ident),
1677      };
1678      let ty_ident = format_ident!("{ident}");
1679
1680      let mut scope = TypeParameters::new(ty);
1681      let derive_ord = if self.ord_types.contains(&full_name) {
1682        quote! {
1683          #[derive(PartialOrd, Ord)]
1684        }
1685      } else {
1686        quote!()
1687      };
1688      let custom_derive = self
1689        .custom_derives
1690        .get(ident)
1691        .cloned()
1692        .unwrap_or_else(|| quote!());
1693
1694      let docs = ty.docs();
1695      let (mut code, params) = match ty.type_def() {
1696        TypeDef::Composite(struct_ty) => {
1697          let fields = struct_ty.fields();
1698          let fields_len = fields.len();
1699          let (is_tuple, mut fields) = self.gen_struct_fields(fields, &mut scope)?;
1700          if let Some(unused_params) = scope.get_unused_params() {
1701            if fields_len > 0 {
1702              fields.append_all(quote! {, });
1703            }
1704            if is_tuple {
1705              fields.append_all(quote! {
1706                #unused_params
1707              });
1708            } else {
1709              fields.append_all(quote! {
1710                _phantom_data: #unused_params
1711              });
1712            }
1713          }
1714          let params = scope.get_type_params();
1715          if is_tuple {
1716            (
1717              quote! {
1718                #(#[doc = #docs])*
1719                #[derive(Clone, Debug, PartialEq, Eq)]
1720                #derive_ord
1721                #custom_derive
1722                #[derive(::codec::Encode, ::codec::Decode)]
1723                #[cfg_attr(all(feature = "std", feature = "type_info"), derive(::scale_info::TypeInfo))]
1724                #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
1725                pub struct #ty_ident #params (#fields);
1726              },
1727              params,
1728            )
1729          } else {
1730            (
1731              quote! {
1732                #(#[doc = #docs])*
1733                #[derive(Clone, Debug, PartialEq, Eq)]
1734                #derive_ord
1735                #custom_derive
1736                #[derive(::codec::Encode, ::codec::Decode)]
1737                #[cfg_attr(all(feature = "std", feature = "type_info"), derive(::scale_info::TypeInfo))]
1738                #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
1739                pub struct #ty_ident #params { #fields }
1740              },
1741              params,
1742            )
1743          }
1744        }
1745        TypeDef::Variant(enum_ty) => {
1746          let mut variants = TokenStream::new();
1747          let mut runtime_events = TokenStream::new();
1748          let is_runtime_event = is_runtime_type && ident == "RuntimeEvent";
1749          for variant in enum_ty.variants() {
1750            let idx = variant.index();
1751            let docs = variant.docs();
1752            let name = variant.name();
1753            let ident = format_ident!("{}", name);
1754            let (is_tuple, fields) = self.gen_enum_fields(variant.fields(), &mut scope)?;
1755            let variant_ty = if is_runtime_event {
1756              let event_ident = format_ident!("{}Event", name);
1757              runtime_events.append_all(quote! {
1758                pub type #event_ident = #(#fields),*;
1759              });
1760              quote! {
1761                (events::#event_ident),
1762              }
1763            } else {
1764              if is_tuple {
1765                if fields.len() > 0 {
1766                  quote! { (#(#fields),*), }
1767                } else {
1768                  quote! { , }
1769                }
1770              } else {
1771                quote! {
1772                  {
1773                    #(#fields),*
1774                  },
1775                }
1776              }
1777            };
1778            variants.append_all(quote! {
1779              #(#[doc = #docs])*
1780              #[codec(index = #idx)]
1781              #ident #variant_ty
1782            });
1783          }
1784          if let Some(unused_params) = scope.get_unused_params() {
1785            variants.append_all(quote! {
1786              PhantomDataVariant(#unused_params)
1787            });
1788          }
1789          if is_runtime_event {
1790            runtime_events = quote! {
1791              pub mod events {
1792                use super::*;
1793                #runtime_events
1794              }
1795            }
1796          }
1797          let params = scope.get_type_params();
1798          (
1799            quote! {
1800              #runtime_events
1801
1802              #(#[doc = #docs])*
1803              #[derive(Clone, Debug, PartialEq, Eq)]
1804              #derive_ord
1805              #custom_derive
1806              #[derive(::codec::Encode, ::codec::Decode)]
1807              #[cfg_attr(all(feature = "std", feature = "type_info"), derive(::scale_info::TypeInfo))]
1808              #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
1809              pub enum #ty_ident #params {
1810                #variants
1811              }
1812            },
1813            params,
1814          )
1815        }
1816        _ => {
1817          return None;
1818        }
1819      };
1820
1821      let is_error_sub_type = match full_name.as_str() {
1822        "sp_runtime::TokenError" => true,
1823        "sp_runtime::TransactionalError" => true,
1824        "sp_arithmetic::ArithmeticError" => true,
1825        _ => false,
1826      };
1827      // Generate `as_static_str` for some enum types:
1828      // * Pallet types: *Call, *Event, *Error.
1829      // * Runtime types: RuntimeCall, RuntimeEvent.
1830      // * Sub error type: TokenError, TransactionalError, ArithmeticError.
1831      let gen_as_static_str = pallet_name.is_some()
1832        || (is_runtime_type && (ident == "RuntimeCall" || ident == "RuntimeEvent"))
1833        || is_error_sub_type;
1834
1835      if gen_as_static_str {
1836        if let Some(as_static_str) =
1837          self.gen_enum_as_static_str(&ty_ident, &params, ty, pallet_name)
1838        {
1839          code.append_all(as_static_str);
1840        }
1841      }
1842
1843      Some(code)
1844    }
1845
1846    fn generate_types(&self) -> TokenStream {
1847      // Start with empty namespace.
1848      let mut modules = ModuleCode::new("".into());
1849      let runtime_ns = [String::from("runtime")];
1850
1851      for ty in self.md.types.types() {
1852        let ty_id = ty.id();
1853        let ty = ty.ty();
1854        let ty_path = ty.path();
1855        let mut ty_ns = ty_path.namespace();
1856        // Only generate type code for types with namespaces.  Basic rust types like
1857        // `Result` and `Option` have no namespace.
1858        if let Some(ns_top) = ty_ns.first() {
1859          // Don't generate code for external types.
1860          if !self.external_modules.contains(ns_top) {
1861            let (ident, is_runtime_type) = match self.is_runtime_type(ty_path) {
1862              Some(name) => {
1863                ty_ns = &runtime_ns;
1864                (name, true)
1865              }
1866              None => (ty_path.ident().unwrap(), false),
1867            };
1868
1869            if let Some(code) = self.gen_type(ty_id, ty, &ident, is_runtime_type) {
1870              if ty_ns.is_empty() {
1871                // No namespace
1872                modules.add_type(ty_ns, ident, code);
1873              } else {
1874                let old_ns = ty_ns.join("::");
1875                if let Some(new_ns) = self.remap_namespaces.get(&old_ns) {
1876                  let remapped = new_ns
1877                    .split("::")
1878                    .map(|s| s.to_string())
1879                    .collect::<Vec<_>>();
1880                  modules.add_type(&remapped, ident, code);
1881                } else {
1882                  // No remap.
1883                  modules.add_type(ty_ns, ident, code);
1884                }
1885              }
1886            }
1887          }
1888        }
1889      }
1890
1891      modules.gen()
1892    }
1893
1894    pub fn generate(self) -> TokenStream {
1895      let mut call_fields = TokenStream::new();
1896      let mut query_fields = TokenStream::new();
1897      let mut paged_query_fields = TokenStream::new();
1898
1899      // Generate module code.
1900      let modules: Vec<_> = self
1901        .md
1902        .pallets
1903        .iter()
1904        .map(|m| {
1905          let (ident, call_api, query_api, paged_query_api, code) = self.gen_module(m);
1906          call_fields.append_all(quote! {
1907            pub fn #ident(&self) -> api::#ident::#call_api<'api> {
1908              api::#ident::#call_api::from(self.api)
1909            }
1910          });
1911          query_fields.append_all(quote! {
1912            pub fn #ident(&self) -> api::#ident::#query_api<'api> {
1913              api::#ident::#query_api {
1914                api: self.api,
1915                #[cfg(not(feature = "ink"))]
1916                at: self.at,
1917              }
1918            }
1919          });
1920
1921          paged_query_fields.append_all(quote! {
1922            #[cfg(not(feature = "ink"))]
1923            pub fn #ident(&self) -> api::#ident::#paged_query_api<'api> {
1924              api::#ident::#paged_query_api {
1925                api: self.api,
1926                at: self.at,
1927              }
1928            }
1929          });
1930
1931          code
1932        })
1933        .collect();
1934
1935      let types_code = self.generate_types();
1936
1937      let dispatch_info = if self.v2_weights {
1938        quote! { frame_support::dispatch::DispatchInfo }
1939      } else if self.dispatch_event_info {
1940        quote! { frame_system::DispatchEventInfo }
1941      } else {
1942        quote! { frame_support::weights::DispatchInfo }
1943      };
1944
1945      let call_ty = &self.call;
1946      let event_ty = &self.event;
1947      quote! {
1948        #[allow(dead_code, unused_imports, non_camel_case_types)]
1949        pub mod types {
1950          use super::WrappedCall;
1951          #types_code
1952        }
1953
1954        #[allow(dead_code, unused_imports, non_camel_case_types)]
1955        pub mod api {
1956          use super::types;
1957          use super::types::*;
1958          use super::WrappedCall;
1959
1960          #( #modules )*
1961        }
1962
1963        #[derive(Clone)]
1964        pub struct Api {
1965          #[cfg(not(feature = "ink"))]
1966          client: ::polymesh_api_client::Client,
1967        }
1968
1969        impl Api {
1970          #[cfg(feature = "ink")]
1971          pub fn new() -> Self {
1972            Self {}
1973          }
1974
1975          #[cfg(feature = "ink")]
1976          pub fn runtime(&self) -> ::polymesh_api_ink::extension::PolymeshRuntimeInstance {
1977            ::polymesh_api_ink::extension::new_instance()
1978          }
1979
1980          #[cfg(feature = "ink")]
1981          pub fn read_storage<T: ::codec::Decode>(&self, key: ::alloc::vec::Vec<u8>) -> ::polymesh_api_ink::error::Result<Option<T>> {
1982            let runtime = self.runtime();
1983            let value = runtime.read_storage(key.into())?
1984              .map(|data| T::decode(&mut data.as_slice()))
1985              .transpose()?;
1986            Ok(value)
1987          }
1988
1989          #[cfg(not(feature = "ink"))]
1990          pub async fn new(url: &str) -> ::polymesh_api_client::error::Result<Self> {
1991            Ok(Self {
1992              client: ::polymesh_api_client::Client::new(url).await?
1993            })
1994          }
1995
1996          pub fn call(&self) -> CallApi {
1997            CallApi { api: self }
1998          }
1999
2000          #[cfg(not(feature = "ink"))]
2001          pub fn query(&self) -> QueryApi {
2002            QueryApi { api: self, at: None }
2003          }
2004
2005          #[cfg(feature = "ink")]
2006          pub fn query(&self) -> QueryApi {
2007            QueryApi { api: self }
2008          }
2009
2010          #[cfg(not(feature = "ink"))]
2011          pub fn query_at(&self, block: ::polymesh_api_client::BlockHash) -> QueryApi {
2012            QueryApi { api: self, at: Some(block) }
2013          }
2014
2015          #[cfg(not(feature = "ink"))]
2016          pub fn paged_query(&self) -> PagedQueryApi {
2017            PagedQueryApi { api: self, at: None }
2018          }
2019
2020          #[cfg(not(feature = "ink"))]
2021          pub fn paged_query_at(&self, block: ::polymesh_api_client::BlockHash) -> PagedQueryApi {
2022            PagedQueryApi { api: self, at: Some(block) }
2023          }
2024
2025          #[cfg(not(feature = "ink"))]
2026          pub fn wrap_call(&self, call: types::#call_ty) -> ::polymesh_api_client::Result<WrappedCall> {
2027            Ok(WrappedCall::new(self, call))
2028          }
2029
2030          #[cfg(feature = "ink")]
2031          pub fn wrap_call(&self, call: ::alloc::vec::Vec<u8>) -> WrappedCall {
2032            WrappedCall::new(call)
2033          }
2034        }
2035
2036        #[cfg(not(feature = "ink"))]
2037        use alloc::boxed::Box;
2038        #[async_trait::async_trait]
2039        #[cfg(not(feature = "ink"))]
2040        impl ::polymesh_api_client::ChainApi for Api {
2041          type RuntimeCall = types::#call_ty;
2042          type RuntimeEvent = types::#event_ty;
2043          type DispatchInfo = types::#dispatch_info;
2044          type DispatchError = types::sp_runtime::DispatchError;
2045
2046          async fn get_nonce(&self, account: ::polymesh_api_client::AccountId) -> ::polymesh_api_client::Result<u32> {
2047            let info = self.query().system().account(account).await?;
2048            Ok(info.nonce)
2049          }
2050
2051          async fn block_events(&self, block: Option<::polymesh_api_client::BlockHash>) -> ::polymesh_api_client::Result<::alloc::vec::Vec<::polymesh_api_client::EventRecord<Self::RuntimeEvent>>> {
2052            let system = match block {
2053              Some(block) => self.query_at(block).system(),
2054              None => self.query().system(),
2055            };
2056            Ok(system.events().await?)
2057          }
2058
2059          fn event_to_extrinsic_result(event: &::polymesh_api_client::EventRecord<Self::RuntimeEvent>) -> Option<::polymesh_api_client::ExtrinsicResult<Self>> {
2060            match &event.event {
2061              types::#event_ty::System(types::frame_system::pallet::SystemEvent::ExtrinsicSuccess { dispatch_info }) =>
2062                Some(::polymesh_api_client::ExtrinsicResult::Success(dispatch_info.clone())),
2063              types::#event_ty::System(types::frame_system::pallet::SystemEvent::ExtrinsicFailed { dispatch_info, dispatch_error }) =>
2064                Some(::polymesh_api_client::ExtrinsicResult::Failed(dispatch_info.clone(), dispatch_error.clone())),
2065              _ => None,
2066            }
2067          }
2068
2069          fn client(&self) -> &::polymesh_api_client::Client {
2070            &self.client
2071          }
2072        }
2073
2074        #[derive(Clone)]
2075        pub struct CallApi<'api> {
2076          api: &'api Api,
2077        }
2078
2079        impl<'api> CallApi<'api> {
2080          #call_fields
2081        }
2082
2083        #[cfg(not(feature = "ink"))]
2084        pub type WrappedCall = ::polymesh_api_client::Call<Api>;
2085        #[cfg(not(feature = "ink"))]
2086        pub type TransactionResults = ::polymesh_api_client::TransactionResults<Api>;
2087
2088        #[cfg(feature = "ink")]
2089        pub type WrappedCall = ::polymesh_api_ink::Call;
2090
2091        #[cfg(not(feature = "ink"))]
2092        impl From<WrappedCall> for types::#call_ty {
2093          fn from(wrapped: WrappedCall) -> Self {
2094            wrapped.into_runtime_call()
2095          }
2096        }
2097
2098        #[cfg(not(feature = "ink"))]
2099        impl From<&WrappedCall> for types::#call_ty {
2100          fn from(wrapped: &WrappedCall) -> Self {
2101            wrapped.runtime_call().clone()
2102          }
2103        }
2104
2105        #[derive(Clone)]
2106        pub struct QueryApi<'api> {
2107          api: &'api Api,
2108          #[cfg(not(feature = "ink"))]
2109          at: Option<::polymesh_api_client::BlockHash>,
2110        }
2111
2112        impl<'api> QueryApi<'api> {
2113          #query_fields
2114        }
2115
2116        #[derive(Clone)]
2117        #[cfg(not(feature = "ink"))]
2118        pub struct PagedQueryApi<'api> {
2119          api: &'api Api,
2120          at: Option<::polymesh_api_client::BlockHash>,
2121        }
2122
2123        #[cfg(not(feature = "ink"))]
2124        impl<'api> PagedQueryApi<'api> {
2125          #paged_query_fields
2126        }
2127      }
2128    }
2129  }
2130
2131  pub fn generate(md: RuntimeMetadataV14) -> TokenStream {
2132    Generator::new(md).generate()
2133  }
2134}
2135
2136pub fn generate(metadata: RuntimeMetadataPrefixed) -> Result<TokenStream, String> {
2137  match metadata.1 {
2138    #[cfg(feature = "v14")]
2139    RuntimeMetadata::V14(v14) => Ok(v14::generate(v14)),
2140    _ => {
2141      return Err(format!("Unsupported metadata version"));
2142    }
2143  }
2144}
2145
2146pub fn macro_codegen(mut buf: &[u8], mod_ident: TokenStream) -> Result<TokenStream, String> {
2147  let metadata = RuntimeMetadataPrefixed::decode(&mut buf).map_err(|e| e.to_string())?;
2148
2149  let code = generate(metadata)?;
2150  Ok(quote! {
2151    pub mod #mod_ident {
2152      #code
2153    }
2154  })
2155}