1
0
Fork 0
mirror of https://codeberg.org/icewind/bitbuffer.git synced 2026-06-03 16:44:06 +02:00

support reading Unit structs

This commit is contained in:
Robin Appelman 2019-06-22 17:02:06 +02:00
commit 896dff8367
2 changed files with 78 additions and 58 deletions

View file

@ -183,8 +183,9 @@ fn derive_bitread_trait(
.push(parse_quote!(_E: ::bitstream_reader::Endianness)); .push(parse_quote!(_E: ::bitstream_reader::Endianness));
} }
let (impl_generics, _, _) = trait_generics.split_for_impl(); let (impl_generics, _, _) = trait_generics.split_for_impl();
let span = input.span();
let parse = parse(&input.data, &name, &input.attrs); let parse = parse(input.data, &name, &input.attrs);
let endianness_placeholder = endianness.unwrap_or("_E".to_owned()); let endianness_placeholder = endianness.unwrap_or("_E".to_owned());
let trait_def_str = format!( let trait_def_str = format!(
@ -193,7 +194,7 @@ fn derive_bitread_trait(
); );
let trait_def = parse_str::<Path>(&trait_def_str).unwrap(); let trait_def = parse_str::<Path>(&trait_def_str).unwrap();
let endianness_ident = Ident::new(&endianness_placeholder, input.span()); let endianness_ident = Ident::new(&endianness_placeholder, span);
let expanded = quote! { let expanded = quote! {
impl #impl_generics #trait_def for #name #ty_generics #where_clause { impl #impl_generics #trait_def for #name #ty_generics #where_clause {
@ -208,52 +209,59 @@ fn derive_bitread_trait(
proc_macro::TokenStream::from(expanded) proc_macro::TokenStream::from(expanded)
} }
fn parse(data: &Data, struct_name: &Ident, attrs: &Vec<Attribute>) -> TokenStream { fn parse(data: Data, struct_name: &Ident, attrs: &Vec<Attribute>) -> TokenStream {
match *data { let span = struct_name.span();
Data::Struct(ref data) => {
match data.fields {
Fields::Named(ref fields) => {
let definitions = fields.named.iter().map(|f| {
let name = &f.ident;
// Get attributes `#[..]` on each field
let size = get_field_size(&f.attrs, f.span());
let field_type = &f.ty;
let span = f.span();
match size {
Some(size) => {
quote_spanned! {span=>
let #name:#field_type = {
let _size: usize = #size;
stream.read_sized(_size)?
};
}
}
None => {
quote_spanned! {span=>
let #name:#field_type = stream.read()?;
}
}
}
});
let struct_definition = fields.named.iter().map(|f| {
let name = &f.ident;
quote_spanned! {f.span()=>
#name,
}
});
let span = data.struct_token.span();
quote_spanned! {span=>
#(#definitions)*
Ok(#struct_name { match data {
#(#struct_definition)* Data::Struct(DataStruct {
}) fields: Fields::Named(fields),
..
}) => {
let definitions = fields.named.iter().map(|f| {
let name = &f.ident;
// Get attributes `#[..]` on each field
let size = get_field_size(&f.attrs, f.span());
let field_type = &f.ty;
let span = f.span();
match size {
Some(size) => {
quote_spanned! {span=>
let #name:#field_type = {
let _size: usize = #size;
stream.read_sized(_size)?
};
}
}
None => {
quote_spanned! {span=>
let #name:#field_type = stream.read()?;
}
} }
} }
_ => unimplemented!(), });
let struct_definition = fields.named.iter().map(|f| {
let name = &f.ident;
quote_spanned! {f.span()=>
#name,
}
});
quote_spanned! {span=>
#(#definitions)*
Ok(#struct_name {
#(#struct_definition)*
})
} }
} }
Data::Enum(ref data) => { Data::Struct(DataStruct {
fields: Fields::Unit,
..
}) => {
quote_spanned! {span=>
Ok(#struct_name)
}
}
Data::Enum(data) => {
let discriminant_bits: u64 = get_attribute_value(attrs, &["discriminant_bits"]).expect( let discriminant_bits: u64 = get_attribute_value(attrs, &["discriminant_bits"]).expect(
"'discriminant_bits' attribute is required when deriving `BinRead` for enums", "'discriminant_bits' attribute is required when deriving `BinRead` for enums",
); );
@ -325,22 +333,22 @@ fn get_field_size(attrs: &[Attribute], span: Span) -> Option<TokenStream> {
get_attribute_value(attrs, &["size"]) get_attribute_value(attrs, &["size"])
.map(|size_lit| match size_lit { .map(|size_lit| match size_lit {
Lit::Int(size) => { Lit::Int(size) => {
quote_spanned! {span=> quote_spanned! {span =>
#size # size
} }
} }
Lit::Str(size_field) => { Lit::Str(size_field) => {
let size = parse_str::<Expr>(&size_field.value()).unwrap(); let size = parse_str::<Expr>(&size_field.value()).unwrap();
quote_spanned! {span=> quote_spanned! {span =>
(#size) as usize ( # size) as usize
} }
} }
_ => panic!("Unsupported value for size attribute"), _ => panic!("Unsupported value for size attribute"),
}) })
.or_else(|| { .or_else(|| {
get_attribute_value::<Lit>(attrs, &["size_bits"]).map(|size_bits_lit| { get_attribute_value::<Lit>(attrs, &["size_bits"]).map(|size_bits_lit| {
quote_spanned! {span=> quote_spanned! {span =>
stream.read_int::<usize>(#size_bits_lit)? stream.read_int::< usize > (# size_bits_lit) ?
} }
}) })
}) })
@ -376,11 +384,11 @@ fn derive_bitsize_trait(
let trait_def = parse_str::<Path>(&trait_def_str).unwrap(); let trait_def = parse_str::<Path>(&trait_def_str).unwrap();
let expanded = quote! { let expanded = quote! {
impl #impl_generics #trait_def for #name #ty_generics #where_clause { impl # impl_generics # trait_def for # name # ty_generics # where_clause {
fn bit_size(#extra_param) -> usize { fn bit_size( # extra_param) -> usize {
#sum # sum
} }
} }
}; };
// panic!("{}", TokenStream::to_string(&expanded)); // panic!("{}", TokenStream::to_string(&expanded));
@ -400,19 +408,19 @@ fn bit_size_sum(data: Data) -> TokenStream {
let field_type = f.ty; let field_type = f.ty;
match get_field_size(&f.attrs, span) { match get_field_size(&f.attrs, span) {
Some(size) => { Some(size) => {
quote_spanned! {span=> quote_spanned! {span =>
::bitstream_reader::bit_size_of_sized::<#field_type>(#size) ::bitstream_reader::bit_size_of_sized::< # field_type> ( # size)
} }
} }
None => { None => {
quote_spanned! {span=> quote_spanned! {span =>
::bitstream_reader::bit_size_of::<#field_type>() ::bitstream_reader::bit_size_of::< # field_type> ()
} }
} }
} }
}); });
quote! { quote! {
0 #(+ #recurse)* 0 # ( + # recurse) *
} }
} }
Data::Struct(DataStruct { Data::Struct(DataStruct {

View file

@ -265,6 +265,18 @@ fn test_read_rest_enum() {
assert_eq!(TestEnumRest::Asd, stream.read().unwrap()); assert_eq!(TestEnumRest::Asd, stream.read().unwrap());
} }
#[derive(BitRead, BitSize, PartialEq, Debug)]
struct EmptyStruct;
fn test_empty_struct() {
let bytes = vec![0, 0, 0, 0];
let buffer = BitBuffer::new(bytes, BigEndian);
let mut stream = BitStream::from(buffer);
assert_eq!(EmptyStruct, stream.read().unwrap());
assert_eq!(0, stream.pos());
assert_eq!(0, bit_size_of::<EmptyStruct>());
}
#[derive(BitSize)] #[derive(BitSize)]
struct SizeStruct { struct SizeStruct {
foo: u8, foo: u8,