scale_typegen/
utils.rs

1use self::generics_list::GenericsList;
2use scale_info::{form::PortableForm, Field, PortableRegistry, Type, TypeDef};
3use std::collections::{HashMap, HashSet};
4
5use crate::TypegenError;
6
7/// Converts a [`scale_info::Type`] into a [`syn::TypePath`].
8pub 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
33/// Deduplicates type paths in the provided Registry.
34pub 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    // First, group types if they are similar (same path, same shape).
39    for (ty_idx, ty) in types.types.iter().enumerate() {
40        // We use the index of the type in the types registry instead of `ty.id`. The two
41        // _should_ be identical, but prior to `scale-info` 2.11.1  they sometimes weren't
42        // when `registry.retain()` was used, and so to avoid older metadata files breaking
43        // things, let's stick to using the index for a while:
44        let ty_idx = ty_idx as u32;
45        let ty = &ty.ty;
46
47        // Ignore types without a path (i.e prelude types).
48        if ty.path.namespace().is_empty() {
49            continue;
50        };
51
52        // get groups that share this path already, if any.
53        let groups_with_same_path = types_with_same_type_path_grouped_by_shape
54            .entry(&ty.path.segments)
55            .or_default();
56
57        // Compare existing groups to check which to add our type ID to.
58        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]; // all types in group are same shape; just check any one of them.
61            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        // We didn't find a matching group, so add it to a new one.
69        if !added_to_existing_group {
70            groups_with_same_path.push(vec![ty_idx])
71        }
72    }
73
74    // Now, rename types as needed based on these groups.
75    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<_>>(); // Collect necessary because otherwise types is borrowed immutably and cannot be modified.
79
80    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}"); // e.g. Header1, Header2, Header3, ...
90            }
91            n += 1;
92        }
93    }
94    Ok(())
95}
96
97/// This attempts to check whether two types are equal in terms of their shape.
98/// In other words: should we de-duplicate these types during codegen.
99///
100/// The basic algorithm here is:
101/// - If type IDs match, they are the same.
102/// - If type IDs can be explained by the same generic parameter, they are the same.
103/// - If type paths or generic names don't match, they are different.
104/// - If the corresponding TypeDefs (shape of type) is different, they are different.
105/// - Else, recurse through any contained type IDs and start from the top.
106pub(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
120// Panics if the given type ID is not found in the registry.
121fn 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    // IDs are the same; types must be identical!
131    if a == b {
132        return true;
133    }
134
135    // Make note of these IDs in case we recurse and see them again.
136    let seen_a = !a_visited.insert(a);
137    let seen_b = !b_visited.insert(b);
138
139    // One type is recursive and the other isn't; they are different.
140    // If neither type is recursive, we keep checking.
141    if seen_a != seen_b {
142        return false;
143    }
144
145    // Both types are recursive, and they look the same based on the above,
146    // so assume all is well, since we've already checked other things in prev recursion.
147    if seen_a && seen_b {
148        return true;
149    }
150
151    // Make note of whether these IDs (might) correspond to any specific generic.
152    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    // Capture a few variables to avoid some repetition later when we recurse.
159    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    // We'll lazily extend our type params only if the shapes match.
165    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 both IDs map to same generic param, then we'll assume equal. If they don't
172    // then we need to keep checking other properties (eg Vec<bool> and Vec<u8> will have
173    // different type IDs but may be the same type if the bool+u8 line up to generic params).
174    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    // Paths differ; types won't be equal then!
181    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        // The type is wrapped in another type such as `Vec<T>` or
197        // marked as skipped with `#[scale_info(skip_type_params(T))]`
198        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        // Check that both type names are present or recurse in case of wrapped types
204        match (&a.type_name, &b.type_name) {
205            (Some(a_type_name), Some(b_type_name)) if !ty_is_skipped_or_wrapped => {
206                // check that both type names are present in Generic Params and have the same indexes
207                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    // Check that all of the fields of some type are equal.
217    #[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    // Check that the shape of the types and contents are equal.
233    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        // Type defs don't match; types aren't the same!
284        _ => false,
285    }
286}
287
288/// Just a small helper for the [`types_equal_inner`] function, to track where generic params
289/// are in order to see whether different type IDs may actually be represented by the same generics.
290mod generics_list {
291    use scale_info::{form::PortableForm, TypeParameter};
292    use std::rc::Rc;
293
294    /// A list of generics by type ID. For a given type ID, we'll either
295    /// return the index of the first generic param we find that matches it,
296    /// or None. We can extend this list with more generics as we go.
297    #[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        /// Return the unique index of a generic in the list, or None if not found
311        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            // if index isn't found here, go back to the previous list and try again.
320            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        /// Returns the unique index of a generic type name, or None if not found.
328        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            // if index isn't found here, go back to the previous list and try again.
337            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        /// Create an empty list.
346        pub fn empty() -> Self {
347            Self::new_inner(None, &[])
348        }
349
350        /// Extend this list with more params.
351        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))] // this is optional
408        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(&registry, &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        // A != B, different field ordering
626        assert!(!types_equal(id_a, id_b, &registry));
627        assert!(!types_equal(id_a, id_bb, &registry));
628
629        // A == C, different generic param names
630        assert!(types_equal(id_a, id_c, &registry));
631
632        // D == E, different generic param names
633        assert!(types_equal(id_d, id_e, &registry));
634
635        assert!(types_equal(id_w, id_y, &registry));
636        assert!(types_equal(id_z, id_y, &registry));
637
638        ensure_unique_type_paths(&mut registry).expect("Corrupted PortableRegistry");
639        let settings = crate::TypeGeneratorSettings::new();
640        let output = crate::TypeGenerator::new(&registry, &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, &registry));
716        assert!(types_equal(id_foo_enum, id_foo_foo_enum, &registry));
717
718        assert!(types_equal(id_a, id_b, &registry));
719        assert!(types_equal(id_a_struct, id_b_struct, &registry));
720
721        let settings = crate::TypeGeneratorSettings::new();
722        let output = crate::TypeGenerator::new(&registry, &settings)
723            .generate_types_mod()
724            .unwrap()
725            .to_token_stream(&settings);
726        // Why codegen for Foo expands this way?
727        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        // before:
804        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        // after:
813        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        // A and B are the same because generics explain the param difference.
857        //
858        //NestedType<T = u32>(u32)
859        //NestedType<T = bool>(bool)
860        nested_type!(A, u32, u32, "T");
861        nested_type!(B, bool, bool, "T");
862        nested_type!(G, u64, u64, "B");
863
864        // As above, but another layer of nesting before generic param used.
865        //
866        //NestedType<T = u32>(Vec<u32>)
867        //NestedType<T = bool>(Vec<bool>)
868        nested_type!(C, bool, Vec<bool>, "T");
869        nested_type!(D, u32, Vec<u32>, "T");
870
871        // A third layer of nesting just to really check the recursion.
872        //
873        //NestedType<T = u32>(Vec<Foo<u32>>)
874        //NestedType<T = bool>(Vec<Foo<bool>>)
875        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        // Despite how many layers of nesting, we identify that the generic
890        // param can explain the difference, so can see them as being equal.
891        assert!(types_equal(id_a, id_b, &registry));
892        assert!(types_equal(id_c, id_d, &registry));
893        assert!(types_equal(id_e, id_f, &registry));
894        assert!(types_equal(id_a, id_g, &registry));
895
896        // Sanity check that the pairs are not equal with each other.
897        assert!(!types_equal(id_a, id_c, &registry));
898        assert!(!types_equal(id_a, id_e, &registry));
899        assert!(!types_equal(id_c, id_e, &registry));
900
901        // Now, check that the generated output is sane and in line with this...
902
903        ensure_unique_type_paths(&mut registry).expect("Corrupted PortableRegistry");
904        let settings = crate::TypeGeneratorSettings::new();
905        let output = crate::TypeGenerator::new(&registry, &settings)
906            .generate_types_mod()
907            .unwrap()
908            .to_token_stream(&settings);
909
910        // This isn't ideal, but I printed out the token stream, and it looks good (ie generates
911        // 3 types after deduplicating with the correct generic param usage), so this test will
912        // check that the output still looks good. To update, copy and `rustfmt` the new output
913        // and then adjust the odd thing until it matches again.
914        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}