pop_chains/call/metadata/
params.rs1use crate::errors::Error;
4use pop_common::format_type;
5use scale_info::{Field, PortableRegistry, TypeDef, form::PortableForm};
6use subxt::Metadata;
7
8#[derive(Clone, Debug, Default, Eq, PartialEq)]
10pub struct Param {
11 pub name: String,
13 pub type_name: String,
15 pub sub_params: Vec<Param>,
17 pub is_optional: bool,
19 pub is_tuple: bool,
21 pub is_variant: bool,
23 pub is_sequence: bool,
25}
26
27pub fn field_to_param(metadata: &Metadata, field: &Field<PortableForm>) -> Result<Param, Error> {
33 let registry = metadata.types();
34 if let Some(name) = field.type_name.as_deref() &&
35 name.contains("RuntimeCall")
36 {
37 return Err(Error::CallableNotSupported);
38 }
39 let name = field.name.as_deref().unwrap_or("Unnamed"); type_to_param(name, registry, field.ty.id)
41}
42
43pub fn type_to_param(
50 name: &str,
51 registry: &PortableRegistry,
52 type_id: u32,
53) -> Result<Param, Error> {
54 let type_info = registry
55 .resolve(type_id)
56 .ok_or_else(|| Error::MetadataParsingError(name.to_string()))?;
57 if type_info.path.segments.contains(&"RuntimeCall".to_string()) {
59 return Err(Error::CallableNotSupported);
60 }
61 for param in &type_info.type_params {
62 if param.name.contains("RuntimeCall") {
63 return Err(Error::CallableNotSupported);
64 }
65 }
66 if type_info.path.segments == ["Option"] {
67 if let Some(sub_type_id) = type_info.type_params.first().and_then(|param| param.ty) {
68 let sub_param = type_to_param(name, registry, sub_type_id.id)?;
70 Ok(Param {
71 name: name.to_string(),
72 type_name: sub_param.type_name,
73 sub_params: sub_param.sub_params,
74 is_optional: true,
75 ..Default::default()
76 })
77 } else {
78 Err(Error::MetadataParsingError(name.to_string()))
79 }
80 } else {
81 let type_name = format_type(type_info, registry);
83 match &type_info.type_def {
84 TypeDef::Primitive(_) | TypeDef::Array(_) | TypeDef::Compact(_) =>
85 Ok(Param { name: name.to_string(), type_name, ..Default::default() }),
86 TypeDef::Composite(composite) => {
87 let sub_params = composite
88 .fields
89 .iter()
90 .map(|field| {
91 type_to_param(field.name.as_deref().unwrap_or(name), registry, field.ty.id)
93 })
94 .collect::<Result<Vec<Param>, Error>>()?;
95
96 Ok(Param { name: name.to_string(), type_name, sub_params, ..Default::default() })
97 },
98 TypeDef::Variant(variant) => {
99 let variant_params = variant
100 .variants
101 .iter()
102 .map(|variant_param| {
103 let variant_sub_params = variant_param
104 .fields
105 .iter()
106 .map(|field| {
107 type_to_param(
109 field.name.as_deref().unwrap_or(&variant_param.name),
110 registry,
111 field.ty.id,
112 )
113 })
114 .collect::<Result<Vec<Param>, Error>>()?;
115 Ok(Param {
116 name: variant_param.name.clone(),
117 type_name: "".to_string(),
118 sub_params: variant_sub_params,
119 is_variant: true,
120 ..Default::default()
121 })
122 })
123 .collect::<Result<Vec<Param>, Error>>()?;
124
125 Ok(Param {
126 name: name.to_string(),
127 type_name,
128 sub_params: variant_params,
129 is_variant: true,
130 ..Default::default()
131 })
132 },
133 TypeDef::Sequence(_) => Ok(Param {
134 name: name.to_string(),
135 type_name,
136 is_sequence: true,
137 ..Default::default()
138 }),
139 TypeDef::Tuple(tuple) => {
140 let sub_params = tuple
141 .fields
142 .iter()
143 .enumerate()
144 .map(|(index, field_id)| {
145 type_to_param(
146 &format!("Index {index} of the tuple {name}"),
147 registry,
148 field_id.id,
149 )
150 })
151 .collect::<Result<Vec<Param>, Error>>()?;
152
153 Ok(Param {
154 name: name.to_string(),
155 type_name,
156 sub_params,
157 is_tuple: true,
158 ..Default::default()
159 })
160 },
161 _ => Err(Error::MetadataParsingError(name.to_string())),
162 }
163 }
164}