1use std::collections::btree_map::Entry;
2
3use crate::{
4 utils::{sanity_pass, types_equal},
5 TypegenError,
6};
7
8use self::{
9 ir::module_ir::ModuleIR,
10 ir::type_ir::{CompositeFieldIR, CompositeIR, CompositeIRKind, EnumIR, TypeIR, TypeIRKind},
11 settings::{
12 derives::{Derives, FlatDerivesRegistry},
13 TypeGeneratorSettings,
14 },
15 type_params::TypeParameters,
16 type_path::{TypeParameter, TypePath, TypePathType},
17};
18
19use proc_macro2::{Ident, TokenStream};
20use quote::quote;
21use scale_info::{form::PortableForm, PortableRegistry, Type, TypeDef};
22use syn::parse_quote;
23
24pub mod error;
26pub mod ir;
28pub mod settings;
30pub mod type_params;
32pub mod type_path;
34pub mod validation;
37
38#[derive(Debug, Clone, Copy)]
40pub struct TypeGenerator<'a> {
41 type_registry: &'a PortableRegistry,
42 settings: &'a TypeGeneratorSettings,
43}
44
45impl<'a> TypeGenerator<'a> {
46 pub fn new(type_registry: &'a PortableRegistry, settings: &'a TypeGeneratorSettings) -> Self {
48 Self {
49 type_registry,
50 settings,
51 }
52 }
53
54 pub fn types_mod_ident(&self) -> &Ident {
56 &self.settings.types_mod_ident
57 }
58
59 pub fn settings(&self) -> &TypeGeneratorSettings {
61 self.settings
62 }
63
64 pub fn types(&self) -> &PortableRegistry {
66 self.type_registry
67 }
68
69 pub fn generate_types_mod(&self) -> Result<ModuleIR, TypegenError> {
71 sanity_pass(self.type_registry)?;
72
73 let flat_derives_registry = self
74 .settings
75 .derives
76 .clone()
77 .flatten_recursive_derives(self.type_registry)?;
78
79 let mut root_mod = ModuleIR::new(
80 self.settings.types_mod_ident.clone(),
81 self.settings.types_mod_ident.clone(),
82 );
83
84 for ty in &self.type_registry.types {
85 let path = &ty.ty.path;
86 if self.settings.substitutes.contains(&path.segments) {
89 continue;
90 }
91
92 let namespace = path.namespace();
93 if namespace.is_empty() {
95 continue;
96 }
97
98 let ty_id = ty.id;
100 if let Some(type_ir) = self.create_type_ir(&ty.ty, &flat_derives_registry)? {
101 let innermost_module = root_mod.get_or_insert_submodule(namespace);
103 match innermost_module.types.entry(path.clone()) {
104 Entry::Vacant(e) => {
105 e.insert((ty_id, type_ir));
106 }
107 Entry::Occupied(e) => {
108 let other_ty_id = e.get().0;
112 if !types_equal(ty_id, other_ty_id, self.type_registry) {
113 return Err(TypegenError::DuplicateTypePath(ty.ty.path.to_string()));
114 }
115 }
116 };
117 }
118 }
119
120 Ok(root_mod)
121 }
122
123 pub fn create_type_ir(
125 &self,
126 ty: &Type<PortableForm>,
127 flat_derives_registry: &FlatDerivesRegistry,
128 ) -> Result<Option<TypeIR>, TypegenError> {
129 if !matches!(ty.type_def, TypeDef::Composite(_) | TypeDef::Variant(_)) {
131 return Ok(None);
132 }
133
134 let mut type_params = TypeParameters::from_scale_info(&ty.type_params);
135
136 let name = ty
137 .path
138 .ident()
139 .map(|e| syn::parse_str::<Ident>(&e))
140 .expect(
141 "Structs and enums should have a name. Checked with namespace.is_empty() above. qed;",
142 )?;
143
144 let docs = self.docs_from_scale_info(&ty.docs);
145
146 let mut could_derive_as_compact: bool = false;
147 let kind = match &ty.type_def {
148 TypeDef::Composite(composite) => {
149 let kind = self.create_composite_ir_kind(&composite.fields, &mut type_params)?;
150
151 if kind.could_derive_as_compact() {
152 could_derive_as_compact = true;
153 }
154
155 TypeIRKind::Struct(CompositeIR { name, kind, docs })
156 }
157 TypeDef::Variant(variant) => {
158 let variants = variant
159 .variants
160 .iter()
161 .map(|v| {
162 let name = syn::parse_str::<Ident>(&v.name)?;
163 let kind = self.create_composite_ir_kind(&v.fields, &mut type_params)?;
164 let docs = self.docs_from_scale_info(&v.docs);
165 Ok((v.index, CompositeIR { kind, name, docs }))
166 })
167 .collect::<Result<Vec<(u8, CompositeIR)>, TypegenError>>()?;
168 TypeIRKind::Enum(EnumIR {
169 name,
170 variants,
171 docs,
172 })
173 }
174 _ => unreachable!("Other variants early return before. qed."),
175 };
176
177 let mut derives = flat_derives_registry.resolve_derives_for_type(ty)?;
178 if could_derive_as_compact {
179 self.add_as_compact_derive(&mut derives);
180 }
181
182 let type_ir = TypeIR {
183 kind,
184 derives,
185 type_params,
186 insert_codec_attributes: self.settings.insert_codec_attributes,
187 };
188 Ok(Some(type_ir))
189 }
190
191 pub fn docs_from_scale_info(&self, docs: &[String]) -> TokenStream {
193 self.settings
194 .should_gen_docs
195 .then_some(quote! { #( #[doc = #docs ] )* })
196 .unwrap_or_default()
197 }
198
199 pub fn create_composite_ir_kind(
201 &self,
202 fields: &[scale_info::Field<PortableForm>],
203 type_params: &mut TypeParameters,
204 ) -> Result<CompositeIRKind, TypegenError> {
205 if fields.is_empty() {
206 return Ok(CompositeIRKind::NoFields);
207 }
208
209 let all_fields_named = fields.iter().all(|f| f.name.is_some());
210 let all_fields_unnamed = fields.iter().all(|f| f.name.is_none());
211
212 if !(all_fields_named || all_fields_unnamed) {
213 return Err(TypegenError::InvalidFields(format!("{:?}", fields)));
214 }
215
216 if all_fields_named {
217 let named_fields = fields
218 .iter()
219 .map(|field| {
220 let field_name = field.name.as_ref().unwrap();
221 let ident = syn::parse_str::<Ident>(field_name)?;
222
223 let path = self.resolve_field_type_path(
224 field.ty.id,
225 type_params.params(),
226 field.type_name.as_deref(),
227 )?;
228 let is_compact = path.is_compact();
229 let is_boxed = field
230 .type_name
231 .as_ref()
232 .map(|e| e.contains("Box<"))
233 .unwrap_or_default();
234
235 for param in path.parent_type_params().iter() {
236 type_params.mark_used(param);
237 }
238
239 Ok((ident, CompositeFieldIR::new(path, is_compact, is_boxed)))
240 })
241 .collect::<Result<Vec<(Ident, CompositeFieldIR)>, TypegenError>>()?;
242 Ok(CompositeIRKind::Named(named_fields))
243 } else if all_fields_unnamed {
244 let unnamed_fields = fields
245 .iter()
246 .map(|field| {
247 let path = self.resolve_field_type_path(
248 field.ty.id,
249 type_params.params(),
250 field.type_name.as_deref(),
251 )?;
252
253 let is_compact = path.is_compact();
254 let is_boxed = field
255 .type_name
256 .as_ref()
257 .map(|e| e.contains("Box<"))
258 .unwrap_or_default();
259
260 for param in path.parent_type_params().iter() {
261 type_params.mark_used(param);
262 }
263
264 Ok(CompositeFieldIR::new(path, is_compact, is_boxed))
265 })
266 .collect::<Result<Vec<CompositeFieldIR>, TypegenError>>()?;
267 Ok(CompositeIRKind::Unnamed(unnamed_fields))
268 } else {
269 unreachable!("Is either all unnamed or all named. qed.")
270 }
271 }
272
273 pub fn upcast_composite(&self, composite: &CompositeIR) -> TypeIR {
276 let mut derives = self.settings.derives.default_derives().clone();
278 if composite.kind.could_derive_as_compact() {
279 self.add_as_compact_derive(&mut derives)
280 }
281 TypeIR {
282 type_params: TypeParameters::from_scale_info(&[]),
283 derives,
284 insert_codec_attributes: self.settings.insert_codec_attributes,
285 kind: TypeIRKind::Struct(composite.clone()),
286 }
287 }
288
289 fn add_as_compact_derive(&self, derives: &mut Derives) {
291 if let Some(compact_as_type_path) = &self.settings.compact_as_type_path {
292 derives.insert_derive(parse_quote!(#compact_as_type_path));
293 }
294 }
295
296 pub fn resolve_field_type_path(
309 &self,
310 id: u32,
311 parent_type_params: &[TypeParameter],
312 original_name: Option<&str>,
313 ) -> Result<TypePath, TypegenError> {
314 self.resolve_type_path_recurse(id, true, parent_type_params, original_name)
315 }
316
317 pub fn resolve_type_path(&self, id: u32) -> Result<TypePath, TypegenError> {
319 self.resolve_type_path_recurse(id, false, &[], None)
320 }
321
322 fn resolve_type_path_recurse(
328 &self,
329 id: u32,
330 is_field: bool,
331 parent_type_params: &[TypeParameter],
332 original_name: Option<&str>,
333 ) -> Result<TypePath, TypegenError> {
334 if let Some(parent_type_param) = parent_type_params.iter().find(|tp| {
335 tp.concrete_type_id == id
336 && original_name.is_none_or(|original_name| tp.original_name == original_name)
337 }) {
338 let type_path = TypePath::from_parameter(parent_type_param.clone());
339 return Ok(type_path);
340 }
341
342 let mut ty = self.resolve_type(id)?;
343
344 if ty.path.ident() == Some("Cow".to_string()) {
345 let inner_ty_id = ty.type_params[0]
346 .ty
347 .ok_or_else(|| {
348 TypegenError::InvalidType(
349 "type parameters to Cow are not expected to be skipped".into(),
350 )
351 })?
352 .id;
353 ty = self.resolve_type(inner_ty_id)?
354 }
355
356 let params: Vec<TypePath> = ty
357 .type_params
358 .iter()
359 .filter_map(|f| {
360 f.ty.map(|f| self.resolve_type_path_recurse(f.id, false, parent_type_params, None))
361 })
362 .collect::<Result<Vec<TypePath>, TypegenError>>()?;
363
364 let ty = match &ty.type_def {
365 TypeDef::Composite(_) | TypeDef::Variant(_) => {
366 self.type_path_maybe_with_substitutes(&ty.path, ¶ms)
367 }
368 TypeDef::Primitive(primitive) => TypePathType::Primitive {
369 def: primitive.clone(),
370 },
371 TypeDef::Array(arr) => {
372 let inner_type = self.resolve_type_path_recurse(
373 arr.type_param.id,
374 false,
375 parent_type_params,
376 None,
377 )?;
378 TypePathType::Array {
379 len: arr.len as usize,
380 of: Box::new(inner_type),
381 }
382 }
383 TypeDef::Sequence(seq) => {
384 let inner_type = self.resolve_type_path_recurse(
385 seq.type_param.id,
386 false,
387 parent_type_params,
388 None,
389 )?;
390 TypePathType::Vec {
391 of: Box::new(inner_type),
392 }
393 }
394 TypeDef::Tuple(tuple) => {
395 let elements = tuple
396 .fields
397 .iter()
398 .map(|f| self.resolve_type_path_recurse(f.id, false, parent_type_params, None))
399 .collect::<Result<Vec<TypePath>, TypegenError>>()?;
400
401 TypePathType::Tuple { elements }
402 }
403 TypeDef::Compact(compact) => {
404 let inner_type = self.resolve_type_path_recurse(
405 compact.type_param.id,
406 false,
407 parent_type_params,
408 None,
409 )?;
410
411 let compact_type_path = self
412 .settings
413 .compact_type_path
414 .as_ref()
415 .ok_or(TypegenError::CompactPathNone)?
416 .clone();
417
418 TypePathType::Compact {
419 inner: Box::new(inner_type),
420 is_field,
421 compact_type_path,
422 }
423 }
424 TypeDef::BitSequence(bitseq) => {
425 let decoded_bits_type_path = self
426 .settings
427 .decoded_bits_type_path
428 .as_ref()
429 .ok_or(TypegenError::DecodedBitsPathNone)?
430 .clone();
431
432 let bit_order_type = self.resolve_type_path_recurse(
433 bitseq.bit_order_type.id,
434 false,
435 parent_type_params,
436 None,
437 )?;
438
439 let bit_store_type = self.resolve_type_path_recurse(
440 bitseq.bit_store_type.id,
441 false,
442 parent_type_params,
443 None,
444 )?;
445
446 TypePathType::BitVec {
447 bit_order_type: Box::new(bit_order_type),
448 bit_store_type: Box::new(bit_store_type),
449 decoded_bits_type_path,
450 }
451 }
452 };
453 Ok(TypePath::from_type(ty))
454 }
455
456 pub fn type_path_maybe_with_substitutes(
458 &self,
459 path: &scale_info::Path<PortableForm>,
460 params: &[TypePath],
461 ) -> TypePathType {
462 if let Some(substitute) =
463 self.settings
464 .substitutes
465 .for_path_with_params(&path.segments, params, self.settings)
466 {
467 substitute
468 } else {
469 TypePathType::from_type_def_path(
470 path,
471 self.settings.types_mod_ident.clone(),
472 params.to_vec(),
473 &self.settings.alloc_crate_path,
474 )
475 }
476 }
477
478 pub fn resolve_type(&self, id: u32) -> Result<&Type<PortableForm>, TypegenError> {
480 let ty = self
481 .type_registry
482 .resolve(id)
483 .ok_or(TypegenError::TypeNotFound(id))?;
484 Ok(ty)
485 }
486}