use proc_macro2::*;
use syn::*;
use quote::*;
use syn::spanned::Spanned;
pub fn struct_helper(identifier: Ident, data_struct: DataStruct, is_padded: bool) -> proc_macro2::TokenStream {
let mut field_parses = TokenStream::default();
let mut return_variables = TokenStream::default();
let mut n = 0;
let whitespace_parse = match is_padded {
true => quote!{ let _ = Option::<Vec::<Whitespace>>::parse(position); },
false => quote!{}
};
field_parses.extend(whitespace_parse.clone());
for field in data_struct.fields.clone() {
let field_identifier = match data_struct.fields {
Fields::Named(..) => field.ident.clone().unwrap(),
Fields::Unnamed(..) => Ident::new( &format!("field_{}", n) ,Span::call_site()),
Fields::Unit => Ident::new( &n.to_string(),Span::call_site())
};
n += 1;
let field_type = field.ty.clone();
let field_maybe =
Ident::new(
&format!("{}_maybe", field_identifier),
proc_macro2::Span::call_site()
);
return_variables.extend(quote_spanned!{field.span()=>
#field_identifier,
}.to_token_stream());
field_parses.extend(quote_spanned!{field.span()=>
let #field_maybe = #field_type::parse(position);
if #field_maybe.is_err() {
let cause = Some(Box::new(#field_maybe.unwrap_err()));
let error = Error {
identifier: stringify!(#identifier).to_string(),
position: start_position,
cause
};
return Err(error);
}
let #field_identifier = #field_maybe.unwrap();
#whitespace_parse
}.to_token_stream());
}
let return_value = match data_struct.fields {
Fields::Named(..) => quote!{ Self { #return_variables } },
Fields::Unnamed(..) => quote!{ Self( #return_variables) },
Fields::Unit => quote!{ Self }
};
let quoted = quote_spanned! {identifier.span()=>
impl Parse for #identifier {
fn parse(position: &mut Position) -> Result<Self> {
let start_position = position.clone();
#field_parses
Ok(#return_value)
}
}
};
quoted
}