add better errors
This commit is contained in:
parent
04c7898aa2
commit
4b1cc379a4
1 changed files with 80 additions and 40 deletions
|
|
@ -3,8 +3,8 @@ use quote::{format_ident, quote, quote_spanned};
|
|||
use syn::parse::{Parse, ParseStream};
|
||||
use syn::spanned::Spanned;
|
||||
use syn::{
|
||||
Attribute, Data, DeriveInput, Field, Fields, Ident, Index, Meta, MetaList, Token, Type,
|
||||
Variant, parse_macro_input,
|
||||
parse_macro_input, Attribute, Data, DeriveInput, Field, Fields, Ident, Index, Meta, MetaList,
|
||||
Token, Type, Variant,
|
||||
};
|
||||
|
||||
/// Derive the type Serializable.
|
||||
|
|
@ -124,9 +124,9 @@ pub fn derive_serializable(input: proc_macro::TokenStream) -> proc_macro::TokenS
|
|||
let input = parse_macro_input!(input as DeriveInput);
|
||||
let name = input.ident;
|
||||
let params = ParamsStruct::parse(&input.attrs);
|
||||
let implem_serialize = get_implem_serialize(&input.data, ¶ms);
|
||||
let implem_deserialize = get_implem_deserialize(&input.data, ¶ms);
|
||||
let implem_size = get_implem_size(&input.data, ¶ms);
|
||||
let implem_serialize = get_implem_serialize(&input.data, ¶ms, &name);
|
||||
let implem_deserialize = get_implem_deserialize(&input.data, ¶ms, &name);
|
||||
let implem_size = get_implem_size(&input.data, ¶ms, &name);
|
||||
let expanded = quote! {
|
||||
impl androscalpel_serializer::Serializable for #name {
|
||||
#[allow(clippy::single_element_loop, clippy::let_and_return)]
|
||||
|
|
@ -316,7 +316,11 @@ fn get_enum_match(variant: &Variant) -> TokenStream {
|
|||
|
||||
/// Return the implementation of the computation of [`androscalpel_serializer::Serializable::size`]
|
||||
/// for a specific field `f` accessible using `field_ref`.
|
||||
fn get_implem_size_for_field(f: &Field, field_ref: TokenStream) -> TokenStream {
|
||||
fn get_implem_size_for_field(
|
||||
f: &Field,
|
||||
field_ref: TokenStream,
|
||||
_struct_name: &Ident,
|
||||
) -> TokenStream {
|
||||
let params = ParamsField::parse(&f.attrs);
|
||||
let prefix_stream = match params.prefix {
|
||||
Some(PrefixParamsField(ref stream)) => {
|
||||
|
|
@ -359,13 +363,13 @@ fn get_implem_size_for_field(f: &Field, field_ref: TokenStream) -> TokenStream {
|
|||
}
|
||||
|
||||
/// Return the implementation of the [`androscalpel_serializer::Serializable::size`].
|
||||
fn get_implem_size(data: &Data, params: &ParamsStruct) -> TokenStream {
|
||||
fn get_implem_size(data: &Data, params: &ParamsStruct, struct_name: &Ident) -> TokenStream {
|
||||
match *data {
|
||||
Data::Struct(ref data) => match data.fields {
|
||||
Fields::Named(ref fields) => {
|
||||
let recurse = fields.named.iter().map(|f| {
|
||||
let name = &f.ident;
|
||||
get_implem_size_for_field(f, quote! { self.#name })
|
||||
get_implem_size_for_field(f, quote! { self.#name }, struct_name)
|
||||
});
|
||||
quote! {
|
||||
0 #(+ #recurse)*
|
||||
|
|
@ -374,7 +378,7 @@ fn get_implem_size(data: &Data, params: &ParamsStruct) -> TokenStream {
|
|||
Fields::Unnamed(ref fields) => {
|
||||
let recurse = fields.unnamed.iter().enumerate().map(|(i, f)| {
|
||||
let index = Index::from(i);
|
||||
get_implem_size_for_field(f, quote! { self.#index })
|
||||
get_implem_size_for_field(f, quote! { self.#index }, struct_name)
|
||||
});
|
||||
quote! {
|
||||
0 #(+ #recurse)*
|
||||
|
|
@ -404,7 +408,7 @@ fn get_implem_size(data: &Data, params: &ParamsStruct) -> TokenStream {
|
|||
Fields::Named(ref fields) => {
|
||||
let recurse = fields.named.iter().map(|f| {
|
||||
let name = &f.ident;
|
||||
get_implem_size_for_field(f, quote! { *#name })
|
||||
get_implem_size_for_field(f, quote! { *#name }, struct_name)
|
||||
});
|
||||
quote_spanned! { v.span() =>
|
||||
//<#prefix_ty as androscalpel_serializer::Serializable>::size(&#val) #(+#recurse )*
|
||||
|
|
@ -414,7 +418,7 @@ fn get_implem_size(data: &Data, params: &ParamsStruct) -> TokenStream {
|
|||
Fields::Unnamed(ref fields) => {
|
||||
let recurse = fields.unnamed.iter().enumerate().map(|(i, f)| {
|
||||
let ident = format_ident!("field{}", i);
|
||||
get_implem_size_for_field(f, quote! { *#ident })
|
||||
get_implem_size_for_field(f, quote! { *#ident }, struct_name)
|
||||
});
|
||||
quote_spanned! { v.span() =>
|
||||
//<#prefix_ty as androscalpel_serializer::Serializable>::size(&#val) #(+#recurse )*
|
||||
|
|
@ -439,14 +443,22 @@ fn get_implem_size(data: &Data, params: &ParamsStruct) -> TokenStream {
|
|||
|
||||
/// Return the implementation of the computation of [`androscalpel_serializer::Serializable::serialize`]
|
||||
/// for a specific field `f` accessible using `field_ref`.
|
||||
fn get_implem_serialize_for_field(f: &Field, field_ref: TokenStream) -> TokenStream {
|
||||
fn get_implem_serialize_for_field(
|
||||
f: &Field,
|
||||
field_ref: TokenStream,
|
||||
struct_name: &Ident,
|
||||
) -> TokenStream {
|
||||
let params = ParamsField::parse(&f.attrs);
|
||||
// TODO: Improve error handling
|
||||
let ident = &f.ident;
|
||||
let prefix_stream = match params.prefix {
|
||||
Some(PrefixParamsField(ref stream)) => {
|
||||
quote_spanned! { f.span() =>
|
||||
for byte in #stream {
|
||||
<u8 as androscalpel_serializer::Serializable>::serialize(&byte, output)?;
|
||||
<u8 as androscalpel_serializer::Serializable>::serialize(&byte, output).map_err(
|
||||
|err| androscalpel_serializer::Error::SerializationError(
|
||||
format!("Failed to serialize '{}.{}' prefix due to: {}", stringify!(#struct_name), stringify!(#ident), err)
|
||||
)
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -458,7 +470,11 @@ fn get_implem_serialize_for_field(f: &Field, field_ref: TokenStream) -> TokenStr
|
|||
Some(SuffixParamsField(ref stream)) => {
|
||||
quote_spanned! { f.span() =>
|
||||
for byte in #stream {
|
||||
<u8 as androscalpel_serializer::Serializable>::serialize(&byte, output)?;
|
||||
<u8 as androscalpel_serializer::Serializable>::serialize(&byte, output).map_err(
|
||||
|err| androscalpel_serializer::Error::SerializationError(
|
||||
format!("Failed to serialize '{}.{}' suffix due to: {}", stringify!(#struct_name), stringify!(#ident), err)
|
||||
)
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -474,15 +490,27 @@ fn get_implem_serialize_for_field(f: &Field, field_ref: TokenStream) -> TokenStr
|
|||
..
|
||||
},
|
||||
) => quote_spanned! { f.span() =>
|
||||
androscalpel_serializer::SerializableUntil::<#d, #u>::serialize(&#field_ref, output, #until)?;
|
||||
androscalpel_serializer::SerializableUntil::<#d, #u>::serialize(&#field_ref, output, #until).map_err(
|
||||
|err| androscalpel_serializer::Error::SerializationError(
|
||||
format!("Failed to serialize '{}.{}' due to: {}", stringify!(#struct_name), stringify!(#ident), err)
|
||||
)
|
||||
)?;
|
||||
},
|
||||
(Type::Array(_), ParamsField { until: None, .. }) => quote_spanned! { f.span() =>
|
||||
for x in #field_ref {
|
||||
androscalpel_serializer::Serializable::serialize(&x, output)?;
|
||||
androscalpel_serializer::Serializable::serialize(&x, output).map_err(
|
||||
|err| androscalpel_serializer::Error::SerializationError(
|
||||
format!("Failed to serialize '{}.{}' due to: {}", stringify!(#struct_name), stringify!(#ident), err)
|
||||
)
|
||||
)?;
|
||||
}
|
||||
},
|
||||
(_, ParamsField { until: None, .. }) => quote_spanned! { f.span() =>
|
||||
androscalpel_serializer::Serializable::serialize(&#field_ref, output)?;
|
||||
androscalpel_serializer::Serializable::serialize(&#field_ref, output).map_err(
|
||||
|err| androscalpel_serializer::Error::SerializationError(
|
||||
format!("Failed to serialize '{}.{}' due to: {}", stringify!(#struct_name), stringify!(#ident), err)
|
||||
)
|
||||
)?;
|
||||
},
|
||||
};
|
||||
quote_spanned! { f.span() =>
|
||||
|
|
@ -492,13 +520,13 @@ fn get_implem_serialize_for_field(f: &Field, field_ref: TokenStream) -> TokenStr
|
|||
}
|
||||
}
|
||||
/// Return the implementation of the [`androscalpel_serializer::Serializable::serialize`].
|
||||
fn get_implem_serialize(data: &Data, params: &ParamsStruct) -> TokenStream {
|
||||
fn get_implem_serialize(data: &Data, params: &ParamsStruct, struct_name: &Ident) -> TokenStream {
|
||||
match *data {
|
||||
Data::Struct(ref data) => match data.fields {
|
||||
Fields::Named(ref fields) => {
|
||||
let recurse = fields.named.iter().map(|f| {
|
||||
let name = &f.ident;
|
||||
get_implem_serialize_for_field(f, quote! { self.#name })
|
||||
get_implem_serialize_for_field(f, quote! { self.#name }, struct_name)
|
||||
});
|
||||
quote! {
|
||||
#(#recurse)*
|
||||
|
|
@ -508,7 +536,7 @@ fn get_implem_serialize(data: &Data, params: &ParamsStruct) -> TokenStream {
|
|||
Fields::Unnamed(ref fields) => {
|
||||
let recurse = fields.unnamed.iter().enumerate().map(|(i, f)| {
|
||||
let index = Index::from(i);
|
||||
get_implem_serialize_for_field(f, quote! { self.#index })
|
||||
get_implem_serialize_for_field(f, quote! { self.#index }, struct_name)
|
||||
});
|
||||
quote! {
|
||||
#(#recurse)*
|
||||
|
|
@ -552,7 +580,7 @@ fn get_implem_serialize(data: &Data, params: &ParamsStruct) -> TokenStream {
|
|||
}
|
||||
let recurse = fields.named.iter().map(|f| {
|
||||
let name = &f.ident;
|
||||
get_implem_serialize_for_field(f, quote! { *#name })
|
||||
get_implem_serialize_for_field(f, quote! { *#name }, struct_name)
|
||||
});
|
||||
quote_spanned! { v.span() =>
|
||||
//<#prefix_ty as androscalpel_serializer::Serializable>::serialize(&#val, output)?;
|
||||
|
|
@ -563,7 +591,7 @@ fn get_implem_serialize(data: &Data, params: &ParamsStruct) -> TokenStream {
|
|||
Fields::Unnamed(ref fields) => {
|
||||
let recurse = fields.unnamed.iter().enumerate().map(|(i, f)| {
|
||||
let ident = format_ident!("field{}", i);
|
||||
get_implem_serialize_for_field(f, quote! { *#ident })
|
||||
get_implem_serialize_for_field(f, quote! { *#ident }, struct_name)
|
||||
});
|
||||
quote_spanned! { v.span() =>
|
||||
//<#prefix_ty as androscalpel_serializer::Serializable>::serialize(&#val, output)?;
|
||||
|
|
@ -594,17 +622,21 @@ fn get_implem_serialize(data: &Data, params: &ParamsStruct) -> TokenStream {
|
|||
|
||||
/// Return the implementation of the computation of [`androscalpel_serializer::Serializable::deserialize`]
|
||||
/// for a specific field `f` accessible using `field_ref`.
|
||||
fn get_implem_deserialize_for_field(f: &Field, field_ref: TokenStream) -> TokenStream {
|
||||
fn get_implem_deserialize_for_field(
|
||||
f: &Field,
|
||||
field_ref: TokenStream,
|
||||
struct_name: &Ident,
|
||||
) -> TokenStream {
|
||||
let params = ParamsField::parse(&f.attrs);
|
||||
let ty = &f.ty;
|
||||
// TODO: Improve error handling
|
||||
let ident = &f.ident;
|
||||
let prefix_stream = match params.prefix {
|
||||
Some(PrefixParamsField(ref stream)) => {
|
||||
quote_spanned! { f.span() =>
|
||||
for byte in #stream {
|
||||
if <u8 as androscalpel_serializer::Serializable>::deserialize(input)? != byte {
|
||||
return Err(androscalpel_serializer::Error::DeserializationError(
|
||||
"Prefix do not match #stream".into()
|
||||
format!("Prefix for '{}.{}' do not match {}", stringify!(#struct_name), stringify!(#ident), stringify!(#stream))
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
@ -620,7 +652,7 @@ fn get_implem_deserialize_for_field(f: &Field, field_ref: TokenStream) -> TokenS
|
|||
for byte in #stream {
|
||||
if <u8 as androscalpel_serializer::Serializable>::deserialize(input)? != byte {
|
||||
return Err(androscalpel_serializer::Error::DeserializationError(
|
||||
"Suffix do not match #stream".into()
|
||||
format!("Suffix for '{}.{}' do not match {}", stringify!(#struct_name), stringify!(#ident), stringify!(stream))
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
@ -640,7 +672,11 @@ fn get_implem_deserialize_for_field(f: &Field, field_ref: TokenStream) -> TokenS
|
|||
) => quote_spanned! { f.span() =>
|
||||
#field_ref {
|
||||
#prefix_stream
|
||||
let val = <#ty as androscalpel_serializer::SerializableUntil::<#d, #u>>::deserialize(input, #until)?;
|
||||
let val = <#ty as androscalpel_serializer::SerializableUntil::<#d, #u>>::deserialize(input, #until).map_err(
|
||||
|err| androscalpel_serializer::Error::DeserializationError(
|
||||
format!("Failed to deserialize '{}.{}' due to: {}", stringify!(#struct_name), stringify!(#ident), err)
|
||||
)
|
||||
)?;
|
||||
#suffix_stream
|
||||
val
|
||||
},
|
||||
|
|
@ -653,7 +689,13 @@ fn get_implem_deserialize_for_field(f: &Field, field_ref: TokenStream) -> TokenS
|
|||
#prefix_stream
|
||||
let mut vec_ = vec![];
|
||||
for _ in 0..(#len) {
|
||||
vec_.push(<#arr_ty as androscalpel_serializer::Serializable>::deserialize(input)?);
|
||||
vec_.push(
|
||||
<#arr_ty as androscalpel_serializer::Serializable>::deserialize(input).map_err(
|
||||
|err| androscalpel_serializer::Error::DeserializationError(
|
||||
format!("Failed to deserialize '{}.{}' due to: {}", stringify!(#struct_name), stringify!(#ident), err)
|
||||
)
|
||||
)?
|
||||
);
|
||||
}
|
||||
#suffix_stream
|
||||
vec_.try_into().unwrap()
|
||||
|
|
@ -672,13 +714,13 @@ fn get_implem_deserialize_for_field(f: &Field, field_ref: TokenStream) -> TokenS
|
|||
}
|
||||
|
||||
/// Return the implementation of the [`androscalpel_serializer::Serializable::deserialize`].
|
||||
fn get_implem_deserialize(data: &Data, params: &ParamsStruct) -> TokenStream {
|
||||
fn get_implem_deserialize(data: &Data, params: &ParamsStruct, struct_name: &Ident) -> TokenStream {
|
||||
match *data {
|
||||
Data::Struct(ref data) => match data.fields {
|
||||
Fields::Named(ref fields) => {
|
||||
let recurse = fields.named.iter().map(|f| {
|
||||
let name = &f.ident;
|
||||
get_implem_deserialize_for_field(f, quote! { #name: })
|
||||
get_implem_deserialize_for_field(f, quote! { #name: }, struct_name)
|
||||
});
|
||||
quote! {
|
||||
Ok(
|
||||
|
|
@ -692,7 +734,7 @@ fn get_implem_deserialize(data: &Data, params: &ParamsStruct) -> TokenStream {
|
|||
let recurse = fields
|
||||
.unnamed
|
||||
.iter()
|
||||
.map(|f| get_implem_deserialize_for_field(f, quote! {}));
|
||||
.map(|f| get_implem_deserialize_for_field(f, quote! {}, struct_name));
|
||||
quote! {
|
||||
Ok(Self(#(#recurse)*))
|
||||
}
|
||||
|
|
@ -717,7 +759,7 @@ fn get_implem_deserialize(data: &Data, params: &ParamsStruct) -> TokenStream {
|
|||
Fields::Named(ref fields) => {
|
||||
let recurse = fields.named.iter().map(|f| {
|
||||
let name = &f.ident;
|
||||
get_implem_deserialize_for_field(f, quote! { #name: })
|
||||
get_implem_deserialize_for_field(f, quote! { #name: }, struct_name)
|
||||
});
|
||||
quote_spanned! { v.span() =>
|
||||
if #val == prefix {
|
||||
|
|
@ -729,7 +771,7 @@ fn get_implem_deserialize(data: &Data, params: &ParamsStruct) -> TokenStream {
|
|||
let recurse = fields
|
||||
.unnamed
|
||||
.iter()
|
||||
.map(|f| get_implem_deserialize_for_field(f, quote! {}));
|
||||
.map(|f| get_implem_deserialize_for_field(f, quote! {}, struct_name));
|
||||
quote_spanned! { v.span() =>
|
||||
if #val == prefix {
|
||||
return Ok(Self::#v_ident (#(#recurse)*));
|
||||
|
|
@ -770,18 +812,16 @@ fn get_implem_deserialize(data: &Data, params: &ParamsStruct) -> TokenStream {
|
|||
// TODO: check first field name is `prefix`?
|
||||
let recurse = fields.named.iter().skip(1).map(|f| {
|
||||
let name = &f.ident;
|
||||
get_implem_deserialize_for_field(f, quote! { #name: })
|
||||
get_implem_deserialize_for_field(f, quote! { #name: }, struct_name)
|
||||
});
|
||||
quote_spanned! { v.span() =>
|
||||
return Ok(Self::#v_ident {prefix, #(#recurse)*});
|
||||
}
|
||||
}
|
||||
Fields::Unnamed(ref fields) => {
|
||||
let recurse = fields
|
||||
.unnamed
|
||||
.iter()
|
||||
.skip(1)
|
||||
.map(|f| get_implem_deserialize_for_field(f, quote! {}));
|
||||
let recurse = fields.unnamed.iter().skip(1).map(|f| {
|
||||
get_implem_deserialize_for_field(f, quote! {}, struct_name)
|
||||
});
|
||||
quote_spanned! { v.span() =>
|
||||
return Ok(Self::#v_ident (prefix, #(#recurse)*));
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue