Update SSZ derive macro, create failing test

This commit is contained in:
Paul Hauner 2019-05-05 12:11:25 +10:00
parent b5d9157722
commit c5f00d1666
No known key found for this signature in database
GPG Key ID: 303E4494BB28068C
2 changed files with 94 additions and 52 deletions

View File

@ -1,5 +1,5 @@
use ssz::{Decodable, Encodable};
use ssz_derive::Encode;
use ssz_derive::{Decode, Encode};
fn round_trip<T: Encodable + Decodable + std::fmt::Debug + PartialEq>(items: Vec<T>) {
for item in items {
@ -40,7 +40,7 @@ fn vec_of_vec_u16_round_trip() {
round_trip(items);
}
#[derive(Debug, PartialEq, Encode)]
#[derive(Debug, PartialEq, Encode, Decode)]
struct FixedLen {
a: u16,
b: u64,
@ -72,7 +72,18 @@ fn fixed_len_struct_encoding() {
}
}
#[derive(Debug, PartialEq, Encode)]
#[test]
fn vec_of_fixed_len_struct() {
let items: Vec<FixedLen> = vec![
FixedLen { a: 0, b: 0, c: 0 },
FixedLen { a: 1, b: 1, c: 1 },
FixedLen { a: 1, b: 0, c: 1 },
];
round_trip(items);
}
#[derive(Debug, PartialEq, Encode, Decode)]
struct VariableLen {
a: u16,
b: Vec<u16>,
@ -119,15 +130,30 @@ fn variable_len_struct_encoding() {
}
}
/*
#[test]
fn vec_of_fixed_len_struct() {
let items: Vec<FixedLen> = vec![
FixedLen { a: 0, b: 0, c: 0 },
FixedLen { a: 1, b: 1, c: 1 },
FixedLen { a: 1, b: 0, c: 1 },
fn vec_of_variable_len_struct() {
let items: Vec<VariableLen> = vec![
VariableLen {
a: 0,
b: vec![],
c: 0,
},
VariableLen {
a: 255,
b: vec![0, 1, 2, 3],
c: 99,
},
VariableLen {
a: 255,
b: vec![0],
c: 99,
},
VariableLen {
a: 50,
b: vec![0],
c: 0,
},
];
round_trip(items);
}
*/

View File

@ -1,26 +1,11 @@
#![recursion_limit="128"]
extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput};
/*
/// Returns a Vec of `syn::Ident` for each named field in the struct.
///
/// # Panics
/// Any unnamed struct field (like in a tuple struct) will raise a panic at compile time.
fn get_named_field_idents<'a>(struct_data: &'a syn::DataStruct) -> Vec<&'a syn::Ident> {
struct_data
.fields
.iter()
.map(|f| match &f.ident {
Some(ref ident) => ident,
_ => panic!("ssz_derive only supports named struct fields."),
})
.collect()
}
*/
/// Returns a Vec of `syn::Ident` for each named field in the struct, whilst filtering out fields
/// that should not be serialized.
///
@ -45,12 +30,9 @@ fn get_serializable_named_field_idents<'a>(
.collect()
}
/// Returns a Vec of `syn::Ident` for each named field in the struct, whilst filtering out fields
/// Returns a Vec of `syn::Type` for each named field in the struct, whilst filtering out fields
/// that should not be serialized.
///
/// # Panics
/// Any unnamed struct field (like in a tuple struct) will raise a panic at compile time.
fn get_serializable_named_field_types<'a>(struct_data: &'a syn::DataStruct) -> Vec<&'a syn::Type> {
fn get_serializable_field_types<'a>(struct_data: &'a syn::DataStruct) -> Vec<&'a syn::Type> {
struct_data
.fields
.iter()
@ -97,7 +79,7 @@ pub fn ssz_encode_derive(input: TokenStream) -> TokenStream {
};
let field_idents = get_serializable_named_field_idents(&struct_data);
let field_types_a = get_serializable_named_field_types(&struct_data);
let field_types_a = get_serializable_field_types(&struct_data);
let field_types_b = field_types_a.clone();
let output = quote! {
@ -110,7 +92,7 @@ pub fn ssz_encode_derive(input: TokenStream) -> TokenStream {
}
fn ssz_fixed_len() -> usize {
if Self::is_ssz_fixed_len() {
if <Self as Encodable>::is_ssz_fixed_len() {
#(
<#field_types_b as ssz::Encodable>::ssz_fixed_len() +
)*
@ -134,7 +116,6 @@ pub fn ssz_encode_derive(input: TokenStream) -> TokenStream {
output.into()
}
/*
/// Returns true if some field has an attribute declaring it should not be deserialized.
///
/// The field attribute is: `#[ssz(skip_deserializing)]`
@ -161,21 +142,38 @@ pub fn ssz_decode_derive(input: TokenStream) -> TokenStream {
_ => panic!("ssz_derive only supports structs."),
};
let all_idents = get_named_field_idents(&struct_data);
let mut register_types = vec![];
let mut decodes = vec![];
let mut is_fixed_lens = vec![];
let mut fixed_lens = vec![];
// Build quotes for fields that should be deserialized and those that should be built from
// `Default`.
let mut quotes = vec![];
for field in &struct_data.fields {
match &field.ident {
Some(ref ident) => {
if should_skip_deserializing(field) {
quotes.push(quote! {
let #ident = <_>::default();
// Field should not be deserialized; use a `Default` impl to instantiate.
decodes.push(quote! {
#ident: <_>::default(),
});
} else {
quotes.push(quote! {
let (#ident, i) = <_>::ssz_decode(bytes, i)?;
let ty = &field.ty;
register_types.push(quote! {
builder.register_type::<#ty>()?;
});
decodes.push(quote! {
#ident: decoder.decode_next()?
});
is_fixed_lens.push(quote! {
<#ty as ssz::Decodable>::is_ssz_fixed_len()
});
fixed_lens.push(quote! {
<#ty as ssz::Decodable>::ssz_fixed_len()
});
}
}
@ -185,22 +183,40 @@ pub fn ssz_decode_derive(input: TokenStream) -> TokenStream {
let output = quote! {
impl ssz::Decodable for #name {
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), ssz::DecodeError> {
fn is_ssz_fixed_len() -> bool {
#(
#quotes
#is_fixed_lens &&
)*
true
}
fn ssz_fixed_len() -> usize {
if <Self as ssz::Decodable>::is_ssz_fixed_len() {
#(
#fixed_lens +
)*
0
} else {
ssz::BYTES_PER_LENGTH_OFFSET
}
}
fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, ssz::DecodeError> {
let mut builder = ssz::SszDecoderBuilder::new(bytes);
#(
#register_types
)*
Ok((
Self {
#(
#all_idents,
)*
},
i
))
let mut decoder = builder.build()?;
Ok(Self {
#(
#decodes,
)*
})
}
}
};
output.into()
}
*/