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<T> EncodeAsType for &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
456impl<const N: usize, V: EncodeAsType> EncodeAsFields for [V; N] {
457    fn encode_as_fields_to<R: TypeResolver>(
458        &self,
459        fields: &mut dyn FieldIter<'_, R::TypeId>,
460        types: &R,
461        out: &mut Vec<u8>,
462    ) -> Result<(), Error> {
463        Composite::new(self.iter().map(|v| (None, CompositeField::new(v))))
464            .encode_composite_fields_to(fields, types, out)
465    }
466}
467
468impl<V: EncodeAsType> EncodeAsFields for &[V] {
469    fn encode_as_fields_to<R: TypeResolver>(
470        &self,
471        fields: &mut dyn FieldIter<'_, R::TypeId>,
472        types: &R,
473        out: &mut Vec<u8>,
474    ) -> Result<(), Error> {
475        Composite::new(self.iter().map(|v| (None, CompositeField::new(v))))
476            .encode_composite_fields_to(fields, types, out)
477    }
478}
479
480impl<V: EncodeAsType> EncodeAsFields for Vec<V> {
481    fn encode_as_fields_to<R: TypeResolver>(
482        &self,
483        fields: &mut dyn FieldIter<'_, R::TypeId>,
484        types: &R,
485        out: &mut Vec<u8>,
486    ) -> Result<(), Error> {
487        Composite::new(self.iter().map(|v| (None, CompositeField::new(v))))
488            .encode_composite_fields_to(fields, types, out)
489    }
490}
491
492macro_rules! impl_tuple_encode_as_fields {
493    ($($param:ident $idx:tt),+) => {
494        impl <$($param: EncodeAsType),+> EncodeAsFields for ($($param,)+) {
495            fn encode_as_fields_to<R: TypeResolver>(
496                &self,
497                fields: &mut dyn FieldIter<'_, R::TypeId>,
498                types: &R,
499                out: &mut Vec<u8>,
500            ) -> Result<(), Error> {
501                Composite::new(
502                    [
503                        $(
504                            (None, CompositeField::new(&self.$idx))
505                        ),+
506                    ].into_iter(),
507                )
508                .encode_composite_fields_to(fields, types, out)
509            }
510        }
511    }
512}
513
514impl_tuple_encode_as_fields!(A 0);
515impl_tuple_encode_as_fields!(A 0, B 1);
516impl_tuple_encode_as_fields!(A 0, B 1, C 2);
517impl_tuple_encode_as_fields!(A 0, B 1, C 2, D 3);
518impl_tuple_encode_as_fields!(A 0, B 1, C 2, D 3, E 4);
519impl_tuple_encode_as_fields!(A 0, B 1, C 2, D 3, E 4, F 5);
520impl_tuple_encode_as_fields!(A 0, B 1, C 2, D 3, E 4, F 5, G 6);
521impl_tuple_encode_as_fields!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7);
522impl_tuple_encode_as_fields!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8);
523impl_tuple_encode_as_fields!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8, J 9);
524impl_tuple_encode_as_fields!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8, J 9, K 10);
525
526impl EncodeAsFields for () {
527    fn encode_as_fields_to<R: TypeResolver>(
528        &self,
529        fields: &mut dyn FieldIter<'_, R::TypeId>,
530        _types: &R,
531        _out: &mut Vec<u8>,
532    ) -> Result<(), Error> {
533        if fields.len() != 0 {
534            Err(Error::new(ErrorKind::WrongLength {
535                actual_len: 0,
536                expected_len: fields.len(),
537            }))
538        } else {
539            Ok(())
540        }
541    }
542}
543
544// Generate EncodeAsType impls for simple types that can be easily transformed
545// into types we have impls for already.
546macro_rules! impl_encode_like {
547    ($ty:ident $(<$( $param:ident ),+>)? as $delegate_ty:ty where |$val:ident| $expr:expr) => {
548        impl $(< $($param: EncodeAsType),+ >)? EncodeAsType for $ty $(<$( $param ),+>)? {
549            fn encode_as_type_to<R: TypeResolver>(
550                &self,
551                type_id: R::TypeId,
552                types: &R,
553                out: &mut Vec<u8>,
554            ) -> Result<(), Error> {
555                let delegate: $delegate_ty = {
556                    let $val = self;
557                    $expr
558                };
559                delegate.encode_as_type_to(type_id, types, out)
560            }
561        }
562    }
563}
564impl_encode_like!(String as &str where |val| val);
565impl_encode_like!(Box<T> as &T where |val| val);
566impl_encode_like!(Arc<T> as &T where |val| val);
567impl_encode_like!(Rc<T> as &T where |val| val);
568impl_encode_like!(char as u32 where |val| *val as u32);
569impl_encode_like!(NonZeroU8 as u8 where |val| val.get());
570impl_encode_like!(NonZeroU16 as u16 where |val| val.get());
571impl_encode_like!(NonZeroU32 as u32 where |val| val.get());
572impl_encode_like!(NonZeroU64 as u64 where |val| val.get());
573impl_encode_like!(NonZeroU128 as u128 where |val| val.get());
574impl_encode_like!(NonZeroI8 as i8 where |val| val.get());
575impl_encode_like!(NonZeroI16 as i16 where |val| val.get());
576impl_encode_like!(NonZeroI32 as i32 where |val| val.get());
577impl_encode_like!(NonZeroI64 as i64 where |val| val.get());
578impl_encode_like!(NonZeroI128 as i128 where |val| val.get());
579impl_encode_like!(Duration as (u64, u32) where |val| (val.as_secs(), val.subsec_nanos()));
580impl_encode_like!(Range<T> as (&T, &T) where |val| (&val.start, &val.end));
581impl_encode_like!(RangeInclusive<T> as (&T, &T) where |val| ((val.start()), (val.end())));
582impl_encode_like!(Compact<T> as &T where |val| &val.0);
583
584// Generate EncodeAsField impls for common smart pointers containing
585// types we have impls for already.
586macro_rules! impl_encode_like_to_fields {
587    ($ty:ident $(<$( $param:ident ),+>)? as $delegate_ty:ty where |$val:ident| $expr:expr) => {
588        impl $(< $($param: EncodeAsFields),+ >)? EncodeAsFields for $ty $(<$( $param ),+>)? {
589            fn encode_as_fields_to<R: TypeResolver>(
590                &self,
591                fields: &mut dyn FieldIter<'_, R::TypeId>,
592                types: &R,
593                out: &mut Vec<u8>,
594            ) -> Result<(), Error> {
595                self.as_ref().encode_as_fields_to(fields, types, out)
596            }
597        }
598    }
599}
600impl_encode_like_to_fields!(Box<T> as &T where |val| val);
601impl_encode_like_to_fields!(Rc<T> as &T where |val| val);
602impl_encode_like_to_fields!(Arc<T> as &T where |val| val);
603
604// Attempt to recurse into some type, returning the innermost type found that has an identical
605// SCALE encoded representation to the given type. For instance, `(T,)` encodes identically to
606// `T`, as does `Mytype { inner: T }` or `[T; 1]`.
607fn find_single_entry_with_same_repr<R: TypeResolver>(type_id: R::TypeId, types: &R) -> R::TypeId {
608    let v = visitor::new(type_id.clone(), |type_id, _| type_id)
609        .visit_tuple(|type_id, fields| {
610            let Some(new_type_id) = fields.next() else {
611                return type_id;
612            };
613            if fields.next().is_some() {
614                return type_id;
615            }
616            find_single_entry_with_same_repr(new_type_id, types)
617        })
618        .visit_composite(|type_id, _, fields| {
619            let Some(field) = fields.next() else {
620                return type_id;
621            };
622            if fields.next().is_some() {
623                return type_id;
624            }
625            find_single_entry_with_same_repr(field.id, types)
626        });
627
628    types.resolve_type(type_id.clone(), v).unwrap_or(type_id)
629}
630
631// Encode some iterator of items to the type provided.
632fn encode_iterable_sequence_to<I, R>(
633    len: usize,
634    it: I,
635    type_id: R::TypeId,
636    types: &R,
637    out: &mut Vec<u8>,
638) -> Result<(), Error>
639where
640    I: Iterator,
641    I::Item: EncodeAsType,
642    R: TypeResolver,
643{
644    let wrong_shape_err = |type_id| {
645        Error::new(ErrorKind::WrongShape {
646            actual: Kind::Array,
647            expected_id: format!("{type_id:?}"),
648        })
649    };
650
651    let v = visitor::new((type_id.clone(), it, out), |(type_id, _, _), _| {
652        Err(wrong_shape_err(type_id))
653    })
654    .visit_array(|(_, it, out), inner_ty_id: R::TypeId, array_len| {
655        if array_len == len {
656            for (idx, item) in it.enumerate() {
657                item.encode_as_type_to(inner_ty_id.clone(), types, out)
658                    .map_err(|e| e.at_idx(idx))?;
659            }
660            Ok(())
661        } else {
662            Err(Error::new(ErrorKind::WrongLength {
663                actual_len: len,
664                expected_len: array_len,
665            }))
666        }
667    })
668    .visit_sequence(|(_, it, out), _, inner_ty_id| {
669        // Sequences are prefixed with their compact encoded length:
670        Compact(len as u32).encode_to(out);
671        for (idx, item) in it.enumerate() {
672            item.encode_as_type_to(inner_ty_id.clone(), types, out)
673                .map_err(|e| e.at_idx(idx))?;
674        }
675        Ok(())
676    })
677    .visit_tuple(|(type_id, it, out), inner_type_ids| {
678        if inner_type_ids.len() == 1 {
679            encode_iterable_sequence_to(len, it, inner_type_ids.next().unwrap(), types, out)
680        } else {
681            Err(wrong_shape_err(type_id))
682        }
683    })
684    .visit_composite(|(type_id, it, out), _, fields| {
685        if fields.len() == 1 {
686            encode_iterable_sequence_to(len, it, fields.next().unwrap().id, types, out)
687        } else {
688            Err(wrong_shape_err(type_id))
689        }
690    });
691
692    resolve_type_and_encode(types, type_id, v)
693}
694
695#[cfg(all(feature = "derive", feature = "bits", feature = "primitive-types"))]
696#[cfg(test)]
697mod test {
698    use super::*;
699    use crate::{EncodeAsFields, Field};
700    use alloc::vec;
701    use codec::Decode;
702    use core::fmt::Debug;
703    use scale_info::{PortableRegistry, TypeInfo};
704
705    /// Given a type definition, return type ID and registry representing it.
706    fn make_type<T: TypeInfo + 'static>() -> (u32, PortableRegistry) {
707        let m = scale_info::MetaType::new::<T>();
708        let mut types = scale_info::Registry::new();
709        let id = types.register_type(&m);
710        let portable_registry: PortableRegistry = types.into();
711
712        (id.id, portable_registry)
713    }
714
715    fn encode_type<V: EncodeAsType, T: TypeInfo + 'static>(value: V) -> Result<Vec<u8>, Error> {
716        let (type_id, types) = make_type::<T>();
717        let bytes = value.encode_as_type(type_id, &types)?;
718        Ok(bytes)
719    }
720
721    fn assert_value_roundtrips_to<
722        V: EncodeAsType,
723        T: PartialEq + Debug + Decode + TypeInfo + 'static,
724    >(
725        value: V,
726        target: T,
727    ) {
728        let bytes = encode_type::<_, T>(&value).expect("can encode");
729        let bytes_cursor = &mut &*bytes;
730        let new_target = T::decode(bytes_cursor).expect("can decode");
731
732        assert_eq!(bytes_cursor.len(), 0, "no bytes should be remaining");
733        assert_eq!(
734            target, new_target,
735            "value does not roundtrip and decode to target"
736        );
737    }
738
739    fn assert_encodes_like_codec<
740        V: Encode + EncodeAsType + PartialEq + Debug + TypeInfo + 'static,
741    >(
742        value: V,
743    ) {
744        let encode_bytes = value.encode();
745        let bytes = encode_type::<V, V>(value).expect("can encode");
746        assert_eq!(
747            bytes, encode_bytes,
748            "scale-encode encoded differently from parity-scale-codec"
749        );
750    }
751
752    fn assert_encodes_fields_like_type<V: EncodeAsFields, T: TypeInfo + Encode + 'static>(
753        value: V,
754        other: T,
755    ) {
756        let encoded_other = other.encode();
757
758        let (type_id, types) = make_type::<T>();
759        let type_def = &types.resolve(type_id).unwrap().type_def;
760
761        let encoded_as_fields = match type_def {
762            scale_info::TypeDef::Composite(c) => {
763                let mut fields = c
764                    .fields
765                    .iter()
766                    .map(|f| Field::new(f.ty.id, f.name.as_deref()));
767                value.encode_as_fields(&mut fields, &types).unwrap()
768            }
769            scale_info::TypeDef::Tuple(t) => {
770                let mut fields = t.fields.iter().map(|f| Field::unnamed(f.id));
771                value.encode_as_fields(&mut fields, &types).unwrap()
772            }
773            _ => {
774                panic!("Expected composite or tuple type def");
775            }
776        };
777
778        assert_eq!(
779            encoded_other, encoded_as_fields,
780            "compare encode_with_fields with other encode"
781        );
782    }
783
784    #[test]
785    fn numeric_roundtrips_encode_ok() {
786        macro_rules! int_value_roundtrip {
787            ($($val:expr; $ty:ty),+) => {$(
788                assert_value_roundtrips_to($val, $val as i8);
789                assert_value_roundtrips_to($val, $val as i16);
790                assert_value_roundtrips_to($val, $val as i32);
791                assert_value_roundtrips_to($val, $val as i64);
792                assert_value_roundtrips_to($val, $val as i128);
793            )+}
794        }
795        macro_rules! uint_value_roundtrip {
796            ($($val:expr; $ty:ty),+) => {$(
797                assert_value_roundtrips_to($val, $val as u8);
798                assert_value_roundtrips_to($val, $val as u16);
799                assert_value_roundtrips_to($val, $val as u32);
800                assert_value_roundtrips_to($val, $val as u64);
801                assert_value_roundtrips_to($val, $val as u128);
802            )+}
803        }
804        macro_rules! int_value_roundtrip_types {
805            ($($val:expr),+) => {$(
806                int_value_roundtrip!($val; i8);
807                int_value_roundtrip!($val; i16);
808                int_value_roundtrip!($val; i32);
809                int_value_roundtrip!($val; i64);
810                int_value_roundtrip!($val; i128);
811            )+}
812        }
813        macro_rules! uint_value_roundtrip_types {
814            ($($val:expr),+) => {$(
815                uint_value_roundtrip!($val; u8);
816                uint_value_roundtrip!($val; u16);
817                uint_value_roundtrip!($val; u32);
818                uint_value_roundtrip!($val; u64);
819                uint_value_roundtrip!($val; u128);
820            )+}
821        }
822        macro_rules! all_value_roundtrip_types {
823            ($($val:expr),+) => {$(
824                int_value_roundtrip_types!($val);
825                uint_value_roundtrip_types!($val);
826            )+}
827        }
828        uint_value_roundtrip_types!(200);
829        int_value_roundtrip_types!(-127, -100, 0, 1, 100, 127);
830        all_value_roundtrip_types!(0, 1, 100, 127);
831    }
832
833    #[test]
834    fn out_of_range_numeric_roundtrips_fail_to_encode() {
835        encode_type::<_, u8>(&1234u16).unwrap_err();
836        encode_type::<_, i8>(&129u8).unwrap_err();
837        encode_type::<_, u8>(&-10i8).unwrap_err();
838    }
839
840    #[test]
841    fn sequence_encodes_like_scale_codec() {
842        let (type_id, types) = make_type::<Vec<u8>>();
843        let e = vec![1u8, 2, 3].encode();
844        let e2 = vec![1u8, 2, 3]
845            .encode_as_type(type_id, &types)
846            .expect("can encode 2");
847        assert_eq!(e, e2);
848    }
849
850    #[test]
851    fn basic_types_encode_like_scale_codec() {
852        assert_encodes_like_codec(true);
853        assert_encodes_like_codec(false);
854        assert_encodes_like_codec("hi");
855        assert_encodes_like_codec("hi".to_string());
856        assert_encodes_like_codec(Box::new("hi"));
857        assert_encodes_like_codec(-1234);
858        assert_encodes_like_codec(100_000_000_000_000u128);
859        assert_encodes_like_codec(());
860        assert_encodes_like_codec(core::marker::PhantomData::<()>);
861        assert_encodes_like_codec([1, 2, 3, 4, 5]);
862        assert_encodes_like_codec([1u8, 2, 3, 4, 5]);
863        assert_encodes_like_codec(vec![1, 2, 3, 4, 5]);
864        assert_encodes_like_codec([1, 2, 3, 4, 5]);
865        assert_encodes_like_codec(Some(1234u32));
866        assert_encodes_like_codec(None as Option<bool>);
867        assert_encodes_like_codec(Ok::<_, &str>("hello"));
868        assert_encodes_like_codec(Err::<u32, _>("aah"));
869        assert_encodes_like_codec(0..100);
870        assert_encodes_like_codec(0..=100);
871
872        // These don't impl TypeInfo so we have to provide the target type to encode to & compare with:
873        assert_value_roundtrips_to(Arc::new("hi"), "hi".to_string());
874        assert_value_roundtrips_to(Rc::new("hi"), "hi".to_string());
875        // encodes_like_codec(core::time::Duration::from_millis(123456));
876    }
877
878    #[test]
879    fn other_container_types_roundtrip_ok() {
880        // These things don't have TypeInfo impls, and so we just assume that they should
881        // encode like any sequence, prefixed with length.
882
883        let v = LinkedList::from([1u8, 2, 3]);
884        assert_value_roundtrips_to(v, vec![1u8, 2, 3]);
885
886        // (it's a max heap, so values ordered max first.)
887        let v = BinaryHeap::from([2, 3, 1]);
888        assert_value_roundtrips_to(v, vec![3u8, 2, 1]);
889
890        let v = BTreeSet::from([1u8, 2, 3]);
891        assert_value_roundtrips_to(v, vec![1u8, 2, 3]);
892
893        let v = VecDeque::from([1u8, 2, 3]);
894        assert_value_roundtrips_to(v, vec![1u8, 2, 3]);
895    }
896
897    #[test]
898    fn btreemap_can_encode_to_struct() {
899        #[derive(Debug, scale_info::TypeInfo, codec::Decode, PartialEq)]
900        struct Foo {
901            a: u8,
902            b: u16,
903            c: u32,
904        }
905
906        let v = BTreeMap::from([("a", 1), ("c", 2), ("b", 3)]);
907
908        // BTreeMap can go to a key-val composite, or unnamed:
909        assert_value_roundtrips_to(v.clone(), Foo { a: 1, b: 3, c: 2 });
910        // BTreeMaps are iterated in order of key:
911        assert_value_roundtrips_to(v, (1, 3, 2));
912    }
913
914    #[test]
915    fn mixed_tuples_roundtrip_ok() {
916        assert_encodes_like_codec(());
917        assert_encodes_like_codec((12345,));
918        assert_encodes_like_codec((123u8, true));
919        assert_encodes_like_codec((123u8, true, "hello"));
920        // Encode isn't implemented for `char` (but we treat it as a u32):
921        assert_encodes_like_codec((123u8, true, "hello".to_string(), 'a' as u32));
922        assert_encodes_like_codec((
923            123u8,
924            true,
925            "hello".to_string(),
926            'a' as u32,
927            123_000_000_000u128,
928        ));
929    }
930
931    #[test]
932    fn sequences_roundtrip_into_eachother() {
933        // Nesting can be resolved (but tuples and sequences are distinct)
934        assert_value_roundtrips_to(([1u8, 2u8, 3u8],), vec![1u8, 2u8, 3u8]);
935        assert_value_roundtrips_to(([(1u8,), (2u8,), (3u8,)],), (([1u8, 2u8, 3u8],),));
936        assert_value_roundtrips_to(((([1u8],),),), (([1u8],),));
937        assert_value_roundtrips_to((([(1u8,)],),), (([1u8],),));
938    }
939
940    #[test]
941    fn tuples_to_structs() {
942        #[derive(Debug, scale_info::TypeInfo, codec::Decode, PartialEq)]
943        struct Foo {
944            a: (u32,),
945            b: u64,
946            c: u128,
947        }
948        assert_value_roundtrips_to(
949            (1u8, 2u8, 3u8),
950            Foo {
951                a: (1,),
952                b: 2,
953                c: 3,
954            },
955        );
956    }
957
958    #[test]
959    fn values_roundtrip_into_wrappers() {
960        #[derive(Debug, scale_info::TypeInfo, codec::Decode, PartialEq)]
961        struct Wrapper<T> {
962            val: T,
963        }
964
965        assert_value_roundtrips_to(true, (true,));
966        assert_value_roundtrips_to(1234u16, (1234u16,));
967        assert_value_roundtrips_to(1234u16, Wrapper { val: 1234u16 });
968        assert_value_roundtrips_to("hi", (("hi".to_string(),),));
969        assert_value_roundtrips_to(
970            "hi",
971            (Wrapper {
972                val: "hi".to_string(),
973            },),
974        );
975    }
976
977    #[test]
978    fn compacts_roundtrip() {
979        assert_encodes_like_codec(Compact(123u16));
980        assert_encodes_like_codec(Compact(123u8));
981        assert_encodes_like_codec(Compact(123u64));
982    }
983
984    #[test]
985    fn tuple_composite_can_encode_to_named_structs() {
986        #[derive(Debug, scale_info::TypeInfo, codec::Decode, PartialEq)]
987        struct Foo {
988            bar: u32,
989            wibble: bool,
990            hello: String,
991        }
992
993        // note: fields do not need to be in order when named:
994        let source_vals = [
995            (Some("hello"), CompositeField::new(&"world")),
996            (Some("bar"), CompositeField::new(&12345u128)),
997            (Some("wibble"), CompositeField::new(&true)),
998        ];
999        let source = Composite::new(source_vals.iter().copied());
1000
1001        // Composite can't implement `EncodeAsType` and so need "manually" encoding:
1002        let (type_id, types) = make_type::<Foo>();
1003        let bytes = source.encode_composite_as_type(type_id, &types).unwrap();
1004        let cursor = &mut &*bytes;
1005
1006        let target = Foo {
1007            bar: 12345,
1008            wibble: true,
1009            hello: "world".to_string(),
1010        };
1011
1012        let new_target = Foo::decode(cursor).unwrap();
1013
1014        assert_eq!(target, new_target);
1015        assert_eq!(cursor.len(), 0);
1016    }
1017
1018    #[test]
1019    fn tuple_composite_can_encode_to_unnamed_structs() {
1020        #[derive(Debug, scale_info::TypeInfo, codec::Decode, PartialEq, Clone)]
1021        struct Foo(u32, bool, String);
1022        let (type_id, types) = make_type::<Foo>();
1023
1024        // note: unnamed target so fields need to be in order (can be named or not)
1025        let source_vals = [
1026            (Some("bar"), CompositeField::new(&12345u128)),
1027            (Some("wibble"), CompositeField::new(&true)),
1028            (Some("hello"), CompositeField::new(&"world")),
1029        ];
1030        let source = Composite::new(source_vals.iter().copied());
1031        let source_bytes = source.encode_composite_as_type(type_id, &types).unwrap();
1032        let source_cursor = &mut &*source_bytes;
1033
1034        let source2_vals = [
1035            (None, CompositeField::new(&12345u128)),
1036            (None, CompositeField::new(&true)),
1037            (None, CompositeField::new(&"world")),
1038        ];
1039        let source2 = Composite::new(source2_vals.iter().copied());
1040        let source2_bytes = source2.encode_composite_as_type(type_id, &types).unwrap();
1041        let source2_cursor = &mut &*source2_bytes;
1042
1043        let target = Foo(12345, true, "world".to_string());
1044        let new_target = Foo::decode(source_cursor).unwrap();
1045        let new_target2 = Foo::decode(source2_cursor).unwrap();
1046
1047        assert_eq!(target, new_target);
1048        assert_eq!(target, new_target2);
1049        assert_eq!(source_cursor.len(), 0);
1050        assert_eq!(source2_cursor.len(), 0);
1051    }
1052
1053    #[test]
1054    fn tuple_composite_names_must_line_up() {
1055        #[derive(Debug, scale_info::TypeInfo, codec::Decode, PartialEq)]
1056        struct Foo {
1057            bar: u32,
1058            wibble: bool,
1059            hello: String,
1060        }
1061
1062        // note: fields do not need to be in order when named:
1063        let source_vals = [
1064            (Some("hello"), CompositeField::new(&"world")),
1065            (Some("bar"), CompositeField::new(&12345u128)),
1066            // wrong name:
1067            (Some("wibbles"), CompositeField::new(&true)),
1068        ];
1069        let source = Composite::new(source_vals.iter().copied());
1070
1071        let (type_id, types) = make_type::<Foo>();
1072        let _bytes = source
1073            .encode_composite_as_type(type_id, &types)
1074            .unwrap_err();
1075    }
1076
1077    #[test]
1078    fn bits_roundtrip_ok() {
1079        use bitvec::{
1080            order::{Lsb0, Msb0},
1081            vec::BitVec,
1082        };
1083        use scale_bits::Bits;
1084
1085        fn test_bits(bits: impl IntoIterator<Item = bool> + Clone) {
1086            let source = Bits::from_iter(bits.clone());
1087
1088            let target = BitVec::<u8, Lsb0>::from_iter(bits.clone());
1089            assert_value_roundtrips_to(source.clone(), target);
1090            let target = BitVec::<u16, Lsb0>::from_iter(bits.clone());
1091            assert_value_roundtrips_to(source.clone(), target);
1092            let target = BitVec::<u32, Lsb0>::from_iter(bits.clone());
1093            assert_value_roundtrips_to(source.clone(), target);
1094            let target = BitVec::<u64, Lsb0>::from_iter(bits.clone());
1095            assert_value_roundtrips_to(source.clone(), target);
1096            let target = BitVec::<u8, Msb0>::from_iter(bits.clone());
1097            assert_value_roundtrips_to(source.clone(), target);
1098            let target = BitVec::<u16, Msb0>::from_iter(bits.clone());
1099            assert_value_roundtrips_to(source.clone(), target);
1100            let target = BitVec::<u32, Msb0>::from_iter(bits.clone());
1101            assert_value_roundtrips_to(source.clone(), target);
1102            let target = BitVec::<u64, Msb0>::from_iter(bits);
1103            assert_value_roundtrips_to(source, target);
1104        }
1105
1106        test_bits([]);
1107        test_bits([true]);
1108        test_bits([false]);
1109        test_bits([true, false, true, true, false]);
1110        test_bits([
1111            true, false, true, true, false, true, false, true, true, false, false,
1112        ]);
1113
1114        // Wrapping the input or output bitvecs is fine; it'll figure it out:
1115        assert_value_roundtrips_to(
1116            Bits::from_iter([true, false, true]),
1117            ((BitVec::<u8, Lsb0>::from_iter([true, false, true]),),),
1118        );
1119        assert_value_roundtrips_to(
1120            (Bits::from_iter([true, false, true]),),
1121            ((BitVec::<u8, Lsb0>::from_iter([true, false, true]),),),
1122        );
1123    }
1124
1125    #[test]
1126    fn hxxx_types_roundtrip_ok() {
1127        use ::primitive_types::{H128, H160, H256, H384, H512, H768};
1128
1129        // Check that Hxxx types roundtirp to themselves or to byte sequences
1130        fn test_hxxx(bytes: impl IntoIterator<Item = u8> + Clone) {
1131            let mut bytes: Vec<u8> = bytes.into_iter().collect();
1132
1133            while bytes.len() < 128 / 8 {
1134                bytes.push(0)
1135            }
1136            assert_value_roundtrips_to(H128::from_slice(&bytes), bytes.clone());
1137            assert_value_roundtrips_to(H128::from_slice(&bytes), H128::from_slice(&bytes));
1138
1139            while bytes.len() < 160 / 8 {
1140                bytes.push(0)
1141            }
1142            assert_value_roundtrips_to(H160::from_slice(&bytes), bytes.clone());
1143            assert_value_roundtrips_to(H160::from_slice(&bytes), H160::from_slice(&bytes));
1144
1145            while bytes.len() < 256 / 8 {
1146                bytes.push(0)
1147            }
1148            assert_value_roundtrips_to(H256::from_slice(&bytes), bytes.clone());
1149            assert_value_roundtrips_to(H256::from_slice(&bytes), H256::from_slice(&bytes));
1150
1151            while bytes.len() < 384 / 8 {
1152                bytes.push(0)
1153            }
1154            assert_value_roundtrips_to(H384::from_slice(&bytes), bytes.clone());
1155            assert_value_roundtrips_to(H384::from_slice(&bytes), H384::from_slice(&bytes));
1156
1157            while bytes.len() < 512 / 8 {
1158                bytes.push(0)
1159            }
1160            assert_value_roundtrips_to(H512::from_slice(&bytes), bytes.clone());
1161            assert_value_roundtrips_to(H512::from_slice(&bytes), H512::from_slice(&bytes));
1162
1163            while bytes.len() < 768 / 8 {
1164                bytes.push(0)
1165            }
1166            assert_value_roundtrips_to(H768::from_slice(&bytes), bytes.clone());
1167            assert_value_roundtrips_to(H768::from_slice(&bytes), H768::from_slice(&bytes));
1168        }
1169
1170        test_hxxx([0u8]);
1171        test_hxxx([1, 2, 3, 4]);
1172    }
1173
1174    #[test]
1175    fn encode_as_fields_works() {
1176        #[derive(TypeInfo, Encode)]
1177        struct Foo {
1178            some_field: u64,
1179            another: u8,
1180        }
1181
1182        assert_encodes_fields_like_type(
1183            BTreeMap::from([
1184                ("other1", 1),
1185                ("another", 2),
1186                ("some_field", 3),
1187                ("other2", 4),
1188            ]),
1189            Foo {
1190                some_field: 3,
1191                another: 2,
1192            },
1193        );
1194
1195        assert_encodes_fields_like_type(
1196            (1u64, 2u8),
1197            Foo {
1198                some_field: 1,
1199                another: 2,
1200            },
1201        );
1202
1203        assert_encodes_fields_like_type(
1204            vec![1u64, 2u64],
1205            Foo {
1206                some_field: 1,
1207                another: 2,
1208            },
1209        );
1210
1211        assert_encodes_fields_like_type(
1212            [1u64, 2u64],
1213            Foo {
1214                some_field: 1,
1215                another: 2,
1216            },
1217        );
1218
1219        assert_encodes_fields_like_type(
1220            &[1u64, 2u64][..],
1221            Foo {
1222                some_field: 1,
1223                another: 2,
1224            },
1225        );
1226    }
1227
1228    #[test]
1229    fn encode_as_fields_via_macro_works() {
1230        #[derive(TypeInfo, Encode)]
1231        struct Foo {
1232            some_field: u64,
1233            another: bool,
1234        }
1235
1236        #[derive(TypeInfo, Encode)]
1237        struct FooUnnamed(
1238            String,
1239            (u8,), // different types still map ok.
1240            bool,
1241            u8,
1242        );
1243
1244        #[derive(EncodeAsType)]
1245        #[encode_as_type(crate_path = "crate")]
1246        struct FooBigger {
1247            random: String,
1248            some_field: u64,
1249            another: bool,
1250            more_random: u8,
1251        }
1252
1253        assert_encodes_fields_like_type(
1254            FooBigger {
1255                random: "hello".to_string(),
1256                some_field: 123,
1257                another: true,
1258                more_random: 1,
1259            },
1260            Foo {
1261                some_field: 123,
1262                another: true,
1263            },
1264        );
1265        assert_encodes_fields_like_type(
1266            FooBigger {
1267                random: "hello".to_string(),
1268                some_field: 123,
1269                another: true,
1270                more_random: 1,
1271            },
1272            FooUnnamed("hello".to_string(), (123,), true, 1),
1273        );
1274        assert_encodes_fields_like_type(
1275            FooBigger {
1276                random: "hello".to_string(),
1277                some_field: 123,
1278                another: true,
1279                more_random: 1,
1280            },
1281            ("hello".to_string(), (123u8,), true, (1u64,)),
1282        );
1283    }
1284
1285    #[test]
1286    #[allow(unused_assignments)]
1287    fn encode_to_number_skipping_attrs_via_macro_works() {
1288        struct NotEncodeAsType;
1289
1290        #[allow(dead_code)]
1291        #[derive(EncodeAsType)]
1292        #[encode_as_type(crate_path = "crate")]
1293        struct FooNotSkipping {
1294            value: u64,
1295            other: bool,
1296            third: String,
1297        }
1298
1299        #[derive(EncodeAsType)]
1300        #[encode_as_type(crate_path = "crate")]
1301        struct FooSkipping {
1302            value: u64,
1303            #[encode_as_type(skip)]
1304            other: bool,
1305            // Even though this type doesn't impl EncodeAsType,
1306            // it's ignored so should be fine:
1307            #[codec(skip)]
1308            third: NotEncodeAsType,
1309        }
1310
1311        assert_value_roundtrips_to(
1312            FooSkipping {
1313                value: 123,
1314                other: true,
1315                third: NotEncodeAsType,
1316            },
1317            123u64,
1318        );
1319    }
1320
1321    #[test]
1322    fn encode_unnamed_to_number_skipping_attrs_via_macro_works() {
1323        struct NotEncodeAsType;
1324
1325        #[derive(EncodeAsType)]
1326        #[encode_as_type(crate_path = "crate")]
1327        struct FooSkipping(
1328            u64,
1329            #[encode_as_type(skip)] bool,
1330            // Even though this type doesn't impl EncodeAsType,
1331            // it's ignored so should be fine:
1332            #[codec(skip)] NotEncodeAsType,
1333        );
1334
1335        assert_value_roundtrips_to(FooSkipping(123, true, NotEncodeAsType), 123u64);
1336    }
1337
1338    // If you don't skip values, you can't turn a multi-value
1339    // struct into a number.
1340    #[test]
1341    #[should_panic]
1342    fn encode_to_number_not_skipping_via_macro_fails() {
1343        #[derive(EncodeAsType)]
1344        #[encode_as_type(crate_path = "crate")]
1345        struct FooNotSkipping {
1346            value: u64,
1347            other: bool,
1348            third: String,
1349        }
1350
1351        assert_value_roundtrips_to(
1352            FooNotSkipping {
1353                value: 123,
1354                other: true,
1355                third: "hello".to_string(),
1356            },
1357            123u64,
1358        );
1359    }
1360
1361    #[test]
1362    fn encode_smart_pointers_as_fields() {
1363        #[derive(TypeInfo, Encode, PartialEq, Debug, Decode)]
1364        struct Foo {
1365            some_field: u64,
1366            another: u8,
1367        }
1368
1369        let map = BTreeMap::from([
1370            ("other1", 1),
1371            ("another", 2),
1372            ("some_field", 3),
1373            ("other2", 4),
1374        ]);
1375        let a = Box::new(map.clone());
1376        assert_encodes_fields_like_type(
1377            a.clone(),
1378            Foo {
1379                some_field: 3,
1380                another: 2,
1381            },
1382        );
1383        assert_value_roundtrips_to(
1384            &a,
1385            Box::new(Foo {
1386                some_field: 3,
1387                another: 2,
1388            }),
1389        );
1390        let b = Rc::new(map.clone());
1391        assert_encodes_fields_like_type(
1392            b.clone(),
1393            Foo {
1394                some_field: 3,
1395                another: 2,
1396            },
1397        );
1398        assert_value_roundtrips_to(
1399            &b,
1400            Rc::new(Foo {
1401                some_field: 3,
1402                another: 2,
1403            }),
1404        );
1405        let c = Arc::new(map.clone());
1406        assert_encodes_fields_like_type(
1407            c.clone(),
1408            Foo {
1409                some_field: 3,
1410                another: 2,
1411            },
1412        );
1413        assert_value_roundtrips_to(
1414            &c,
1415            Arc::new(Foo {
1416                some_field: 3,
1417                another: 2,
1418            }),
1419        );
1420    }
1421}