mirror of
https://codeberg.org/icewind/bitbuffer.git
synced 2026-06-03 16:44:06 +02:00
fix size expressions
This commit is contained in:
parent
f5e329ab61
commit
b7fa549e79
3 changed files with 58 additions and 22 deletions
|
|
@ -5,7 +5,7 @@ use quote::{quote, quote_spanned};
|
||||||
use syn::spanned::Spanned;
|
use syn::spanned::Spanned;
|
||||||
use syn::{
|
use syn::{
|
||||||
parse_macro_input, parse_quote, parse_str, Attribute, Data, DataStruct, DeriveInput, Expr,
|
parse_macro_input, parse_quote, parse_str, Attribute, Data, DataStruct, DeriveInput, Expr,
|
||||||
Fields, GenericParam, Ident, Index, Lit, Member, Path,
|
Fields, GenericParam, Ident, Index, Lit, Member, Path, Type,
|
||||||
};
|
};
|
||||||
use syn_util::get_attribute_value;
|
use syn_util::get_attribute_value;
|
||||||
|
|
||||||
|
|
@ -100,8 +100,14 @@ fn write(data: Data, struct_name: &Ident, attrs: &[Attribute]) -> TokenStream {
|
||||||
span: field.span(),
|
span: field.span(),
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
// extract int fields to be used in size expressions
|
||||||
|
if type_is_int(&field.ty) {
|
||||||
quote_spanned! { field.span() =>
|
quote_spanned! { field.span() =>
|
||||||
let #name = &self.#member;
|
#[allow(unused_variables)]
|
||||||
|
let #name = self.#member;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote! {}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -109,22 +115,24 @@ fn write(data: Data, struct_name: &Ident, attrs: &[Attribute]) -> TokenStream {
|
||||||
// Get attributes `#[..]` on each field
|
// Get attributes `#[..]` on each field
|
||||||
let size = get_field_size(&f.attrs, f.span());
|
let size = get_field_size(&f.attrs, f.span());
|
||||||
let span = f.span();
|
let span = f.span();
|
||||||
let name = f
|
let member = f.ident.clone().map(Member::Named).unwrap_or_else(|| {
|
||||||
.ident
|
Member::Unnamed(Index {
|
||||||
.clone()
|
index: i as u32,
|
||||||
.unwrap_or_else(|| Ident::new(&format!("__{}", i), span));
|
span,
|
||||||
|
})
|
||||||
|
});
|
||||||
match size {
|
match size {
|
||||||
Some(size) => {
|
Some(size) => {
|
||||||
quote_spanned! { span =>
|
quote_spanned! { span =>
|
||||||
{
|
{
|
||||||
let _size: usize = #size;
|
let _size: usize = #size;
|
||||||
__target__stream.write_sized(#name, _size)?;
|
__target__stream.write_sized(&self.#member, _size)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
quote_spanned! { span => {
|
quote_spanned! { span => {
|
||||||
__target__stream.write(#name)?;
|
__target__stream.write(&self.#member)?;
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -258,15 +266,9 @@ fn get_field_size(attrs: &[Attribute], span: Span) -> Option<TokenStream> {
|
||||||
}
|
}
|
||||||
Lit::Str(size_field) => {
|
Lit::Str(size_field) => {
|
||||||
let size = parse_str::<Expr>(&size_field.value()).expect("size");
|
let size = parse_str::<Expr>(&size_field.value()).expect("size");
|
||||||
if size_field.value() == "input_size" {
|
|
||||||
quote_spanned! {span =>
|
quote_spanned! {span =>
|
||||||
(#size) as usize
|
(#size) as usize
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
quote_spanned! {span =>
|
|
||||||
(*#size) as usize
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => panic!("Unsupported value for size attribute"),
|
_ => panic!("Unsupported value for size attribute"),
|
||||||
})
|
})
|
||||||
|
|
@ -278,3 +280,19 @@ fn get_field_size(attrs: &[Attribute], span: Span) -> Option<TokenStream> {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn type_is_int(ty: &Type) -> bool {
|
||||||
|
if let Type::Path(path) = ty {
|
||||||
|
if let Some(ident) = path.path.get_ident() {
|
||||||
|
let name = ident.to_string();
|
||||||
|
matches!(
|
||||||
|
name.as_str(),
|
||||||
|
"u8" | "u16" | "u32" | "u64" | "usize" | "i8" | "i16" | "i32" | "i64" | "isize"
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,8 @@ use bitbuffer::{BitReadStream, Endianness};
|
||||||
use bitbuffer_derive::{BitWrite, BitWriteSized};
|
use bitbuffer_derive::{BitWrite, BitWriteSized};
|
||||||
|
|
||||||
#[derive(BitWrite)]
|
#[derive(BitWrite)]
|
||||||
struct TestStruct {
|
struct TestSizeExpression {
|
||||||
foo: u8,
|
size: u8,
|
||||||
|
#[size = "size + 2"]
|
||||||
str: String,
|
str: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(BitWrite)]
|
|
||||||
struct UnnamedSize(u8, #[size = 5] String, bool);
|
|
||||||
|
|
|
||||||
|
|
@ -260,3 +260,23 @@ fn test_empty_struct() {
|
||||||
stream.write(&EmptyStruct).unwrap();
|
stream.write(&EmptyStruct).unwrap();
|
||||||
assert_eq!(Vec::<u8>::new(), stream.finish());
|
assert_eq!(Vec::<u8>::new(), stream.finish());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(BitWrite)]
|
||||||
|
struct TestSizeExpression {
|
||||||
|
size: u8,
|
||||||
|
#[size = "size + 2"]
|
||||||
|
str: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_read_size_expression() {
|
||||||
|
let bytes = vec![0b0000_0011, b'a', b'b', b'c', b'd', b'e'];
|
||||||
|
let mut stream = BitWriteStream::new(BigEndian);
|
||||||
|
|
||||||
|
let val = TestSizeExpression {
|
||||||
|
size: 3,
|
||||||
|
str: String::from("abcde"),
|
||||||
|
};
|
||||||
|
stream.write(&val).unwrap();
|
||||||
|
assert_eq!(bytes, stream.finish());
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue