1#[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
49pub 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
243macro_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
354macro_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 };
393
394macro_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
456macro_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
496macro_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
516fn 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
543fn 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 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 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 assert_value_roundtrips_to(Arc::new("hi"), "hi".to_string());
786 assert_value_roundtrips_to(Rc::new("hi"), "hi".to_string());
787 }
789
790 #[test]
791 fn other_container_types_roundtrip_ok() {
792 let v = LinkedList::from([1u8, 2, 3]);
796 assert_value_roundtrips_to(v, vec![1u8, 2, 3]);
797
798 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 assert_value_roundtrips_to(v.clone(), Foo { a: 1, b: 3, c: 2 });
822 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 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 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 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 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 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 let source_vals = [
976 (Some("hello"), CompositeField::new(&"world")),
977 (Some("bar"), CompositeField::new(&12345u128)),
978 (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 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 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,), 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 #[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 #[codec(skip)] NotEncodeAsType,
1212 );
1213
1214 assert_value_roundtrips_to(FooSkipping(123, true, NotEncodeAsType), 123u64);
1215 }
1216
1217 #[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}