use crate::{
error::{Error, ErrorKind, Kind, Location},
EncodeAsType,
};
use codec::{Compact, Encode};
use scale_info::{form::PortableForm, Field, PortableRegistry, TypeDef};
use std::collections::HashMap;
#[doc(hidden)]
pub struct Composite<Tuples>(pub Tuples);
macro_rules! count_idents {
() => (0usize);
( $t:ident, $($ts:ident,)* ) => (1usize + count_idents!($($ts,)*));
}
macro_rules! impl_encode_composite {
($($name:ident: $t:ident),*) => {
impl < $($t),* > EncodeAsType for Composite<( $((Option<&'static str>, $t),)* )> where $($t: EncodeAsType),* {
#[allow(unused_assignments)]
#[allow(unused_mut)]
#[allow(unused_variables)]
fn encode_as_type_to(&self, type_id: u32, types: &PortableRegistry, out: &mut Vec<u8>) -> Result<(), Error> {
let ($($name,)*) = &self.0;
const LEN: usize = count_idents!($($t,)*);
let ty = types
.resolve(type_id)
.ok_or_else(|| Error::new(ErrorKind::TypeNotFound(type_id)))?;
match ty.type_def() {
TypeDef::Tuple(tuple) if tuple.fields().len() == LEN => {
let fields = tuple.fields();
let mut idx = 0;
$({
let loc = if let Some(name) = $name.0 {
Location::field(name)
} else {
Location::idx(idx)
};
$name.1
.encode_as_type_to(fields[idx].id(), types, out)
.map_err(|e| e.at(loc))?;
idx += 1;
})*
Ok(())
},
TypeDef::Array(array) if array.len() == LEN as u32 => {
let mut idx = 0;
$({
let loc = if let Some(name) = $name.0 {
Location::field(name)
} else {
Location::idx(idx)
};
$name.1
.encode_as_type_to(array.type_param().id(), types, out)
.map_err(|e| e.at(loc))?;
idx += 1;
})*
Ok(())
},
TypeDef::Sequence(seq) => {
let mut idx = 0;
Compact(LEN as u32).encode_to(out);
$({
let loc = if let Some(name) = $name.0 {
Location::field(name)
} else {
Location::idx(idx)
};
$name.1
.encode_as_type_to(seq.type_param().id(), types, out)
.map_err(|e| e.at(loc))?;
idx += 1;
})*
Ok(())
},
TypeDef::Composite(composite) if composite.fields().len() == LEN => {
let fields = composite.fields();
self.encode_fields_to(fields, type_id, types, out)
},
_ => {
if LEN == 1 {
$({
$name.1
.encode_as_type_to(type_id, types, out)
.map_err(|e| e.at_idx(0))?;
})*
Ok(())
} else {
Err(Error::new(ErrorKind::WrongShape { actual: Kind::Tuple, expected: type_id }))
}
}
}
}
}
}
}
#[rustfmt::skip]
const _: () = {
impl_encode_composite!();
impl_encode_composite!(a: A);
impl_encode_composite!(a: A, b: B);
impl_encode_composite!(a: A, b: B, c: C);
impl_encode_composite!(a: A, b: B, c: C, d: D);
impl_encode_composite!(a: A, b: B, c: C, d: D, e: E);
impl_encode_composite!(a: A, b: B, c: C, d: D, e: E, f: F);
impl_encode_composite!(a: A, b: B, c: C, d: D, e: E, f: F, g: G);
impl_encode_composite!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H);
impl_encode_composite!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I);
impl_encode_composite!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J);
impl_encode_composite!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K);
impl_encode_composite!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L);
impl_encode_composite!(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);
impl_encode_composite!(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);
impl_encode_composite!(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);
impl_encode_composite!(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);
impl_encode_composite!(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);
impl_encode_composite!(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);
impl_encode_composite!(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);
impl_encode_composite!(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, t: T);
impl_encode_composite!(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, t: T, u: U);
impl_encode_composite!(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, t: T, u: U, v: V);
impl_encode_composite!(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, t: T, u: U, v: V, w: W);
impl_encode_composite!(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, t: T, u: U, v: V, w: W, x: X);
impl_encode_composite!(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, t: T, u: U, v: V, w: W, x: X, y: Y);
impl_encode_composite!(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, t: T, u: U, v: V, w: W, x: X, y: Y, z: Z);
impl_encode_composite!(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, t: T, u: U, v: V, w: W, x: X, y: Y, z: Z, a1: A1);
impl_encode_composite!(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, t: T, u: U, v: V, w: W, x: X, y: Y, z: Z, a1: A1, b1: B1);
impl_encode_composite!(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, t: T, u: U, v: V, w: W, x: X, y: Y, z: Z, a1: A1, b1: B1, c1: C1);
impl_encode_composite!(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, t: T, u: U, v: V, w: W, x: X, y: Y, z: Z, a1: A1, b1: B1, c1: C1, d1: D1);
impl_encode_composite!(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, t: T, u: U, v: V, w: W, x: X, y: Y, z: Z, a1: A1, b1: B1, c1: C1, d1: D1, e1: E1);
impl_encode_composite!(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, t: T, u: U, v: V, w: W, x: X, y: Y, z: Z, a1: A1, b1: B1, c1: C1, d1: D1, e1: E1, f1: F1);
};
pub(crate) trait EncodeFieldsAsType {
fn encode_fields_to(
&self,
fields: &[Field<PortableForm>],
type_id: u32,
types: &PortableRegistry,
out: &mut Vec<u8>,
) -> Result<(), Error>;
}
macro_rules! impl_encode_composite_fields {
($($name:ident: $t:ident),*) => {
impl < $($t),* > EncodeFieldsAsType for Composite<( $((Option<&'static str>, $t),)* )> where $($t: EncodeAsType),* {
#[allow(unused_assignments)]
#[allow(unused_mut)]
#[allow(unused_variables)]
fn encode_fields_to(&self, fields: &[Field<PortableForm>], type_id: u32, types: &PortableRegistry, out: &mut Vec<u8>) -> Result<(), Error> {
let ($($name,)*) = &self.0;
const LEN: usize = count_idents!($($t,)*);
let is_named = {
let is_target_named = fields.iter().any(|f| f.name().is_some());
let mut is_source_named = false;
$(
if $name.0.is_some() { is_source_named = true }
)*
is_target_named && is_source_named
};
if is_named {
let source_fields_by_name = {
let mut s = HashMap::<&'static str, &dyn EncodeAsType>::new();
$(
s.insert($name.0.unwrap_or(""), &$name.1 as &dyn EncodeAsType);
)*
s
};
for field in fields {
let name = field.name().map(|n| &**n).unwrap_or("");
let Some(value) = source_fields_by_name.get(name) else {
return Err(Error::new(ErrorKind::CannotFindField { name: name.to_string() }))
};
value.encode_as_type_to(field.ty().id(), types, out)
.map_err(|e| e.at_field(name.to_string()))?;
}
Ok(())
} else {
if fields.len() != LEN {
return Err(Error::new(ErrorKind::WrongLength {
actual_len: LEN,
expected_len: fields.len(),
expected: type_id
}))
}
let mut idx = 0;
$({
let loc = if let Some(name) = $name.0 {
Location::field(name)
} else {
Location::idx(idx)
};
$name.1
.encode_as_type_to(fields[idx].ty().id(), types, out)
.map_err(|e| e.at(loc))?;
idx += 1;
})*
Ok(())
}
}
}
}
}
#[rustfmt::skip]
const _: () = {
impl_encode_composite_fields!();
impl_encode_composite_fields!(a: A);
impl_encode_composite_fields!(a: A, b: B);
impl_encode_composite_fields!(a: A, b: B, c: C);
impl_encode_composite_fields!(a: A, b: B, c: C, d: D);
impl_encode_composite_fields!(a: A, b: B, c: C, d: D, e: E);
impl_encode_composite_fields!(a: A, b: B, c: C, d: D, e: E, f: F);
impl_encode_composite_fields!(a: A, b: B, c: C, d: D, e: E, f: F, g: G);
impl_encode_composite_fields!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H);
impl_encode_composite_fields!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I);
impl_encode_composite_fields!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J);
impl_encode_composite_fields!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K);
impl_encode_composite_fields!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L);
impl_encode_composite_fields!(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);
impl_encode_composite_fields!(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);
impl_encode_composite_fields!(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);
impl_encode_composite_fields!(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);
impl_encode_composite_fields!(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);
impl_encode_composite_fields!(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);
impl_encode_composite_fields!(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);
impl_encode_composite_fields!(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, t: T);
impl_encode_composite_fields!(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, t: T, u: U);
impl_encode_composite_fields!(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, t: T, u: U, v: V);
impl_encode_composite_fields!(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, t: T, u: U, v: V, w: W);
impl_encode_composite_fields!(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, t: T, u: U, v: V, w: W, x: X);
impl_encode_composite_fields!(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, t: T, u: U, v: V, w: W, x: X, y: Y);
impl_encode_composite_fields!(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, t: T, u: U, v: V, w: W, x: X, y: Y, z: Z);
impl_encode_composite_fields!(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, t: T, u: U, v: V, w: W, x: X, y: Y, z: Z, a1: A1);
impl_encode_composite_fields!(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, t: T, u: U, v: V, w: W, x: X, y: Y, z: Z, a1: A1, b1: B1);
impl_encode_composite_fields!(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, t: T, u: U, v: V, w: W, x: X, y: Y, z: Z, a1: A1, b1: B1, c1: C1);
impl_encode_composite_fields!(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, t: T, u: U, v: V, w: W, x: X, y: Y, z: Z, a1: A1, b1: B1, c1: C1, d1: D1);
impl_encode_composite_fields!(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, t: T, u: U, v: V, w: W, x: X, y: Y, z: Z, a1: A1, b1: B1, c1: C1, d1: D1, e1: E1);
impl_encode_composite_fields!(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, t: T, u: U, v: V, w: W, x: X, y: Y, z: Z, a1: A1, b1: B1, c1: C1, d1: D1, e1: E1, f1: F1);
};