1use self::generics_list::GenericsList;
2use scale_info::{form::PortableForm, Field, PortableRegistry, Type, TypeDef};
3use std::collections::{HashMap, HashSet};
4
5use crate::TypegenError;
6
7pub fn syn_type_path(ty: &Type<PortableForm>) -> Result<syn::TypePath, TypegenError> {
9 let joined_path = ty.path.segments.join("::");
10 let ty_path: syn::TypePath =
11 syn::parse_str::<syn::TypePath>(&joined_path).map_err(|e| TypegenError::SynParseError {
12 string: joined_path,
13 target: core::any::type_name::<syn::TypePath>(),
14 error: e,
15 })?;
16 Ok(ty_path)
17}
18
19pub(crate) fn sanity_pass(types: &PortableRegistry) -> Result<(), TypegenError> {
20 for (idx, ty) in types.types.iter().enumerate() {
21 let idx = idx as u32;
22 if ty.id != idx {
23 return Err(TypegenError::RegistryTypeIdsInvalid {
24 given_ty_id: ty.id,
25 expected_ty_id: idx,
26 ty_def: format!("{:#?}", ty.ty),
27 });
28 }
29 }
30 Ok(())
31}
32
33pub fn ensure_unique_type_paths(types: &mut PortableRegistry) -> Result<(), TypegenError> {
35 sanity_pass(types)?;
36 let mut types_with_same_type_path_grouped_by_shape = HashMap::<&[String], Vec<Vec<u32>>>::new();
37
38 for (ty_idx, ty) in types.types.iter().enumerate() {
40 let ty_idx = ty_idx as u32;
45 let ty = &ty.ty;
46
47 if ty.path.namespace().is_empty() {
49 continue;
50 };
51
52 let groups_with_same_path = types_with_same_type_path_grouped_by_shape
54 .entry(&ty.path.segments)
55 .or_default();
56
57 let mut added_to_existing_group = false;
59 for group in groups_with_same_path.iter_mut() {
60 let other_ty_in_group_idx = group[0]; if types_equal(ty_idx, other_ty_in_group_idx, types) {
62 group.push(ty_idx);
63 added_to_existing_group = true;
64 break;
65 }
66 }
67
68 if !added_to_existing_group {
70 groups_with_same_path.push(vec![ty_idx])
71 }
72 }
73
74 let groups_that_need_renaming = types_with_same_type_path_grouped_by_shape
76 .into_values()
77 .filter(|g| g.len() > 1)
78 .collect::<Vec<_>>(); for groups_with_same_path in groups_that_need_renaming {
81 let mut n = 1;
82 for group_with_same_shape in groups_with_same_path {
83 for ty_id in group_with_same_shape {
84 let ty = types
85 .types
86 .get_mut(ty_id as usize)
87 .expect("type is present (2); qed;");
88 let name = ty.ty.path.segments.last_mut().expect("This is only empty for builtin types, that are filtered out with namespace().is_empty() above; qed;");
89 *name = format!("{name}{n}"); }
91 n += 1;
92 }
93 }
94 Ok(())
95}
96
97pub(crate) fn types_equal(a: u32, b: u32, types: &PortableRegistry) -> bool {
107 let mut a_visited = HashSet::new();
108 let mut b_visited = HashSet::new();
109 types_equal_inner(
110 a,
111 &GenericsList::empty(),
112 &mut a_visited,
113 b,
114 &GenericsList::empty(),
115 &mut b_visited,
116 types,
117 )
118}
119
120fn types_equal_inner(
122 a: u32,
123 a_parent_params: &GenericsList,
124 a_visited: &mut HashSet<u32>,
125 b: u32,
126 b_parent_params: &GenericsList,
127 b_visited: &mut HashSet<u32>,
128 types: &PortableRegistry,
129) -> bool {
130 if a == b {
132 return true;
133 }
134
135 let seen_a = !a_visited.insert(a);
137 let seen_b = !b_visited.insert(b);
138
139 if seen_a != seen_b {
142 return false;
143 }
144
145 if seen_a && seen_b {
148 return true;
149 }
150
151 let a_generic_idx = a_parent_params.index_for_type_id(a);
153 let b_generic_idx = b_parent_params.index_for_type_id(b);
154
155 let a_ty = types.resolve(a).expect("type a should exist in registry");
156 let b_ty = types.resolve(b).expect("type b should exist in registry");
157
158 let mut types_equal_recurse =
160 |a: u32, a_params: &GenericsList, b: u32, b_params: &GenericsList| -> bool {
161 types_equal_inner(a, a_params, a_visited, b, b_params, b_visited, types)
162 };
163
164 let calc_params = || {
166 let a_params = a_parent_params.extend(&a_ty.type_params);
167 let b_params = b_parent_params.extend(&b_ty.type_params);
168 (a_params, b_params)
169 };
170
171 if let (Some(a_idx), Some(b_idx)) = (a_generic_idx, b_generic_idx) {
175 if a_idx == b_idx {
176 return true;
177 }
178 }
179
180 if a_ty.path.segments != b_ty.path.segments {
182 return false;
183 }
184
185 #[rustfmt::skip]
186 let mut compare_fields = |
187 a: &Field<PortableForm>,
188 a_params: &GenericsList,
189 b: &Field<PortableForm>,
190 b_params: &GenericsList
191 | -> bool {
192 if a.name != b.name {
193 return false;
194 }
195
196 let ty_is_skipped_or_wrapped = a_params
199 .index_for_type_id(a.ty.id)
200 .zip(b_params.index_for_type_id(b.ty.id))
201 .is_none();
202
203 match (&a.type_name, &b.type_name) {
205 (Some(a_type_name), Some(b_type_name)) if !ty_is_skipped_or_wrapped => {
206 a_params
208 .index_for_type_name(a_type_name)
209 .zip(b_params.index_for_type_name(b_type_name))
210 .is_some_and(|(a, b)| a == b)
211 }
212 _ => types_equal_recurse(a.ty.id, a_params, b.ty.id, b_params),
213 }
214 };
215
216 #[rustfmt::skip]
218 let mut fields_equal = |
219 a: &[Field<PortableForm>],
220 a_params: &GenericsList,
221 b: &[Field<PortableForm>],
222 b_params: &GenericsList,
223 | -> bool {
224 if a.len() != b.len() {
225 return false;
226 }
227 a.iter().zip(b.iter()).all(|(a, b)| {
228 compare_fields(a, a_params, b, b_params)
229 })
230 };
231
232 match (&a_ty.type_def, &b_ty.type_def) {
234 (TypeDef::Composite(a), TypeDef::Composite(b)) => {
235 let (a_params, b_params) = calc_params();
236 fields_equal(&a.fields, &a_params, &b.fields, &b_params)
237 }
238 (TypeDef::Variant(a), TypeDef::Variant(b)) => {
239 let (a_params, b_params) = calc_params();
240 a.variants.len() == b.variants.len()
241 && a.variants.iter().zip(b.variants.iter()).all(|(a, b)| {
242 a.name == b.name && fields_equal(&a.fields, &a_params, &b.fields, &b_params)
243 })
244 }
245 (TypeDef::Sequence(a), TypeDef::Sequence(b)) => {
246 let (a_params, b_params) = calc_params();
247 types_equal_recurse(a.type_param.id, &a_params, b.type_param.id, &b_params)
248 }
249 (TypeDef::Array(a), TypeDef::Array(b)) => {
250 let (a_params, b_params) = calc_params();
251 a.len == b.len
252 && types_equal_recurse(a.type_param.id, &a_params, b.type_param.id, &b_params)
253 }
254 (TypeDef::Tuple(a), TypeDef::Tuple(b)) => {
255 let (a_params, b_params) = calc_params();
256 a.fields.len() == b.fields.len()
257 && a.fields
258 .iter()
259 .zip(b.fields.iter())
260 .all(|(a, b)| types_equal_recurse(a.id, &a_params, b.id, &b_params))
261 }
262 (TypeDef::Primitive(a), TypeDef::Primitive(b)) => a == b,
263 (TypeDef::Compact(a), TypeDef::Compact(b)) => {
264 let (a_params, b_params) = calc_params();
265 types_equal_recurse(a.type_param.id, &a_params, b.type_param.id, &b_params)
266 }
267 (TypeDef::BitSequence(a), scale_info::TypeDef::BitSequence(b)) => {
268 let (a_params, b_params) = calc_params();
269 let order_equal = types_equal_recurse(
270 a.bit_order_type.id,
271 &a_params,
272 b.bit_order_type.id,
273 &b_params,
274 );
275 let store_equal = types_equal_recurse(
276 a.bit_store_type.id,
277 &a_params,
278 b.bit_store_type.id,
279 &b_params,
280 );
281 order_equal && store_equal
282 }
283 _ => false,
285 }
286}
287
288mod generics_list {
291 use scale_info::{form::PortableForm, TypeParameter};
292 use std::rc::Rc;
293
294 #[derive(Clone, Debug)]
298 pub struct GenericsList {
299 inner: Rc<GenericsListInner>,
300 }
301
302 #[derive(Clone, Debug)]
303 struct GenericsListInner {
304 previous: Option<GenericsList>,
305 start_idx: usize,
306 generics_by_id: Vec<(u32, String)>,
307 }
308
309 impl GenericsList {
310 pub fn index_for_type_id(&self, type_id: u32) -> Option<usize> {
312 let maybe_index = self
313 .inner
314 .generics_by_id
315 .iter()
316 .position(|(id, _)| *id == type_id)
317 .map(|index| self.inner.start_idx + index);
318
319 maybe_index.or_else(|| {
321 self.inner
322 .previous
323 .as_ref()
324 .and_then(|prev| prev.index_for_type_id(type_id))
325 })
326 }
327 pub fn index_for_type_name(&self, name: &str) -> Option<usize> {
329 let maybe_index = self
330 .inner
331 .generics_by_id
332 .iter()
333 .position(|(_, type_name)| *type_name == name)
334 .map(|index| self.inner.start_idx + index);
335
336 maybe_index.or_else(|| {
338 self.inner
339 .previous
340 .as_ref()
341 .and_then(|prev| prev.index_for_type_name(name))
342 })
343 }
344
345 pub fn empty() -> Self {
347 Self::new_inner(None, &[])
348 }
349
350 pub fn extend(&self, params: &[TypeParameter<PortableForm>]) -> Self {
352 Self::new_inner(Some(self.clone()), params)
353 }
354
355 fn new_inner(
356 maybe_self: Option<GenericsList>,
357 params: &[TypeParameter<PortableForm>],
358 ) -> Self {
359 let generics_by_id = params
360 .iter()
361 .filter_map(|p| p.ty.map(|ty| (ty.id, p.name.clone())))
362 .collect();
363
364 let start_idx = match &maybe_self {
365 Some(list) => list.inner.start_idx + list.inner.generics_by_id.len(),
366 None => 0,
367 };
368
369 GenericsList {
370 inner: Rc::new(GenericsListInner {
371 previous: maybe_self,
372 start_idx,
373 generics_by_id,
374 }),
375 }
376 }
377 }
378}
379
380#[cfg(test)]
381mod tests {
382 use crate::typegen::ir::ToTokensWithSettings;
383 use pretty_assertions::assert_eq;
384
385 use super::*;
386 use quote::quote;
387 use scale_info::{
388 meta_type, Field, Path, PortableRegistry, TypeDef, TypeDefComposite, TypeInfo,
389 TypeParameter,
390 };
391
392 #[test]
393 fn associated_types_are_properly_deduplicated() {
394 trait X {
395 type Assoc;
396 }
397 struct A;
398 impl X for A {
399 type Assoc = u8;
400 }
401 struct B;
402 impl X for B {
403 type Assoc = u32;
404 }
405
406 #[derive(TypeInfo)]
407 #[scale_info(skip_type_params(T))] struct Foo<T: X> {
409 _field: T::Assoc,
410 }
411
412 #[allow(unused)]
413 #[derive(TypeInfo)]
414 struct Bar {
415 p: Foo<A>,
416 q: Foo<B>,
417 }
418
419 let mut registry = scale_info::Registry::new();
420 let _ = registry.register_type(&scale_info::meta_type::<Bar>()).id;
421 let mut registry = scale_info::PortableRegistry::from(registry);
422
423 ensure_unique_type_paths(&mut registry).expect("Corrupted PortableRegistry");
424
425 let settings = crate::TypeGeneratorSettings::new();
426 let generated = crate::typegen::ir::ToTokensWithSettings::to_token_stream(
427 &crate::TypeGenerator::new(®istry, &settings)
428 .generate_types_mod()
429 .unwrap(),
430 &settings,
431 );
432
433 let expected = quote!(
434 pub mod types {
435 use super::types;
436 pub mod scale_typegen {
437 use super::types;
438 pub mod utils {
439 use super::types;
440 pub mod tests {
441 use super::types;
442 pub struct Bar {
443 pub p: types::scale_typegen::utils::tests::Foo1,
444 pub q: types::scale_typegen::utils::tests::Foo2,
445 }
446 pub struct Foo1 {
447 pub _field: ::core::primitive::u8,
448 }
449 pub struct Foo2 {
450 pub _field: ::core::primitive::u32,
451 }
452 }
453 }
454 }
455 }
456 );
457
458 assert_eq!(expected.to_string(), generated.to_string());
459 }
460
461 #[test]
462 fn generics_unification() {
463 macro_rules! nested_type {
464 ($ty:ident, $generic:ty, $inner:ty) => {
465 struct $ty;
466 impl scale_info::TypeInfo for $ty {
467 type Identity = Self;
468 fn type_info() -> scale_info::Type {
469 scale_info::Type {
470 path: Path::new("ParamType", "my::module"),
471 type_params: vec![TypeParameter::new(
472 "T",
473 Some(meta_type::<$generic>()),
474 )],
475 type_def: TypeDef::Composite(TypeDefComposite::new([Field::new(
476 None,
477 meta_type::<$inner>(),
478 Some("T"),
479 Vec::new(),
480 )])),
481 docs: vec![],
482 }
483 }
484 }
485 };
486 }
487
488 struct A;
489 impl scale_info::TypeInfo for A {
490 type Identity = Self;
491 fn type_info() -> scale_info::Type {
492 scale_info::Type {
493 path: Path::new("NestedType", "my::module"),
494 type_params: vec![
495 TypeParameter::new("T", Some(meta_type::<u8>())),
496 TypeParameter::new("U", Some(meta_type::<u16>())),
497 TypeParameter::new("V", Some(meta_type::<u32>())),
498 ],
499 type_def: TypeDef::Composite(TypeDefComposite::new([
500 Field::new(None, meta_type::<u8>(), Some("T"), Vec::new()),
501 Field::new(None, meta_type::<u16>(), Some("U"), Vec::new()),
502 Field::new(None, meta_type::<u32>(), Some("V"), Vec::new()),
503 ])),
504 docs: vec![],
505 }
506 }
507 }
508
509 struct B;
510 impl scale_info::TypeInfo for B {
511 type Identity = Self;
512 fn type_info() -> scale_info::Type {
513 scale_info::Type {
514 path: Path::new("NestedType", "my::module"),
515 type_params: vec![
516 TypeParameter::new("T", Some(meta_type::<u8>())),
517 TypeParameter::new("U", Some(meta_type::<u16>())),
518 TypeParameter::new("V", Some(meta_type::<u32>())),
519 ],
520 type_def: TypeDef::Composite(TypeDefComposite::new([
521 Field::new(None, meta_type::<u32>(), Some("V"), Vec::new()),
522 Field::new(None, meta_type::<u16>(), Some("U"), Vec::new()),
523 Field::new(None, meta_type::<u8>(), Some("T"), Vec::new()),
524 ])),
525 docs: vec![],
526 }
527 }
528 }
529 struct BB;
530 impl scale_info::TypeInfo for BB {
531 type Identity = Self;
532 fn type_info() -> scale_info::Type {
533 scale_info::Type {
534 path: Path::new("NestedType", "my::module"),
535 type_params: vec![
536 TypeParameter::new("V", Some(meta_type::<u8>())),
537 TypeParameter::new("U", Some(meta_type::<u16>())),
538 TypeParameter::new("T", Some(meta_type::<u32>())),
539 ],
540 type_def: TypeDef::Composite(TypeDefComposite::new([
541 Field::new(None, meta_type::<u32>(), Some("T"), Vec::new()),
542 Field::new(None, meta_type::<u16>(), Some("U"), Vec::new()),
543 Field::new(None, meta_type::<u8>(), Some("V"), Vec::new()),
544 ])),
545 docs: vec![],
546 }
547 }
548 }
549
550 struct C;
551 impl scale_info::TypeInfo for C {
552 type Identity = Self;
553 fn type_info() -> scale_info::Type {
554 scale_info::Type {
555 path: Path::new("NestedType", "my::module"),
556 type_params: vec![
557 TypeParameter::new("A", Some(meta_type::<u8>())),
558 TypeParameter::new("D", Some(meta_type::<u16>())),
559 TypeParameter::new("B", Some(meta_type::<u32>())),
560 ],
561 type_def: TypeDef::Composite(TypeDefComposite::new([
562 Field::new(None, meta_type::<u8>(), Some("A"), Vec::new()),
563 Field::new(None, meta_type::<u16>(), Some("D"), Vec::new()),
564 Field::new(None, meta_type::<u32>(), Some("B"), Vec::new()),
565 ])),
566 docs: vec![],
567 }
568 }
569 }
570
571 struct D;
572 impl scale_info::TypeInfo for D {
573 type Identity = Self;
574 fn type_info() -> scale_info::Type {
575 scale_info::Type {
576 path: Path::new("Foo", "my::module"),
577 type_params: vec![TypeParameter::new("A", Some(meta_type::<u8>()))],
578 type_def: TypeDef::Composite(TypeDefComposite::new([Field::new(
579 None,
580 meta_type::<u8>(),
581 Some("A"),
582 Vec::new(),
583 )])),
584 docs: vec![],
585 }
586 }
587 }
588 struct E;
589 impl scale_info::TypeInfo for E {
590 type Identity = Self;
591 fn type_info() -> scale_info::Type {
592 scale_info::Type {
593 path: Path::new("Foo", "my::module"),
594 type_params: vec![TypeParameter::new("B", Some(meta_type::<u16>()))],
595 type_def: TypeDef::Composite(TypeDefComposite::new([Field::new(
596 None,
597 meta_type::<u16>(),
598 Some("B"),
599 Vec::new(),
600 )])),
601 docs: vec![],
602 }
603 }
604 }
605
606 let mut registry = scale_info::Registry::new();
607 let id_b = registry.register_type(&meta_type::<B>()).id;
608 let id_bb = registry.register_type(&meta_type::<BB>()).id;
609 let id_a = registry.register_type(&meta_type::<A>()).id;
610 let id_c = registry.register_type(&meta_type::<C>()).id;
611
612 let id_d = registry.register_type(&meta_type::<D>()).id;
613 let id_e = registry.register_type(&meta_type::<E>()).id;
614
615 nested_type!(Y, A, A);
616 nested_type!(W, B, B);
617 nested_type!(Z, C, C);
618
619 let id_y = registry.register_type(&meta_type::<Y>()).id;
620 let id_w = registry.register_type(&meta_type::<W>()).id;
621 let id_z = registry.register_type(&meta_type::<Z>()).id;
622
623 let mut registry = PortableRegistry::from(registry);
624
625 assert!(!types_equal(id_a, id_b, ®istry));
627 assert!(!types_equal(id_a, id_bb, ®istry));
628
629 assert!(types_equal(id_a, id_c, ®istry));
631
632 assert!(types_equal(id_d, id_e, ®istry));
634
635 assert!(types_equal(id_w, id_y, ®istry));
636 assert!(types_equal(id_z, id_y, ®istry));
637
638 ensure_unique_type_paths(&mut registry).expect("Corrupted PortableRegistry");
639 let settings = crate::TypeGeneratorSettings::new();
640 let output = crate::TypeGenerator::new(®istry, &settings)
641 .generate_types_mod()
642 .unwrap()
643 .to_token_stream(&settings);
644
645 let expected = quote! {
646 pub mod types {
647 use super::types;
648 pub mod my {
649 use super::types;
650 pub mod module {
651 use super::types;
652 pub struct Foo<_0>(pub _0, );
653 pub struct NestedType1<_0, _1, _2>(pub _2, pub _1, pub _0, );
654 pub struct NestedType2<_0, _1, _2>(pub _0, pub _1, pub _2, );
655 pub struct ParamType < _0 > (pub _0 ,) ;
656 }
657 }
658 }
659 };
660
661 assert_eq!(expected.to_string(), output.to_string())
662 }
663
664 #[test]
665 fn recursive_data() {
666 #[derive(TypeInfo)]
667 #[allow(dead_code)]
668 pub enum Test<A> {
669 None,
670 Many { inner: Vec<Self> },
671 Param(A),
672 }
673
674 #[derive(TypeInfo)]
675 #[allow(dead_code)]
676 pub struct TestStruct<A> {
677 param: A,
678 inner: Vec<Self>,
679 }
680
681 #[derive(TypeInfo)]
682 #[allow(dead_code)]
683 pub struct Foo<T> {
684 inner: Vec<T>,
685 }
686
687 #[derive(TypeInfo)]
688 #[allow(dead_code)]
689 pub enum FooEnum<T> {
690 None,
691 Go(Vec<T>),
692 }
693
694 let mut registry = scale_info::Registry::new();
695 let id_a = registry.register_type(&meta_type::<Test<u8>>()).id;
696 let id_b = registry.register_type(&meta_type::<Test<u32>>()).id;
697
698 let id_foo = registry.register_type(&meta_type::<Foo<u32>>()).id;
699
700 let id_foo_foo = registry
701 .register_type(&meta_type::<Foo<Foo<TestStruct<u32>>>>())
702 .id;
703
704 let id_foo_enum = registry.register_type(&meta_type::<FooEnum<u32>>()).id;
705 let id_foo_foo_enum = registry
706 .register_type(&meta_type::<FooEnum<FooEnum<TestStruct<u32>>>>())
707 .id;
708 let id_a_struct = registry.register_type(&meta_type::<TestStruct<u32>>()).id;
709 let id_b_struct = registry
710 .register_type(&meta_type::<TestStruct<TestStruct<u64>>>())
711 .id;
712
713 let registry = PortableRegistry::from(registry);
714
715 assert!(types_equal(id_foo, id_foo_foo, ®istry));
716 assert!(types_equal(id_foo_enum, id_foo_foo_enum, ®istry));
717
718 assert!(types_equal(id_a, id_b, ®istry));
719 assert!(types_equal(id_a_struct, id_b_struct, ®istry));
720
721 let settings = crate::TypeGeneratorSettings::new();
722 let output = crate::TypeGenerator::new(®istry, &settings)
723 .generate_types_mod()
724 .unwrap()
725 .to_token_stream(&settings);
726 let expected = quote! {
728 pub mod types {
729 use super::types;
730 pub mod scale_typegen {
731 use super::types;
732 pub mod utils {
733 use super::types;
734 pub mod tests {
735 use super::types;
736 pub struct Foo < _0 > {
737 pub inner : :: std :: vec :: Vec < _0 > ,
738 }
739 pub enum FooEnum < _0 > {
740 None ,
741 Go (:: std :: vec :: Vec < _0 > ,) ,
742 }
743 pub enum Test<_0> {
744 None,
745 Many {
746 inner: ::std::vec::Vec<
747 types::scale_typegen::utils::tests::Test<_0>
748 >,
749 },
750 Param(_0, ),
751 }
752 pub struct TestStruct<_0> {
753 pub param: _0,
754 pub inner: ::std::vec::Vec<
755 types::scale_typegen::utils::tests::TestStruct<_0>
756 >,
757 }
758 }
759 }
760 }
761 }
762 };
763
764 assert_eq!(expected.to_string(), output.to_string())
765 }
766 #[test]
767 fn ensure_unique_type_paths_test() {
768 macro_rules! foo {
769 ($ty:ident, $prim:ident ) => {
770 struct $ty;
771 impl scale_info::TypeInfo for $ty {
772 type Identity = Self;
773 fn type_info() -> scale_info::Type {
774 scale_info::Type {
775 path: Path::new("Foo", "my::module"),
776 type_params: vec![],
777 type_def: scale_info::TypeDef::Primitive(
778 scale_info::TypeDefPrimitive::$prim,
779 ),
780 docs: vec![],
781 }
782 }
783 }
784 };
785 }
786
787 foo!(Foo1, Bool);
788 foo!(Foo2, Bool);
789 foo!(Foo3, U32);
790 foo!(Foo4, U128);
791 foo!(Foo5, U128);
792 foo!(Foo6, U128);
793
794 let mut registry = scale_info::Registry::new();
795 let id_1 = registry.register_type(&meta_type::<Foo1>()).id;
796 let id_2 = registry.register_type(&meta_type::<Foo2>()).id;
797 let id_3 = registry.register_type(&meta_type::<Foo3>()).id;
798 let id_4 = registry.register_type(&meta_type::<Foo4>()).id;
799 let id_5 = registry.register_type(&meta_type::<Foo5>()).id;
800 let id_6 = registry.register_type(&meta_type::<Foo6>()).id;
801 let mut registry = PortableRegistry::from(registry);
802
803 let ident = |id: u32| registry.resolve(id).unwrap().path.ident().unwrap();
805 assert_eq!(ident(id_1), "Foo");
806 assert_eq!(ident(id_2), "Foo");
807 assert_eq!(ident(id_3), "Foo");
808 assert_eq!(ident(id_4), "Foo");
809 assert_eq!(ident(id_5), "Foo");
810 assert_eq!(ident(id_6), "Foo");
811
812 ensure_unique_type_paths(&mut registry).expect("Corrupted PortableRegistry");
814
815 let ident = |id: u32| registry.resolve(id).unwrap().path.ident().unwrap();
816 assert_eq!(ident(id_1), "Foo1");
817 assert_eq!(ident(id_2), "Foo1");
818 assert_eq!(ident(id_3), "Foo2");
819 assert_eq!(ident(id_4), "Foo3");
820 assert_eq!(ident(id_5), "Foo3");
821 assert_eq!(ident(id_6), "Foo3");
822 }
823
824 #[test]
825 fn types_equal_recursing_test() {
826 #[derive(TypeInfo)]
827 struct Foo<T> {
828 _inner: T,
829 }
830
831 macro_rules! nested_type {
832 ($ty:ident, $generic:ty, $inner:ty, $param_name:literal) => {
833 struct $ty;
834 impl scale_info::TypeInfo for $ty {
835 type Identity = Self;
836 fn type_info() -> scale_info::Type {
837 scale_info::Type {
838 path: Path::new("NestedType", "my::module"),
839 type_params: vec![TypeParameter::new(
840 $param_name,
841 Some(meta_type::<$generic>()),
842 )],
843 type_def: TypeDef::Composite(TypeDefComposite::new([Field::new(
844 None,
845 meta_type::<$inner>(),
846 None,
847 Vec::new(),
848 )])),
849 docs: vec![],
850 }
851 }
852 }
853 };
854 }
855
856 nested_type!(A, u32, u32, "T");
861 nested_type!(B, bool, bool, "T");
862 nested_type!(G, u64, u64, "B");
863
864 nested_type!(C, bool, Vec<bool>, "T");
869 nested_type!(D, u32, Vec<u32>, "T");
870
871 nested_type!(E, bool, Vec<Foo<bool>>, "T");
876 nested_type!(F, u32, Vec<Foo<u32>>, "T");
877
878 let mut registry = scale_info::Registry::new();
879 let id_a = registry.register_type(&meta_type::<A>()).id;
880 let id_b = registry.register_type(&meta_type::<B>()).id;
881 let id_c = registry.register_type(&meta_type::<C>()).id;
882 let id_d = registry.register_type(&meta_type::<D>()).id;
883 let id_e = registry.register_type(&meta_type::<E>()).id;
884 let id_f = registry.register_type(&meta_type::<F>()).id;
885 let id_g = registry.register_type(&meta_type::<G>()).id;
886
887 let mut registry = PortableRegistry::from(registry);
888
889 assert!(types_equal(id_a, id_b, ®istry));
892 assert!(types_equal(id_c, id_d, ®istry));
893 assert!(types_equal(id_e, id_f, ®istry));
894 assert!(types_equal(id_a, id_g, ®istry));
895
896 assert!(!types_equal(id_a, id_c, ®istry));
898 assert!(!types_equal(id_a, id_e, ®istry));
899 assert!(!types_equal(id_c, id_e, ®istry));
900
901 ensure_unique_type_paths(&mut registry).expect("Corrupted PortableRegistry");
904 let settings = crate::TypeGeneratorSettings::new();
905 let output = crate::TypeGenerator::new(®istry, &settings)
906 .generate_types_mod()
907 .unwrap()
908 .to_token_stream(&settings);
909
910 let expected = quote! {
915 pub mod types {
916 use super::types;
917 pub mod my {
918 use super::types;
919 pub mod module {
920 use super::types;
921 pub struct NestedType1<_0>(pub _0,);
922 pub struct NestedType2<_0>(pub ::std::vec::Vec<_0>,);
923 pub struct NestedType3<_0>(
924 pub ::std::vec::Vec<types::scale_typegen::utils::tests::Foo<_0> >,
925 );
926 }
927 }
928 pub mod scale_typegen {
929 use super::types;
930 pub mod utils {
931 use super::types;
932 pub mod tests {
933 use super::types;
934 pub struct Foo<_0> {
935 pub _inner: _0,
936 }
937 }
938 }
939 }
940 }
941 };
942
943 assert_eq!(output.to_string(), expected.to_string());
944 }
945}