Files
pezkuwi-subxt/substrate/primitives/npos-elections/compact/src/codec.rs
T
Bastian Köcher e3e651f72c Happy new year (#7814)
* Happy new year

Updates the copyright years and fixes wrong license headers.

* Fix the template

* Split HEADER into HEADER-APACHE & HEADER-GPL
2021-01-04 09:03:13 +00:00

204 lines
4.9 KiB
Rust

// This file is part of Substrate.
// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Code generation for the ratio assignment type' encode/decode impl.
use crate::field_name_for;
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
pub(crate) fn codec_impl(
ident: syn::Ident,
voter_type: syn::Type,
target_type: syn::Type,
weight_type: syn::Type,
count: usize,
) -> TokenStream2 {
let encode = encode_impl(ident.clone(), count);
let decode = decode_impl(ident, voter_type, target_type, weight_type, count);
quote! {
#encode
#decode
}
}
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 = field_name_for(1);
quote! {
let #name =
<
Vec<(_npos::codec::Compact<#voter_type>, _npos::codec::Compact<#target_type>)>
as
_npos::codec::Decode
>::decode(value)?;
let #name = #name
.into_iter()
.map(|(v, t)| (v.0, t.0))
.collect::<Vec<_>>();
}
};
let decode_impl_double = {
let name = field_name_for(2);
quote! {
let #name =
<
Vec<(
_npos::codec::Compact<#voter_type>,
(_npos::codec::Compact<#target_type>, _npos::codec::Compact<#weight_type>),
_npos::codec::Compact<#target_type>,
)>
as
_npos::codec::Decode
>::decode(value)?;
let #name = #name
.into_iter()
.map(|(v, (t1, w), t2)| (v.0, (t1.0, w.0), t2.0))
.collect::<Vec<_>>();
}
};
let decode_impl_rest = (3..=count).map(|c| {
let name = field_name_for(c);
let inner_impl = (0..c-1).map(|i|
quote! { ( (inner[#i].0).0, (inner[#i].1).0 ), }
).collect::<TokenStream2>();
quote! {
let #name =
<
Vec<(
_npos::codec::Compact<#voter_type>,
[(_npos::codec::Compact<#target_type>, _npos::codec::Compact<#weight_type>); #c-1],
_npos::codec::Compact<#target_type>,
)>
as _npos::codec::Decode
>::decode(value)?;
let #name = #name
.into_iter()
.map(|(v, inner, t_last)| (
v.0,
[ #inner_impl ],
t_last.0,
))
.collect::<Vec<_>>();
}
}).collect::<TokenStream2>();
let all_field_names = (1..=count).map(|c| {
let name = field_name_for(c);
quote! { #name, }
}).collect::<TokenStream2>();
quote!(
impl _npos::codec::Decode for #ident {
fn decode<I: _npos::codec::Input>(value: &mut I) -> Result<Self, _npos::codec::Error> {
#decode_impl_single
#decode_impl_double
#decode_impl_rest
// The above code generates variables with the decoded value with the same name as
// filed names of the struct, i.e. `let votes4 = decode_value_of_votes4`. All we
// have to do is collect them into the main struct now.
Ok(#ident { #all_field_names })
}
}
)
}
// General attitude is that we will convert inner values to `Compact` and then use the normal
// `Encode` implementation.
fn encode_impl(ident: syn::Ident, count: usize) -> TokenStream2 {
let encode_impl_single = {
let name = field_name_for(1);
quote! {
let #name = self.#name
.iter()
.map(|(v, t)| (
_npos::codec::Compact(v.clone()),
_npos::codec::Compact(t.clone()),
))
.collect::<Vec<_>>();
#name.encode_to(&mut r);
}
};
let encode_impl_double = {
let name = field_name_for(2);
quote! {
let #name = self.#name
.iter()
.map(|(v, (t1, w), t2)| (
_npos::codec::Compact(v.clone()),
(
_npos::codec::Compact(t1.clone()),
_npos::codec::Compact(w.clone())
),
_npos::codec::Compact(t2.clone()),
))
.collect::<Vec<_>>();
#name.encode_to(&mut r);
}
};
let encode_impl_rest = (3..=count).map(|c| {
let name = field_name_for(c);
// we use the knowledge of the length to avoid copy_from_slice.
let inners_compact_array = (0..c-1).map(|i|
quote!{(
_npos::codec::Compact(inner[#i].0.clone()),
_npos::codec::Compact(inner[#i].1.clone()),
),}
).collect::<TokenStream2>();
quote! {
let #name = self.#name
.iter()
.map(|(v, inner, t_last)| (
_npos::codec::Compact(v.clone()),
[ #inners_compact_array ],
_npos::codec::Compact(t_last.clone()),
))
.collect::<Vec<_>>();
#name.encode_to(&mut r);
}
}).collect::<TokenStream2>();
quote!(
impl _npos::codec::Encode for #ident {
fn encode(&self) -> Vec<u8> {
let mut r = vec![];
#encode_impl_single
#encode_impl_double
#encode_impl_rest
r
}
}
)
}