polymesh_api_client/
type_codec.rs

1use codec::{Compact, Decode, Encode, Input, Output};
2use serde_json::{json, Map, Value};
3
4#[cfg(not(feature = "std"))]
5use alloc::{format, string::String};
6use sp_std::prelude::*;
7
8use crate::error::*;
9use crate::schema::*;
10use crate::type_def::*;
11
12pub mod de;
13
14#[derive(Clone)]
15pub struct TypeCodec {
16  type_lookup: TypeLookup,
17  ty: Type,
18  id: TypeId,
19}
20
21impl TypeCodec {
22  pub fn new(type_lookup: &TypeLookup, type_ref: TypeRef) -> Option<Self> {
23    type_ref.ty.map(|ty| Self {
24      type_lookup: type_lookup.clone(),
25      ty,
26      id: type_ref.id,
27    })
28  }
29
30  pub fn decode_value<I: Input>(&self, input: &mut I, is_compact: bool) -> Result<Value> {
31    self.ty.decode_value(&self.type_lookup, input, is_compact)
32  }
33
34  pub fn decode(&self, mut data: &[u8]) -> Result<Value> {
35    self.decode_value(&mut data, false)
36  }
37
38  pub fn encode_to<T: Output + ?Sized>(&self, value: &Value, dest: &mut T) -> Result<()> {
39    self.ty.encode_to(&self.type_lookup, value, dest, false)
40  }
41
42  pub fn encode(&self, value: &Value) -> Result<Vec<u8>> {
43    let mut buf = Vec::with_capacity(1024);
44    self.encode_to(value, &mut buf)?;
45    Ok(buf)
46  }
47
48  pub fn from_slice<'a, T>(&'a self, data: &'a [u8]) -> Result<T>
49  where
50    T: serde::de::Deserialize<'a>,
51  {
52    let mut deserializer = de::TypeDeserializer::from_slice(self, data);
53    Ok(T::deserialize(&mut deserializer)?)
54  }
55}
56
57impl TypeLookup {
58  pub fn type_codec(&self, name: &str) -> Option<TypeCodec> {
59    let type_ref = self.resolve(name);
60    TypeCodec::new(self, type_ref)
61  }
62
63  pub fn decode_value<I: Input>(
64    &self,
65    type_id: TypeId,
66    input: &mut I,
67    is_compact: bool,
68  ) -> Result<Value> {
69    let ty = self
70      .get_type(type_id)
71      .ok_or_else(|| Error::DecodeTypeFailed(format!("Missing type_id: {type_id:?}")))?;
72    if ty.path().is_empty() {
73      log::trace!("decode type[{type_id:?}]");
74    } else {
75      log::trace!("decode type[{type_id:?}]: {}", ty.path());
76    }
77    ty.decode_value(self, input, is_compact)
78  }
79
80  pub fn encode_to<T: Output + ?Sized>(
81    &self,
82    type_id: TypeId,
83    value: &Value,
84    dest: &mut T,
85    is_compact: bool,
86  ) -> Result<()> {
87    let ty = self
88      .get_type(type_id)
89      .ok_or_else(|| Error::DecodeTypeFailed(format!("Missing type_id: {type_id:?}")))?;
90    if ty.path().is_empty() {
91      log::trace!("encode type[{type_id:?}]");
92    } else {
93      log::trace!("encode type[{type_id:?}]: {}", ty.path());
94    }
95    ty.encode_to(self, value, dest, is_compact)
96  }
97}
98
99impl Type {
100  pub fn decode_value<I: Input>(
101    &self,
102    type_lookup: &TypeLookup,
103    input: &mut I,
104    is_compact: bool,
105  ) -> Result<Value> {
106    if !self.path().is_empty() {
107      log::trace!("decode type: {}", self.path());
108    }
109    self
110      .type_def
111      .decode_value(self, type_lookup, input, is_compact)
112  }
113
114  pub fn encode_to<T: Output + ?Sized>(
115    &self,
116    type_lookup: &TypeLookup,
117    value: &Value,
118    dest: &mut T,
119    is_compact: bool,
120  ) -> Result<()> {
121    if !self.path().is_empty() {
122      log::trace!("encode type: {}", self.path());
123    }
124    self
125      .type_def
126      .encode_to(self, type_lookup, value, dest, is_compact)
127  }
128}
129
130impl TypeDef {
131  pub fn decode_value<I: Input>(
132    &self,
133    ty: &Type,
134    type_lookup: &TypeLookup,
135    input: &mut I,
136    is_compact: bool,
137  ) -> Result<Value> {
138    match self {
139      TypeDef::Composite(def) => def.decode_value(type_lookup, input, is_compact),
140      TypeDef::Variant(def) => {
141        let is_option = ty.path().segments == &["Option"];
142        def.decode_value(type_lookup, input, is_compact, is_option)
143      }
144      TypeDef::Sequence(def) => def.decode_value(type_lookup, input, is_compact),
145      TypeDef::Array(def) => def.decode_value(type_lookup, input, is_compact),
146      TypeDef::Tuple(def) => def.decode_value(type_lookup, input, is_compact),
147      TypeDef::Primitive(prim) => {
148        log::trace!("decode Primitive: {prim:?}, is_compact: {is_compact}");
149        match prim {
150          TypeDefPrimitive::Bool => match input.read_byte()? {
151            0 => Ok(json!(false)),
152            1 => Ok(json!(true)),
153            num => Err(Error::DecodeTypeFailed(format!(
154              "Invalid bool byte: {num:?}"
155            ))),
156          },
157          TypeDefPrimitive::Char => {
158            let ch = input.read_byte()? as char;
159            Ok(json!(ch))
160          }
161          TypeDefPrimitive::Str => {
162            let s = String::decode(input)?;
163            Ok(json!(s))
164          }
165          TypeDefPrimitive::U8 => {
166            let num = u8::decode(input)?;
167            Ok(json!(num))
168          }
169          TypeDefPrimitive::U16 => {
170            let num = if is_compact {
171              Compact::<u16>::decode(input)?.0
172            } else {
173              u16::decode(input)?
174            };
175            Ok(json!(num))
176          }
177          TypeDefPrimitive::U32 => {
178            let num = if is_compact {
179              Compact::<u32>::decode(input)?.0
180            } else {
181              u32::decode(input)?
182            };
183            Ok(json!(num))
184          }
185          TypeDefPrimitive::U64 => {
186            let num = if is_compact {
187              Compact::<u64>::decode(input)?.0
188            } else {
189              u64::decode(input)?
190            };
191            Ok(json!(num))
192          }
193          TypeDefPrimitive::U128 => {
194            let num = if is_compact {
195              Compact::<u128>::decode(input)?.0
196            } else {
197              u128::decode(input)?
198            };
199            Ok(json!(num))
200          }
201          TypeDefPrimitive::U256 => {
202            unimplemented!();
203          }
204          TypeDefPrimitive::I8 => {
205            let num = i8::decode(input)?;
206            Ok(json!(num))
207          }
208          TypeDefPrimitive::I16 => {
209            let num = if is_compact {
210              Compact::<u16>::decode(input)?.0 as i16
211            } else {
212              i16::decode(input)?
213            };
214            Ok(json!(num))
215          }
216          TypeDefPrimitive::I32 => {
217            let num = if is_compact {
218              Compact::<u32>::decode(input)?.0 as i32
219            } else {
220              i32::decode(input)?
221            };
222            Ok(json!(num))
223          }
224          TypeDefPrimitive::I64 => {
225            let num = if is_compact {
226              Compact::<u64>::decode(input)?.0 as i64
227            } else {
228              i64::decode(input)?
229            };
230            Ok(json!(num))
231          }
232          TypeDefPrimitive::I128 => {
233            let num = if is_compact {
234              Compact::<u128>::decode(input)?.0 as i128
235            } else {
236              i128::decode(input)?
237            };
238            Ok(json!(num))
239          }
240          TypeDefPrimitive::I256 => {
241            unimplemented!();
242          }
243        }
244      }
245      TypeDef::Compact(def) => def.decode_value(type_lookup, input, is_compact),
246    }
247  }
248
249  pub fn encode_to<T: Output + ?Sized>(
250    &self,
251    ty: &Type,
252    type_lookup: &TypeLookup,
253    value: &Value,
254    dest: &mut T,
255    is_compact: bool,
256  ) -> Result<()> {
257    match self {
258      TypeDef::Composite(def) => def.encode_to(type_lookup, value, dest, is_compact),
259      TypeDef::Variant(def) => {
260        let is_option = ty.path().segments == &["Option"];
261        def.encode_to(type_lookup, value, dest, is_compact, is_option)
262      }
263      TypeDef::Sequence(def) => def.encode_to(type_lookup, value, dest, is_compact),
264      TypeDef::Array(def) => def.encode_to(type_lookup, value, dest, is_compact),
265      TypeDef::Tuple(def) => def.encode_to(type_lookup, value, dest, is_compact),
266      TypeDef::Primitive(prim) => {
267        log::trace!("encode Primitive: {prim:?}, is_compact: {is_compact}");
268        match prim {
269          TypeDefPrimitive::Bool => match value.as_bool() {
270            Some(v) => {
271              dest.push_byte(if v { 1 } else { 0 });
272              Ok(())
273            }
274            None => Err(Error::EncodeTypeFailed(format!(
275              "Expected a bool, got {:?}",
276              value
277            ))),
278          },
279          TypeDefPrimitive::Char => match value.as_str() {
280            Some(v) if v.len() == 1 => {
281              let ch = v.as_bytes()[0];
282              dest.push_byte(ch);
283              Ok(())
284            }
285            _ => Err(Error::EncodeTypeFailed(format!(
286              "Expected a char (string), got {:?}",
287              value
288            ))),
289          },
290          TypeDefPrimitive::Str => match value.as_str() {
291            Some(v) => {
292              v.encode_to(dest);
293              Ok(())
294            }
295            None => Err(Error::EncodeTypeFailed(format!(
296              "Expected a string, got {:?}",
297              value
298            ))),
299          },
300          TypeDefPrimitive::U8 => match value.as_u64() {
301            Some(num) => {
302              let num: u8 = num
303                .try_into()
304                .map_err(|e| Error::EncodeTypeFailed(format!("Not a u8 number: {e:?}")))?;
305              num.encode_to(dest);
306              Ok(())
307            }
308            None => Err(Error::EncodeTypeFailed(format!(
309              "Expected a number, got {:?}",
310              value
311            ))),
312          },
313          TypeDefPrimitive::U16 => match value.as_u64() {
314            Some(num) => {
315              let num: u16 = num
316                .try_into()
317                .map_err(|e| Error::EncodeTypeFailed(format!("Not a u16 number: {e:?}")))?;
318              if is_compact {
319                Compact(num).encode_to(dest);
320              } else {
321                num.encode_to(dest);
322              }
323              Ok(())
324            }
325            None => Err(Error::EncodeTypeFailed(format!(
326              "Expected a number, got {:?}",
327              value
328            ))),
329          },
330          TypeDefPrimitive::U32 => match value.as_u64() {
331            Some(num) => {
332              let num: u32 = num
333                .try_into()
334                .map_err(|e| Error::EncodeTypeFailed(format!("Not a u32 number: {e:?}")))?;
335              if is_compact {
336                Compact(num).encode_to(dest);
337              } else {
338                num.encode_to(dest);
339              }
340              Ok(())
341            }
342            None => Err(Error::EncodeTypeFailed(format!(
343              "Expected a number, got {:?}",
344              value
345            ))),
346          },
347          TypeDefPrimitive::U64 => match value.as_u64() {
348            Some(num) => {
349              if is_compact {
350                Compact(num).encode_to(dest);
351              } else {
352                num.encode_to(dest);
353              }
354              Ok(())
355            }
356            None => Err(Error::EncodeTypeFailed(format!(
357              "Expected a number, got {:?}",
358              value
359            ))),
360          },
361          TypeDefPrimitive::U128 => match value.as_u64() {
362            Some(num) => {
363              let num: u128 = num
364                .try_into()
365                .map_err(|e| Error::EncodeTypeFailed(format!("Not a u128 number: {e:?}")))?;
366              if is_compact {
367                Compact(num).encode_to(dest);
368              } else {
369                num.encode_to(dest);
370              }
371              Ok(())
372            }
373            None => Err(Error::EncodeTypeFailed(format!(
374              "Expected a number, got {:?}",
375              value
376            ))),
377          },
378          TypeDefPrimitive::U256 => {
379            unimplemented!();
380          }
381          TypeDefPrimitive::I8 => match value.as_i64() {
382            Some(num) => {
383              let num: i8 = num
384                .try_into()
385                .map_err(|e| Error::EncodeTypeFailed(format!("Not a i8 number: {e:?}")))?;
386              num.encode_to(dest);
387              Ok(())
388            }
389            None => Err(Error::EncodeTypeFailed(format!(
390              "Expected a number, got {:?}",
391              value
392            ))),
393          },
394          TypeDefPrimitive::I16 => match value.as_i64() {
395            Some(num) => {
396              let num: i16 = num
397                .try_into()
398                .map_err(|e| Error::EncodeTypeFailed(format!("Not a i16 number: {e:?}")))?;
399              if is_compact {
400                Compact(num as u128).encode_to(dest);
401              } else {
402                num.encode_to(dest);
403              }
404              Ok(())
405            }
406            None => Err(Error::EncodeTypeFailed(format!(
407              "Expected a number, got {:?}",
408              value
409            ))),
410          },
411          TypeDefPrimitive::I32 => match value.as_i64() {
412            Some(num) => {
413              let num: i32 = num
414                .try_into()
415                .map_err(|e| Error::EncodeTypeFailed(format!("Not a i32 number: {e:?}")))?;
416              if is_compact {
417                Compact(num as u128).encode_to(dest);
418              } else {
419                num.encode_to(dest);
420              }
421              Ok(())
422            }
423            None => Err(Error::EncodeTypeFailed(format!(
424              "Expected a number, got {:?}",
425              value
426            ))),
427          },
428          TypeDefPrimitive::I64 => match value.as_i64() {
429            Some(num) => {
430              if is_compact {
431                Compact(num as u128).encode_to(dest);
432              } else {
433                num.encode_to(dest);
434              }
435              Ok(())
436            }
437            None => Err(Error::EncodeTypeFailed(format!(
438              "Expected a number, got {:?}",
439              value
440            ))),
441          },
442          TypeDefPrimitive::I128 => match value.as_i64() {
443            Some(num) => {
444              let num: i128 = num
445                .try_into()
446                .map_err(|e| Error::EncodeTypeFailed(format!("Not a i128 number: {e:?}")))?;
447              if is_compact {
448                Compact(num as u128).encode_to(dest);
449              } else {
450                num.encode_to(dest);
451              }
452              Ok(())
453            }
454            None => Err(Error::EncodeTypeFailed(format!(
455              "Expected a number, got {:?}",
456              value
457            ))),
458          },
459          TypeDefPrimitive::I256 => {
460            unimplemented!();
461          }
462        }
463      }
464      TypeDef::Compact(def) => def.encode_to(type_lookup, value, dest, is_compact),
465    }
466  }
467}
468
469fn decode_fields<I: Input>(
470  fields: &Vec<Field>,
471  is_struct: bool,
472  type_lookup: &TypeLookup,
473  input: &mut I,
474  is_compact: bool,
475) -> Result<Value> {
476  let len = fields.len();
477  if len == 0 {
478    return Ok(Value::Null);
479  }
480  match fields.len() {
481    0 => Ok(Value::Null),
482    1 if fields[0].name.is_none() => {
483      Ok(type_lookup.decode_value(fields[0].ty, input, is_compact)?)
484    }
485    len if is_struct => {
486      let mut m = Map::with_capacity(len);
487      for (idx, field) in fields.iter().enumerate() {
488        let name = field
489          .name
490          .as_ref()
491          .cloned()
492          .unwrap_or_else(|| format!("{idx}"));
493        log::trace!("decode Composite field: {name}");
494        m.insert(name, type_lookup.decode_value(field.ty, input, is_compact)?);
495      }
496      Ok(m.into())
497    }
498    len => {
499      log::trace!("decode Composite tuple fields");
500      let mut arr = Vec::with_capacity(len);
501      for field in fields.iter() {
502        arr.push(type_lookup.decode_value(field.ty, input, is_compact)?);
503      }
504      Ok(arr.into())
505    }
506  }
507}
508
509fn encode_struct_fields<T: Output + ?Sized>(
510  fields: &Vec<Field>,
511  type_lookup: &TypeLookup,
512  value: &Value,
513  dest: &mut T,
514  is_compact: bool,
515) -> Result<()> {
516  let len = fields.len();
517  match value {
518    Value::Object(map) if map.len() == len => {
519      for field in fields {
520        let value = field.name.as_ref().and_then(|n| map.get(n));
521        match value {
522          Some(value) => {
523            log::trace!("encode Composite struct field: {:?}", field);
524            type_lookup.encode_to(field.ty, value, dest, is_compact)?;
525          }
526          None => {
527            return Err(Error::EncodeTypeFailed(format!(
528              "Encode struct missing field {:?}",
529              field.name
530            )));
531          }
532        }
533      }
534      Ok(())
535    }
536    Value::Object(map) => Err(Error::EncodeTypeFailed(format!(
537      "Encode struct expected {len} field, got {}",
538      map.len()
539    ))),
540    _ => Err(Error::EncodeTypeFailed(format!(
541      "Encode struct expect an object got {:?}",
542      value
543    ))),
544  }
545}
546
547fn encode_tuple_fields<T: Output + ?Sized>(
548  fields: &Vec<Field>,
549  type_lookup: &TypeLookup,
550  value: &Value,
551  dest: &mut T,
552  is_compact: bool,
553) -> Result<()> {
554  let len = fields.len();
555  if len == 1 {
556    return type_lookup.encode_to(fields[0].ty, value, dest, is_compact);
557  }
558  match value.as_array() {
559    Some(arr) if arr.len() == len => {
560      for (v, field) in arr.into_iter().zip(fields.iter()) {
561        log::trace!("encode Composite tuple field: {:?}", field);
562        type_lookup.encode_to(field.ty, v, dest, is_compact)?;
563      }
564      Ok(())
565    }
566    Some(arr) => Err(Error::EncodeTypeFailed(format!(
567      "Encode struct tuple expect array with length {len}, got {}",
568      arr.len()
569    ))),
570    None => Err(Error::EncodeTypeFailed(format!(
571      "Encode struct tuple expect array value got {:?}",
572      value
573    ))),
574  }
575}
576
577fn encode_fields<T: Output + ?Sized>(
578  fields: &Vec<Field>,
579  is_struct: bool,
580  type_lookup: &TypeLookup,
581  value: &Value,
582  dest: &mut T,
583  is_compact: bool,
584) -> Result<()> {
585  if is_struct {
586    encode_struct_fields(fields, type_lookup, value, dest, is_compact)
587  } else {
588    encode_tuple_fields(fields, type_lookup, value, dest, is_compact)
589  }
590}
591
592impl TypeDefComposite {
593  pub fn decode_value<I: Input>(
594    &self,
595    type_lookup: &TypeLookup,
596    input: &mut I,
597    is_compact: bool,
598  ) -> Result<Value> {
599    decode_fields(
600      &self.fields,
601      self.is_struct(),
602      type_lookup,
603      input,
604      is_compact,
605    )
606  }
607
608  pub fn encode_to<T: Output + ?Sized>(
609    &self,
610    type_lookup: &TypeLookup,
611    value: &Value,
612    dest: &mut T,
613    is_compact: bool,
614  ) -> Result<()> {
615    encode_fields(
616      &self.fields,
617      self.is_struct(),
618      type_lookup,
619      value,
620      dest,
621      is_compact,
622    )
623  }
624}
625
626impl TypeDefVariant {
627  pub fn decode_value<I: Input>(
628    &self,
629    type_lookup: &TypeLookup,
630    input: &mut I,
631    is_compact: bool,
632    is_option: bool,
633  ) -> Result<Value> {
634    let val = input.read_byte()?;
635    match (val, self.get_by_idx(val), is_option) {
636      (0, Some(_variant), true) => Ok(Value::Null),
637      (1, Some(variant), true) => decode_fields(
638        &variant.fields,
639        variant.is_struct(),
640        type_lookup,
641        input,
642        is_compact,
643      ),
644      (_, Some(variant), _) if variant.fields.len() == 0 => Ok(json!(variant.name)),
645      (_, Some(variant), _) => {
646        let mut m = Map::new();
647        let name = variant.name.clone();
648        m.insert(
649          name,
650          decode_fields(
651            &variant.fields,
652            variant.is_struct(),
653            type_lookup,
654            input,
655            is_compact,
656          )?,
657        );
658        Ok(m.into())
659      }
660      (_, None, _) if val == 0 => Ok(Value::Null),
661      (_, None, _) => {
662        log::debug!(
663          "Invalid variant: {}, bytes remaining: {:?}, variants: {:?}",
664          val,
665          input.remaining_len()?,
666          self.variants
667        );
668        Err(Error::DecodeTypeFailed(format!("Invalid variant: {val}")))
669      }
670    }
671  }
672
673  fn encode_option<T: Output + ?Sized>(
674    &self,
675    type_lookup: &TypeLookup,
676    value: &Value,
677    dest: &mut T,
678    is_compact: bool,
679  ) -> Result<()> {
680    if value.is_null() {
681      dest.push_byte(0);
682      return Ok(());
683    }
684    dest.push_byte(1);
685    let variant = self
686      .variants
687      .get(1)
688      .ok_or_else(|| Error::EncodeTypeFailed("Option type doesn't have a Some variant".into()))?;
689    encode_fields(
690      &variant.fields,
691      variant.is_struct(),
692      type_lookup,
693      value,
694      dest,
695      is_compact,
696    )
697  }
698
699  pub fn encode_to<T: Output + ?Sized>(
700    &self,
701    type_lookup: &TypeLookup,
702    value: &Value,
703    dest: &mut T,
704    is_compact: bool,
705    is_option: bool,
706  ) -> Result<()> {
707    if is_option {
708      return self.encode_option(type_lookup, value, dest, is_compact);
709    }
710    let len = self.variants.len();
711    match value {
712      Value::Null if len == 0 => {
713        // unit
714        dest.push_byte(0);
715        Ok(())
716      }
717      Value::String(s) => match self.get_by_name(&s) {
718        Some(v) if v.fields.len() == 0 => {
719          log::trace!("encode enum variant: {:?}", v);
720          dest.push_byte(v.index);
721          Ok(())
722        }
723        Some(v) => Err(Error::EncodeTypeFailed(format!(
724          "Variant {} has fields, got just the name.",
725          v.name
726        ))),
727        None => Err(Error::EncodeTypeFailed(format!("Unknown variant name {s}"))),
728      },
729      Value::Object(map) if map.len() == 1 => match map.iter().next() {
730        Some((key, value)) => match self.get_by_name(&key) {
731          Some(v) if v.fields.len() == 0 => {
732            log::trace!("encode enum variant: {:?}", v);
733            dest.push_byte(v.index);
734            Ok(())
735          }
736          Some(v) => {
737            log::trace!("encode enum variant: {:?}", v);
738            dest.push_byte(v.index);
739            if v.fields.len() > 0 {
740              encode_fields(
741                &v.fields,
742                v.is_struct(),
743                type_lookup,
744                value,
745                dest,
746                is_compact,
747              )
748            } else {
749              Ok(())
750            }
751          }
752          None => Err(Error::EncodeTypeFailed(format!(
753            "Unknown variant {:?}",
754            map
755          ))),
756        },
757        None => Err(Error::EncodeTypeFailed(format!(
758          "Unknown variant {:?}",
759          map
760        ))),
761      },
762      Value::Object(map) => Err(Error::EncodeTypeFailed(format!(
763        "Expect a variant, got a map with the wrong number of fields {}",
764        map.len()
765      ))),
766      value => Err(Error::EncodeTypeFailed(format!(
767        "Expect a variant, got {value:?}"
768      ))),
769    }
770  }
771}
772
773impl TypeDefSequence {
774  pub fn decode_value<I: Input>(
775    &self,
776    type_lookup: &TypeLookup,
777    input: &mut I,
778    is_compact: bool,
779  ) -> Result<Value> {
780    let len = Compact::<u64>::decode(input)?.0 as usize;
781    let ty = type_lookup
782      .get_type(self.type_param)
783      .ok_or_else(|| Error::DecodeTypeFailed(format!("Missing type_id: {:?}", self.type_param)))?;
784    if ty.is_u8() {
785      log::trace!("--- decode byte sequence[{len}]: {:?}", ty);
786      let mut vec = Vec::with_capacity(len);
787      // Byte array.
788      for _ in 0..len {
789        vec.push(input.read_byte()?);
790      }
791      Ok(Value::String(hex::encode(vec)))
792    } else {
793      let mut vec = Vec::with_capacity(len.max(256));
794      for _ in 0..len {
795        vec.push(ty.decode_value(type_lookup, input, is_compact)?);
796      }
797      Ok(vec.into())
798    }
799  }
800
801  pub fn encode_to<T: Output + ?Sized>(
802    &self,
803    type_lookup: &TypeLookup,
804    value: &Value,
805    dest: &mut T,
806    is_compact: bool,
807  ) -> Result<()> {
808    let ty = type_lookup
809      .get_type(self.type_param)
810      .ok_or_else(|| Error::DecodeTypeFailed(format!("Missing type_id: {:?}", self.type_param)))?;
811    match value {
812      Value::Array(arr) => {
813        let len = Compact::<u64>(arr.len() as u64);
814        len.encode_to(dest);
815        log::trace!("encode sequence: len={}", arr.len());
816        for v in arr {
817          ty.encode_to(type_lookup, v, dest, is_compact)?;
818        }
819        Ok(())
820      }
821      Value::String(s) if ty.is_u8() => {
822        let off = if s.starts_with("0x") { 2 } else { 0 };
823        let arr = hex::decode(&s[off..])?;
824        log::trace!("--- encode byte sequence[{}]: {:?}", arr.len(), ty);
825        let len = Compact::<u64>(arr.len() as u64);
826        len.encode_to(dest);
827        // Try hex decoding for byte arrays.
828        dest.write(&arr[..]);
829        Ok(())
830      }
831      _ => Err(Error::EncodeTypeFailed(format!(
832        "Encode sequence expect array value got {:?}",
833        value
834      ))),
835    }
836  }
837}
838
839impl TypeDefArray {
840  pub fn decode_value<I: Input>(
841    &self,
842    type_lookup: &TypeLookup,
843    input: &mut I,
844    is_compact: bool,
845  ) -> Result<Value> {
846    let len = self.len as usize;
847    let ty = type_lookup
848      .get_type(self.type_param)
849      .ok_or_else(|| Error::DecodeTypeFailed(format!("Missing type_id: {:?}", self.type_param)))?;
850    if ty.is_u8() {
851      log::trace!("--- decode byte array[{len}]: {:?}", ty);
852      let mut vec = Vec::with_capacity(len);
853      // Byte array.
854      for _ in 0..len {
855        vec.push(input.read_byte()?);
856      }
857      Ok(Value::String(hex::encode(vec)))
858    } else {
859      let mut vec = Vec::with_capacity(len);
860      for _ in 0..len {
861        vec.push(ty.decode_value(type_lookup, input, is_compact)?);
862      }
863      Ok(vec.into())
864    }
865  }
866
867  pub fn encode_to<T: Output + ?Sized>(
868    &self,
869    type_lookup: &TypeLookup,
870    value: &Value,
871    dest: &mut T,
872    is_compact: bool,
873  ) -> Result<()> {
874    let len = self.len as usize;
875    let ty = type_lookup
876      .get_type(self.type_param)
877      .ok_or_else(|| Error::DecodeTypeFailed(format!("Missing type_id: {:?}", self.type_param)))?;
878    match value {
879      Value::Array(arr) if arr.len() == len => {
880        log::trace!("encode array: len={len}");
881        for v in arr {
882          ty.encode_to(type_lookup, v, dest, is_compact)?;
883        }
884        Ok(())
885      }
886      Value::Array(arr) => Err(Error::EncodeTypeFailed(format!(
887        "Expect array with length {len}, got {}",
888        arr.len()
889      ))),
890      Value::String(s) if ty.is_u8() && s.len() >= 2 * len => {
891        log::trace!("--- encode byte array[{len}]: {:?}", ty);
892        // Try hex decoding for byte arrays.
893        let off = if s.starts_with("0x") { 2 } else { 0 };
894        let arr = hex::decode(&s[off..])?;
895        dest.write(&arr[..]);
896        Ok(())
897      }
898      _ => Err(Error::EncodeTypeFailed(format!(
899        "Expect array value got {:?}",
900        value
901      ))),
902    }
903  }
904}
905
906impl TypeDefTuple {
907  pub fn decode_value<I: Input>(
908    &self,
909    type_lookup: &TypeLookup,
910    input: &mut I,
911    is_compact: bool,
912  ) -> Result<Value> {
913    match self.fields.len() {
914      0 => Ok(Value::Null),
915      1 => Ok(type_lookup.decode_value(self.fields[0], input, is_compact)?),
916      len => {
917        let mut vec = Vec::with_capacity(len);
918        for field in &self.fields {
919          vec.push(type_lookup.decode_value(*field, input, is_compact)?);
920        }
921        Ok(vec.into())
922      }
923    }
924  }
925
926  pub fn encode_to<T: Output + ?Sized>(
927    &self,
928    type_lookup: &TypeLookup,
929    value: &Value,
930    dest: &mut T,
931    is_compact: bool,
932  ) -> Result<()> {
933    let len = self.fields.len();
934    log::trace!("encode tuple: len={len}");
935    if len == 1 {
936      return type_lookup.encode_to(self.fields[0], value, dest, is_compact);
937    }
938    match value.as_array() {
939      Some(arr) if arr.len() == len => {
940        for (v, field) in arr.into_iter().zip(self.fields.iter()) {
941          type_lookup.encode_to(*field, v, dest, is_compact)?;
942        }
943        Ok(())
944      }
945      Some(arr) => Err(Error::EncodeTypeFailed(format!(
946        "Encode tuple expect array with length {len}, got {}",
947        arr.len()
948      ))),
949      None => Err(Error::EncodeTypeFailed(format!(
950        "Encode tuple expect array value got {:?}",
951        value
952      ))),
953    }
954  }
955}
956
957impl TypeDefCompact {
958  pub fn decode_value<I: Input>(
959    &self,
960    type_lookup: &TypeLookup,
961    input: &mut I,
962    _is_compact: bool,
963  ) -> Result<Value> {
964    type_lookup.decode_value(self.type_param, input, true)
965  }
966
967  pub fn encode_to<T: Output + ?Sized>(
968    &self,
969    type_lookup: &TypeLookup,
970    value: &Value,
971    dest: &mut T,
972    _is_compact: bool,
973  ) -> Result<()> {
974    type_lookup.encode_to(self.type_param, value, dest, true)
975  }
976}