use crate::vote_field;
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
pub(crate) fn codec_and_info_impl(
ident: syn::Ident,
voter_type: syn::Type,
target_type: syn::Type,
weight_type: syn::Type,
count: usize,
) -> TokenStream2 {
let encode = encode_impl(&ident, count);
let decode = decode_impl(&ident, &voter_type, &target_type, &weight_type, count);
let scale_info = scale_info_impl(&ident, &voter_type, &target_type, &weight_type, count);
quote! {
impl _fepsp::codec::EncodeLike for #ident {}
#encode
#decode
#scale_info
}
}
fn decode_impl(
ident: &syn::Ident,
voter_type: &syn::Type,
target_type: &syn::Type,
weight_type: &syn::Type,
count: usize,
) -> TokenStream2 {
let decode_impl_single = {
let name = vote_field(1);
quote! {
let #name =
<
_fepsp::Vec<(_fepsp::codec::Compact<#voter_type>, _fepsp::codec::Compact<#target_type>)>
as
_fepsp::codec::Decode
>::decode(value)?;
let #name = #name
.into_iter()
.map(|(v, t)| (v.0, t.0))
.collect::<_fepsp::Vec<_>>();
}
};
let decode_impl_rest = (2..=count)
.map(|c| {
let name = vote_field(c);
let inner_impl = (0..c - 1)
.map(|i| quote! { ( (inner[#i].0).0, (inner[#i].1).0 ), })
.collect::<TokenStream2>();
quote! {
let #name =
<
_fepsp::Vec<(
_fepsp::codec::Compact<#voter_type>,
[(_fepsp::codec::Compact<#target_type>, _fepsp::codec::Compact<#weight_type>); #c-1],
_fepsp::codec::Compact<#target_type>,
)>
as _fepsp::codec::Decode
>::decode(value)?;
let #name = #name
.into_iter()
.map(|(v, inner, t_last)| (
v.0,
[ #inner_impl ],
t_last.0,
))
.collect::<_fepsp::Vec<_>>();
}
})
.collect::<TokenStream2>();
let all_field_names = (1..=count)
.map(|c| {
let name = vote_field(c);
quote! { #name, }
})
.collect::<TokenStream2>();
quote!(
impl _fepsp::codec::Decode for #ident {
fn decode<I: _fepsp::codec::Input>(value: &mut I) -> Result<Self, _fepsp::codec::Error> {
#decode_impl_single
#decode_impl_rest
Ok(#ident { #all_field_names })
}
}
)
}
fn encode_impl(ident: &syn::Ident, count: usize) -> TokenStream2 {
let encode_impl_single = {
let name = vote_field(1);
quote! {
let #name = self.#name
.iter()
.map(|(v, t)| (
_fepsp::codec::Compact(v.clone()),
_fepsp::codec::Compact(t.clone()),
))
.collect::<_fepsp::Vec<_>>();
#name.encode_to(&mut r);
}
};
let encode_impl_rest = (2..=count)
.map(|c| {
let name = vote_field(c);
let inners_solution_array = (0..c - 1)
.map(|i| {
quote! {(
_fepsp::codec::Compact(inner[#i].0.clone()),
_fepsp::codec::Compact(inner[#i].1.clone()),
),}
})
.collect::<TokenStream2>();
quote! {
let #name = self.#name
.iter()
.map(|(v, inner, t_last)| (
_fepsp::codec::Compact(v.clone()),
[ #inners_solution_array ],
_fepsp::codec::Compact(t_last.clone()),
))
.collect::<_fepsp::Vec<_>>();
#name.encode_to(&mut r);
}
})
.collect::<TokenStream2>();
quote!(
impl _fepsp::codec::Encode for #ident {
fn encode(&self) -> _fepsp::Vec<u8> {
let mut r = vec![];
#encode_impl_single
#encode_impl_rest
r
}
}
)
}
fn scale_info_impl(
ident: &syn::Ident,
voter_type: &syn::Type,
target_type: &syn::Type,
weight_type: &syn::Type,
count: usize,
) -> TokenStream2 {
let scale_info_impl_single = {
let name = format!("{}", vote_field(1));
quote! {
.field(|f|
f.ty::<_fepsp::Vec<
(_fepsp::codec::Compact<#voter_type>, _fepsp::codec::Compact<#target_type>)
>>()
.name(#name)
)
}
};
let scale_info_impl_double = {
let name = format!("{}", vote_field(2));
quote! {
.field(|f|
f.ty::<_fepsp::Vec<(
_fepsp::codec::Compact<#voter_type>,
(_fepsp::codec::Compact<#target_type>, _fepsp::codec::Compact<#weight_type>),
_fepsp::codec::Compact<#target_type>
)>>()
.name(#name)
)
}
};
let scale_info_impl_rest = (3..=count)
.map(|c| {
let name = format!("{}", vote_field(c));
quote! {
.field(|f|
f.ty::<_fepsp::Vec<(
_fepsp::codec::Compact<#voter_type>,
[
(_fepsp::codec::Compact<#target_type>, _fepsp::codec::Compact<#weight_type>);
#c - 1
],
_fepsp::codec::Compact<#target_type>
)>>()
.name(#name)
)
}
})
.collect::<TokenStream2>();
quote!(
impl _fepsp::scale_info::TypeInfo for #ident {
type Identity = Self;
fn type_info() -> _fepsp::scale_info::Type<_fepsp::scale_info::form::MetaForm> {
_fepsp::scale_info::Type::builder()
.path(_fepsp::scale_info::Path::new(stringify!(#ident), module_path!()))
.composite(
_fepsp::scale_info::build::Fields::named()
#scale_info_impl_single
#scale_info_impl_double
#scale_info_impl_rest
)
}
}
)
}