scale_info/
portable.rs

1// Copyright 2019-2022 Parity Technologies (UK) Ltd.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! The registry stores type definitions in a space-efficient manner.
16//!
17//! This is done by deduplicating common types in order to reuse their
18//! definitions which otherwise can grow arbitrarily large. A type is uniquely
19//! identified by its type identifier that is therefore used to refer to types
20//! and their definitions.
21//!
22//! Types with the same name are uniquely identifiable by introducing
23//! namespaces. The normal Rust namespace of a type is used, except for the Rust
24//! prelude types that live in the so-called root namespace which is empty.
25
26use crate::{
27    form::PortableForm,
28    interner::Interner,
29    prelude::{collections::BTreeMap, fmt::Debug, mem, vec::Vec},
30    Path, Registry, Type, TypeDef, TypeDefPrimitive,
31};
32use scale::Encode;
33
34/// A read-only registry containing types in their portable form for serialization.
35#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
36#[cfg_attr(feature = "serde", derive(serde::Serialize))]
37#[cfg_attr(all(feature = "serde", feature = "decode"), derive(serde::Deserialize))]
38#[cfg_attr(any(feature = "std", feature = "decode"), derive(scale::Decode))]
39#[derive(Clone, Debug, PartialEq, Eq, Encode)]
40pub struct PortableRegistry {
41    /// The types contained by the [`PortableRegistry`].
42    pub types: Vec<PortableType>,
43}
44
45impl From<Registry> for PortableRegistry {
46    fn from(registry: Registry) -> Self {
47        PortableRegistry {
48            types: registry
49                .types()
50                .map(|(k, v)| PortableType {
51                    id: k.id,
52                    ty: v.clone(),
53                })
54                .collect::<Vec<_>>(),
55        }
56    }
57}
58
59impl PortableRegistry {
60    /// Returns the type definition for the given identifier, `None` if no type found for that ID.
61    pub fn resolve(&self, id: u32) -> Option<&Type<PortableForm>> {
62        self.types.get(id as usize).map(|ty| &ty.ty)
63    }
64
65    /// Returns all types with their associated identifiers.
66    #[deprecated(
67        since = "2.5.0",
68        note = "Prefer to access the fields directly; this getter will be removed in the next major version"
69    )]
70    pub fn types(&self) -> &[PortableType] {
71        &self.types
72    }
73
74    /// Retains only the portable types needed to express the provided ids.
75    ///
76    /// The type IDs retained are returned as key to the [`BTreeMap`].
77    /// The value of the map represents the new ID of that type.
78    ///
79    /// # Note
80    ///
81    /// A given type ID can be defined by nesting type IDs, such as the case
82    /// of a [`TypeDef::Composite`] and others. To retain a valid [`PortableRegistry`]
83    /// all the types needed to express an ID are included. Therefore, the number of
84    /// elements defined by the result equals or exceeds the number of provided IDs.
85    pub fn retain<F>(&mut self, mut filter: F) -> BTreeMap<u32, u32>
86    where
87        F: FnMut(u32) -> bool,
88    {
89        let mut retained_mappings = BTreeMap::new();
90        let mut new_types = crate::prelude::vec![];
91
92        fn placeholder_type() -> PortableType {
93            PortableType {
94                id: u32::MAX,
95                ty: Type {
96                    type_def: TypeDef::Primitive(TypeDefPrimitive::Bool),
97                    path: Path::default(),
98                    type_params: crate::prelude::vec![],
99                    docs: crate::prelude::vec![],
100                },
101            }
102        }
103
104        fn retain_type(
105            id: u32,
106            types: &mut [PortableType],
107            new_types: &mut Vec<PortableType>,
108            retained_mappings: &mut BTreeMap<u32, u32>,
109        ) -> u32 {
110            // Type already retained; just return the new ID for it:
111            if let Some(id) = retained_mappings.get(&id) {
112                return *id;
113            }
114
115            // First, save a spot for this type in our new registry. We do this straight away
116            // so that we can add the type ID to the retained mappings _before_ recursing into
117            // it below. This means that if a type contains itself, we'll bail above when we
118            // see the same type again.
119            let new_id = new_types.len() as u32;
120            new_types.push(placeholder_type());
121            retained_mappings.insert(id, new_id);
122
123            // Now, take the actual type we'll be retaining out of the old registry,
124            // swapping it with a placeholder type to avoid any allocations. Because of
125            // the above, nothing should ever try to access this placeholder type anyway.
126            let mut ty = mem::replace(&mut types[id as usize], placeholder_type());
127            ty.id = new_id;
128
129            // Now we recursively retain any type parameters in the type we're retaining.
130            // Update their IDs to point to the new locations of the retained types.
131            for param in ty.ty.type_params.iter_mut() {
132                let Some(param_ty) = &param.ty else { continue };
133                let new_id = retain_type(param_ty.id, types, new_types, retained_mappings);
134                param.ty = Some(Into::into(new_id));
135            }
136
137            // Also recurse into any types inside this type to retain them too. Update their IDs
138            // to point to the new locations of the retained types.
139            match &mut ty.ty.type_def {
140                TypeDef::Composite(composite) => {
141                    for field in composite.fields.iter_mut() {
142                        let new_id = retain_type(field.ty.id, types, new_types, retained_mappings);
143                        field.ty = new_id.into();
144                    }
145                }
146                TypeDef::Variant(variant) => {
147                    for var in variant.variants.iter_mut() {
148                        for field in var.fields.iter_mut() {
149                            let new_id =
150                                retain_type(field.ty.id, types, new_types, retained_mappings);
151                            field.ty = new_id.into();
152                        }
153                    }
154                }
155                TypeDef::Sequence(sequence) => {
156                    let new_id =
157                        retain_type(sequence.type_param.id, types, new_types, retained_mappings);
158                    sequence.type_param = new_id.into();
159                }
160                TypeDef::Array(array) => {
161                    let new_id =
162                        retain_type(array.type_param.id, types, new_types, retained_mappings);
163                    array.type_param = new_id.into();
164                }
165                TypeDef::Tuple(tuple) => {
166                    for ty in tuple.fields.iter_mut() {
167                        let new_id = retain_type(ty.id, types, new_types, retained_mappings);
168                        *ty = new_id.into();
169                    }
170                }
171                TypeDef::Primitive(_) => (),
172                TypeDef::Compact(compact) => {
173                    let new_id =
174                        retain_type(compact.type_param.id, types, new_types, retained_mappings);
175                    compact.type_param = new_id.into();
176                }
177                TypeDef::BitSequence(bit_seq) => {
178                    let bit_store_id = retain_type(
179                        bit_seq.bit_store_type.id,
180                        types,
181                        new_types,
182                        retained_mappings,
183                    );
184                    let bit_order_id = retain_type(
185                        bit_seq.bit_order_type.id,
186                        types,
187                        new_types,
188                        retained_mappings,
189                    );
190
191                    bit_seq.bit_store_type = bit_store_id.into();
192                    bit_seq.bit_order_type = bit_order_id.into();
193                }
194            }
195
196            // Now we've updated the IDs etc of this type, we put it into the new registry
197            // and override our placeholder type that was saving its space for us.
198            new_types[new_id as usize] = ty;
199            new_id
200        }
201
202        for id in 0..self.types.len() as u32 {
203            // We don't care about the type; move on:
204            if !filter(id) {
205                continue;
206            }
207
208            retain_type(id, &mut self.types, &mut new_types, &mut retained_mappings);
209        }
210
211        self.types = new_types;
212        retained_mappings
213    }
214}
215
216/// Represent a type in it's portable form.
217#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
218#[cfg_attr(feature = "serde", derive(serde::Serialize))]
219#[cfg_attr(all(feature = "serde", feature = "decode"), derive(serde::Deserialize))]
220#[cfg_attr(any(feature = "std", feature = "decode"), derive(scale::Decode))]
221#[derive(Clone, Debug, PartialEq, Eq, Encode)]
222pub struct PortableType {
223    /// The ID of the portable type.
224    #[codec(compact)]
225    pub id: u32,
226    /// The portable form of the type.
227    #[cfg_attr(feature = "serde", serde(rename = "type"))]
228    pub ty: Type<PortableForm>,
229}
230
231impl PortableType {
232    /// Construct a custom `PortableType`.
233    pub fn new(id: u32, ty: Type<PortableForm>) -> Self {
234        Self { id, ty }
235    }
236
237    /// Returns the index of the [`PortableType`].
238    #[deprecated(
239        since = "2.5.0",
240        note = "Prefer to access the fields directly; this getter will be removed in the next major version"
241    )]
242    pub fn id(&self) -> u32 {
243        self.id
244    }
245
246    /// Returns the type of the [`PortableType`].
247    #[deprecated(
248        since = "2.5.0",
249        note = "Prefer to access the fields directly; this getter will be removed in the next major version"
250    )]
251    pub fn ty(&self) -> &Type<PortableForm> {
252        &self.ty
253    }
254}
255
256/// Construct a [`PortableRegistry`].
257///
258/// Guarantees that the resulting [`PortableRegistry`] has the list of types in the correct order,
259/// since downstream libs assume that a `u32` type id corresponds to the index of the type
260/// definition type table.
261#[derive(Debug, Default)]
262pub struct PortableRegistryBuilder {
263    types: Interner<Type<PortableForm>>,
264}
265
266impl PortableRegistryBuilder {
267    /// Create a new [`PortableRegistryBuilder`].
268    pub fn new() -> Self {
269        Default::default()
270    }
271
272    /// Register a type, returning the assigned ID.
273    ///
274    /// If the type is already registered it will return the existing ID.
275    pub fn register_type(&mut self, ty: Type<PortableForm>) -> u32 {
276        self.types.intern_or_get(ty).1.into_untracked().id
277    }
278
279    /// Returns the type id that would be assigned to a newly registered type.
280    pub fn next_type_id(&self) -> u32 {
281        self.types.elements().len() as u32
282    }
283
284    /// Returns a reference to the type registered at the given ID (if any).
285    pub fn get(&self, id: u32) -> Option<&Type<PortableForm>> {
286        self.types.elements().get(id as usize)
287    }
288
289    /// Finalize and return a valid [`PortableRegistry`] instance.
290    pub fn finish(&self) -> PortableRegistry {
291        let types = self
292            .types
293            .elements()
294            .iter()
295            .enumerate()
296            .map(|(i, ty)| PortableType {
297                id: i as u32,
298                ty: ty.clone(),
299            })
300            .collect();
301        PortableRegistry { types }
302    }
303}
304
305#[cfg(test)]
306mod tests {
307    use scale::Compact;
308
309    use super::*;
310    use crate::ty::TypeDefPrimitive;
311    use crate::{build::*, prelude::vec, *};
312
313    fn ty<T: TypeInfo + 'static>() -> MetaType {
314        MetaType::new::<T>()
315    }
316
317    fn make_registry(tys: impl IntoIterator<Item = MetaType>) -> (Vec<u32>, PortableRegistry) {
318        // Register our types, recording the corresponding IDs.
319        let mut types = Registry::new();
320        let mut ids = vec![];
321        for ty in tys.into_iter() {
322            let id = types.register_type(&ty);
323            ids.push(id.id);
324        }
325
326        let registry = types.into();
327        (ids, registry)
328    }
329
330    #[test]
331    fn retain_seq_type() {
332        let (ids, mut registry) = make_registry([ty::<bool>(), ty::<Vec<u32>>(), ty::<String>()]);
333
334        assert_eq!(registry.types.len(), 4);
335
336        // Retain only the vec.
337        let vec_id = ids[1];
338        let retained_ids = registry.retain(|id| id == vec_id);
339
340        assert_eq!(retained_ids.len(), 2);
341        assert_eq!(registry.types.len(), 2);
342
343        // Check that vec was retained and has correct ID.
344        let new_vec_id = *retained_ids
345            .get(&vec_id)
346            .expect("vec should have been retained");
347        let registry_ty = registry
348            .types
349            .get(new_vec_id as usize)
350            .expect("vec should exist");
351
352        assert_eq!(registry_ty.id, new_vec_id);
353
354        // Check that vec type info is as expected.
355        let seq = match &registry_ty.ty.type_def {
356            TypeDef::Sequence(s) => s,
357            def => panic!("Expected a sequence type, got {def:?}"),
358        };
359
360        let vec_param = registry
361            .resolve(seq.type_param.id)
362            .expect("vec param should be exist");
363        assert!(matches!(
364            vec_param.type_def,
365            TypeDef::Primitive(TypeDefPrimitive::U32)
366        ));
367    }
368
369    #[test]
370    fn retain_array_type() {
371        let (ids, mut registry) = make_registry([ty::<bool>(), ty::<[u32; 16]>(), ty::<String>()]);
372
373        assert_eq!(registry.types.len(), 4);
374
375        // Retain only the array.
376        let arr_id = ids[1];
377        let retained_ids = registry.retain(|id| id == arr_id);
378
379        assert_eq!(retained_ids.len(), 2);
380        assert_eq!(registry.types.len(), 2);
381
382        // Check that array was retained and has correct ID.
383        let new_arr_id = *retained_ids
384            .get(&arr_id)
385            .expect("array should have been retained");
386        let registry_ty = registry
387            .types
388            .get(new_arr_id as usize)
389            .expect("array should exist");
390
391        assert_eq!(registry_ty.id, new_arr_id);
392
393        // Check that array type info is as expected.
394        let arr = match &registry_ty.ty.type_def {
395            TypeDef::Array(a) => a,
396            def => panic!("Expected an array type, got {def:?}"),
397        };
398
399        let array_param = registry
400            .resolve(arr.type_param.id)
401            .expect("array param should be exist");
402        assert!(matches!(
403            array_param.type_def,
404            TypeDef::Primitive(TypeDefPrimitive::U32)
405        ));
406    }
407
408    #[test]
409    fn retain_tuple_type() {
410        let (ids, mut registry) =
411            make_registry([ty::<bool>(), ty::<(u32, [u8; 32], bool)>(), ty::<String>()]);
412
413        assert_eq!(registry.types.len(), 6);
414
415        // Retain only the tuple.
416        let tuple_id = ids[1];
417        let retained_ids = registry.retain(|id| id == tuple_id);
418
419        // We only actually ditch the String when retaining:
420        assert_eq!(retained_ids.len(), 5);
421        assert_eq!(registry.types.len(), 5);
422
423        // Check that tuple was retained and has correct ID.
424        let new_tuple_id = *retained_ids
425            .get(&tuple_id)
426            .expect("tuple should have been retained");
427        let registry_ty = registry
428            .types
429            .get(new_tuple_id as usize)
430            .expect("tuple should exist");
431
432        assert_eq!(registry_ty.id, new_tuple_id);
433
434        // Check that tuple type info is as expected.
435        let tup = match &registry_ty.ty.type_def {
436            TypeDef::Tuple(t) => t,
437            def => panic!("Expected an tuple type, got {def:?}"),
438        };
439
440        // Check that tuple fields are as expected.
441        assert!(matches!(
442            registry.resolve(tup.fields[0].id).unwrap().type_def,
443            TypeDef::Primitive(TypeDefPrimitive::U32)
444        ));
445        assert!(matches!(
446            registry.resolve(tup.fields[1].id).unwrap().type_def,
447            TypeDef::Array(_)
448        ));
449        assert!(matches!(
450            registry.resolve(tup.fields[2].id).unwrap().type_def,
451            TypeDef::Primitive(TypeDefPrimitive::Bool)
452        ));
453    }
454
455    #[test]
456    fn retain_composite_type() {
457        #[derive(scale_info_derive::TypeInfo)]
458        #[allow(dead_code)]
459        struct Foo {
460            a: u32,
461            b: [u8; 32],
462            c: bool,
463        }
464
465        let (ids, mut registry) = make_registry([ty::<bool>(), ty::<Foo>(), ty::<String>()]);
466
467        assert_eq!(registry.types.len(), 6);
468
469        // Retain only the struct.
470        let struct_id = ids[1];
471        let retained_ids = registry.retain(|id| id == struct_id);
472
473        // We only actually ditch the String when retaining:
474        assert_eq!(retained_ids.len(), 5);
475        assert_eq!(registry.types.len(), 5);
476
477        // Check that struct was retained and has correct ID.
478        let struct_id = *retained_ids
479            .get(&struct_id)
480            .expect("struct should have been retained");
481        let registry_ty = registry
482            .types
483            .get(struct_id as usize)
484            .expect("struct should exist");
485
486        assert_eq!(registry_ty.id, struct_id);
487
488        // Check that struct type info is as expected.
489        let struc = match &registry_ty.ty.type_def {
490            TypeDef::Composite(s) => s,
491            def => panic!("Expected an struct type, got {def:?}"),
492        };
493
494        // Check that struct fields are as expected.
495        assert_eq!(struc.fields.len(), 3);
496        assert_eq!(struc.fields[0].name, Some("a".to_owned()));
497        assert!(matches!(
498            registry.resolve(struc.fields[0].ty.id).unwrap().type_def,
499            TypeDef::Primitive(TypeDefPrimitive::U32)
500        ));
501        assert_eq!(struc.fields[1].name, Some("b".to_owned()));
502        assert!(matches!(
503            registry.resolve(struc.fields[1].ty.id).unwrap().type_def,
504            TypeDef::Array(_)
505        ));
506        assert_eq!(struc.fields[2].name, Some("c".to_owned()));
507        assert!(matches!(
508            registry.resolve(struc.fields[2].ty.id).unwrap().type_def,
509            TypeDef::Primitive(TypeDefPrimitive::Bool)
510        ));
511    }
512
513    #[test]
514    fn retain_variant_type() {
515        #[derive(scale_info_derive::TypeInfo)]
516        #[allow(dead_code)]
517        enum Foo {
518            A(u32),
519            B(bool),
520        }
521
522        let (ids, mut registry) = make_registry([ty::<bool>(), ty::<Foo>(), ty::<String>()]);
523
524        assert_eq!(registry.types.len(), 4);
525
526        // Retain only the variant.
527        let variant_id = ids[1];
528        let retained_ids = registry.retain(|id| id == variant_id);
529
530        // We only actually ditch the String when retaining:
531        assert_eq!(retained_ids.len(), 3);
532        assert_eq!(registry.types.len(), 3);
533
534        // Check that variant was retained and has correct ID.
535        let variant_id = *retained_ids
536            .get(&variant_id)
537            .expect("variant should have been retained");
538        let registry_ty = registry
539            .types
540            .get(variant_id as usize)
541            .expect("variant should exist");
542
543        assert_eq!(registry_ty.id, variant_id);
544
545        // Check that variant type info is as expected.
546        let var = match &registry_ty.ty.type_def {
547            TypeDef::Variant(v) => v,
548            def => panic!("Expected a variant type, got {def:?}"),
549        };
550
551        assert_eq!(var.variants.len(), 2);
552        assert_eq!(var.variants[0].name, "A".to_owned());
553        assert_eq!(var.variants[0].fields.len(), 1);
554        assert!(matches!(
555            registry
556                .resolve(var.variants[0].fields[0].ty.id)
557                .unwrap()
558                .type_def,
559            TypeDef::Primitive(TypeDefPrimitive::U32)
560        ));
561
562        assert_eq!(var.variants[1].name, "B".to_owned());
563        assert_eq!(var.variants[1].fields.len(), 1);
564        assert!(matches!(
565            registry
566                .resolve(var.variants[1].fields[0].ty.id)
567                .unwrap()
568                .type_def,
569            TypeDef::Primitive(TypeDefPrimitive::Bool)
570        ));
571    }
572
573    #[test]
574    fn retain_compact_type() {
575        let (ids, mut registry) =
576            make_registry([ty::<bool>(), ty::<String>(), ty::<Compact<u32>>()]);
577
578        assert_eq!(registry.types.len(), 4);
579
580        // Retain only the compact.
581        let compact_id = ids[2];
582        let retained_ids = registry.retain(|id| id == compact_id);
583
584        assert_eq!(retained_ids.len(), 2);
585        assert_eq!(registry.types.len(), 2);
586
587        // Check that compact was retained and has correct ID.
588        let compact_id = *retained_ids
589            .get(&compact_id)
590            .expect("compact should have been retained");
591        let registry_ty = registry
592            .types
593            .get(compact_id as usize)
594            .expect("compact should exist");
595
596        assert_eq!(registry_ty.id, compact_id);
597
598        // Check that compact type info is as expected.
599        let compact = match &registry_ty.ty.type_def {
600            TypeDef::Compact(c) => c,
601            def => panic!("Expected a compact type, got {def:?}"),
602        };
603
604        // And the compact param should be a u32.
605        assert!(matches!(
606            registry.resolve(compact.type_param.id).unwrap().type_def,
607            TypeDef::Primitive(TypeDefPrimitive::U32)
608        ));
609    }
610
611    #[test]
612    fn retain_bitsequence_type() {
613        // Use a more verbose method to build the registry to avoid
614        // needing to pull in BitVec as a dev dep:
615        let mut builder = PortableRegistryBuilder::new();
616
617        // Register a couple of primitives:
618        let bool_type = Type::new(Path::default(), vec![], TypeDefPrimitive::Bool, vec![]);
619        let _bool_type_id = builder.register_type(bool_type);
620
621        let u32_type = Type::new(Path::default(), vec![], TypeDefPrimitive::U32, vec![]);
622        let u32_type_id = builder.register_type(u32_type);
623
624        let u64_type = Type::new(Path::default(), vec![], TypeDefPrimitive::U64, vec![]);
625        let u64_type_id = builder.register_type(u64_type);
626
627        // Register a bit sequence:
628        let bit_seq_type = Type::new(
629            Path::default(),
630            vec![],
631            TypeDefBitSequence::new_portable(u32_type_id.into(), u64_type_id.into()),
632            vec![],
633        );
634        let bit_seq_type_id = builder.register_type(bit_seq_type);
635
636        // Now we have a registry with the above types in:
637        let mut registry = builder.finish();
638
639        assert_eq!(registry.types.len(), 4);
640
641        // Retain only the bitseq.
642        let retained_ids = registry.retain(|id| id == bit_seq_type_id);
643
644        // One bitsequence entry + 2 params for it:
645        assert_eq!(retained_ids.len(), 3);
646        assert_eq!(registry.types.len(), 3);
647
648        // Check that bitseq was retained and has correct ID.
649        let bitseq_id = *retained_ids
650            .get(&bit_seq_type_id)
651            .expect("bitseq should have been retained");
652        let registry_ty = registry
653            .types
654            .get(bitseq_id as usize)
655            .expect("bitseq should exist");
656
657        assert_eq!(registry_ty.id, bitseq_id);
658
659        // Check that bitseq type info is as expected.
660        let bitseq = match &registry_ty.ty.type_def {
661            TypeDef::BitSequence(b) => b,
662            def => panic!("Expected a bit sequence type, got {def:?}"),
663        };
664        assert!(matches!(
665            registry.resolve(bitseq.bit_store_type.id).unwrap().type_def,
666            TypeDef::Primitive(TypeDefPrimitive::U32)
667        ));
668        assert!(matches!(
669            registry.resolve(bitseq.bit_order_type.id).unwrap().type_def,
670            TypeDef::Primitive(TypeDefPrimitive::U64)
671        ));
672    }
673
674    #[test]
675    fn retain_recursive_type() {
676        #[derive(scale_info_derive::TypeInfo)]
677        #[allow(dead_code)]
678        enum Recursive {
679            Value(Box<Recursive>),
680            Empty,
681        }
682
683        let (ids, mut registry) = make_registry([ty::<bool>(), ty::<Recursive>(), ty::<String>()]);
684
685        assert_eq!(registry.types.len(), 3);
686
687        // Retain only the recursive type.
688        let variant_id = ids[1];
689        let retained_ids = registry.retain(|id| id == variant_id);
690
691        assert_eq!(retained_ids.len(), 1);
692        assert_eq!(registry.types.len(), 1);
693
694        // Check that variant was retained and has correct ID.
695        let variant_id = *retained_ids
696            .get(&variant_id)
697            .expect("variant should have been retained");
698        let registry_ty = registry
699            .types
700            .get(variant_id as usize)
701            .expect("variant should exist");
702
703        assert_eq!(registry_ty.id, variant_id);
704
705        // Check that variant type info is as expected.
706        let var = match &registry_ty.ty.type_def {
707            TypeDef::Variant(v) => v,
708            def => panic!("Expected a variant type, got {def:?}"),
709        };
710
711        assert_eq!(var.variants.len(), 2);
712        assert_eq!(var.variants[0].name, "Value".to_owned());
713        assert_eq!(var.variants[0].fields.len(), 1);
714        assert!(matches!(
715            registry
716                .resolve(var.variants[0].fields[0].ty.id)
717                .unwrap()
718                .type_def,
719            TypeDef::Variant(_)
720        ));
721
722        assert_eq!(var.variants[1].name, "Empty".to_owned());
723        assert_eq!(var.variants[1].fields.len(), 0);
724    }
725
726    #[test]
727    fn type_ids_are_sequential() {
728        let mut registry = Registry::new();
729        registry.register_type(&MetaType::new::<u32>());
730        registry.register_type(&MetaType::new::<bool>());
731        registry.register_type(&MetaType::new::<Option<(u32, bool)>>());
732
733        let readonly: PortableRegistry = registry.into();
734
735        assert_eq!(4, readonly.types.len());
736
737        for (expected, ty) in readonly.types.iter().enumerate() {
738            assert_eq!(expected as u32, ty.id);
739        }
740    }
741
742    #[test]
743    fn construct_portable_registry() {
744        let mut builder = PortableRegistryBuilder::new();
745        let u32_type = Type::new(Path::default(), vec![], TypeDefPrimitive::U32, vec![]);
746        let u32_type_id = builder.register_type(u32_type.clone());
747
748        let vec_u32_type = Type::new(
749            Path::default(),
750            vec![],
751            TypeDefSequence::new(u32_type_id.into()),
752            vec![],
753        );
754        let vec_u32_type_id = builder.register_type(vec_u32_type.clone());
755
756        let self_referential_type_id = builder.next_type_id();
757
758        let composite_type = Type::builder_portable()
759            .path(Path::from_segments_unchecked(["MyStruct".into()]))
760            .composite(
761                Fields::named()
762                    .field_portable(|f| f.name("primitive".into()).ty(u32_type_id))
763                    .field_portable(|f| f.name("vec_of_u32".into()).ty(vec_u32_type_id))
764                    .field_portable(|f| {
765                        f.name("self_referential".into())
766                            .ty(self_referential_type_id)
767                    }),
768            );
769        let composite_type_id = builder.register_type(composite_type.clone());
770
771        assert_eq!(self_referential_type_id, composite_type_id);
772
773        assert_eq!(builder.get(u32_type_id).unwrap(), &u32_type);
774        assert_eq!(builder.get(vec_u32_type_id).unwrap(), &vec_u32_type);
775        assert_eq!(builder.get(composite_type_id).unwrap(), &composite_type);
776
777        let registry = builder.finish();
778
779        assert_eq!(Some(&u32_type), registry.resolve(u32_type_id));
780        assert_eq!(Some(&vec_u32_type), registry.resolve(vec_u32_type_id));
781        assert_eq!(Some(&composite_type), registry.resolve(composite_type_id));
782    }
783}