Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Prev Previous commit
Next Next commit
Get rid of some repetition.
  • Loading branch information
tomusdrw committed Aug 7, 2018
commit ac85a7fbd1e909332fcb9c0b9cac63b8a607a251
120 changes: 52 additions & 68 deletions substrate/codec/derive/src/decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,42 +20,19 @@ use syn::{
spanned::Spanned,
};

pub fn quote(data: &Data, type_name: &Ident, input_: &TokenStream) -> TokenStream {
pub fn quote(data: &Data, type_name: &Ident, input: &TokenStream) -> TokenStream {
let call_site = Span::call_site();
match *data {
Data::Struct(ref data) => match data.fields {
Fields::Named(ref fields) => {
let recurse = fields.named.iter().map(|f| {
let name = &f.ident;
let field = quote_spanned!(call_site => #name);

quote_spanned! { f.span() =>
#field: ::codec::Decode::decode(#input_)?
}
});

quote_spanned! {call_site =>
Some(Self {
#( #recurse, )*
})
}
},
Fields::Unnamed(ref fields) => {
let recurse = fields.unnamed.iter().map(|f| {
quote_spanned! { f.span() =>
::codec::Decode::decode(#input_)?
}
});

quote_spanned! {call_site =>
Some(#type_name (
#( #recurse, )*
))
}
},
Fields::Named(_) | Fields::Unnamed(_) => create_instance(
call_site,
quote! { #type_name },
input,
&data.fields,
),
Fields::Unit => {
quote_spanned! {call_site =>
drop(#input_);
drop(#input);
Some(#type_name)
}
},
Expand All @@ -70,42 +47,12 @@ pub fn quote(data: &Data, type_name: &Ident, input_: &TokenStream) -> TokenStrea
.map(|&(_, ref expr)| quote! { #expr })
.unwrap_or_else(|| quote! { #i });

let create = match v.fields {
Fields::Named(ref fields) => {
let recurse = fields.named.iter().map(|f| {
let name = &f.ident;
let field = quote_spanned!(call_site => #name);

quote_spanned! { f.span() =>
#field: ::codec::Decode::decode(#input_)?
}
});

quote_spanned! {call_site =>
Some(#type_name :: #name {
#( #recurse, )*
})
}
},
Fields::Unnamed(ref fields) => {
let recurse = fields.unnamed.iter().map(|f| {
quote_spanned! { f.span() =>
::codec::Decode::decode(#input_)?
}
});

quote_spanned! {call_site =>
Some(#type_name :: #name (
#( #recurse, )*
))
}
},
Fields::Unit => {
quote_spanned! {call_site =>
Some(#type_name :: #name)
}
},
};
let create = create_instance(
call_site,
quote! { #type_name :: #name },
input,
&v.fields,
);

quote_spanned! { v.span() =>
x if x == #index as u8 => {
Expand All @@ -115,7 +62,7 @@ pub fn quote(data: &Data, type_name: &Ident, input_: &TokenStream) -> TokenStrea
});

quote! {
match #input_.read_byte()? {
match #input.read_byte()? {
#( #recurse )*
_ => None,
}
Expand All @@ -128,4 +75,41 @@ pub fn quote(data: &Data, type_name: &Ident, input_: &TokenStream) -> TokenStrea
}
}

fn create_instance(call_site: Span, name: TokenStream, input: &TokenStream, fields: &Fields) -> TokenStream {
match *fields {
Fields::Named(ref fields) => {
let recurse = fields.named.iter().map(|f| {
let name = &f.ident;
let field = quote_spanned!(call_site => #name);

quote_spanned! { f.span() =>
#field: ::codec::Decode::decode(#input)?
}
});

quote_spanned! {call_site =>
Some(#name {
#( #recurse, )*
})
}
},
Fields::Unnamed(ref fields) => {
let recurse = fields.unnamed.iter().map(|f| {
quote_spanned! { f.span() =>
::codec::Decode::decode(#input)?
}
});

quote_spanned! {call_site =>
Some(#name (
#( #recurse, )*
))
}
},
Fields::Unit => {
quote_spanned! {call_site =>
Some(#name)
}
},
}
}
124 changes: 70 additions & 54 deletions substrate/codec/derive/src/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,44 +16,53 @@

use proc_macro2::{Span, TokenStream};
use syn::{
Data, Fields, Ident, Index,
Data, Field, Fields, Ident, Index,
punctuated::Punctuated,
spanned::Spanned,
token::Comma,
};

pub fn quote(data: &Data, type_name: &Ident, self_: &TokenStream, dest_: &TokenStream) -> TokenStream {
type FieldsList = Punctuated<Field, Comma>;

fn encode_fields<F>(
dest: &TokenStream,
fields: &FieldsList,
field_name: F,
) -> TokenStream where
F: Fn(usize, &Option<Ident>) -> TokenStream,
{
let recurse = fields.iter().enumerate().map(|(i, f)| {
let field = field_name(i, &f.ident);

quote_spanned! { f.span() =>
#dest.push(#field);
}
});

quote! {
#( #recurse )*
}
}

pub fn quote(data: &Data, type_name: &Ident, self_: &TokenStream, dest: &TokenStream) -> TokenStream {
let call_site = Span::call_site();
match *data {
Data::Struct(ref data) => match data.fields {
Fields::Named(ref fields) => {
let recurse = fields.named.iter().map(|f| {
let name = &f.ident;
let field = quote_spanned!(call_site => #self_.#name);

quote_spanned! { f.span() =>
#dest_.push(&#field);
}
});

quote_spanned! { call_site =>
#( #recurse )*
}
},
Fields::Unnamed(ref fields) => {
let recurse = fields.unnamed.iter().enumerate().map(|(i, f)| {
Fields::Named(ref fields) => encode_fields(
dest,
&fields.named,
|_, name| quote_spanned!(call_site => &#self_.#name),
),
Fields::Unnamed(ref fields) => encode_fields(
dest,
&fields.unnamed,
|i, _| {
let index = Index { index: i as u32, span: call_site };
let field = quote_spanned!(call_site => #self_.#index);
quote_spanned! { f.span() =>
#dest_.push(&#field);
}
});

quote! {
#( #recurse )*
}
},
// Do nothing, we don't encode unit type and assume it's always decodable.
Fields::Unit => quote! {
drop(#dest_);
quote_spanned!(call_site => &#self_.#index)
},
),
Fields::Unit => quote_spanned! { call_site =>
drop(#dest);
},
},
Data::Enum(ref data) => {
Expand All @@ -68,45 +77,52 @@ pub fn quote(data: &Data, type_name: &Ident, self_: &TokenStream, dest_: &TokenS

match f.fields {
Fields::Named(ref fields) => {
let names = fields.named.iter().map(|f| {
let field_name = &f.ident;
quote_spanned!(call_site => #field_name)
}).collect::<Vec<_>>();

let fields = names.iter();
let encode_fields = names.iter().map(|f| {
quote_spanned! { call_site => #dest_.push(#f); }
});
let field_name = |_, ident: &Option<Ident>| quote_spanned!(call_site => #ident);
let names = fields.named
.iter()
.enumerate()
.map(|(i, f)| field_name(i, &f.ident));

let encode_fields = encode_fields(
dest,
&fields.named,
|a, b| field_name(a, b),
);

quote_spanned! { f.span() =>
#type_name :: #name { #( ref #fields, )* } => {
#dest_.push_byte(#index as u8);
#( #encode_fields )*
#type_name :: #name { #( ref #names, )* } => {
#dest.push_byte(#index as u8);
#encode_fields
}
}
},
Fields::Unnamed(ref fields) => {
let names = fields.unnamed.iter().enumerate().map(|(i, _f)| {
let field_name = |i, _: &Option<Ident>| {
let ident = Ident::new(&format!("f_{}", i), call_site);
quote_spanned!(call_site => #ident)
}).collect::<Vec<_>>();

let fields = names.iter();
let encode_fields = names.iter().map(|f| {
quote_spanned! { call_site => #dest_.push(#f); }
});
};
let names = fields.unnamed
.iter()
.enumerate()
.map(|(i, f)| field_name(i, &f.ident));

let encode_fields = encode_fields(
dest,
&fields.unnamed,
|a, b| field_name(a, b),
);

quote_spanned! { f.span() =>
#type_name :: #name ( #( ref #fields, )* ) => {
#dest_.push_byte(#index as u8);
#( #encode_fields )*
#type_name :: #name ( #( ref #names, )* ) => {
#dest.push_byte(#index as u8);
#encode_fields
}
}
},
Fields::Unit => {
quote_spanned! { f.span() =>
#type_name :: #name => {
#dest_.push_byte(#index as u8);
#dest.push_byte(#index as u8);
}
}
},
Expand Down
12 changes: 6 additions & 6 deletions substrate/codec/derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,10 @@ pub fn decode_derive(input: TokenStream) -> TokenStream {
}

fn add_trait_bounds(mut generics: Generics, bounds: syn::TypeParamBound) -> Generics {
for param in &mut generics.params {
if let GenericParam::Type(ref mut type_param) = *param {
type_param.bounds.push(bounds.clone());
}
}
generics
for param in &mut generics.params {
if let GenericParam::Type(ref mut type_param) = *param {
type_param.bounds.push(bounds.clone());
}
}
generics
}