scale_encode/impls/
mod.rs

1// Copyright (C) 2023 Parity Technologies (UK) Ltd. (admin@parity.io)
2// This file is a part of the scale-encode crate.
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//         http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16#[cfg(feature = "bits")]
17mod bits;
18mod composite;
19#[cfg(feature = "primitive-types")]
20mod primitive_types;
21mod variant;
22
23use crate::{
24    error::{Error, ErrorKind, Kind},
25    EncodeAsFields, EncodeAsType,
26};
27use alloc::{
28    borrow::ToOwned,
29    boxed::Box,
30    collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque},
31    format,
32    rc::Rc,
33    string::{String, ToString},
34    sync::Arc,
35    vec::Vec,
36};
37use codec::{Compact, Encode};
38use core::{
39    marker::PhantomData,
40    num::{
41        NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroU128, NonZeroU16,
42        NonZeroU32, NonZeroU64, NonZeroU8,
43    },
44    ops::{Range, RangeInclusive},
45    time::Duration,
46};
47use scale_type_resolver::{visitor, FieldIter, Primitive, ResolvedTypeVisitor, TypeResolver};
48
49// Useful to help encode key-value types or custom variant types manually.
50// Primarily used in the derive macro.
51pub use composite::{Composite, CompositeField};
52pub use variant::Variant;
53
54fn resolve_type_and_encode<
55    'resolver,
56    R: TypeResolver,
57    V: ResolvedTypeVisitor<'resolver, TypeId = R::TypeId, Value = Result<(), Error>>,
58>(
59    types: &'resolver R,
60    type_id: R::TypeId,
61    visitor: V,
62) -> Result<(), Error> {
63    match types.resolve_type(type_id, visitor) {
64        Ok(res) => res,
65        Err(e) => Err(Error::new(ErrorKind::TypeResolvingError(e.to_string()))),
66    }
67}
68
69impl EncodeAsType for bool {
70    fn encode_as_type_to<R: TypeResolver>(
71        &self,
72        type_id: R::TypeId,
73        types: &R,
74        out: &mut Vec<u8>,
75    ) -> Result<(), Error> {
76        let type_id = find_single_entry_with_same_repr(type_id, types);
77
78        let wrong_shape_err = |type_id| {
79            Error::new(ErrorKind::WrongShape {
80                actual: Kind::Bool,
81                expected_id: format!("{type_id:?}"),
82            })
83        };
84
85        let v = visitor::new(type_id.clone(), |type_id, _| Err(wrong_shape_err(type_id)))
86            .visit_primitive(|type_id, primitive| {
87                if primitive == Primitive::Bool {
88                    self.encode_to(out);
89                    Ok(())
90                } else {
91                    Err(wrong_shape_err(type_id))
92                }
93            })
94            .visit_not_found(|type_id| {
95                Err(Error::new(ErrorKind::TypeNotFound(format!("{type_id:?}"))))
96            });
97
98        resolve_type_and_encode(types, type_id, v)
99    }
100}
101
102impl EncodeAsType for str {
103    fn encode_as_type_to<R: TypeResolver>(
104        &self,
105        type_id: R::TypeId,
106        types: &R,
107        out: &mut Vec<u8>,
108    ) -> Result<(), Error> {
109        let type_id = find_single_entry_with_same_repr(type_id, types);
110
111        let wrong_shape_err = |type_id| {
112            Error::new(ErrorKind::WrongShape {
113                actual: Kind::Str,
114                expected_id: format!("{type_id:?}"),
115            })
116        };
117
118        let v = visitor::new(type_id.clone(), |type_id, _| Err(wrong_shape_err(type_id)))
119            .visit_primitive(|type_id, primitive| {
120                if primitive == Primitive::Str {
121                    self.encode_to(out);
122                    Ok(())
123                } else {
124                    Err(wrong_shape_err(type_id))
125                }
126            })
127            .visit_not_found(|type_id| {
128                Err(Error::new(ErrorKind::TypeNotFound(format!("{type_id:?}"))))
129            });
130
131        resolve_type_and_encode(types, type_id, v)
132    }
133}
134
135impl<'a, T> EncodeAsType for &'a T
136where
137    T: EncodeAsType + ?Sized,
138{
139    fn encode_as_type_to<R: TypeResolver>(
140        &self,
141        type_id: R::TypeId,
142        types: &R,
143        out: &mut Vec<u8>,
144    ) -> Result<(), Error> {
145        (*self).encode_as_type_to(type_id, types, out)
146    }
147}
148
149impl<'a, T> EncodeAsType for alloc::borrow::Cow<'a, T>
150where
151    T: 'a + EncodeAsType + ToOwned + ?Sized,
152{
153    fn encode_as_type_to<R: TypeResolver>(
154        &self,
155        type_id: R::TypeId,
156        types: &R,
157        out: &mut Vec<u8>,
158    ) -> Result<(), Error> {
159        (**self).encode_as_type_to(type_id, types, out)
160    }
161}
162
163impl<T> EncodeAsType for [T]
164where
165    T: EncodeAsType,
166{
167    fn encode_as_type_to<R: TypeResolver>(
168        &self,
169        type_id: R::TypeId,
170        types: &R,
171        out: &mut Vec<u8>,
172    ) -> Result<(), Error> {
173        encode_iterable_sequence_to(self.len(), self.iter(), type_id, types, out)
174    }
175}
176
177impl<const N: usize, T: EncodeAsType> EncodeAsType for [T; N] {
178    fn encode_as_type_to<R: TypeResolver>(
179        &self,
180        type_id: R::TypeId,
181        types: &R,
182        out: &mut Vec<u8>,
183    ) -> Result<(), Error> {
184        self[..].encode_as_type_to(type_id, types, out)
185    }
186}
187
188impl<T> EncodeAsType for PhantomData<T> {
189    fn encode_as_type_to<R: TypeResolver>(
190        &self,
191        type_id: R::TypeId,
192        types: &R,
193        out: &mut Vec<u8>,
194    ) -> Result<(), Error> {
195        ().encode_as_type_to(type_id, types, out)
196    }
197}
198
199impl<T: EncodeAsType, E: EncodeAsType> EncodeAsType for Result<T, E> {
200    fn encode_as_type_to<R: TypeResolver>(
201        &self,
202        type_id: R::TypeId,
203        types: &R,
204        out: &mut Vec<u8>,
205    ) -> Result<(), Error> {
206        match self {
207            Ok(v) => Variant {
208                name: "Ok",
209                fields: Composite::new([(None, CompositeField::new(v))].iter().copied()),
210            }
211            .encode_variant_as_type_to(type_id, types, out),
212            Err(e) => Variant {
213                name: "Err",
214                fields: Composite::new([(None, CompositeField::new(e))].iter().copied()),
215            }
216            .encode_variant_as_type_to(type_id, types, out),
217        }
218    }
219}
220
221impl<T: EncodeAsType> EncodeAsType for Option<T> {
222    fn encode_as_type_to<R: TypeResolver>(
223        &self,
224        type_id: R::TypeId,
225        types: &R,
226        out: &mut Vec<u8>,
227    ) -> Result<(), Error> {
228        match self {
229            Some(v) => Variant {
230                name: "Some",
231                fields: Composite::new([(None, CompositeField::new(v))].iter().copied()),
232            }
233            .encode_variant_as_type_to(type_id, types, out),
234            None => Variant {
235                name: "None",
236                fields: Composite::new([].iter().copied()),
237            }
238            .encode_variant_as_type_to(type_id, types, out),
239        }
240    }
241}
242
243// Encode any numeric type implementing ToNumber, above, into the type ID given.
244macro_rules! impl_encode_number {
245    ($ty:ty) => {
246        impl EncodeAsType for $ty {
247            fn encode_as_type_to<R: TypeResolver>(
248                &self,
249                type_id: R::TypeId,
250                types: &R,
251                out: &mut Vec<u8>,
252            ) -> Result<(), Error> {
253                let type_id = find_single_entry_with_same_repr(type_id, types);
254
255                let wrong_shape_err = |type_id| {
256                    Error::new(ErrorKind::WrongShape {
257                        actual: Kind::Number,
258                        expected_id: format!("{type_id:?}"),
259                    })
260                };
261
262                let v = visitor::new((type_id.clone(), out), |(type_id, _out), _kind| Err(wrong_shape_err(type_id)))
263                    .visit_primitive(|(type_id, out), primitive| {
264                        fn try_num<T: TryFrom<$ty> + Encode>(
265                            num: $ty,
266                            target_id: impl core::fmt::Debug,
267                            out: &mut Vec<u8>,
268                        ) -> Result<(), Error> {
269                            let n: T = num.try_into().map_err(|_| {
270                                Error::new(ErrorKind::NumberOutOfRange {
271                                    value: num.to_string(),
272                                    expected_id: format!("{target_id:?}"),
273                                })
274                            })?;
275                            n.encode_to(out);
276                            Ok(())
277                        }
278
279                        match primitive {
280                            Primitive::U8 => try_num::<u8>(*self, type_id, out),
281                            Primitive::U16 => try_num::<u16>(*self, type_id, out),
282                            Primitive::U32 => try_num::<u32>(*self, type_id, out),
283                            Primitive::U64 => try_num::<u64>(*self, type_id, out),
284                            Primitive::U128 => try_num::<u128>(*self, type_id, out),
285                            Primitive::I8 => try_num::<i8>(*self, type_id, out),
286                            Primitive::I16 => try_num::<i16>(*self, type_id, out),
287                            Primitive::I32 => try_num::<i32>(*self, type_id, out),
288                            Primitive::I64 => try_num::<i64>(*self, type_id, out),
289                            Primitive::I128 => try_num::<i128>(*self, type_id, out),
290                            _ => Err(wrong_shape_err(type_id)),
291                        }
292                    })
293                    .visit_compact(|(_,out), inner_type_id| {
294                        let inner_type_id = find_single_entry_with_same_repr(inner_type_id, types);
295
296                        macro_rules! try_compact_num {
297                            ($num:expr, $inner_type_id:ident, $target_kind:expr, $out:expr, $type:ty) => {{
298                                let n: $type = $num.try_into().map_err(|_| {
299                                    Error::new(ErrorKind::NumberOutOfRange {
300                                        value: $num.to_string(),
301                                        expected_id: format!("{:?}", $inner_type_id),
302                                    })
303                                })?;
304                                Compact(n).encode_to($out);
305                                Ok(())
306                            }};
307                        }
308
309                        let v = visitor::new((inner_type_id.clone(),out), |(inner_type_id,_out), _| Err(wrong_shape_err(inner_type_id))).visit_primitive(
310                            |(inner_type_id,out), primitive| match primitive {
311                                Primitive::U8 => {
312                                    try_compact_num!(*self, inner_type_id, NumericKind::U8, out, u8)
313                                }
314                                Primitive::U16 => {
315                                    try_compact_num!(*self, inner_type_id, NumericKind::U16, out, u16)
316                                }
317                                Primitive::U32 => {
318                                    try_compact_num!(*self, inner_type_id, NumericKind::U32, out, u32)
319                                }
320                                Primitive::U64 => {
321                                    try_compact_num!(*self, inner_type_id, NumericKind::U64, out, u64)
322                                }
323                                Primitive::U128 => {
324                                    try_compact_num!(*self, inner_type_id, NumericKind::U128, out, u128)
325                                }
326                                _ => Err(wrong_shape_err(inner_type_id)),
327                            },
328                        );
329
330                        resolve_type_and_encode(types, inner_type_id, v)
331                    })
332                    .visit_not_found(|(type_id,_out)| {
333                        Err(Error::new(ErrorKind::TypeNotFound(format!("{type_id:?}"))))
334                    });
335
336                resolve_type_and_encode(types, type_id, v)
337            }
338        }
339    };
340}
341impl_encode_number!(u8);
342impl_encode_number!(u16);
343impl_encode_number!(u32);
344impl_encode_number!(u64);
345impl_encode_number!(u128);
346impl_encode_number!(usize);
347impl_encode_number!(i8);
348impl_encode_number!(i16);
349impl_encode_number!(i32);
350impl_encode_number!(i64);
351impl_encode_number!(i128);
352impl_encode_number!(isize);
353
354// Encode tuple types to any matching type.
355macro_rules! impl_encode_tuple {
356    ($($name:ident: $t:ident),*) => {
357        impl < $($t),* > EncodeAsType for ($($t,)*) where $($t: EncodeAsType),* {
358            fn encode_as_type_to<Resolver: TypeResolver>(&self, type_id: Resolver::TypeId, types: &Resolver, out: &mut Vec<u8>) -> Result<(), Error> {
359                let ($($name,)*) = self;
360                Composite::new([
361                    $(
362                        (None as Option<&'static str>, CompositeField::new($name))
363                    ,)*
364                ].iter().copied()).encode_composite_as_type_to(type_id, types, out)
365            }
366        }
367    }
368}
369#[rustfmt::skip]
370const _: () = {
371    impl_encode_tuple!();
372    impl_encode_tuple!(a: A);
373    impl_encode_tuple!(a: A, b: B);
374    impl_encode_tuple!(a: A, b: B, c: C);
375    impl_encode_tuple!(a: A, b: B, c: C, d: D);
376    impl_encode_tuple!(a: A, b: B, c: C, d: D, e: E);
377    impl_encode_tuple!(a: A, b: B, c: C, d: D, e: E, f: F);
378    impl_encode_tuple!(a: A, b: B, c: C, d: D, e: E, f: F, g: G);
379    impl_encode_tuple!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H);
380    impl_encode_tuple!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I);
381    impl_encode_tuple!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J);
382    impl_encode_tuple!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K);
383    impl_encode_tuple!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L);
384    impl_encode_tuple!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M);
385    impl_encode_tuple!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N);
386    impl_encode_tuple!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N, o: O);
387    impl_encode_tuple!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N, o: O, p: P);
388    impl_encode_tuple!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N, o: O, p: P, q: Q);
389    impl_encode_tuple!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N, o: O, p: P, q: Q, r: R);
390    impl_encode_tuple!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N, o: O, p: P, q: Q, r: R, s: S);
391    // ^ Note: We make sure to support as many as parity-scale-codec's Encode impls do.
392};
393
394// Implement encoding via iterators for ordered collections
395macro_rules! impl_encode_seq_via_iterator {
396    ($ty:ident $( [$($param:ident),+] )?) => {
397        impl $(< $($param),+ >)? EncodeAsType for $ty $(< $($param),+ >)?
398        where $( $($param: EncodeAsType),+ )?
399        {
400            fn encode_as_type_to<R: TypeResolver>(
401                &self,
402                type_id: R::TypeId,
403                types: &R,
404                out: &mut Vec<u8>,
405            ) -> Result<(), Error> {
406                encode_iterable_sequence_to(self.len(), self.iter(), type_id, types, out)
407            }
408        }
409    }
410}
411impl_encode_seq_via_iterator!(BTreeSet[K]);
412impl_encode_seq_via_iterator!(LinkedList[V]);
413impl_encode_seq_via_iterator!(BinaryHeap[V]);
414impl_encode_seq_via_iterator!(VecDeque[V]);
415impl_encode_seq_via_iterator!(Vec[V]);
416
417impl<K: AsRef<str>, V: EncodeAsType> EncodeAsType for BTreeMap<K, V> {
418    fn encode_as_type_to<R: TypeResolver>(
419        &self,
420        type_id: R::TypeId,
421        types: &R,
422        out: &mut Vec<u8>,
423    ) -> Result<(), Error> {
424        let v = visitor::new((type_id.clone(), out), |(type_id, out), _| {
425            Composite::new(
426                self.iter()
427                    .map(|(k, v)| (Some(k.as_ref()), CompositeField::new(v))),
428            )
429            .encode_composite_as_type_to(type_id, types, out)
430        })
431        .visit_array(|(type_id, out), _, _| {
432            encode_iterable_sequence_to(self.len(), self.values(), type_id, types, out)
433        })
434        .visit_sequence(|(type_id, out), _, _| {
435            encode_iterable_sequence_to(self.len(), self.values(), type_id, types, out)
436        });
437
438        resolve_type_and_encode(types, type_id, v)
439    }
440}
441impl<K: AsRef<str>, V: EncodeAsType> EncodeAsFields for BTreeMap<K, V> {
442    fn encode_as_fields_to<R: TypeResolver>(
443        &self,
444        fields: &mut dyn FieldIter<'_, R::TypeId>,
445        types: &R,
446        out: &mut Vec<u8>,
447    ) -> Result<(), Error> {
448        Composite::new(
449            self.iter()
450                .map(|(k, v)| (Some(k.as_ref()), CompositeField::new(v))),
451        )
452        .encode_composite_fields_to(fields, types, out)
453    }
454}
455
456// Generate EncodeAsType impls for simple types that can be easily transformed
457// into types we have impls for already.
458macro_rules! impl_encode_like {
459    ($ty:ident $(<$( $param:ident ),+>)? as $delegate_ty:ty where |$val:ident| $expr:expr) => {
460        impl $(< $($param: EncodeAsType),+ >)? EncodeAsType for $ty $(<$( $param ),+>)? {
461            fn encode_as_type_to<R: TypeResolver>(
462                &self,
463                type_id: R::TypeId,
464                types: &R,
465                out: &mut Vec<u8>,
466            ) -> Result<(), Error> {
467                let delegate: $delegate_ty = {
468                    let $val = self;
469                    $expr
470                };
471                delegate.encode_as_type_to(type_id, types, out)
472            }
473        }
474    }
475}
476impl_encode_like!(String as &str where |val| val);
477impl_encode_like!(Box<T> as &T where |val| val);
478impl_encode_like!(Arc<T> as &T where |val| val);
479impl_encode_like!(Rc<T> as &T where |val| val);
480impl_encode_like!(char as u32 where |val| *val as u32);
481impl_encode_like!(NonZeroU8 as u8 where |val| val.get());
482impl_encode_like!(NonZeroU16 as u16 where |val| val.get());
483impl_encode_like!(NonZeroU32 as u32 where |val| val.get());
484impl_encode_like!(NonZeroU64 as u64 where |val| val.get());
485impl_encode_like!(NonZeroU128 as u128 where |val| val.get());
486impl_encode_like!(NonZeroI8 as i8 where |val| val.get());
487impl_encode_like!(NonZeroI16 as i16 where |val| val.get());
488impl_encode_like!(NonZeroI32 as i32 where |val| val.get());
489impl_encode_like!(NonZeroI64 as i64 where |val| val.get());
490impl_encode_like!(NonZeroI128 as i128 where |val| val.get());
491impl_encode_like!(Duration as (u64, u32) where |val| (val.as_secs(), val.subsec_nanos()));
492impl_encode_like!(Range<T> as (&T, &T) where |val| (&val.start, &val.end));
493impl_encode_like!(RangeInclusive<T> as (&T, &T) where |val| ((val.start()), (val.end())));
494impl_encode_like!(Compact<T> as &T where |val| &val.0);
495
496// Generate EncodeAsField impls for common smart pointers containing
497// types we have impls for already.
498macro_rules! impl_encode_like_to_fields {
499    ($ty:ident $(<$( $param:ident ),+>)? as $delegate_ty:ty where |$val:ident| $expr:expr) => {
500        impl $(< $($param: EncodeAsFields),+ >)? EncodeAsFields for $ty $(<$( $param ),+>)? {
501            fn encode_as_fields_to<R: TypeResolver>(
502                &self,
503                fields: &mut dyn FieldIter<'_, R::TypeId>,
504                types: &R,
505                out: &mut Vec<u8>,
506            ) -> Result<(), Error> {
507                self.as_ref().encode_as_fields_to(fields, types, out)
508            }
509        }
510    }
511}
512impl_encode_like_to_fields!(Box<T> as &T where |val| val);
513impl_encode_like_to_fields!(Rc<T> as &T where |val| val);
514impl_encode_like_to_fields!(Arc<T> as &T where |val| val);
515
516// Attempt to recurse into some type, returning the innermost type found that has an identical
517// SCALE encoded representation to the given type. For instance, `(T,)` encodes identically to
518// `T`, as does `Mytype { inner: T }` or `[T; 1]`.
519fn find_single_entry_with_same_repr<R: TypeResolver>(type_id: R::TypeId, types: &R) -> R::TypeId {
520    let v = visitor::new(type_id.clone(), |type_id, _| type_id)
521        .visit_tuple(|type_id, fields| {
522            let Some(new_type_id) = fields.next() else {
523                return type_id;
524            };
525            if fields.next().is_some() {
526                return type_id;
527            }
528            find_single_entry_with_same_repr(new_type_id, types)
529        })
530        .visit_composite(|type_id, _, fields| {
531            let Some(field) = fields.next() else {
532                return type_id;
533            };
534            if fields.next().is_some() {
535                return type_id;
536            }
537            find_single_entry_with_same_repr(field.id, types)
538        });
539
540    types.resolve_type(type_id.clone(), v).unwrap_or(type_id)
541}
542
543// Encode some iterator of items to the type provided.
544fn encode_iterable_sequence_to<I, R>(
545    len: usize,
546    it: I,
547    type_id: R::TypeId,
548    types: &R,
549    out: &mut Vec<u8>,
550) -> Result<(), Error>
551where
552    I: Iterator,
553    I::Item: EncodeAsType,
554    R: TypeResolver,
555{
556    let wrong_shape_err = |type_id| {
557        Error::new(ErrorKind::WrongShape {
558            actual: Kind::Array,
559            expected_id: format!("{type_id:?}"),
560        })
561    };
562
563    let v = visitor::new((type_id.clone(), it, out), |(type_id, _, _), _| {
564        Err(wrong_shape_err(type_id))
565    })
566    .visit_array(|(_, it, out), inner_ty_id: R::TypeId, array_len| {
567        if array_len == len {
568            for (idx, item) in it.enumerate() {
569                item.encode_as_type_to(inner_ty_id.clone(), types, out)
570                    .map_err(|e| e.at_idx(idx))?;
571            }
572            Ok(())
573        } else {
574            Err(Error::new(ErrorKind::WrongLength {
575                actual_len: len,
576                expected_len: array_len,
577            }))
578        }
579    })
580    .visit_sequence(|(_, it, out), _, inner_ty_id| {
581        // Sequences are prefixed with their compact encoded length:
582        Compact(len as u32).encode_to(out);
583        for (idx, item) in it.enumerate() {
584            item.encode_as_type_to(inner_ty_id.clone(), types, out)
585                .map_err(|e| e.at_idx(idx))?;
586        }
587        Ok(())
588    })
589    .visit_tuple(|(type_id, it, out), inner_type_ids| {
590        if inner_type_ids.len() == 1 {
591            encode_iterable_sequence_to(len, it, inner_type_ids.next().unwrap(), types, out)
592        } else {
593            Err(wrong_shape_err(type_id))
594        }
595    })
596    .visit_composite(|(type_id, it, out), _, fields| {
597        if fields.len() == 1 {
598            encode_iterable_sequence_to(len, it, fields.next().unwrap().id, types, out)
599        } else {
600            Err(wrong_shape_err(type_id))
601        }
602    });
603
604    resolve_type_and_encode(types, type_id, v)
605}
606
607#[cfg(all(feature = "derive", feature = "bits", feature = "primitive-types"))]
608#[cfg(test)]
609mod test {
610    use super::*;
611    use crate::{EncodeAsFields, Field};
612    use alloc::vec;
613    use codec::Decode;
614    use core::fmt::Debug;
615    use scale_info::{PortableRegistry, TypeInfo};
616
617    /// Given a type definition, return type ID and registry representing it.
618    fn make_type<T: TypeInfo + 'static>() -> (u32, PortableRegistry) {
619        let m = scale_info::MetaType::new::<T>();
620        let mut types = scale_info::Registry::new();
621        let id = types.register_type(&m);
622        let portable_registry: PortableRegistry = types.into();
623
624        (id.id, portable_registry)
625    }
626
627    fn encode_type<V: EncodeAsType, T: TypeInfo + 'static>(value: V) -> Result<Vec<u8>, Error> {
628        let (type_id, types) = make_type::<T>();
629        let bytes = value.encode_as_type(type_id, &types)?;
630        Ok(bytes)
631    }
632
633    fn assert_value_roundtrips_to<
634        V: EncodeAsType,
635        T: PartialEq + Debug + Decode + TypeInfo + 'static,
636    >(
637        value: V,
638        target: T,
639    ) {
640        let bytes = encode_type::<_, T>(&value).expect("can encode");
641        let bytes_cursor = &mut &*bytes;
642        let new_target = T::decode(bytes_cursor).expect("can decode");
643
644        assert_eq!(bytes_cursor.len(), 0, "no bytes should be remaining");
645        assert_eq!(
646            target, new_target,
647            "value does not roundtrip and decode to target"
648        );
649    }
650
651    fn assert_encodes_like_codec<
652        V: Encode + EncodeAsType + PartialEq + Debug + TypeInfo + 'static,
653    >(
654        value: V,
655    ) {
656        let encode_bytes = value.encode();
657        let bytes = encode_type::<V, V>(value).expect("can encode");
658        assert_eq!(
659            bytes, encode_bytes,
660            "scale-encode encoded differently from parity-scale-codec"
661        );
662    }
663
664    fn assert_encodes_fields_like_type<V: EncodeAsFields, T: TypeInfo + Encode + 'static>(
665        value: V,
666        other: T,
667    ) {
668        let encoded_other = other.encode();
669
670        let (type_id, types) = make_type::<T>();
671        let type_def = &types.resolve(type_id).unwrap().type_def;
672
673        let encoded_as_fields = match type_def {
674            scale_info::TypeDef::Composite(c) => {
675                let mut fields = c
676                    .fields
677                    .iter()
678                    .map(|f| Field::new(f.ty.id, f.name.as_deref()));
679                value.encode_as_fields(&mut fields, &types).unwrap()
680            }
681            scale_info::TypeDef::Tuple(t) => {
682                let mut fields = t.fields.iter().map(|f| Field::unnamed(f.id));
683                value.encode_as_fields(&mut fields, &types).unwrap()
684            }
685            _ => {
686                panic!("Expected composite or tuple type def");
687            }
688        };
689
690        assert_eq!(
691            encoded_other, encoded_as_fields,
692            "compare encode_with_fields with other encode"
693        );
694    }
695
696    #[test]
697    fn numeric_roundtrips_encode_ok() {
698        macro_rules! int_value_roundtrip {
699            ($($val:expr; $ty:ty),+) => {$(
700                assert_value_roundtrips_to($val, $val as i8);
701                assert_value_roundtrips_to($val, $val as i16);
702                assert_value_roundtrips_to($val, $val as i32);
703                assert_value_roundtrips_to($val, $val as i64);
704                assert_value_roundtrips_to($val, $val as i128);
705            )+}
706        }
707        macro_rules! uint_value_roundtrip {
708            ($($val:expr; $ty:ty),+) => {$(
709                assert_value_roundtrips_to($val, $val as u8);
710                assert_value_roundtrips_to($val, $val as u16);
711                assert_value_roundtrips_to($val, $val as u32);
712                assert_value_roundtrips_to($val, $val as u64);
713                assert_value_roundtrips_to($val, $val as u128);
714            )+}
715        }
716        macro_rules! int_value_roundtrip_types {
717            ($($val:expr),+) => {$(
718                int_value_roundtrip!($val; i8);
719                int_value_roundtrip!($val; i16);
720                int_value_roundtrip!($val; i32);
721                int_value_roundtrip!($val; i64);
722                int_value_roundtrip!($val; i128);
723            )+}
724        }
725        macro_rules! uint_value_roundtrip_types {
726            ($($val:expr),+) => {$(
727                uint_value_roundtrip!($val; u8);
728                uint_value_roundtrip!($val; u16);
729                uint_value_roundtrip!($val; u32);
730                uint_value_roundtrip!($val; u64);
731                uint_value_roundtrip!($val; u128);
732            )+}
733        }
734        macro_rules! all_value_roundtrip_types {
735            ($($val:expr),+) => {$(
736                int_value_roundtrip_types!($val);
737                uint_value_roundtrip_types!($val);
738            )+}
739        }
740        uint_value_roundtrip_types!(200);
741        int_value_roundtrip_types!(-127, -100, 0, 1, 100, 127);
742        all_value_roundtrip_types!(0, 1, 100, 127);
743    }
744
745    #[test]
746    fn out_of_range_numeric_roundtrips_fail_to_encode() {
747        encode_type::<_, u8>(&1234u16).unwrap_err();
748        encode_type::<_, i8>(&129u8).unwrap_err();
749        encode_type::<_, u8>(&-10i8).unwrap_err();
750    }
751
752    #[test]
753    fn sequence_encodes_like_scale_codec() {
754        let (type_id, types) = make_type::<Vec<u8>>();
755        let e = vec![1u8, 2, 3].encode();
756        let e2 = vec![1u8, 2, 3]
757            .encode_as_type(type_id, &types)
758            .expect("can encode 2");
759        assert_eq!(e, e2);
760    }
761
762    #[test]
763    fn basic_types_encode_like_scale_codec() {
764        assert_encodes_like_codec(true);
765        assert_encodes_like_codec(false);
766        assert_encodes_like_codec("hi");
767        assert_encodes_like_codec("hi".to_string());
768        assert_encodes_like_codec(Box::new("hi"));
769        assert_encodes_like_codec(-1234);
770        assert_encodes_like_codec(100_000_000_000_000u128);
771        assert_encodes_like_codec(());
772        assert_encodes_like_codec(core::marker::PhantomData::<()>);
773        assert_encodes_like_codec([1, 2, 3, 4, 5]);
774        assert_encodes_like_codec([1u8, 2, 3, 4, 5]);
775        assert_encodes_like_codec(vec![1, 2, 3, 4, 5]);
776        assert_encodes_like_codec([1, 2, 3, 4, 5]);
777        assert_encodes_like_codec(Some(1234u32));
778        assert_encodes_like_codec(None as Option<bool>);
779        assert_encodes_like_codec(Ok::<_, &str>("hello"));
780        assert_encodes_like_codec(Err::<u32, _>("aah"));
781        assert_encodes_like_codec(0..100);
782        assert_encodes_like_codec(0..=100);
783
784        // These don't impl TypeInfo so we have to provide the target type to encode to & compare with:
785        assert_value_roundtrips_to(Arc::new("hi"), "hi".to_string());
786        assert_value_roundtrips_to(Rc::new("hi"), "hi".to_string());
787        // encodes_like_codec(core::time::Duration::from_millis(123456));
788    }
789
790    #[test]
791    fn other_container_types_roundtrip_ok() {
792        // These things don't have TypeInfo impls, and so we just assume that they should
793        // encode like any sequence, prefixed with length.
794
795        let v = LinkedList::from([1u8, 2, 3]);
796        assert_value_roundtrips_to(v, vec![1u8, 2, 3]);
797
798        // (it's a max heap, so values ordered max first.)
799        let v = BinaryHeap::from([2, 3, 1]);
800        assert_value_roundtrips_to(v, vec![3u8, 2, 1]);
801
802        let v = BTreeSet::from([1u8, 2, 3]);
803        assert_value_roundtrips_to(v, vec![1u8, 2, 3]);
804
805        let v = VecDeque::from([1u8, 2, 3]);
806        assert_value_roundtrips_to(v, vec![1u8, 2, 3]);
807    }
808
809    #[test]
810    fn btreemap_can_encode_to_struct() {
811        #[derive(Debug, scale_info::TypeInfo, codec::Decode, PartialEq)]
812        struct Foo {
813            a: u8,
814            b: u16,
815            c: u32,
816        }
817
818        let v = BTreeMap::from([("a", 1), ("c", 2), ("b", 3)]);
819
820        // BTreeMap can go to a key-val composite, or unnamed:
821        assert_value_roundtrips_to(v.clone(), Foo { a: 1, b: 3, c: 2 });
822        // BTreeMaps are iterated in order of key:
823        assert_value_roundtrips_to(v, (1, 3, 2));
824    }
825
826    #[test]
827    fn mixed_tuples_roundtrip_ok() {
828        assert_encodes_like_codec(());
829        assert_encodes_like_codec((12345,));
830        assert_encodes_like_codec((123u8, true));
831        assert_encodes_like_codec((123u8, true, "hello"));
832        // Encode isn't implemented for `char` (but we treat it as a u32):
833        assert_encodes_like_codec((123u8, true, "hello".to_string(), 'a' as u32));
834        assert_encodes_like_codec((
835            123u8,
836            true,
837            "hello".to_string(),
838            'a' as u32,
839            123_000_000_000u128,
840        ));
841    }
842
843    #[test]
844    fn sequences_roundtrip_into_eachother() {
845        // Nesting can be resolved (but tuples and sequences are distinct)
846        assert_value_roundtrips_to(([1u8, 2u8, 3u8],), vec![1u8, 2u8, 3u8]);
847        assert_value_roundtrips_to(([(1u8,), (2u8,), (3u8,)],), (([1u8, 2u8, 3u8],),));
848        assert_value_roundtrips_to(((([1u8],),),), (([1u8],),));
849        assert_value_roundtrips_to((([(1u8,)],),), (([1u8],),));
850    }
851
852    #[test]
853    fn tuples_to_structs() {
854        #[derive(Debug, scale_info::TypeInfo, codec::Decode, PartialEq)]
855        struct Foo {
856            a: (u32,),
857            b: u64,
858            c: u128,
859        }
860        assert_value_roundtrips_to(
861            (1u8, 2u8, 3u8),
862            Foo {
863                a: (1,),
864                b: 2,
865                c: 3,
866            },
867        );
868    }
869
870    #[test]
871    fn values_roundtrip_into_wrappers() {
872        #[derive(Debug, scale_info::TypeInfo, codec::Decode, PartialEq)]
873        struct Wrapper<T> {
874            val: T,
875        }
876
877        assert_value_roundtrips_to(true, (true,));
878        assert_value_roundtrips_to(1234u16, (1234u16,));
879        assert_value_roundtrips_to(1234u16, Wrapper { val: 1234u16 });
880        assert_value_roundtrips_to("hi", (("hi".to_string(),),));
881        assert_value_roundtrips_to(
882            "hi",
883            (Wrapper {
884                val: "hi".to_string(),
885            },),
886        );
887    }
888
889    #[test]
890    fn compacts_roundtrip() {
891        assert_encodes_like_codec(Compact(123u16));
892        assert_encodes_like_codec(Compact(123u8));
893        assert_encodes_like_codec(Compact(123u64));
894    }
895
896    #[test]
897    fn tuple_composite_can_encode_to_named_structs() {
898        #[derive(Debug, scale_info::TypeInfo, codec::Decode, PartialEq)]
899        struct Foo {
900            bar: u32,
901            wibble: bool,
902            hello: String,
903        }
904
905        // note: fields do not need to be in order when named:
906        let source_vals = [
907            (Some("hello"), CompositeField::new(&"world")),
908            (Some("bar"), CompositeField::new(&12345u128)),
909            (Some("wibble"), CompositeField::new(&true)),
910        ];
911        let source = Composite::new(source_vals.iter().copied());
912
913        // Composite can't implement `EncodeAsType` and so need "manually" encoding:
914        let (type_id, types) = make_type::<Foo>();
915        let bytes = source.encode_composite_as_type(type_id, &types).unwrap();
916        let cursor = &mut &*bytes;
917
918        let target = Foo {
919            bar: 12345,
920            wibble: true,
921            hello: "world".to_string(),
922        };
923
924        let new_target = Foo::decode(cursor).unwrap();
925
926        assert_eq!(target, new_target);
927        assert_eq!(cursor.len(), 0);
928    }
929
930    #[test]
931    fn tuple_composite_can_encode_to_unnamed_structs() {
932        #[derive(Debug, scale_info::TypeInfo, codec::Decode, PartialEq, Clone)]
933        struct Foo(u32, bool, String);
934        let (type_id, types) = make_type::<Foo>();
935
936        // note: unnamed target so fields need to be in order (can be named or not)
937        let source_vals = [
938            (Some("bar"), CompositeField::new(&12345u128)),
939            (Some("wibble"), CompositeField::new(&true)),
940            (Some("hello"), CompositeField::new(&"world")),
941        ];
942        let source = Composite::new(source_vals.iter().copied());
943        let source_bytes = source.encode_composite_as_type(type_id, &types).unwrap();
944        let source_cursor = &mut &*source_bytes;
945
946        let source2_vals = [
947            (None, CompositeField::new(&12345u128)),
948            (None, CompositeField::new(&true)),
949            (None, CompositeField::new(&"world")),
950        ];
951        let source2 = Composite::new(source2_vals.iter().copied());
952        let source2_bytes = source2.encode_composite_as_type(type_id, &types).unwrap();
953        let source2_cursor = &mut &*source2_bytes;
954
955        let target = Foo(12345, true, "world".to_string());
956        let new_target = Foo::decode(source_cursor).unwrap();
957        let new_target2 = Foo::decode(source2_cursor).unwrap();
958
959        assert_eq!(target, new_target);
960        assert_eq!(target, new_target2);
961        assert_eq!(source_cursor.len(), 0);
962        assert_eq!(source2_cursor.len(), 0);
963    }
964
965    #[test]
966    fn tuple_composite_names_must_line_up() {
967        #[derive(Debug, scale_info::TypeInfo, codec::Decode, PartialEq)]
968        struct Foo {
969            bar: u32,
970            wibble: bool,
971            hello: String,
972        }
973
974        // note: fields do not need to be in order when named:
975        let source_vals = [
976            (Some("hello"), CompositeField::new(&"world")),
977            (Some("bar"), CompositeField::new(&12345u128)),
978            // wrong name:
979            (Some("wibbles"), CompositeField::new(&true)),
980        ];
981        let source = Composite::new(source_vals.iter().copied());
982
983        let (type_id, types) = make_type::<Foo>();
984        let _bytes = source
985            .encode_composite_as_type(type_id, &types)
986            .unwrap_err();
987    }
988
989    #[test]
990    fn bits_roundtrip_ok() {
991        use bitvec::{
992            order::{Lsb0, Msb0},
993            vec::BitVec,
994        };
995        use scale_bits::Bits;
996
997        fn test_bits(bits: impl IntoIterator<Item = bool> + Clone) {
998            let source = Bits::from_iter(bits.clone());
999
1000            let target = BitVec::<u8, Lsb0>::from_iter(bits.clone());
1001            assert_value_roundtrips_to(source.clone(), target);
1002            let target = BitVec::<u16, Lsb0>::from_iter(bits.clone());
1003            assert_value_roundtrips_to(source.clone(), target);
1004            let target = BitVec::<u32, Lsb0>::from_iter(bits.clone());
1005            assert_value_roundtrips_to(source.clone(), target);
1006            let target = BitVec::<u64, Lsb0>::from_iter(bits.clone());
1007            assert_value_roundtrips_to(source.clone(), target);
1008            let target = BitVec::<u8, Msb0>::from_iter(bits.clone());
1009            assert_value_roundtrips_to(source.clone(), target);
1010            let target = BitVec::<u16, Msb0>::from_iter(bits.clone());
1011            assert_value_roundtrips_to(source.clone(), target);
1012            let target = BitVec::<u32, Msb0>::from_iter(bits.clone());
1013            assert_value_roundtrips_to(source.clone(), target);
1014            let target = BitVec::<u64, Msb0>::from_iter(bits);
1015            assert_value_roundtrips_to(source, target);
1016        }
1017
1018        test_bits([]);
1019        test_bits([true]);
1020        test_bits([false]);
1021        test_bits([true, false, true, true, false]);
1022        test_bits([
1023            true, false, true, true, false, true, false, true, true, false, false,
1024        ]);
1025
1026        // Wrapping the input or output bitvecs is fine; it'll figure it out:
1027        assert_value_roundtrips_to(
1028            Bits::from_iter([true, false, true]),
1029            ((BitVec::<u8, Lsb0>::from_iter([true, false, true]),),),
1030        );
1031        assert_value_roundtrips_to(
1032            (Bits::from_iter([true, false, true]),),
1033            ((BitVec::<u8, Lsb0>::from_iter([true, false, true]),),),
1034        );
1035    }
1036
1037    #[test]
1038    fn hxxx_types_roundtrip_ok() {
1039        use ::primitive_types::{H128, H160, H256, H384, H512, H768};
1040
1041        // Check that Hxxx types roundtirp to themselves or to byte sequences
1042        fn test_hxxx(bytes: impl IntoIterator<Item = u8> + Clone) {
1043            let mut bytes: Vec<u8> = bytes.into_iter().collect();
1044
1045            while bytes.len() < 128 / 8 {
1046                bytes.push(0)
1047            }
1048            assert_value_roundtrips_to(H128::from_slice(&bytes), bytes.clone());
1049            assert_value_roundtrips_to(H128::from_slice(&bytes), H128::from_slice(&bytes));
1050
1051            while bytes.len() < 160 / 8 {
1052                bytes.push(0)
1053            }
1054            assert_value_roundtrips_to(H160::from_slice(&bytes), bytes.clone());
1055            assert_value_roundtrips_to(H160::from_slice(&bytes), H160::from_slice(&bytes));
1056
1057            while bytes.len() < 256 / 8 {
1058                bytes.push(0)
1059            }
1060            assert_value_roundtrips_to(H256::from_slice(&bytes), bytes.clone());
1061            assert_value_roundtrips_to(H256::from_slice(&bytes), H256::from_slice(&bytes));
1062
1063            while bytes.len() < 384 / 8 {
1064                bytes.push(0)
1065            }
1066            assert_value_roundtrips_to(H384::from_slice(&bytes), bytes.clone());
1067            assert_value_roundtrips_to(H384::from_slice(&bytes), H384::from_slice(&bytes));
1068
1069            while bytes.len() < 512 / 8 {
1070                bytes.push(0)
1071            }
1072            assert_value_roundtrips_to(H512::from_slice(&bytes), bytes.clone());
1073            assert_value_roundtrips_to(H512::from_slice(&bytes), H512::from_slice(&bytes));
1074
1075            while bytes.len() < 768 / 8 {
1076                bytes.push(0)
1077            }
1078            assert_value_roundtrips_to(H768::from_slice(&bytes), bytes.clone());
1079            assert_value_roundtrips_to(H768::from_slice(&bytes), H768::from_slice(&bytes));
1080        }
1081
1082        test_hxxx([0u8]);
1083        test_hxxx([1, 2, 3, 4]);
1084    }
1085
1086    #[test]
1087    fn encode_as_fields_works() {
1088        #[derive(TypeInfo, Encode)]
1089        struct Foo {
1090            some_field: u64,
1091            another: u8,
1092        }
1093
1094        assert_encodes_fields_like_type(
1095            BTreeMap::from([
1096                ("other1", 1),
1097                ("another", 2),
1098                ("some_field", 3),
1099                ("other2", 4),
1100            ]),
1101            Foo {
1102                some_field: 3,
1103                another: 2,
1104            },
1105        )
1106    }
1107
1108    #[test]
1109    fn encode_as_fields_via_macro_works() {
1110        #[derive(TypeInfo, Encode)]
1111        struct Foo {
1112            some_field: u64,
1113            another: bool,
1114        }
1115
1116        #[derive(TypeInfo, Encode)]
1117        struct FooUnnamed(
1118            String,
1119            (u8,), // different types still map ok.
1120            bool,
1121            u8,
1122        );
1123
1124        #[derive(EncodeAsType)]
1125        #[encode_as_type(crate_path = "crate")]
1126        struct FooBigger {
1127            random: String,
1128            some_field: u64,
1129            another: bool,
1130            more_random: u8,
1131        }
1132
1133        assert_encodes_fields_like_type(
1134            FooBigger {
1135                random: "hello".to_string(),
1136                some_field: 123,
1137                another: true,
1138                more_random: 1,
1139            },
1140            Foo {
1141                some_field: 123,
1142                another: true,
1143            },
1144        );
1145        assert_encodes_fields_like_type(
1146            FooBigger {
1147                random: "hello".to_string(),
1148                some_field: 123,
1149                another: true,
1150                more_random: 1,
1151            },
1152            FooUnnamed("hello".to_string(), (123,), true, 1),
1153        );
1154        assert_encodes_fields_like_type(
1155            FooBigger {
1156                random: "hello".to_string(),
1157                some_field: 123,
1158                another: true,
1159                more_random: 1,
1160            },
1161            ("hello".to_string(), (123u8,), true, (1u64,)),
1162        );
1163    }
1164
1165    #[test]
1166    fn encode_to_number_skipping_attrs_via_macro_works() {
1167        struct NotEncodeAsType;
1168
1169        #[allow(dead_code)]
1170        #[derive(EncodeAsType)]
1171        #[encode_as_type(crate_path = "crate")]
1172        struct FooNotSkipping {
1173            value: u64,
1174            other: bool,
1175            third: String,
1176        }
1177
1178        #[derive(EncodeAsType)]
1179        #[encode_as_type(crate_path = "crate")]
1180        struct FooSkipping {
1181            value: u64,
1182            #[encode_as_type(skip)]
1183            other: bool,
1184            // Even though this type doesn't impl EncodeAsType,
1185            // it's ignored so should be fine:
1186            #[codec(skip)]
1187            third: NotEncodeAsType,
1188        }
1189
1190        assert_value_roundtrips_to(
1191            FooSkipping {
1192                value: 123,
1193                other: true,
1194                third: NotEncodeAsType,
1195            },
1196            123u64,
1197        );
1198    }
1199
1200    #[test]
1201    fn encode_unnamed_to_number_skipping_attrs_via_macro_works() {
1202        struct NotEncodeAsType;
1203
1204        #[derive(EncodeAsType)]
1205        #[encode_as_type(crate_path = "crate")]
1206        struct FooSkipping(
1207            u64,
1208            #[encode_as_type(skip)] bool,
1209            // Even though this type doesn't impl EncodeAsType,
1210            // it's ignored so should be fine:
1211            #[codec(skip)] NotEncodeAsType,
1212        );
1213
1214        assert_value_roundtrips_to(FooSkipping(123, true, NotEncodeAsType), 123u64);
1215    }
1216
1217    // If you don't skip values, you can't turn a multi-value
1218    // struct into a number.
1219    #[test]
1220    #[should_panic]
1221    fn encode_to_number_not_skipping_via_macro_fails() {
1222        #[derive(EncodeAsType)]
1223        #[encode_as_type(crate_path = "crate")]
1224        struct FooNotSkipping {
1225            value: u64,
1226            other: bool,
1227            third: String,
1228        }
1229
1230        assert_value_roundtrips_to(
1231            FooNotSkipping {
1232                value: 123,
1233                other: true,
1234                third: "hello".to_string(),
1235            },
1236            123u64,
1237        );
1238    }
1239
1240    #[test]
1241    fn encode_smart_pointers_as_fields() {
1242        #[derive(TypeInfo, Encode, PartialEq, Debug, Decode)]
1243        struct Foo {
1244            some_field: u64,
1245            another: u8,
1246        }
1247
1248        let map = BTreeMap::from([
1249            ("other1", 1),
1250            ("another", 2),
1251            ("some_field", 3),
1252            ("other2", 4),
1253        ]);
1254        let a = Box::new(map.clone());
1255        assert_encodes_fields_like_type(
1256            a.clone(),
1257            Foo {
1258                some_field: 3,
1259                another: 2,
1260            },
1261        );
1262        assert_value_roundtrips_to(
1263            &a,
1264            Box::new(Foo {
1265                some_field: 3,
1266                another: 2,
1267            }),
1268        );
1269        let b = Rc::new(map.clone());
1270        assert_encodes_fields_like_type(
1271            b.clone(),
1272            Foo {
1273                some_field: 3,
1274                another: 2,
1275            },
1276        );
1277        assert_value_roundtrips_to(
1278            &b,
1279            Rc::new(Foo {
1280                some_field: 3,
1281                another: 2,
1282            }),
1283        );
1284        let c = Arc::new(map.clone());
1285        assert_encodes_fields_like_type(
1286            c.clone(),
1287            Foo {
1288                some_field: 3,
1289                another: 2,
1290            },
1291        );
1292        assert_value_roundtrips_to(
1293            &c,
1294            Arc::new(Foo {
1295                some_field: 3,
1296                another: 2,
1297            }),
1298        );
1299    }
1300}