1use super::{
18 AccountId32,
19 decode::Decoder,
20 encode::Encoder,
21 env_types::{
22 self,
23 CustomTypeDecoder,
24 CustomTypeEncoder,
25 EnvTypesTranscoder,
26 PathKey,
27 TypesByPath,
28 },
29 scon::Value,
30};
31
32use anyhow::Result;
33use scale::Output;
34use scale_info::{
35 PortableRegistry,
36 TypeInfo,
37};
38use std::{
39 collections::HashMap,
40 fmt::Debug,
41};
42
43pub struct Transcoder {
46 env_types: EnvTypesTranscoder,
47}
48
49impl Transcoder {
50 pub fn new(env_types: EnvTypesTranscoder) -> Self {
51 Self { env_types }
52 }
53
54 pub fn encode<O>(
55 &self,
56 registry: &PortableRegistry,
57 type_id: u32,
58 value: &Value,
59 output: &mut O,
60 ) -> Result<()>
61 where
62 O: Output + Debug,
63 {
64 let encoder = Encoder::new(registry, &self.env_types);
65 encoder.encode(type_id, value, output)
66 }
67
68 pub fn decode(
69 &self,
70 registry: &PortableRegistry,
71 type_id: u32,
72 input: &mut &[u8],
73 ) -> Result<Value> {
74 let decoder = Decoder::new(registry, &self.env_types);
75 decoder.decode(type_id, input)
76 }
77}
78
79pub struct TranscoderBuilder {
81 types_by_path: TypesByPath,
82 encoders: HashMap<u32, Box<dyn CustomTypeEncoder>>,
83 decoders: HashMap<u32, Box<dyn CustomTypeDecoder>>,
84}
85
86impl TranscoderBuilder {
87 pub fn new(registry: &PortableRegistry) -> Self {
88 let types_by_path = registry
89 .types
90 .iter()
91 .map(|ty| (PathKey::from(&ty.ty.path), ty.id))
92 .collect::<TypesByPath>();
93 Self {
94 types_by_path,
95 encoders: HashMap::new(),
96 decoders: HashMap::new(),
97 }
98 }
99
100 pub fn with_default_custom_type_transcoders(self) -> Self {
101 self.register_custom_type_transcoder::<AccountId32, _>(env_types::AccountId)
102 .register_custom_type_transcoder::<<ink_env::DefaultEnvironment as ink_env::Environment>::AccountId, _>(env_types::AccountId)
103 .register_custom_type_transcoder::<<ink_env::DefaultEnvironment as ink_env::Environment>::Hash, _>(env_types::H256)
104 .register_custom_type_transcoder::<primitive_types::H160, _>(env_types::H160)
105 .register_custom_type_transcoder::<primitive_types::H256, _>(env_types::H256)
106 .register_custom_type_transcoder::<primitive_types::U256, _>(env_types::U256)
107 }
108
109 pub fn register_custom_type_transcoder<T, U>(self, transcoder: U) -> Self
110 where
111 T: TypeInfo + 'static,
112 U: CustomTypeEncoder + CustomTypeDecoder + Clone + 'static,
113 {
114 self.register_custom_type_encoder::<T, U>(transcoder.clone())
115 .register_custom_type_decoder::<T, U>(transcoder)
116 }
117
118 pub fn register_custom_type_encoder<T, U>(self, encoder: U) -> Self
119 where
120 T: TypeInfo + 'static,
121 U: CustomTypeEncoder + 'static,
122 {
123 let mut this = self;
124
125 let path_key = PathKey::from_type::<T>();
126 let type_id = this.types_by_path.get(&path_key);
127
128 match type_id {
129 Some(type_id) => {
130 let existing = this.encoders.insert(*type_id, Box::new(encoder));
131 tracing::debug!("Registered custom encoder for type `{:?}`", type_id);
132 if existing.is_some() {
133 panic!(
134 "Attempted to register encoder with existing type id {type_id:?}"
135 );
136 }
137 }
138 None => {
139 tracing::debug!("No matching type in registry for path {:?}.", path_key);
142 }
143 }
144 this
145 }
146
147 pub fn register_custom_type_decoder<T, U>(self, encoder: U) -> Self
148 where
149 T: TypeInfo + 'static,
150 U: CustomTypeDecoder + 'static,
151 {
152 let mut this = self;
153
154 let path_key = PathKey::from_type::<T>();
155 let type_id = this.types_by_path.get(&path_key);
156 tracing::trace!(
157 "Registering custom decoder for type `{:?}` with path `{:?}`",
158 type_id,
159 path_key
160 );
161
162 match type_id {
163 Some(type_id) => {
164 let existing = this.decoders.insert(*type_id, Box::new(encoder));
165 tracing::debug!("Registered custom decoder for type `{:?}`", type_id);
166 if existing.is_some() {
167 panic!(
168 "Attempted to register decoder with existing type id {type_id:?}"
169 );
170 }
171 }
172 None => {
173 tracing::debug!("No matching type in registry for path {:?}.", path_key);
176 }
177 }
178 this
179 }
180
181 pub fn done(self) -> Transcoder {
182 let env_types_transcoder = EnvTypesTranscoder::new(self.encoders, self.decoders);
183 Transcoder::new(env_types_transcoder)
184 }
185}
186
187#[cfg(test)]
188mod tests {
189 use super::{
190 super::scon::{
191 self,
192 Hex,
193 Map,
194 Seq,
195 Tuple,
196 Value,
197 },
198 *,
199 };
200 use primitive_types::H160;
201 use scale::Encode;
202 use scale_info::{
203 MetaType,
204 Registry,
205 TypeInfo,
206 };
207 use std::str::FromStr;
208
209 fn registry_with_type<T>() -> Result<(PortableRegistry, u32)>
210 where
211 T: scale_info::TypeInfo + 'static,
212 {
213 let mut registry = Registry::new();
214 let type_id = registry.register_type(&MetaType::new::<T>());
215 let registry: PortableRegistry = registry.into();
216
217 Ok((registry, type_id.id))
218 }
219
220 fn transcode_roundtrip<T>(input: &str, expected_output: Value) -> Result<()>
221 where
222 T: scale_info::TypeInfo + 'static,
223 {
224 let (registry, ty) = registry_with_type::<T>()?;
225 let transcoder = TranscoderBuilder::new(®istry)
226 .with_default_custom_type_transcoders()
227 .done();
228
229 let value = scon::parse_value(input)?;
230
231 let mut output = Vec::new();
232 transcoder.encode(®istry, ty, &value, &mut output)?;
233 let decoded = transcoder.decode(®istry, ty, &mut &output[..])?;
234 assert_eq!(expected_output, decoded, "decoding");
235 Ok(())
236 }
237
238 #[test]
239 fn transcode_bool() -> Result<()> {
240 transcode_roundtrip::<bool>("true", Value::Bool(true))?;
241 transcode_roundtrip::<bool>("false", Value::Bool(false))
242 }
243
244 #[test]
245 fn transcode_char_unsupported() -> Result<()> {
246 let (registry, ty) = registry_with_type::<char>()?;
247 let transcoder = Transcoder::new(Default::default());
248 let encoded = u32::from('c').encode();
249
250 assert!(
251 transcoder
252 .encode(®istry, ty, &Value::Char('c'), &mut Vec::new())
253 .is_err()
254 );
255 assert!(transcoder.decode(®istry, ty, &mut &encoded[..]).is_err());
256 Ok(())
257 }
258
259 #[test]
260 fn transcode_str() -> Result<()> {
261 transcode_roundtrip::<String>("\"ink!\"", Value::String("ink!".to_string()))
262 }
263
264 #[test]
265 fn transcode_unsigned_integers() -> Result<()> {
266 transcode_roundtrip::<u8>("0", Value::UInt(0))?;
267 transcode_roundtrip::<u8>("255", Value::UInt(255))?;
268
269 transcode_roundtrip::<u16>("0", Value::UInt(0))?;
270 transcode_roundtrip::<u16>("65535", Value::UInt(65535))?;
271
272 transcode_roundtrip::<u32>("0", Value::UInt(0))?;
273 transcode_roundtrip::<u32>("4294967295", Value::UInt(4294967295))?;
274
275 transcode_roundtrip::<u64>("0", Value::UInt(0))?;
276 transcode_roundtrip::<u64>(
277 "\"18_446_744_073_709_551_615\"",
278 Value::UInt(18446744073709551615),
279 )?;
280
281 transcode_roundtrip::<u128>("0", Value::UInt(0))?;
282 transcode_roundtrip::<u128>(
283 "\"340_282_366_920_938_463_463_374_607_431_768_211_455\"",
284 Value::UInt(340282366920938463463374607431768211455),
285 )
286 }
287
288 #[test]
289 fn transcode_integers() -> Result<()> {
290 transcode_roundtrip::<i8>("-128", Value::Int(i8::MIN.into()))?;
291 transcode_roundtrip::<i8>("127", Value::Int(i8::MAX.into()))?;
292
293 transcode_roundtrip::<i16>("-32768", Value::Int(i16::MIN.into()))?;
294 transcode_roundtrip::<i16>("32767", Value::Int(i16::MAX.into()))?;
295
296 transcode_roundtrip::<i32>("-2147483648", Value::Int(i32::MIN.into()))?;
297 transcode_roundtrip::<i32>("2147483647", Value::Int(i32::MAX.into()))?;
298
299 transcode_roundtrip::<i64>("-9223372036854775808", Value::Int(i64::MIN.into()))?;
300 transcode_roundtrip::<i64>(
301 "\"9_223_372_036_854_775_807\"",
302 Value::Int(i64::MAX.into()),
303 )?;
304
305 transcode_roundtrip::<i128>(
306 "-170141183460469231731687303715884105728",
307 Value::Int(i128::MIN),
308 )?;
309 transcode_roundtrip::<i128>(
310 "\"170141183460469231731687303715884105727\"",
311 Value::Int(i128::MAX),
312 )
313 }
314
315 #[test]
316 fn transcode_byte_array() -> Result<()> {
317 transcode_roundtrip::<[u8; 2]>(
318 r#"0x0000"#,
319 Value::Seq(vec![Value::UInt(0x00), Value::UInt(0x00)].into()),
320 )?;
321 transcode_roundtrip::<[u8; 4]>(
322 r#"0xDEADBEEF"#,
323 Value::Seq(
324 vec![
325 Value::UInt(0xDE),
326 Value::UInt(0xAD),
327 Value::UInt(0xBE),
328 Value::UInt(0xEF),
329 ]
330 .into(),
331 ),
332 )?;
333 transcode_roundtrip::<[u8; 4]>(
334 r#"0xdeadbeef"#,
335 Value::Seq(
336 vec![
337 Value::UInt(0xDE),
338 Value::UInt(0xAD),
339 Value::UInt(0xBE),
340 Value::UInt(0xEF),
341 ]
342 .into(),
343 ),
344 )
345 }
346
347 #[test]
348 fn transcode_array() -> Result<()> {
349 transcode_roundtrip::<[u32; 3]>(
350 "[1, 2, 3]",
351 Value::Seq(vec![Value::UInt(1), Value::UInt(2), Value::UInt(3)].into()),
352 )?;
353 transcode_roundtrip::<[String; 2]>(
354 "[\"hello\", \"world\"]",
355 Value::Seq(
356 vec![
357 Value::String("hello".to_string()),
358 Value::String("world".to_string()),
359 ]
360 .into(),
361 ),
362 )
363 }
364
365 #[test]
366 fn transcode_seq() -> Result<()> {
367 transcode_roundtrip::<Vec<u32>>(
368 "[1, 2, 3]",
369 Value::Seq(vec![Value::UInt(1), Value::UInt(2), Value::UInt(3)].into()),
370 )?;
371 transcode_roundtrip::<Vec<String>>(
372 "[\"hello\", \"world\"]",
373 Value::Seq(
374 vec![
375 Value::String("hello".to_string()),
376 Value::String("world".to_string()),
377 ]
378 .into(),
379 ),
380 )
381 }
382
383 #[test]
384 fn transcode_tuple() -> Result<()> {
385 transcode_roundtrip::<(u32, String, [u8; 4])>(
386 r#"(1, "ink!", 0xDEADBEEF)"#,
387 Value::Tuple(Tuple::new(
388 None,
389 vec![
390 Value::UInt(1),
391 Value::String("ink!".to_string()),
392 Value::Seq(
393 vec![
394 Value::UInt(0xDE),
395 Value::UInt(0xAD),
396 Value::UInt(0xBE),
397 Value::UInt(0xEF),
398 ]
399 .into(),
400 ),
401 ],
402 )),
403 )
404 }
405
406 #[test]
407 fn transcode_composite_struct() -> Result<()> {
408 #[allow(dead_code)]
409 #[derive(TypeInfo)]
410 struct S {
411 a: u32,
412 b: String,
413 c: [u8; 4],
414 d: Vec<S>,
416 }
417
418 transcode_roundtrip::<S>(
419 r#"S(a: 1, b: "ink!", c: 0xDEADBEEF, d: [S(a: 2, b: "ink!", c: 0xDEADBEEF, d: [])])"#,
420 Value::Map(
421 vec![
422 (Value::String("a".to_string()), Value::UInt(1)),
423 (
424 Value::String("b".to_string()),
425 Value::String("ink!".to_string()),
426 ),
427 (
428 Value::String("c".to_string()),
429 Value::Seq(
430 vec![
431 Value::UInt(0xDE),
432 Value::UInt(0xAD),
433 Value::UInt(0xBE),
434 Value::UInt(0xEF),
435 ]
436 .into(),
437 ),
438 ),
439 (
440 Value::String("d".to_string()),
441 Value::Seq(
442 vec![Value::Map(
443 vec![
444 (Value::String("a".to_string()), Value::UInt(2)),
445 (
446 Value::String("b".to_string()),
447 Value::String("ink!".to_string()),
448 ),
449 (
450 Value::String("c".to_string()),
451 Value::Seq(
452 vec![
453 Value::UInt(0xDE),
454 Value::UInt(0xAD),
455 Value::UInt(0xBE),
456 Value::UInt(0xEF),
457 ]
458 .into(),
459 ),
460 ),
461 (
462 Value::String("d".to_string()),
463 Value::Seq(
464 Vec::new()
465 .into_iter()
466 .collect::<Vec<_>>()
467 .into(),
468 ),
469 ),
470 ]
471 .into_iter()
472 .collect(),
473 )]
474 .into(),
475 ),
476 ),
477 ]
478 .into_iter()
479 .collect(),
480 ),
481 )
482 }
483
484 #[test]
485 fn transcode_composite_struct_nested() -> Result<()> {
486 #[allow(dead_code)]
487 #[derive(TypeInfo)]
488 struct S {
489 nested: Nested,
490 }
491
492 #[allow(dead_code)]
493 #[derive(TypeInfo)]
494 struct Nested(u32);
495
496 transcode_roundtrip::<S>(
497 r#"S { nested: Nested(33) }"#,
498 Value::Map(Map::new(
499 Some("S"),
500 vec![(
501 Value::String("nested".to_string()),
502 Value::Tuple(Tuple::new(
503 Some("Nested"),
504 vec![Value::UInt(33)].into_iter().collect(),
505 )),
506 )]
507 .into_iter()
508 .collect(),
509 )),
510 )
511 }
512
513 #[test]
514 fn transcode_composite_struct_out_of_order_fields() -> Result<()> {
515 #[allow(dead_code)]
516 #[derive(TypeInfo)]
517 struct S {
518 a: u32,
519 b: String,
520 c: [u8; 4],
521 }
522
523 transcode_roundtrip::<S>(
524 r#"S(b: "ink!", a: 1, c: 0xDEADBEEF)"#,
525 Value::Map(
526 vec![
527 (Value::String("a".to_string()), Value::UInt(1)),
528 (
529 Value::String("b".to_string()),
530 Value::String("ink!".to_string()),
531 ),
532 (
533 Value::String("c".to_string()),
534 Value::Seq(
535 vec![
536 Value::UInt(0xDE),
537 Value::UInt(0xAD),
538 Value::UInt(0xBE),
539 Value::UInt(0xEF),
540 ]
541 .into(),
542 ),
543 ),
544 ]
545 .into_iter()
546 .collect(),
547 ),
548 )
549 }
550
551 #[test]
552 fn transcode_composite_tuple_struct() -> Result<()> {
553 #[allow(dead_code)]
554 #[derive(TypeInfo)]
555 struct S(u32, String, [u8; 4]);
556
557 transcode_roundtrip::<S>(
558 r#"S(1, "ink!", 0xDEADBEEF)"#,
559 Value::Tuple(Tuple::new(
560 Some("S"),
561 vec![
562 Value::UInt(1),
563 Value::String("ink!".to_string()),
564 Value::Seq(
565 vec![
566 Value::UInt(0xDE),
567 Value::UInt(0xAD),
568 Value::UInt(0xBE),
569 Value::UInt(0xEF),
570 ]
571 .into(),
572 ),
573 ],
574 )),
575 )
576 }
577
578 #[test]
579 fn transcode_composite_single_field_struct() -> Result<()> {
580 #[allow(dead_code)]
581 #[derive(TypeInfo)]
582 struct S([u8; 4]);
583
584 transcode_roundtrip::<S>(
585 r#"0xDEADBEEF"#,
586 Value::Tuple(Tuple::new(
587 Some("S"),
588 vec![Value::Seq(
589 vec![
590 Value::UInt(0xDE),
591 Value::UInt(0xAD),
592 Value::UInt(0xBE),
593 Value::UInt(0xEF),
594 ]
595 .into(),
596 )],
597 )),
598 )
599 }
600
601 #[test]
602 fn transcode_composite_single_field_tuple() -> Result<()> {
603 transcode_roundtrip::<([u8; 4],)>(
604 r#"0xDEADBEEF"#,
605 Value::Tuple(Tuple::new(
606 None,
607 vec![Value::Seq(
608 vec![
609 Value::UInt(0xDE),
610 Value::UInt(0xAD),
611 Value::UInt(0xBE),
612 Value::UInt(0xEF),
613 ]
614 .into(),
615 )],
616 )),
617 )
618 }
619
620 #[test]
621 fn transcode_enum_variant_tuple() -> Result<()> {
622 #[derive(TypeInfo)]
623 #[allow(dead_code)]
624 enum E {
625 A(u32, String),
626 B { a: [u8; 4], b: Vec<E> },
627 C,
628 }
629
630 transcode_roundtrip::<E>(
631 r#"A(1, "2")"#,
632 Value::Tuple(Tuple::new(
633 Some("A"),
634 vec![Value::UInt(1), Value::String("2".into())],
635 )),
636 )
637 }
638
639 #[test]
640 fn transcode_enum_variant_map() -> Result<()> {
641 #[derive(TypeInfo)]
642 #[allow(dead_code)]
643 enum E {
644 A { a: u32, b: bool },
645 }
646
647 transcode_roundtrip::<E>(
648 r#"A { a: 33, b: false }"#,
649 Value::Map(Map::new(
650 Some("A"),
651 vec![
652 (Value::String("a".to_string()), Value::UInt(33)),
653 (Value::String("b".to_string()), Value::Bool(false)),
654 ]
655 .into_iter()
656 .collect(),
657 )),
658 )
659 }
660
661 #[test]
662 fn transcode_enum_variant_map_out_of_order_fields() -> Result<()> {
663 #[derive(TypeInfo)]
664 #[allow(dead_code)]
665 enum E {
666 A { a: u32, b: bool },
667 }
668
669 transcode_roundtrip::<E>(
670 r#"A { a: 33, b: false }"#,
671 Value::Map(Map::new(
672 Some("A"),
673 vec![
674 (Value::String("a".to_string()), Value::UInt(33)),
675 (Value::String("b".to_string()), Value::Bool(false)),
676 ]
677 .into_iter()
678 .collect(),
679 )),
680 )
681 }
682
683 #[test]
684 fn transcode_option() -> Result<()> {
685 transcode_roundtrip::<Option<u32>>(
686 r#"Some(32)"#,
687 Value::Tuple(Tuple::new(Some("Some"), vec![Value::UInt(32)])),
688 )?;
689
690 transcode_roundtrip::<Option<u32>>(
691 r#"None"#,
692 Value::Tuple(Tuple::new(Some("None"), Vec::new())),
693 )
694 }
695
696 #[test]
697 fn transcode_account_id_custom_ss58_encoding() -> Result<()> {
698 type AccountId = AccountId32;
699
700 #[allow(dead_code)]
701 #[derive(TypeInfo)]
702 struct S {
703 no_alias: AccountId32,
704 aliased: AccountId,
705 }
706
707 transcode_roundtrip::<S>(
708 r#"S(
709 no_alias: 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY,
710 aliased: 5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty,
711 )"#,
712 Value::Map(Map::new(
713 Some("S"),
714 vec![
715 (
716 Value::String("no_alias".into()),
717 Value::Literal(
718 "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY".into(),
719 ),
720 ),
721 (
722 Value::String("aliased".into()),
723 Value::Literal(
724 "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty".into(),
725 ),
726 ),
727 ]
728 .into_iter()
729 .collect(),
730 )),
731 )
732 }
733
734 #[test]
735 fn transcode_account_id_custom_ss58_encoding_seq() -> Result<()> {
736 transcode_roundtrip::<Vec<AccountId32>>(
737 r#"[
738 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY,
739 5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty,
740 ]"#,
741 Value::Seq(Seq::new(vec![
742 Value::Literal("5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY".into()),
743 Value::Literal("5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty".into()),
744 ])),
745 )
746 }
747
748 #[test]
749 fn decode_h256_as_hex_string() -> Result<()> {
750 #[allow(dead_code)]
751 #[derive(TypeInfo)]
752 struct S {
753 hash: primitive_types::H256,
754 }
755
756 transcode_roundtrip::<S>(
757 r#"S(
758 hash: 0x3428ebe146f5b82415da82724bcf75f053768738dcac5f83ab7d82a70a0ff2de,
759 )"#,
760 Value::Map(Map::new(
761 Some("S"),
762 vec![
763 (
764 Value::String("hash".into()),
765 Value::Hex(
766 Hex::from_str("0x3428ebe146f5b82415da82724bcf75f053768738dcac5f83ab7d82a70a0ff2de")?,
767 ),
768 ),
769 ]
770 .into_iter()
771 .collect(),
772 )),
773 )
774 }
775
776 #[test]
777 fn transcode_compact_primitives() -> Result<()> {
778 transcode_roundtrip::<scale::Compact<u8>>(r#"33"#, Value::UInt(33))?;
779
780 transcode_roundtrip::<scale::Compact<u16>>(r#"33"#, Value::UInt(33))?;
781
782 transcode_roundtrip::<scale::Compact<u32>>(r#"33"#, Value::UInt(33))?;
783
784 transcode_roundtrip::<scale::Compact<u64>>(r#"33"#, Value::UInt(33))?;
785
786 transcode_roundtrip::<scale::Compact<u128>>(r#"33"#, Value::UInt(33))
787 }
788
789 #[test]
790 fn transcode_compact_struct() -> Result<()> {
791 #[derive(scale::Encode, scale::CompactAs, TypeInfo)]
792 struct CompactStruct(u32);
793
794 #[allow(dead_code)]
795 #[derive(scale::Encode, TypeInfo)]
796 struct S {
797 #[codec(compact)]
798 a: CompactStruct,
799 }
800
801 transcode_roundtrip::<S>(
802 r#"S { a: CompactStruct(33) }"#,
803 Value::Map(Map::new(
804 Some("S"),
805 vec![(
806 Value::String("a".to_string()),
807 Value::Tuple(Tuple::new(
808 Some("CompactStruct"),
809 vec![Value::UInt(33)],
810 )),
811 )]
812 .into_iter()
813 .collect(),
814 )),
815 )
816 }
817
818 #[test]
819 fn transcode_hex_literal_uints() -> Result<()> {
820 #[derive(scale::Encode, TypeInfo)]
821 struct S(u8, u16, u32, u64, u128);
822
823 transcode_roundtrip::<S>(
824 r#"S (0xDE, 0xDEAD, 0xDEADBEEF, 0xDEADBEEF12345678, 0xDEADBEEF0123456789ABCDEF01234567)"#,
825 Value::Tuple(Tuple::new(
826 Some("S"),
827 vec![
828 Value::UInt(0xDE),
829 Value::UInt(0xDEAD),
830 Value::UInt(0xDEADBEEF),
831 Value::UInt(0xDEADBEEF12345678),
832 Value::UInt(0xDEADBEEF0123456789ABCDEF01234567),
833 ]
834 .into_iter()
835 .collect(),
836 )),
837 )
838 }
839
840 #[test]
841 fn transcode_h160_vec() -> Result<()> {
842 transcode_roundtrip::<Vec<H160>>(
843 r#"[
844 0x9621dde636de098b43efb0fa9b61facfe328f99d,
845 0x41dccbd49b26c50d34355ed86ff0fa9e489d1e01
846 ]"#,
847 Value::Seq(Seq::new(vec![
848 Value::Hex(Hex::from_str("0x9621dde636de098b43efb0fa9b61facfe328f99d")?),
849 Value::Hex(Hex::from_str("0x41dccbd49b26c50d34355ed86ff0fa9e489d1e01")?),
850 ])),
851 )
852 }
853}