mirror of
https://codeberg.org/icewind/bitbuffer.git
synced 2026-06-03 16:44:06 +02:00
allow deriving BitSize and BitSizeSized
This commit is contained in:
parent
fe95592d57
commit
fe91298c1f
2 changed files with 105 additions and 2 deletions
|
|
@ -391,3 +391,77 @@ fn get_attr(attrs: &Vec<Attribute>, name: &str) -> Option<Lit> {
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// See the [crate documentation](index.html) for details
|
||||||
|
#[proc_macro_derive(BitSize, attributes(size))]
|
||||||
|
pub fn derive_bitsize(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||||
|
derive_bitsize_trait(input, "BitSize".to_owned(), None)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See the [crate documentation](index.html) for details
|
||||||
|
#[proc_macro_derive(BitSizeSized, attributes(size))]
|
||||||
|
pub fn derive_bitsize_sized(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||||
|
let extra_param = parse_str::<TokenStream>("input_size: usize").unwrap();
|
||||||
|
derive_bitsize_trait(input, "BitSizeSized".to_owned(), Some(extra_param))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn derive_bitsize_trait(
|
||||||
|
input: proc_macro::TokenStream,
|
||||||
|
trait_name: String,
|
||||||
|
extra_param: Option<TokenStream>,
|
||||||
|
) -> proc_macro::TokenStream {
|
||||||
|
let input: DeriveInput = parse_macro_input!(input as DeriveInput);
|
||||||
|
|
||||||
|
let name = &input.ident;
|
||||||
|
|
||||||
|
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
|
||||||
|
|
||||||
|
let sum = bit_size_sum(&input.data);
|
||||||
|
|
||||||
|
let trait_def_str = format!("::bitstream_reader::{}", trait_name);
|
||||||
|
let trait_def = parse_str::<Path>(&trait_def_str).unwrap();
|
||||||
|
|
||||||
|
let expanded = quote! {
|
||||||
|
impl #impl_generics #trait_def for #name #ty_generics #where_clause {
|
||||||
|
fn bit_size(#extra_param) -> usize {
|
||||||
|
#sum
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// panic!("{}", TokenStream::to_string(&expanded));
|
||||||
|
|
||||||
|
proc_macro::TokenStream::from(expanded)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate an expression to sum up the heap size of each field.
|
||||||
|
fn bit_size_sum(data: &Data) -> TokenStream {
|
||||||
|
match *data {
|
||||||
|
Data::Struct(ref data) => match data.fields {
|
||||||
|
Fields::Named(ref fields) => {
|
||||||
|
let recurse = fields.named.iter().map(|f| {
|
||||||
|
let field_type = &f.ty;
|
||||||
|
let size = get_field_size(&f.attrs, f.span());
|
||||||
|
match size {
|
||||||
|
Some(size) => {
|
||||||
|
quote_spanned! {f.span()=>
|
||||||
|
::bitstream_reader::bit_size_of_sized::<#field_type>(#size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
quote_spanned! {f.span()=>
|
||||||
|
::bitstream_reader::bit_size_of::<#field_type>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
quote! {
|
||||||
|
0 #(+ #recurse)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Fields::Unit => quote!(0),
|
||||||
|
_ => unimplemented!(),
|
||||||
|
},
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
use bitstream_reader::{BigEndian, BitBuffer, BitStream, Endianness, LittleEndian};
|
use bitstream_reader::{
|
||||||
use bitstream_reader_derive::{BitRead, BitReadSized};
|
bit_size_of, bit_size_of_sized, BigEndian, BitBuffer, BitStream, Endianness, LittleEndian,
|
||||||
|
};
|
||||||
|
use bitstream_reader_derive::{BitRead, BitReadSized, BitSize, BitSizeSized};
|
||||||
|
|
||||||
#[derive(BitRead, PartialEq, Debug)]
|
#[derive(BitRead, PartialEq, Debug)]
|
||||||
struct TestStruct {
|
struct TestStruct {
|
||||||
|
|
@ -259,3 +261,30 @@ fn test_read_rest_enum() {
|
||||||
assert_eq!(TestEnumRest::Bar, stream.read().unwrap());
|
assert_eq!(TestEnumRest::Bar, stream.read().unwrap());
|
||||||
assert_eq!(TestEnumRest::Asd, stream.read().unwrap());
|
assert_eq!(TestEnumRest::Asd, stream.read().unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(BitSize)]
|
||||||
|
struct SizeStruct {
|
||||||
|
foo: u8,
|
||||||
|
#[size = 6]
|
||||||
|
str: String,
|
||||||
|
bar: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_bit_size() {
|
||||||
|
assert_eq!(bit_size_of::<SizeStruct>(), 8 + 8 * 6 + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(BitSizeSized)]
|
||||||
|
struct SizeStructSized {
|
||||||
|
foo: u8,
|
||||||
|
#[size = "input_size"]
|
||||||
|
str: String,
|
||||||
|
bar: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_bit_size_sized() {
|
||||||
|
assert_eq!(bit_size_of_sized::<SizeStructSized>(6), 8 + 8 * 6 + 1);
|
||||||
|
assert_eq!(bit_size_of_sized::<SizeStructSized>(16), 8 + 8 * 16 + 1);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue