add prefix / suffix to field
This commit is contained in:
parent
33e770e04a
commit
5dd96fb173
4 changed files with 176 additions and 22 deletions
3
androscalpel_serializer/src/constant.rs
Normal file
3
androscalpel_serializer/src/constant.rs
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
//! Constants definition
|
||||
|
||||
pub use androscalpel_serializer_derive::*;
|
||||
|
|
@ -5,7 +5,7 @@ use std::io::{Cursor, Read, Seek, SeekFrom, Write};
|
|||
|
||||
pub use androscalpel_serializer_derive::*;
|
||||
|
||||
mod leb;
|
||||
pub mod leb;
|
||||
pub use leb::*;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
|
|
@ -849,4 +849,29 @@ mod test {
|
|||
);
|
||||
assert!(TestEnum::deserialize_from_slice(&[255u8]).is_err());
|
||||
}
|
||||
|
||||
#[derive(Serializable, PartialEq, Debug)]
|
||||
struct TestPrefixSuffix {
|
||||
#[prefix([0x42])]
|
||||
#[suffix([0x66, 0x66])]
|
||||
a: u32,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deserialize_prefix_suffix() {
|
||||
assert_eq!(
|
||||
TestPrefixSuffix::deserialize_from_slice(&[0x42, 0, 1, 2, 3, 0x66, 0x66]).unwrap(),
|
||||
TestPrefixSuffix { a: 0x00010203 }
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialize_prefix_suffix() {
|
||||
assert_eq!(
|
||||
TestPrefixSuffix { a: 0x00010203 }
|
||||
.serialize_to_vec()
|
||||
.unwrap(),
|
||||
vec![0x42, 0, 1, 2, 3, 0x66, 0x66]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
pub mod constant;
|
||||
pub mod core;
|
||||
|
||||
pub use crate::core::*;
|
||||
pub use constant::*;
|
||||
|
|
|
|||
|
|
@ -42,7 +42,29 @@ use syn::{
|
|||
/// );
|
||||
/// ```
|
||||
///
|
||||
#[proc_macro_derive(Serializable, attributes(until, prefix, prefix_type))]
|
||||
/// ## Prefix and suffix
|
||||
///
|
||||
/// To define a constant prefix before a serialised field or suffixe after, use `#[prefix(<prefix>)]`
|
||||
/// and `#[suffix(<suffix>)]`. The prefix/suffix must be `u8`s `Iterator`.
|
||||
///
|
||||
/// ```
|
||||
/// pub use androscalpel_serializer::*;
|
||||
///
|
||||
/// #[derive(Serializable, PartialEq, Debug)]
|
||||
/// struct Example {
|
||||
/// #[prefix([0x42])]
|
||||
/// #[suffix([0x66, 0x66])]
|
||||
/// a: u32,
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// Example::deserialize_from_slice(&[0x42, 0, 1, 2, 3, 0x66, 0x66]).unwrap(),
|
||||
/// Example { a: 0x00010203 }
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
///
|
||||
#[proc_macro_derive(Serializable, attributes(until, prefix, prefix_type, suffix))]
|
||||
pub fn derive_serializable(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let input = parse_macro_input!(input as DeriveInput);
|
||||
let name = input.ident;
|
||||
|
|
@ -83,9 +105,9 @@ impl Parse for UntilParams {
|
|||
}
|
||||
}
|
||||
|
||||
/// Parsed Parameters for the `#[prefix(val)]` attribute.
|
||||
struct PrefixParams(TokenStream);
|
||||
impl Parse for PrefixParams {
|
||||
/// Parsed Parameters for the `#[prefix(val)]` attribute of an enum variant.
|
||||
struct PrefixParamsVariant(TokenStream);
|
||||
impl Parse for PrefixParamsVariant {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
let value = input.parse()?;
|
||||
Ok(Self(value))
|
||||
|
|
@ -107,16 +129,36 @@ struct ParamsStruct {
|
|||
pub prefix_type: Option<PrefixTypeParams>,
|
||||
}
|
||||
|
||||
/// Parsed Parameters for the `#[prefix(val)]` attribute of an struct field.
|
||||
struct PrefixParamsField(TokenStream);
|
||||
impl Parse for PrefixParamsField {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
let value = input.parse()?;
|
||||
Ok(Self(value))
|
||||
}
|
||||
}
|
||||
|
||||
/// Parsed Parameters for the `#[suffix(val)]` attribute of an struct field.
|
||||
struct SuffixParamsField(TokenStream);
|
||||
impl Parse for SuffixParamsField {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
let value = input.parse()?;
|
||||
Ok(Self(value))
|
||||
}
|
||||
}
|
||||
|
||||
/// All the attributes parameters for a field
|
||||
#[derive(Default)]
|
||||
struct ParamsField {
|
||||
pub until: Option<UntilParams>,
|
||||
pub prefix: Option<PrefixParamsField>,
|
||||
pub suffix: Option<SuffixParamsField>,
|
||||
}
|
||||
|
||||
/// All the attributes parameters for a variant
|
||||
#[derive(Default)]
|
||||
struct ParamsVariant {
|
||||
pub prefix: Option<PrefixParams>,
|
||||
pub prefix: Option<PrefixParamsVariant>,
|
||||
}
|
||||
|
||||
impl ParamsStruct {
|
||||
|
|
@ -147,8 +189,11 @@ impl ParamsField {
|
|||
Meta::List(MetaList { path, tokens, .. }) if path.is_ident("until") => {
|
||||
params.until = Some(syn::parse2(tokens.clone()).unwrap())
|
||||
}
|
||||
Meta::List(MetaList { path, .. }) if path.is_ident("prefix") => {
|
||||
panic!("Fields cannot take the attribut 'prefix'")
|
||||
Meta::List(MetaList { path, tokens, .. }) if path.is_ident("prefix") => {
|
||||
params.prefix = Some(syn::parse2(tokens.clone()).unwrap())
|
||||
}
|
||||
Meta::List(MetaList { path, tokens, .. }) if path.is_ident("suffix") => {
|
||||
params.suffix = Some(syn::parse2(tokens.clone()).unwrap())
|
||||
}
|
||||
Meta::List(MetaList { path, .. }) if path.is_ident("prefix_type") => {
|
||||
panic!("Fields cannot take the attribut 'prefix_type'")
|
||||
|
|
@ -211,22 +256,38 @@ fn get_enum_match(variant: &Variant) -> TokenStream {
|
|||
/// for a specific field `f` accessible using `field_ref`.
|
||||
fn get_implem_size_for_field(f: &Field, field_ref: TokenStream) -> TokenStream {
|
||||
let params = ParamsField::parse(&f.attrs);
|
||||
match (&f.ty, params) {
|
||||
let prefix_stream = if let Some(PrefixParamsField(ref stream)) = params.prefix {
|
||||
quote_spanned! { f.span() =>
|
||||
#stream.iter().collect::<Vec<_>>().len()
|
||||
}
|
||||
} else {
|
||||
quote_spanned! { f.span() => 0 }
|
||||
};
|
||||
let suffix_stream = if let Some(SuffixParamsField(ref stream)) = params.suffix {
|
||||
quote_spanned! { f.span() =>
|
||||
#stream.iter().collect::<Vec<_>>().len()
|
||||
}
|
||||
} else {
|
||||
quote_spanned! { f.span() => 0 }
|
||||
};
|
||||
let main_stream = match (&f.ty, params) {
|
||||
(
|
||||
_,
|
||||
ParamsField {
|
||||
until: Some(UntilParams(d, u, until)),
|
||||
..
|
||||
},
|
||||
) => quote_spanned! { f.span() =>
|
||||
androscalpel_serializer::SerializableUntil::<#d, #u>::size(&#field_ref, #until)
|
||||
},
|
||||
(Type::Array(_), ParamsField { until: None }) => quote_spanned! { f.span() =>
|
||||
(Type::Array(_), ParamsField { until: None, .. }) => quote_spanned! { f.span() =>
|
||||
#field_ref.iter().map(androscalpel_serializer::Serializable::size).sum::<usize>()
|
||||
},
|
||||
(_, ParamsField { until: None }) => quote_spanned! { f.span() =>
|
||||
(_, ParamsField { until: None, .. }) => quote_spanned! { f.span() =>
|
||||
androscalpel_serializer::Serializable::size(&#field_ref)
|
||||
},
|
||||
}
|
||||
};
|
||||
quote_spanned! { f.span() => #prefix_stream + #main_stream + #suffix_stream }
|
||||
}
|
||||
|
||||
/// Return the implementation of the [`androscalpel_serializer::Serializable::size`].
|
||||
|
|
@ -263,7 +324,7 @@ fn get_implem_size(data: &Data, params: &ParamsStruct) -> TokenStream {
|
|||
let prefix = params.prefix.expect(
|
||||
"Cannot derive Serializable for variant without the #[prefix(val)] attribute",
|
||||
);
|
||||
let PrefixParams(val) = prefix;
|
||||
let PrefixParamsVariant(val) = prefix;
|
||||
let match_ = get_enum_match(v);
|
||||
let body = match v.fields {
|
||||
Fields::Named(ref fields) => {
|
||||
|
|
@ -304,23 +365,47 @@ fn get_implem_size(data: &Data, params: &ParamsStruct) -> TokenStream {
|
|||
fn get_implem_serialize_for_field(f: &Field, field_ref: TokenStream) -> TokenStream {
|
||||
let params = ParamsField::parse(&f.attrs);
|
||||
// TODO: Improve error handling
|
||||
match (&f.ty, params) {
|
||||
let prefix_stream = if let Some(PrefixParamsField(ref stream)) = params.prefix {
|
||||
quote_spanned! { f.span() =>
|
||||
for byte in #stream {
|
||||
<u8 as androscalpel_serializer::Serializable>::serialize(&byte, output)?;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote_spanned! { f.span() => }
|
||||
};
|
||||
let suffix_stream = if let Some(SuffixParamsField(ref stream)) = params.suffix {
|
||||
quote_spanned! { f.span() =>
|
||||
for byte in #stream {
|
||||
<u8 as androscalpel_serializer::Serializable>::serialize(&byte, output)?;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote_spanned! { f.span() => }
|
||||
};
|
||||
let main_stream = match (&f.ty, params) {
|
||||
(
|
||||
_,
|
||||
ParamsField {
|
||||
until: Some(UntilParams(d, u, until)),
|
||||
..
|
||||
},
|
||||
) => quote_spanned! { f.span() =>
|
||||
androscalpel_serializer::SerializableUntil::<#d, #u>::serialize(&#field_ref, output, #until)?;
|
||||
},
|
||||
(Type::Array(_), ParamsField { until: None }) => quote_spanned! { f.span() =>
|
||||
(Type::Array(_), ParamsField { until: None, .. }) => quote_spanned! { f.span() =>
|
||||
for x in #field_ref {
|
||||
androscalpel_serializer::Serializable::serialize(&x, output)?;
|
||||
}
|
||||
},
|
||||
(_, ParamsField { until: None }) => quote_spanned! { f.span() =>
|
||||
(_, ParamsField { until: None, .. }) => quote_spanned! { f.span() =>
|
||||
androscalpel_serializer::Serializable::serialize(&#field_ref, output)?;
|
||||
},
|
||||
};
|
||||
quote_spanned! { f.span() =>
|
||||
#prefix_stream
|
||||
#main_stream
|
||||
#suffix_stream
|
||||
}
|
||||
}
|
||||
/// Return the implementation of the [`androscalpel_serializer::Serializable::serialize`].
|
||||
|
|
@ -359,7 +444,7 @@ fn get_implem_serialize(data: &Data, params: &ParamsStruct) -> TokenStream {
|
|||
let prefix = params.prefix.expect(
|
||||
"Cannot derive Serializable for variant without the #[prefix(val)] attribute",
|
||||
);
|
||||
let PrefixParams(val) = prefix;
|
||||
let PrefixParamsVariant(val) = prefix;
|
||||
let match_ = get_enum_match(v);
|
||||
let body = match v.fields {
|
||||
Fields::Named(ref fields) => {
|
||||
|
|
@ -408,30 +493,69 @@ fn get_implem_deserialize_for_field(f: &Field, field_ref: TokenStream) -> TokenS
|
|||
let params = ParamsField::parse(&f.attrs);
|
||||
let ty = &f.ty;
|
||||
// TODO: Improve error handling
|
||||
let prefix_stream = if let Some(PrefixParamsField(ref stream)) = params.prefix {
|
||||
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()
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote_spanned! { f.span() => }
|
||||
};
|
||||
let suffix_stream = if let Some(SuffixParamsField(ref stream)) = params.suffix {
|
||||
quote_spanned! { f.span() =>
|
||||
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()
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote_spanned! { f.span() => }
|
||||
};
|
||||
match (ty, params) {
|
||||
(
|
||||
_,
|
||||
ParamsField {
|
||||
until: Some(UntilParams(d, u, until)),
|
||||
..
|
||||
},
|
||||
) => quote_spanned! { f.span() =>
|
||||
#field_ref <#ty as androscalpel_serializer::SerializableUntil::<#d, #u>>::deserialize(input, #until)?,
|
||||
#field_ref {
|
||||
#prefix_stream
|
||||
let val = <#ty as androscalpel_serializer::SerializableUntil::<#d, #u>>::deserialize(input, #until)?;
|
||||
#suffix_stream
|
||||
val
|
||||
},
|
||||
},
|
||||
(Type::Array(arr), ParamsField { until: None }) => {
|
||||
(Type::Array(arr), ParamsField { until: None, .. }) => {
|
||||
let len = &arr.len;
|
||||
let arr_ty = &arr.elem;
|
||||
quote_spanned! { f.span() =>
|
||||
#field_ref {
|
||||
#prefix_stream
|
||||
let mut vec_ = vec![];
|
||||
for _ in 0..(#len) {
|
||||
vec_.push(<#arr_ty as androscalpel_serializer::Serializable>::deserialize(input)?);
|
||||
}
|
||||
#suffix_stream
|
||||
vec_.try_into().unwrap()
|
||||
},
|
||||
}
|
||||
}
|
||||
(_, ParamsField { until: None }) => quote_spanned! { f.span() =>
|
||||
#field_ref <#ty as androscalpel_serializer::Serializable>::deserialize(input)?,
|
||||
(_, ParamsField { until: None, .. }) => quote_spanned! { f.span() =>
|
||||
#field_ref {
|
||||
#prefix_stream
|
||||
let val = <#ty as androscalpel_serializer::Serializable>::deserialize(input)?;
|
||||
#suffix_stream
|
||||
val
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -471,7 +595,7 @@ fn get_implem_deserialize(data: &Data, params: &ParamsStruct) -> TokenStream {
|
|||
let recurse = data.variants.iter().map(|v| {
|
||||
let v_ident = &v.ident;
|
||||
let v_params = ParamsVariant::parse(&v.attrs);
|
||||
let PrefixParams(val) = v_params.prefix.expect(
|
||||
let PrefixParamsVariant(val) = v_params.prefix.expect(
|
||||
"Cannot derive Serializable for variant without the #[prefix(val)] attribute",
|
||||
);
|
||||
match v.fields {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue