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

allow wildcard in enum parsing

This commit is contained in:
Robin Appelman 2019-03-01 23:07:20 +01:00
commit c571326ed7
3 changed files with 49 additions and 8 deletions

View file

@ -12,7 +12,7 @@ name = "bitstream_reader_derive"
proc-macro = true proc-macro = true
[dependencies] [dependencies]
syn = "0.15" syn = { version = "0.15", features = ["full"] }
quote = "0.6" quote = "0.6"
proc-macro2 = "0.4" proc-macro2 = "0.4"

View file

@ -138,9 +138,10 @@ extern crate proc_macro;
use proc_macro2::{Span, TokenStream}; use proc_macro2::{Span, TokenStream};
use quote::{quote, quote_spanned}; use quote::{quote, quote_spanned};
use syn::spanned::Spanned; use syn::spanned::Spanned;
use syn::token::Token;
use syn::{ use syn::{
parse_macro_input, parse_quote, parse_str, Attribute, Data, DeriveInput, Expr, Fields, Ident, parse_macro_input, parse_quote, parse_str, Attribute, Data, DeriveInput, Expr, Fields, Ident,
Lit, LitStr, Meta, Path, Lit, LitStr, Meta, Pat, Path,
}; };
/// See the [crate documentation](index.html) for details /// See the [crate documentation](index.html) for details
@ -273,7 +274,7 @@ fn parse(data: &Data, struct_name: &Ident, attrs: &Vec<Attribute>) -> TokenStrea
let mut last_discriminant = -1; let mut last_discriminant = -1;
let mut discriminants = Vec::with_capacity(data.variants.len()); let mut discriminants = Vec::with_capacity(data.variants.len());
for variant in &data.variants { for variant in &data.variants {
let discriminant = variant let discriminant: Option<usize> = variant
.discriminant .discriminant
.clone() .clone()
.map(|(_, expr)| match expr { .map(|(_, expr)| match expr {
@ -282,12 +283,19 @@ fn parse(data: &Data, struct_name: &Ident, attrs: &Vec<Attribute>) -> TokenStrea
}) })
.or_else(|| get_attr(&variant.attrs, "discriminant")) .or_else(|| get_attr(&variant.attrs, "discriminant"))
.map(|lit| match lit { .map(|lit| match lit {
Lit::Int(lit) => lit.value(), Lit::Int(lit) => Some(lit.value() as usize),
_ => panic!("discriminant is required to be an integer literal"), Lit::Str(lit) => match lit.value().as_str() {
"_" => None,
_ => {
panic!("discriminant is required to be an integer literal or \"_\"")
}
},
_ => panic!("discriminant is required to be an integer literal or \"_\""),
}) })
.unwrap_or_else(|| (last_discriminant + 1) as u64) .unwrap_or_else(|| Some((last_discriminant + 1) as usize));
as usize; if let Some(disc) = discriminant {
last_discriminant = discriminant as isize; last_discriminant = disc as isize;
}
discriminants.push(discriminant) discriminants.push(discriminant)
} }
let match_arms = let match_arms =
@ -297,6 +305,10 @@ fn parse(data: &Data, struct_name: &Ident, attrs: &Vec<Attribute>) -> TokenStrea
.map(|(variant, discriminant)| { .map(|(variant, discriminant)| {
let span = variant.span(); let span = variant.span();
let variant_name = &variant.ident; let variant_name = &variant.ident;
let discriminant_string = discriminant
.map(|value| value.to_string())
.unwrap_or("_".to_string());
let discriminant = parse_str::<Pat>(discriminant_string.as_str()).unwrap();
let read_fields = match &variant.fields { let read_fields = match &variant.fields {
Fields::Unit => quote_spanned! {span=> Fields::Unit => quote_spanned! {span=>
#struct_name::#variant_name #struct_name::#variant_name

View file

@ -230,3 +230,32 @@ fn test_read_struct3() {
assert_eq!(5, result.size); assert_eq!(5, result.size);
assert_eq!(5, result.stream.bit_len()); assert_eq!(5, result.stream.bit_len());
} }
#[derive(BitRead, PartialEq, Debug)]
#[discriminant_bits = 2]
enum TestEnumRest {
Foo,
Bar,
#[discriminant = "_"]
Asd,
}
#[test]
fn test_read_rest_enum() {
let bytes = vec![
0b1100_0110,
0b1000_0100,
0b1000_0100,
0b1000_0100,
0b1000_0100,
0b1000_0100,
0b1000_0100,
0b1000_0100,
];
let buffer = BitBuffer::new(bytes, BigEndian);
let mut stream = BitStream::from(buffer);
assert_eq!(TestEnumRest::Asd, stream.read().unwrap());
assert_eq!(TestEnumRest::Foo, stream.read().unwrap());
assert_eq!(TestEnumRest::Bar, stream.read().unwrap());
assert_eq!(TestEnumRest::Asd, stream.read().unwrap());
}