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 = syn::parse_str(&joined_path)?;
11    Ok(ty_path)
12}
13
14pub(crate) fn sanity_pass(types: &PortableRegistry) -> Result<(), TypegenError> {
15    for (idx, ty) in types.types.iter().enumerate() {
16        let idx = idx as u32;
17        if ty.id != idx {
18            return Err(TypegenError::RegistryTypeIdsInvalid {
19                given_ty_id: ty.id,
20                expected_ty_id: idx,
21                ty_def: format!("{:#?}", ty.ty),
22            });
23        }
24    }
25    Ok(())
26}
27
28/// Deduplicates type paths in the provided Registry.
29pub fn ensure_unique_type_paths(types: &mut PortableRegistry) -> Result<(), TypegenError> {
30    sanity_pass(types)?;
31    let mut types_with_same_type_path_grouped_by_shape = HashMap::<&[String], Vec<Vec<u32>>>::new();
32
33    // First, group types if they are similar (same path, same shape).
34    for (ty_idx, ty) in types.types.iter().enumerate() {
35        // We use the index of the type in the types registry instead of `ty.id`. The two
36        // _should_ be identical, but prior to `scale-info` 2.11.1  they sometimes weren't
37        // when `registry.retain()` was used, and so to avoid older metadata files breaking
38        // things, let's stick to using the index for a while:
39        let ty_idx = ty_idx as u32;
40        let ty = &ty.ty;
41
42        // Ignore types without a path (i.e prelude types).
43        if ty.path.namespace().is_empty() {
44            continue;
45        };
46
47        // get groups that share this path already, if any.
48        let groups_with_same_path = types_with_same_type_path_grouped_by_shape
49            .entry(&ty.path.segments)
50            .or_default();
51
52        // Compare existing groups to check which to add our type ID to.
53        let mut added_to_existing_group = false;
54        for group in groups_with_same_path.iter_mut() {
55            let other_ty_in_group_idx = group[0]; // all types in group are same shape; just check any one of them.
56            if types_equal(ty_idx, other_ty_in_group_idx, types) {
57                group.push(ty_idx);
58                added_to_existing_group = true;
59                break;
60            }
61        }
62
63        // We didn't find a matching group, so add it to a new one.
64        if !added_to_existing_group {
65            groups_with_same_path.push(vec![ty_idx])
66        }
67    }
68
69    // Now, rename types as needed based on these groups.
70    let groups_that_need_renaming = types_with_same_type_path_grouped_by_shape
71        .into_values()
72        .filter(|g| g.len() > 1)
73        .collect::<Vec<_>>(); // Collect necessary because otherwise types is borrowed immutably and cannot be modified.
74
75    for groups_with_same_path in groups_that_need_renaming {
76        let mut n = 1;
77        for group_with_same_shape in groups_with_same_path {
78            for ty_id in group_with_same_shape {
79                let ty = types
80                    .types
81                    .get_mut(ty_id as usize)
82                    .expect("type is present (2); qed;");
83                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;");
84                *name = format!("{name}{n}"); // e.g. Header1, Header2, Header3, ...
85            }
86            n += 1;
87        }
88    }
89    Ok(())
90}
91
92/// This attempts to check whether two types are equal in terms of their shape.
93/// In other words: should we de-duplicate these types during codegen.
94///
95/// The basic algorithm here is:
96/// - If type IDs match, they are the same.
97/// - If type IDs can be explained by the same generic parameter, they are the same.
98/// - If type paths or generic names don't match, they are different.
99/// - If the corresponding TypeDefs (shape of type) is different, they are different.
100/// - Else, recurse through any contained type IDs and start from the top.
101pub(crate) fn types_equal(a: u32, b: u32, types: &PortableRegistry) -> bool {
102    let mut a_visited = HashSet::new();
103    let mut b_visited = HashSet::new();
104    types_equal_inner(
105        a,
106        &GenericsList::empty(),
107        &mut a_visited,
108        b,
109        &GenericsList::empty(),
110        &mut b_visited,
111        types,
112    )
113}
114
115// Panics if the given type ID is not found in the registry.
116fn types_equal_inner(
117    a: u32,
118    a_parent_params: &GenericsList,
119    a_visited: &mut HashSet<u32>,
120    b: u32,
121    b_parent_params: &GenericsList,
122    b_visited: &mut HashSet<u32>,
123    types: &PortableRegistry,
124) -> bool {
125    // IDs are the same; types must be identical!
126    if a == b {
127        return true;
128    }
129
130    // Make note of these IDs in case we recurse and see them again.
131    let seen_a = !a_visited.insert(a);
132    let seen_b = !b_visited.insert(b);
133
134    // One type is recursive and the other isn't; they are different.
135    // If neither type is recursive, we keep checking.
136    if seen_a != seen_b {
137        return false;
138    }
139
140    // Both types are recursive, and they look the same based on the above,
141    // so assume all is well, since we've already checked other things in prev recursion.
142    if seen_a && seen_b {
143        return true;
144    }
145
146    // Make note of whether these IDs (might) correspond to any specific generic.
147    let a_generic_idx = a_parent_params.index_for_type_id(a);
148    let b_generic_idx = b_parent_params.index_for_type_id(b);
149
150    let a_ty = types.resolve(a).expect("type a should exist in registry");
151    let b_ty = types.resolve(b).expect("type b should exist in registry");
152
153    // Capture a few variables to avoid some repetition later when we recurse.
154    let mut types_equal_recurse =
155        |a: u32, a_params: &GenericsList, b: u32, b_params: &GenericsList| -> bool {
156            types_equal_inner(a, a_params, a_visited, b, b_params, b_visited, types)
157        };
158
159    // We'll lazily extend our type params only if the shapes match.
160    let calc_params = || {
161        let a_params = a_parent_params.extend(&a_ty.type_params);
162        let b_params = b_parent_params.extend(&b_ty.type_params);
163        (a_params, b_params)
164    };
165
166    // If both IDs map to same generic param, then we'll assume equal. If they don't
167    // then we need to keep checking other properties (eg Vec<bool> and Vec<u8> will have
168    // different type IDs but may be the same type if the bool+u8 line up to generic params).
169    if let (Some(a_idx), Some(b_idx)) = (a_generic_idx, b_generic_idx) {
170        if a_idx == b_idx {
171            return true;
172        }
173    }
174
175    // Paths differ; types won't be equal then!
176    if a_ty.path.segments != b_ty.path.segments {
177        return false;
178    }
179
180    #[rustfmt::skip]
181    let mut compare_fields = |
182        a: &Field<PortableForm>,
183        a_params: &GenericsList,
184        b: &Field<PortableForm>,
185        b_params: &GenericsList
186    | -> bool {
187        if a.name != b.name {
188            return false;
189        }
190
191        // The type is wrapped in another type such as `Vec<T>` or
192        // marked as skipped with `#[scale_info(skip_type_params(T))]`
193        let ty_is_skipped_or_wrapped = a_params
194            .index_for_type_id(a.ty.id)
195            .zip(b_params.index_for_type_id(b.ty.id))
196            .is_none();
197
198        // Check that both type names are present or recurse in case of wrapped types
199        match (&a.type_name, &b.type_name) {
200            (Some(a_type_name), Some(b_type_name)) if !ty_is_skipped_or_wrapped => {
201                // check that both type names are present in Generic Params and have the same indexes
202                a_params
203                    .index_for_type_name(a_type_name)
204                    .zip(b_params.index_for_type_name(b_type_name))
205                    .is_some_and(|(a, b)| a == b)
206            }
207            _ => types_equal_recurse(a.ty.id, a_params, b.ty.id, b_params),
208        }
209    };
210
211    // Check that all of the fields of some type are equal.
212    #[rustfmt::skip]
213    let mut fields_equal = |
214        a: &[Field<PortableForm>],
215        a_params: &GenericsList,
216        b: &[Field<PortableForm>],
217        b_params: &GenericsList,
218    | -> bool {
219        if a.len() != b.len() {
220            return false;
221        }
222        a.iter().zip(b.iter()).all(|(a, b)| {
223           compare_fields(a, a_params, b, b_params)
224        })
225    };
226
227    // Check that the shape of the types and contents are equal.
228    match (&a_ty.type_def, &b_ty.type_def) {
229        (TypeDef::Composite(a), TypeDef::Composite(b)) => {
230            let (a_params, b_params) = calc_params();
231            fields_equal(&a.fields, &a_params, &b.fields, &b_params)
232        }
233        (TypeDef::Variant(a), TypeDef::Variant(b)) => {
234            let (a_params, b_params) = calc_params();
235            a.variants.len() == b.variants.len()
236                && a.variants.iter().zip(b.variants.iter()).all(|(a, b)| {
237                    a.name == b.name && fields_equal(&a.fields, &a_params, &b.fields, &b_params)
238                })
239        }
240        (TypeDef::Sequence(a), TypeDef::Sequence(b)) => {
241            let (a_params, b_params) = calc_params();
242            types_equal_recurse(a.type_param.id, &a_params, b.type_param.id, &b_params)
243        }
244        (TypeDef::Array(a), TypeDef::Array(b)) => {
245            let (a_params, b_params) = calc_params();
246            a.len == b.len
247                && types_equal_recurse(a.type_param.id, &a_params, b.type_param.id, &b_params)
248        }
249        (TypeDef::Tuple(a), TypeDef::Tuple(b)) => {
250            let (a_params, b_params) = calc_params();
251            a.fields.len() == b.fields.len()
252                && a.fields
253                    .iter()
254                    .zip(b.fields.iter())
255                    .all(|(a, b)| types_equal_recurse(a.id, &a_params, b.id, &b_params))
256        }
257        (TypeDef::Primitive(a), TypeDef::Primitive(b)) => a == b,
258        (TypeDef::Compact(a), TypeDef::Compact(b)) => {
259            let (a_params, b_params) = calc_params();
260            types_equal_recurse(a.type_param.id, &a_params, b.type_param.id, &b_params)
261        }
262        (TypeDef::BitSequence(a), scale_info::TypeDef::BitSequence(b)) => {
263            let (a_params, b_params) = calc_params();
264            let order_equal = types_equal_recurse(
265                a.bit_order_type.id,
266                &a_params,
267                b.bit_order_type.id,
268                &b_params,
269            );
270            let store_equal = types_equal_recurse(
271                a.bit_store_type.id,
272                &a_params,
273                b.bit_store_type.id,
274                &b_params,
275            );
276            order_equal && store_equal
277        }
278        // Type defs don't match; types aren't the same!
279        _ => false,
280    }
281}
282
283/// Just a small helper for the [`types_equal_inner`] function, to track where generic params
284/// are in order to see whether different type IDs may actually be represented by the same generics.
285mod generics_list {
286    use scale_info::{form::PortableForm, TypeParameter};
287    use std::rc::Rc;
288
289    /// A list of generics by type ID. For a given type ID, we'll either
290    /// return the index of the first generic param we find that matches it,
291    /// or None. We can extend this list with more generics as we go.
292    #[derive(Clone, Debug)]
293    pub struct GenericsList {
294        inner: Rc<GenericsListInner>,
295    }
296
297    #[derive(Clone, Debug)]
298    struct GenericsListInner {
299        previous: Option<GenericsList>,
300        start_idx: usize,
301        generics_by_id: Vec<(u32, String)>,
302    }
303
304    impl GenericsList {
305        /// Return the unique index of a generic in the list, or None if not found
306        pub fn index_for_type_id(&self, type_id: u32) -> Option<usize> {
307            let maybe_index = self
308                .inner
309                .generics_by_id
310                .iter()
311                .position(|(id, _)| *id == type_id)
312                .map(|index| self.inner.start_idx + index);
313
314            // if index isn't found here, go back to the previous list and try again.
315            maybe_index.or_else(|| {
316                self.inner
317                    .previous
318                    .as_ref()
319                    .and_then(|prev| prev.index_for_type_id(type_id))
320            })
321        }
322        /// Returns the unique index of a generic type name, or None if not found.
323        pub fn index_for_type_name(&self, name: &str) -> Option<usize> {
324            let maybe_index = self
325                .inner
326                .generics_by_id
327                .iter()
328                .position(|(_, type_name)| *type_name == name)
329                .map(|index| self.inner.start_idx + index);
330
331            // if index isn't found here, go back to the previous list and try again.
332            maybe_index.or_else(|| {
333                self.inner
334                    .previous
335                    .as_ref()
336                    .and_then(|prev| prev.index_for_type_name(name))
337            })
338        }
339
340        /// Create an empty list.
341        pub fn empty() -> Self {
342            Self::new_inner(None, &[])
343        }
344
345        /// Extend this list with more params.
346        pub fn extend(&self, params: &[TypeParameter<PortableForm>]) -> Self {
347            Self::new_inner(Some(self.clone()), params)
348        }
349
350        fn new_inner(
351            maybe_self: Option<GenericsList>,
352            params: &[TypeParameter<PortableForm>],
353        ) -> Self {
354            let generics_by_id = params
355                .iter()
356                .filter_map(|p| p.ty.map(|ty| (ty.id, p.name.clone())))
357                .collect();
358
359            let start_idx = match &maybe_self {
360                Some(list) => list.inner.start_idx + list.inner.generics_by_id.len(),
361                None => 0,
362            };
363
364            GenericsList {
365                inner: Rc::new(GenericsListInner {
366                    previous: maybe_self,
367                    start_idx,
368                    generics_by_id,
369                }),
370            }
371        }
372    }
373}
374
375#[cfg(test)]
376mod tests {
377    use crate::typegen::ir::ToTokensWithSettings;
378    use pretty_assertions::assert_eq;
379
380    use super::*;
381    use quote::quote;
382    use scale_info::{
383        meta_type, Field, Path, PortableRegistry, TypeDef, TypeDefComposite, TypeInfo,
384        TypeParameter,
385    };
386
387    #[test]
388    fn associated_types_are_properly_deduplicated() {
389        trait X {
390            type Assoc;
391        }
392        struct A;
393        impl X for A {
394            type Assoc = u8;
395        }
396        struct B;
397        impl X for B {
398            type Assoc = u32;
399        }
400
401        #[derive(TypeInfo)]
402        #[scale_info(skip_type_params(T))] // this is optional
403        struct Foo<T: X> {
404            _field: T::Assoc,
405        }
406
407        #[allow(unused)]
408        #[derive(TypeInfo)]
409        struct Bar {
410            p: Foo<A>,
411            q: Foo<B>,
412        }
413
414        let mut registry = scale_info::Registry::new();
415        let _ = registry.register_type(&scale_info::meta_type::<Bar>()).id;
416        let mut registry = scale_info::PortableRegistry::from(registry);
417
418        ensure_unique_type_paths(&mut registry).expect("Corrupted PortableRegistry");
419
420        let settings = crate::TypeGeneratorSettings::new();
421        let generated = crate::typegen::ir::ToTokensWithSettings::to_token_stream(
422            &crate::TypeGenerator::new(&registry, &settings)
423                .generate_types_mod()
424                .unwrap(),
425            &settings,
426        );
427
428        let expected = quote!(
429            pub mod types {
430                use super::types;
431                pub mod scale_typegen {
432                    use super::types;
433                    pub mod utils {
434                        use super::types;
435                        pub mod tests {
436                            use super::types;
437                            pub struct Bar {
438                                pub p: types::scale_typegen::utils::tests::Foo1,
439                                pub q: types::scale_typegen::utils::tests::Foo2,
440                            }
441                            pub struct Foo1 {
442                                pub _field: ::core::primitive::u8,
443                            }
444                            pub struct Foo2 {
445                                pub _field: ::core::primitive::u32,
446                            }
447                        }
448                    }
449                }
450            }
451        );
452
453        assert_eq!(expected.to_string(), generated.to_string());
454    }
455
456    #[test]
457    fn generics_unification() {
458        macro_rules! nested_type {
459            ($ty:ident, $generic:ty, $inner:ty) => {
460                struct $ty;
461                impl scale_info::TypeInfo for $ty {
462                    type Identity = Self;
463                    fn type_info() -> scale_info::Type {
464                        scale_info::Type {
465                            path: Path::new("ParamType", "my::module"),
466                            type_params: vec![TypeParameter::new(
467                                "T",
468                                Some(meta_type::<$generic>()),
469                            )],
470                            type_def: TypeDef::Composite(TypeDefComposite::new([Field::new(
471                                None,
472                                meta_type::<$inner>(),
473                                Some("T"),
474                                Vec::new(),
475                            )])),
476                            docs: vec![],
477                        }
478                    }
479                }
480            };
481        }
482
483        struct A;
484        impl scale_info::TypeInfo for A {
485            type Identity = Self;
486            fn type_info() -> scale_info::Type {
487                scale_info::Type {
488                    path: Path::new("NestedType", "my::module"),
489                    type_params: vec![
490                        TypeParameter::new("T", Some(meta_type::<u8>())),
491                        TypeParameter::new("U", Some(meta_type::<u16>())),
492                        TypeParameter::new("V", Some(meta_type::<u32>())),
493                    ],
494                    type_def: TypeDef::Composite(TypeDefComposite::new([
495                        Field::new(None, meta_type::<u8>(), Some("T"), Vec::new()),
496                        Field::new(None, meta_type::<u16>(), Some("U"), Vec::new()),
497                        Field::new(None, meta_type::<u32>(), Some("V"), Vec::new()),
498                    ])),
499                    docs: vec![],
500                }
501            }
502        }
503
504        struct B;
505        impl scale_info::TypeInfo for B {
506            type Identity = Self;
507            fn type_info() -> scale_info::Type {
508                scale_info::Type {
509                    path: Path::new("NestedType", "my::module"),
510                    type_params: vec![
511                        TypeParameter::new("T", Some(meta_type::<u8>())),
512                        TypeParameter::new("U", Some(meta_type::<u16>())),
513                        TypeParameter::new("V", Some(meta_type::<u32>())),
514                    ],
515                    type_def: TypeDef::Composite(TypeDefComposite::new([
516                        Field::new(None, meta_type::<u32>(), Some("V"), Vec::new()),
517                        Field::new(None, meta_type::<u16>(), Some("U"), Vec::new()),
518                        Field::new(None, meta_type::<u8>(), Some("T"), Vec::new()),
519                    ])),
520                    docs: vec![],
521                }
522            }
523        }
524        struct BB;
525        impl scale_info::TypeInfo for BB {
526            type Identity = Self;
527            fn type_info() -> scale_info::Type {
528                scale_info::Type {
529                    path: Path::new("NestedType", "my::module"),
530                    type_params: vec![
531                        TypeParameter::new("V", Some(meta_type::<u8>())),
532                        TypeParameter::new("U", Some(meta_type::<u16>())),
533                        TypeParameter::new("T", Some(meta_type::<u32>())),
534                    ],
535                    type_def: TypeDef::Composite(TypeDefComposite::new([
536                        Field::new(None, meta_type::<u32>(), Some("T"), Vec::new()),
537                        Field::new(None, meta_type::<u16>(), Some("U"), Vec::new()),
538                        Field::new(None, meta_type::<u8>(), Some("V"), Vec::new()),
539                    ])),
540                    docs: vec![],
541                }
542            }
543        }
544
545        struct C;
546        impl scale_info::TypeInfo for C {
547            type Identity = Self;
548            fn type_info() -> scale_info::Type {
549                scale_info::Type {
550                    path: Path::new("NestedType", "my::module"),
551                    type_params: vec![
552                        TypeParameter::new("A", Some(meta_type::<u8>())),
553                        TypeParameter::new("D", Some(meta_type::<u16>())),
554                        TypeParameter::new("B", Some(meta_type::<u32>())),
555                    ],
556                    type_def: TypeDef::Composite(TypeDefComposite::new([
557                        Field::new(None, meta_type::<u8>(), Some("A"), Vec::new()),
558                        Field::new(None, meta_type::<u16>(), Some("D"), Vec::new()),
559                        Field::new(None, meta_type::<u32>(), Some("B"), Vec::new()),
560                    ])),
561                    docs: vec![],
562                }
563            }
564        }
565
566        struct D;
567        impl scale_info::TypeInfo for D {
568            type Identity = Self;
569            fn type_info() -> scale_info::Type {
570                scale_info::Type {
571                    path: Path::new("Foo", "my::module"),
572                    type_params: vec![TypeParameter::new("A", Some(meta_type::<u8>()))],
573                    type_def: TypeDef::Composite(TypeDefComposite::new([Field::new(
574                        None,
575                        meta_type::<u8>(),
576                        Some("A"),
577                        Vec::new(),
578                    )])),
579                    docs: vec![],
580                }
581            }
582        }
583        struct E;
584        impl scale_info::TypeInfo for E {
585            type Identity = Self;
586            fn type_info() -> scale_info::Type {
587                scale_info::Type {
588                    path: Path::new("Foo", "my::module"),
589                    type_params: vec![TypeParameter::new("B", Some(meta_type::<u16>()))],
590                    type_def: TypeDef::Composite(TypeDefComposite::new([Field::new(
591                        None,
592                        meta_type::<u16>(),
593                        Some("B"),
594                        Vec::new(),
595                    )])),
596                    docs: vec![],
597                }
598            }
599        }
600
601        let mut registry = scale_info::Registry::new();
602        let id_b = registry.register_type(&meta_type::<B>()).id;
603        let id_bb = registry.register_type(&meta_type::<BB>()).id;
604        let id_a = registry.register_type(&meta_type::<A>()).id;
605        let id_c = registry.register_type(&meta_type::<C>()).id;
606
607        let id_d = registry.register_type(&meta_type::<D>()).id;
608        let id_e = registry.register_type(&meta_type::<E>()).id;
609
610        nested_type!(Y, A, A);
611        nested_type!(W, B, B);
612        nested_type!(Z, C, C);
613
614        let id_y = registry.register_type(&meta_type::<Y>()).id;
615        let id_w = registry.register_type(&meta_type::<W>()).id;
616        let id_z = registry.register_type(&meta_type::<Z>()).id;
617
618        let mut registry = PortableRegistry::from(registry);
619
620        // A != B, different field ordering
621        assert!(!types_equal(id_a, id_b, &registry));
622        assert!(!types_equal(id_a, id_bb, &registry));
623
624        // A == C, different generic param names
625        assert!(types_equal(id_a, id_c, &registry));
626
627        // D == E, different generic param names
628        assert!(types_equal(id_d, id_e, &registry));
629
630        assert!(types_equal(id_w, id_y, &registry));
631        assert!(types_equal(id_z, id_y, &registry));
632
633        ensure_unique_type_paths(&mut registry).expect("Corrupted PortableRegistry");
634        let settings = crate::TypeGeneratorSettings::new();
635        let output = crate::TypeGenerator::new(&registry, &settings)
636            .generate_types_mod()
637            .unwrap()
638            .to_token_stream(&settings);
639
640        let expected = quote! {
641                pub mod types {
642                use super::types;
643                pub mod my {
644                    use super::types;
645                    pub mod module {
646                        use super::types;
647                        pub struct Foo<_0>(pub _0, );
648                        pub struct NestedType1<_0, _1, _2>(pub _2, pub _1, pub _0, );
649                        pub struct NestedType2<_0, _1, _2>(pub _0, pub _1, pub _2, );
650                        pub struct ParamType < _0 > (pub _0 ,) ;
651                    }
652                }
653            }
654        };
655
656        assert_eq!(expected.to_string(), output.to_string())
657    }
658
659    #[test]
660    fn recursive_data() {
661        #[derive(TypeInfo)]
662        #[allow(dead_code)]
663        pub enum Test<A> {
664            None,
665            Many { inner: Vec<Self> },
666            Param(A),
667        }
668
669        #[derive(TypeInfo)]
670        #[allow(dead_code)]
671        pub struct TestStruct<A> {
672            param: A,
673            inner: Vec<Self>,
674        }
675
676        #[derive(TypeInfo)]
677        #[allow(dead_code)]
678        pub struct Foo<T> {
679            inner: Vec<T>,
680        }
681
682        #[derive(TypeInfo)]
683        #[allow(dead_code)]
684        pub enum FooEnum<T> {
685            None,
686            Go(Vec<T>),
687        }
688
689        let mut registry = scale_info::Registry::new();
690        let id_a = registry.register_type(&meta_type::<Test<u8>>()).id;
691        let id_b = registry.register_type(&meta_type::<Test<u32>>()).id;
692
693        let id_foo = registry.register_type(&meta_type::<Foo<u32>>()).id;
694
695        let id_foo_foo = registry
696            .register_type(&meta_type::<Foo<Foo<TestStruct<u32>>>>())
697            .id;
698
699        let id_foo_enum = registry.register_type(&meta_type::<FooEnum<u32>>()).id;
700        let id_foo_foo_enum = registry
701            .register_type(&meta_type::<FooEnum<FooEnum<TestStruct<u32>>>>())
702            .id;
703        let id_a_struct = registry.register_type(&meta_type::<TestStruct<u32>>()).id;
704        let id_b_struct = registry
705            .register_type(&meta_type::<TestStruct<TestStruct<u64>>>())
706            .id;
707
708        let registry = PortableRegistry::from(registry);
709
710        assert!(types_equal(id_foo, id_foo_foo, &registry));
711        assert!(types_equal(id_foo_enum, id_foo_foo_enum, &registry));
712
713        assert!(types_equal(id_a, id_b, &registry));
714        assert!(types_equal(id_a_struct, id_b_struct, &registry));
715
716        let settings = crate::TypeGeneratorSettings::new();
717        let output = crate::TypeGenerator::new(&registry, &settings)
718            .generate_types_mod()
719            .unwrap()
720            .to_token_stream(&settings);
721        // Why codegen for Foo expands this way?
722        let expected = quote! {
723            pub mod types {
724                use super::types;
725                pub mod scale_typegen {
726                    use super::types;
727                    pub mod utils {
728                        use super::types;
729                        pub mod tests {
730                            use super::types;
731                            pub struct Foo < _0 > {
732                                pub inner : :: std :: vec :: Vec < _0 > ,
733                            }
734                            pub enum FooEnum < _0 > {
735                                None ,
736                                Go (:: std :: vec :: Vec < _0 > ,) ,
737                            }
738                            pub enum Test<_0> {
739                                None,
740                                Many {
741                                    inner: ::std::vec::Vec<
742                                        types::scale_typegen::utils::tests::Test<_0>
743                                    >,
744                                },
745                                Param(_0, ),
746                            }
747                            pub struct TestStruct<_0> {
748                                pub param: _0,
749                                pub inner: ::std::vec::Vec<
750                                    types::scale_typegen::utils::tests::TestStruct<_0>
751                                >,
752                            }
753                        }
754                    }
755                }
756            }
757        };
758
759        assert_eq!(expected.to_string(), output.to_string())
760    }
761    #[test]
762    fn ensure_unique_type_paths_test() {
763        macro_rules! foo {
764            ($ty:ident, $prim:ident ) => {
765                struct $ty;
766                impl scale_info::TypeInfo for $ty {
767                    type Identity = Self;
768                    fn type_info() -> scale_info::Type {
769                        scale_info::Type {
770                            path: Path::new("Foo", "my::module"),
771                            type_params: vec![],
772                            type_def: scale_info::TypeDef::Primitive(
773                                scale_info::TypeDefPrimitive::$prim,
774                            ),
775                            docs: vec![],
776                        }
777                    }
778                }
779            };
780        }
781
782        foo!(Foo1, Bool);
783        foo!(Foo2, Bool);
784        foo!(Foo3, U32);
785        foo!(Foo4, U128);
786        foo!(Foo5, U128);
787        foo!(Foo6, U128);
788
789        let mut registry = scale_info::Registry::new();
790        let id_1 = registry.register_type(&meta_type::<Foo1>()).id;
791        let id_2 = registry.register_type(&meta_type::<Foo2>()).id;
792        let id_3 = registry.register_type(&meta_type::<Foo3>()).id;
793        let id_4 = registry.register_type(&meta_type::<Foo4>()).id;
794        let id_5 = registry.register_type(&meta_type::<Foo5>()).id;
795        let id_6 = registry.register_type(&meta_type::<Foo6>()).id;
796        let mut registry = PortableRegistry::from(registry);
797
798        // before:
799        let ident = |id: u32| registry.resolve(id).unwrap().path.ident().unwrap();
800        assert_eq!(ident(id_1), "Foo");
801        assert_eq!(ident(id_2), "Foo");
802        assert_eq!(ident(id_3), "Foo");
803        assert_eq!(ident(id_4), "Foo");
804        assert_eq!(ident(id_5), "Foo");
805        assert_eq!(ident(id_6), "Foo");
806
807        // after:
808        ensure_unique_type_paths(&mut registry).expect("Corrupted PortableRegistry");
809
810        let ident = |id: u32| registry.resolve(id).unwrap().path.ident().unwrap();
811        assert_eq!(ident(id_1), "Foo1");
812        assert_eq!(ident(id_2), "Foo1");
813        assert_eq!(ident(id_3), "Foo2");
814        assert_eq!(ident(id_4), "Foo3");
815        assert_eq!(ident(id_5), "Foo3");
816        assert_eq!(ident(id_6), "Foo3");
817    }
818
819    #[test]
820    fn types_equal_recursing_test() {
821        #[derive(TypeInfo)]
822        struct Foo<T> {
823            _inner: T,
824        }
825
826        macro_rules! nested_type {
827            ($ty:ident, $generic:ty, $inner:ty, $param_name:literal) => {
828                struct $ty;
829                impl scale_info::TypeInfo for $ty {
830                    type Identity = Self;
831                    fn type_info() -> scale_info::Type {
832                        scale_info::Type {
833                            path: Path::new("NestedType", "my::module"),
834                            type_params: vec![TypeParameter::new(
835                                $param_name,
836                                Some(meta_type::<$generic>()),
837                            )],
838                            type_def: TypeDef::Composite(TypeDefComposite::new([Field::new(
839                                None,
840                                meta_type::<$inner>(),
841                                None,
842                                Vec::new(),
843                            )])),
844                            docs: vec![],
845                        }
846                    }
847                }
848            };
849        }
850
851        // A and B are the same because generics explain the param difference.
852        //
853        //NestedType<T = u32>(u32)
854        //NestedType<T = bool>(bool)
855        nested_type!(A, u32, u32, "T");
856        nested_type!(B, bool, bool, "T");
857        nested_type!(G, u64, u64, "B");
858
859        // As above, but another layer of nesting before generic param used.
860        //
861        //NestedType<T = u32>(Vec<u32>)
862        //NestedType<T = bool>(Vec<bool>)
863        nested_type!(C, bool, Vec<bool>, "T");
864        nested_type!(D, u32, Vec<u32>, "T");
865
866        // A third layer of nesting just to really check the recursion.
867        //
868        //NestedType<T = u32>(Vec<Foo<u32>>)
869        //NestedType<T = bool>(Vec<Foo<bool>>)
870        nested_type!(E, bool, Vec<Foo<bool>>, "T");
871        nested_type!(F, u32, Vec<Foo<u32>>, "T");
872
873        let mut registry = scale_info::Registry::new();
874        let id_a = registry.register_type(&meta_type::<A>()).id;
875        let id_b = registry.register_type(&meta_type::<B>()).id;
876        let id_c = registry.register_type(&meta_type::<C>()).id;
877        let id_d = registry.register_type(&meta_type::<D>()).id;
878        let id_e = registry.register_type(&meta_type::<E>()).id;
879        let id_f = registry.register_type(&meta_type::<F>()).id;
880        let id_g = registry.register_type(&meta_type::<G>()).id;
881
882        let mut registry = PortableRegistry::from(registry);
883
884        // Despite how many layers of nesting, we identify that the generic
885        // param can explain the difference, so can see them as being equal.
886        assert!(types_equal(id_a, id_b, &registry));
887        assert!(types_equal(id_c, id_d, &registry));
888        assert!(types_equal(id_e, id_f, &registry));
889        assert!(types_equal(id_a, id_g, &registry));
890
891        // Sanity check that the pairs are not equal with each other.
892        assert!(!types_equal(id_a, id_c, &registry));
893        assert!(!types_equal(id_a, id_e, &registry));
894        assert!(!types_equal(id_c, id_e, &registry));
895
896        // Now, check that the generated output is sane and in line with this...
897
898        ensure_unique_type_paths(&mut registry).expect("Corrupted PortableRegistry");
899        let settings = crate::TypeGeneratorSettings::new();
900        let output = crate::TypeGenerator::new(&registry, &settings)
901            .generate_types_mod()
902            .unwrap()
903            .to_token_stream(&settings);
904
905        // This isn't ideal, but I printed out the token stream, and it looks good (ie generates
906        // 3 types after deduplicating with the correct generic param usage), so this test will
907        // check that the output still looks good. To update, copy and `rustfmt` the new output
908        // and then adjust the odd thing until it matches again.
909        let expected = quote! {
910            pub mod types {
911                use super::types;
912                pub mod my {
913                    use super::types;
914                    pub mod module {
915                        use super::types;
916                        pub struct NestedType1<_0>(pub _0,);
917                        pub struct NestedType2<_0>(pub ::std::vec::Vec<_0>,);
918                        pub struct NestedType3<_0>(
919                            pub ::std::vec::Vec<types::scale_typegen::utils::tests::Foo<_0> >,
920                        );
921                    }
922                }
923                pub mod scale_typegen {
924                    use super::types;
925                    pub mod utils {
926                        use super::types;
927                        pub mod tests {
928                            use super::types;
929                            pub struct Foo<_0> {
930                                pub _inner: _0,
931                            }
932                        }
933                    }
934                }
935            }
936        };
937
938        assert_eq!(output.to_string(), expected.to_string());
939    }
940}