From 47b2f7e722a2e52fff87d845cc1e10725d33fbee Mon Sep 17 00:00:00 2001 From: wcampbell Date: Tue, 6 Jun 2023 00:22:12 -0400 Subject: [PATCH 01/30] Reduce code for u8 byte read --- src/impls/primitive.rs | 49 ++++++------------------------------------ 1 file changed, 7 insertions(+), 42 deletions(-) diff --git a/src/impls/primitive.rs b/src/impls/primitive.rs index f77a1ea3..8dfdfd0d 100644 --- a/src/impls/primitive.rs +++ b/src/impls/primitive.rs @@ -9,54 +9,19 @@ use alloc::format; impl DekuRead<'_, (Endian, ByteSize)> for u8 { fn read( input: &BitSlice, - (_, size): (Endian, ByteSize), + (_, _): (Endian, ByteSize), ) -> Result<(&BitSlice, Self), DekuError> { const MAX_TYPE_BITS: usize = BitSize::of::().0; - let bit_size: usize = size.0 * 8; - - // TODO - // if they never give [bits] or [bytes] we don't need to check the size - if bit_size > MAX_TYPE_BITS { - return Err(DekuError::Parse(format!( - "too much data: container of {MAX_TYPE_BITS} bits cannot hold {bit_size} bits", + if input.len() < MAX_TYPE_BITS { + return Err(DekuError::Incomplete(crate::error::NeedSize::new( + MAX_TYPE_BITS, ))); } - if input.len() < bit_size { - return Err(DekuError::Incomplete(crate::error::NeedSize::new(bit_size))); - } - - let (bit_slice, rest) = input.split_at(bit_size); - let pad = 8 * ((bit_slice.len() + 7) / 8) - bit_slice.len(); - - let value = if pad == 0 - && bit_slice.len() == MAX_TYPE_BITS - && bit_slice.domain().region().unwrap().1.len() * 8 == MAX_TYPE_BITS - { - // if everything is aligned, just read the value - bit_slice.load::() - } else { - let mut bits: BitVec = BitVec::with_capacity(bit_slice.len() + pad); - - // Copy bits to new BitVec - bits.extend_from_bitslice(bit_slice); - - // Force align - //i.e. [1110, 10010110] -> [11101001, 0110] - bits.force_align(); - - let bytes: &[u8] = bits.as_raw_slice(); - - // cannot use from_X_bytes as we don't have enough bytes for $typ - // read manually - let mut res: u8 = 0; - for b in bytes.iter().rev() { - res |= *b; - } - - res - }; + // SAFETY: We already check that input.len() < bit_size above + let (bit_slice, rest) = unsafe { input.split_at_unchecked(MAX_TYPE_BITS) }; + let value = bit_slice.load::(); Ok((rest, value)) } } From bdd52bd3fa09730077746ae8198a301072122ce1 Mon Sep 17 00:00:00 2001 From: wcampbell Date: Wed, 14 Jun 2023 00:28:14 -0400 Subject: [PATCH 02/30] Refactor DekuRead to return bits read - Instead of always returning a new performance costly BitSlice, just return the amount of bits read and just increment the starting len into the BitSlice in DekuRead and DekuContainerRead functions. --- benches/deku.rs | 6 +- deku-derive/src/lib.rs | 16 +- deku-derive/src/macros/deku_read.rs | 74 ++++--- deku-derive/src/macros/deku_write.rs | 10 +- deku-derive/src/macros/mod.rs | 3 +- examples/custom_reader_and_writer.rs | 9 +- examples/enums.rs | 5 +- examples/enums_catch_all.rs | 4 +- examples/example.rs | 24 +-- examples/ipv4.rs | 11 +- src/attributes.rs | 26 +-- src/ctx.rs | 1 + src/error.rs | 3 +- src/impls/bool.rs | 27 ++- src/impls/boxed.rs | 34 +-- src/impls/cow.rs | 22 +- src/impls/cstring.rs | 23 +- src/impls/hashmap.rs | 86 ++++---- src/impls/hashset.rs | 68 +++--- src/impls/ipaddr.rs | 37 ++-- src/impls/nonzero.rs | 23 +- src/impls/option.rs | 16 +- src/impls/primitive.rs | 202 +++++++++--------- src/impls/slice.rs | 73 ++++--- src/impls/tuple.rs | 27 ++- src/impls/unit.rs | 17 +- src/impls/vec.rs | 58 ++--- src/lib.rs | 20 +- src/prelude.rs | 5 +- tests/test_alloc.rs | 6 +- tests/test_attributes/test_assert.rs | 3 +- tests/test_attributes/test_assert_eq.rs | 3 +- tests/test_attributes/test_cond.rs | 3 +- tests/test_attributes/test_ctx.rs | 20 +- .../test_limits/test_bits_read.rs | 15 +- .../test_limits/test_bytes_read.rs | 15 +- .../test_attributes/test_limits/test_count.rs | 19 +- .../test_attributes/test_limits/test_until.rs | 23 +- tests/test_attributes/test_map.rs | 3 +- tests/test_attributes/test_padding/mod.rs | 15 +- .../test_padding/test_pad_bits_after.rs | 3 +- .../test_padding/test_pad_bits_before.rs | 3 +- .../test_padding/test_pad_bytes_after.rs | 19 +- .../test_padding/test_pad_bytes_before.rs | 19 +- tests/test_attributes/test_skip.rs | 3 +- tests/test_attributes/test_temp.rs | 11 +- tests/test_attributes/test_update.rs | 11 +- tests/test_catch_all.rs | 4 +- .../test_compile/cases/internal_variables.rs | 4 +- .../test_compile/cases/unknown_endian.stderr | 23 +- tests/test_enum.rs | 3 +- tests/test_from_bytes.rs | 35 ++- tests/test_generic.rs | 3 +- tests/test_magic.rs | 3 +- tests/test_regression.rs | 2 +- tests/test_struct.rs | 63 +++--- 56 files changed, 661 insertions(+), 603 deletions(-) diff --git a/benches/deku.rs b/benches/deku.rs index 72106c36..f52791a8 100644 --- a/benches/deku.rs +++ b/benches/deku.rs @@ -105,13 +105,13 @@ fn criterion_benchmark(c: &mut Criterion) { }); let deku_read_vec_input = { - let mut v = [0xFFu8; 101].to_vec(); + let mut v = [0xffu8; 101].to_vec(); v[0] = 100u8; v }; let deku_write_vec_input = DekuVec { count: 100, - data: vec![0xFF; 100], + data: vec![0xff; 100], }; c.bench_function("deku_read_vec", |b| { b.iter(|| deku_read_vec(black_box(&deku_read_vec_input))) @@ -122,7 +122,7 @@ fn criterion_benchmark(c: &mut Criterion) { let deku_write_vec_input = DekuVecPerf { count: 100, - data: vec![0xFF; 100], + data: vec![0xff; 100], }; c.bench_function("deku_read_vec_perf", |b| { b.iter(|| deku_read_vec_perf(black_box(&deku_read_vec_input))) diff --git a/deku-derive/src/lib.rs b/deku-derive/src/lib.rs index f9dbde48..35c68ab2 100644 --- a/deku-derive/src/lib.rs +++ b/deku-derive/src/lib.rs @@ -4,13 +4,18 @@ Procedural macros that implement `DekuRead` and `DekuWrite` traits #![warn(missing_docs)] -use crate::macros::{deku_read::emit_deku_read, deku_write::emit_deku_write}; +use std::borrow::Cow; +use std::convert::TryFrom; + use darling::{ast, FromDeriveInput, FromField, FromMeta, FromVariant, ToTokens}; use proc_macro2::TokenStream; use quote::quote; -use std::borrow::Cow; -use std::convert::TryFrom; -use syn::{punctuated::Punctuated, spanned::Spanned, AttributeArgs}; +use syn::punctuated::Punctuated; +use syn::spanned::Spanned; +use syn::AttributeArgs; + +use crate::macros::deku_read::emit_deku_read; +use crate::macros::deku_write::emit_deku_write; mod macros; @@ -1006,10 +1011,11 @@ pub fn deku_derive( #[cfg(test)] mod tests { - use super::*; use rstest::rstest; use syn::parse_str; + use super::*; + #[rstest(input, // Valid struct case::struct_empty(r#"struct Test {}"#), diff --git a/deku-derive/src/macros/deku_read.rs b/deku-derive/src/macros/deku_read.rs index 5410608e..0e1e25a6 100644 --- a/deku-derive/src/macros/deku_read.rs +++ b/deku-derive/src/macros/deku_read.rs @@ -1,16 +1,16 @@ +use std::convert::TryFrom; + +use darling::ast::{Data, Fields}; +use darling::ToTokens; +use proc_macro2::TokenStream; +use quote::quote; +use syn::spanned::Spanned; + use crate::macros::{ gen_ctx_types_and_arg, gen_field_args, gen_internal_field_ident, gen_internal_field_idents, gen_type_from_ctx_id, pad_bits, token_contains_string, wrap_default_ctx, }; use crate::{DekuData, DekuDataEnum, DekuDataStruct, FieldData, Id}; -use darling::{ - ast::{Data, Fields}, - ToTokens, -}; -use proc_macro2::TokenStream; -use quote::quote; -use std::convert::TryFrom; -use syn::spanned::Spanned; pub(crate) fn emit_deku_read(input: &DekuData) -> Result { match &input.data { @@ -64,19 +64,15 @@ fn emit_struct(input: &DekuData) -> Result { use core::convert::TryFrom; use ::#crate_::bitvec::BitView; let __deku_input_bits = __deku_input.0.view_bits::<::#crate_::bitvec::Msb0>(); - - let mut __deku_rest = __deku_input_bits; - __deku_rest = &__deku_rest[__deku_input.1..]; + let mut __deku_rest = &__deku_input_bits[__deku_input.1..]; + let mut __deku_total_read = 0; #magic_read #(#field_reads)* let __deku_value = #initialize_struct; - let __deku_pad = 8 * ((__deku_rest.len() + 7) / 8) - __deku_rest.len(); - let __deku_read_idx = __deku_input_bits.len() - (__deku_rest.len() + __deku_pad); - - Ok(((__deku_input_bits[__deku_read_idx..].domain().region().unwrap().1, __deku_pad), __deku_value)) + Ok((__deku_total_read, __deku_value)) }, &input.ctx, &input.ctx_default, @@ -98,18 +94,19 @@ fn emit_struct(input: &DekuData) -> Result { let read_body = quote! { use core::convert::TryFrom; let mut __deku_rest = __deku_input_bits; + let mut __deku_total_read = 0; #magic_read #(#field_reads)* let __deku_value = #initialize_struct; - Ok((__deku_rest, __deku_value)) + Ok((__deku_total_read, __deku_value)) }; tokens.extend(quote! { impl #imp ::#crate_::DekuRead<#lifetime, #ctx_types> for #ident #wher { - fn read(__deku_input_bits: &#lifetime ::#crate_::bitvec::BitSlice, #ctx_arg) -> core::result::Result<(&#lifetime ::#crate_::bitvec::BitSlice, Self), ::#crate_::DekuError> { + fn read(__deku_input_bits: &#lifetime ::#crate_::bitvec::BitSlice, #ctx_arg) -> core::result::Result<(usize, Self), ::#crate_::DekuError> { #read_body } } @@ -120,7 +117,7 @@ fn emit_struct(input: &DekuData) -> Result { tokens.extend(quote! { impl #imp ::#crate_::DekuRead<#lifetime> for #ident #wher { - fn read(__deku_input_bits: &#lifetime ::#crate_::bitvec::BitSlice, _: ()) -> core::result::Result<(&#lifetime ::#crate_::bitvec::BitSlice, Self), ::#crate_::DekuError> { + fn read(__deku_input_bits: &#lifetime ::#crate_::bitvec::BitSlice, _: ()) -> core::result::Result<(usize, Self), ::#crate_::DekuError> { #read_body } } @@ -229,7 +226,8 @@ fn emit_enum(input: &DekuData) -> Result { // if we're consuming an id, set the rest to new_rest before reading the variant let new_rest = if consume_id { quote! { - __deku_rest = __deku_new_rest; + __deku_rest = &__deku_rest[__deku_amt_read..]; + __deku_total_read += __deku_amt_read; } } else { quote! {} @@ -289,11 +287,11 @@ fn emit_enum(input: &DekuData) -> Result { let variant_id_read = if id.is_some() { quote! { - let (__deku_new_rest, __deku_variant_id) = (__deku_rest, (#id)); + let (__deku_amt_read, __deku_variant_id) = (0, (#id)); } } else if id_type.is_some() { quote! { - let (__deku_new_rest, __deku_variant_id) = <#id_type>::read(__deku_rest, (#id_args))?; + let (__deku_amt_read, __deku_variant_id) = <#id_type>::read(__deku_rest, (#id_args))?; } } else { // either `id` or `type` needs to be specified @@ -317,18 +315,14 @@ fn emit_enum(input: &DekuData) -> Result { use core::convert::TryFrom; use ::#crate_::bitvec::BitView; let __deku_input_bits = __deku_input.0.view_bits::<::#crate_::bitvec::Msb0>(); - - let mut __deku_rest = __deku_input_bits; - __deku_rest = &__deku_rest[__deku_input.1..]; + let mut __deku_rest = &__deku_input_bits[__deku_input.1..]; + let mut __deku_total_read = 0; #magic_read #variant_read - let __deku_pad = 8 * ((__deku_rest.len() + 7) / 8) - __deku_rest.len(); - let __deku_read_idx = __deku_input_bits.len() - (__deku_rest.len() + __deku_pad); - - Ok(((__deku_input_bits[__deku_read_idx..].domain().region().unwrap().1, __deku_pad), __deku_value)) + Ok((__deku_total_read, __deku_value)) }, &input.ctx, &input.ctx_default, @@ -349,18 +343,19 @@ fn emit_enum(input: &DekuData) -> Result { let read_body = quote! { use core::convert::TryFrom; let mut __deku_rest = __deku_input_bits; + let mut __deku_total_read = 0; #magic_read #variant_read - Ok((__deku_rest, __deku_value)) + Ok((__deku_total_read, __deku_value)) }; tokens.extend(quote! { #[allow(non_snake_case)] impl #imp ::#crate_::DekuRead<#lifetime, #ctx_types> for #ident #wher { - fn read(__deku_input_bits: &#lifetime ::#crate_::bitvec::BitSlice, #ctx_arg) -> core::result::Result<(&#lifetime ::#crate_::bitvec::BitSlice, Self), ::#crate_::DekuError> { + fn read(__deku_input_bits: &#lifetime ::#crate_::bitvec::BitSlice, #ctx_arg) -> core::result::Result<(usize, Self), ::#crate_::DekuError> { #read_body } } @@ -372,7 +367,7 @@ fn emit_enum(input: &DekuData) -> Result { tokens.extend(quote! { #[allow(non_snake_case)] impl #imp ::#crate_::DekuRead<#lifetime> for #ident #wher { - fn read(__deku_input_bits: &#lifetime ::#crate_::bitvec::BitSlice, _: ()) -> core::result::Result<(&#lifetime ::#crate_::bitvec::BitSlice, Self), ::#crate_::DekuError> { + fn read(__deku_input_bits: &#lifetime ::#crate_::bitvec::BitSlice, _: ()) -> core::result::Result<(usize, Self), ::#crate_::DekuError> { #read_body } } @@ -414,12 +409,13 @@ fn emit_magic_read(input: &DekuData) -> TokenStream { let __deku_magic = #magic; for __deku_byte in __deku_magic { - let (__deku_new_rest, __deku_read_byte) = u8::read(__deku_rest, ())?; + let (__deku_amt_read, __deku_read_byte) = u8::read(__deku_rest, ())?; if *__deku_byte != __deku_read_byte { return Err(::#crate_::DekuError::Parse(format!("Missing magic value {:?}", #magic))); } - __deku_rest = __deku_new_rest; + __deku_rest = &__deku_rest[__deku_amt_read..]; + __deku_total_read += __deku_amt_read; } } } else { @@ -497,6 +493,7 @@ fn emit_padding(bit_size: &TokenStream) -> TokenStream { if __deku_rest.len() >= __deku_pad { let (__deku_padded_bits, __deku_new_rest) = __deku_rest.split_at(__deku_pad); __deku_rest = __deku_new_rest; + __deku_total_read += __deku_pad; } else { return Err(::#crate_::DekuError::Incomplete(::#crate_::error::NeedSize::new(__deku_pad))); } @@ -655,10 +652,11 @@ fn emit_field_read( ); let field_read_normal = quote! { - let (__deku_new_rest, __deku_value) = #field_read_func?; + let (__deku_amt_read, __deku_value) = #field_read_func?; let __deku_value: #field_type = #field_map(__deku_value)?; - __deku_rest = __deku_new_rest; + __deku_rest = &__deku_rest[__deku_amt_read..]; + __deku_total_read += __deku_amt_read; __deku_value }; @@ -732,7 +730,7 @@ pub fn emit_from_bytes( quote! { impl #imp ::#crate_::DekuContainerRead<#lifetime> for #ident #wher { #[allow(non_snake_case)] - fn from_bytes(__deku_input: (&#lifetime [u8], usize)) -> core::result::Result<((&#lifetime [u8], usize), Self), ::#crate_::DekuError> { + fn from_bytes(__deku_input: (&#lifetime [u8], usize)) -> core::result::Result<(usize, Self), ::#crate_::DekuError> { #body } } @@ -752,8 +750,8 @@ pub fn emit_try_from( type Error = ::#crate_::DekuError; fn try_from(input: &#lifetime [u8]) -> core::result::Result { - let (rest, res) = ::from_bytes((input, 0))?; - if !rest.0.is_empty() { + let (amt_read, res) = ::from_bytes((input, 0))?; + if (amt_read / 8) != input.len() { return Err(::#crate_::DekuError::Parse(format!("Too much data"))); } Ok(res) diff --git a/deku-derive/src/macros/deku_write.rs b/deku-derive/src/macros/deku_write.rs index 331aea5d..87ef27f0 100644 --- a/deku-derive/src/macros/deku_write.rs +++ b/deku-derive/src/macros/deku_write.rs @@ -1,12 +1,14 @@ +use std::convert::TryFrom; + +use darling::ast::{Data, Fields}; +use proc_macro2::TokenStream; +use quote::quote; + use crate::macros::{ gen_ctx_types_and_arg, gen_field_args, gen_struct_destruction, pad_bits, token_contains_string, wrap_default_ctx, }; use crate::{DekuData, DekuDataEnum, DekuDataStruct, FieldData, Id}; -use darling::ast::{Data, Fields}; -use proc_macro2::TokenStream; -use quote::quote; -use std::convert::TryFrom; pub(crate) fn emit_deku_write(input: &DekuData) -> Result { match &input.data { diff --git a/deku-derive/src/macros/mod.rs b/deku-derive/src/macros/mod.rs index eaae7a86..23fe20ec 100644 --- a/deku-derive/src/macros/mod.rs +++ b/deku-derive/src/macros/mod.rs @@ -1,4 +1,3 @@ -use crate::Num; use proc_macro2::{Ident, Span, TokenStream}; use quote::{quote, ToTokens}; use syn::parse::Parser; @@ -6,6 +5,8 @@ use syn::punctuated::Punctuated; use syn::spanned::Spanned; use syn::token::Comma; +use crate::Num; + pub(crate) mod deku_read; pub(crate) mod deku_write; diff --git a/examples/custom_reader_and_writer.rs b/examples/custom_reader_and_writer.rs index 29e35e58..099795c8 100644 --- a/examples/custom_reader_and_writer.rs +++ b/examples/custom_reader_and_writer.rs @@ -1,13 +1,14 @@ +use std::convert::TryInto; + use deku::bitvec::{BitSlice, BitVec, Msb0}; use deku::ctx::BitSize; use deku::prelude::*; -use std::convert::TryInto; fn bit_flipper_read( field_a: u8, rest: &BitSlice, bit_size: BitSize, -) -> Result<(&BitSlice, u8), DekuError> { +) -> Result<(usize, u8), DekuError> { // Access to previously read fields println!("field_a = 0x{:X}", field_a); @@ -18,12 +19,12 @@ fn bit_flipper_read( println!("bit_size: {:?}", bit_size); // read field_b, calling original func - let (rest, value) = u8::read(rest, bit_size)?; + let (amt_read, value) = u8::read(rest, bit_size)?; // flip the bits on value if field_a is 0x01 let value = if field_a == 0x01 { !value } else { value }; - Ok((rest, value)) + Ok((amt_read, value)) } fn bit_flipper_write( diff --git a/examples/enums.rs b/examples/enums.rs index f6a16a90..522b9801 100644 --- a/examples/enums.rs +++ b/examples/enums.rs @@ -1,6 +1,7 @@ +use std::convert::TryFrom; + use deku::prelude::*; use hexlit::hex; -use std::convert::TryFrom; #[derive(Debug, PartialEq, DekuRead, DekuWrite)] #[deku(type = "u8")] @@ -21,6 +22,8 @@ enum DekuTest { Var5 { id: u8 }, #[deku(id_pat = "&id if id > 6")] Var6 { id: u8 }, + #[deku(id_pat = "_")] + VarDefault { id: u8, value: u8 }, } fn main() { diff --git a/examples/enums_catch_all.rs b/examples/enums_catch_all.rs index b967ad86..8126d1e0 100644 --- a/examples/enums_catch_all.rs +++ b/examples/enums_catch_all.rs @@ -1,7 +1,7 @@ +use std::convert::{TryFrom, TryInto}; + use deku::prelude::*; use hexlit::hex; -use std::convert::TryFrom; -use std::convert::TryInto; #[derive(Clone, Copy, PartialEq, Eq, Debug, DekuWrite, DekuRead)] #[deku(type = "u8")] diff --git a/examples/example.rs b/examples/example.rs index 6e957d33..9f29414a 100644 --- a/examples/example.rs +++ b/examples/example.rs @@ -1,8 +1,9 @@ #![allow(clippy::unusual_byte_groupings)] -use deku::prelude::*; use std::convert::{TryFrom, TryInto}; +use deku::prelude::*; + #[derive(Debug, PartialEq, DekuRead, DekuWrite)] struct FieldF { #[deku(bits = "6")] @@ -15,7 +16,6 @@ struct FieldF { // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | field_a | field_b |c| field_d | e | f | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// #[derive(Debug, PartialEq, DekuRead, DekuWrite)] // #[deku(endian = "little")] // By default it uses the system endianness, but can be overwritten struct DekuTest { @@ -36,16 +36,16 @@ struct DekuTest { fn main() { let test_data: &[u8] = [ - 0xAB, + 0xab, 0b1010010_1, - 0xAB, - 0xCD, + 0xab, + 0xcd, 0b1100_0110, 0x02, - 0xBE, - 0xEF, - 0xC0, - 0xFE, + 0xbe, + 0xef, + 0xc0, + 0xfe, ] .as_ref(); @@ -53,14 +53,14 @@ fn main() { assert_eq!( DekuTest { - field_a: 0xAB, + field_a: 0xab, field_b: 0b0_1010010, field_c: 0b0000000_1, - field_d: 0xABCD, + field_d: 0xabcd, field_e: 0b0000_0011, field_f: FieldF { data: 0b00_000110 }, num_items: 2, - items: vec![0xBEEF, 0xC0FE], + items: vec![0xbeef, 0xc0fe], }, test_deku ); diff --git a/examples/ipv4.rs b/examples/ipv4.rs index 77052834..ff3cf589 100644 --- a/examples/ipv4.rs +++ b/examples/ipv4.rs @@ -1,8 +1,9 @@ -use deku::prelude::*; -use hexlit::hex; use std::convert::{TryFrom, TryInto}; use std::net::Ipv4Addr; +use deku::prelude::*; +use hexlit::hex; + /// Ipv4 Header /// ```text /// 0 1 2 3 @@ -42,9 +43,9 @@ pub struct Ipv4Header { pub protocol: u8, // Protocol pub checksum: u16, // Header checksum pub src: Ipv4Addr, // Source IP Address - pub dst: Ipv4Addr, // Destination IP Address - // options - // padding + pub dst: Ipv4Addr, /* Destination IP Address + * options + * padding */ } fn main() { diff --git a/src/attributes.rs b/src/attributes.rs index 45b70fc7..41e72580 100644 --- a/src/attributes.rs +++ b/src/attributes.rs @@ -810,9 +810,9 @@ impl DekuTest { /// Read and convert to String fn read( rest: &BitSlice, - ) -> Result<(&BitSlice, String), DekuError> { - let (rest, value) = u8::read(rest, ())?; - Ok((rest, value.to_string())) + ) -> Result<(usize, String), DekuError> { + let (amt_read, value) = u8::read(rest, ())?; + Ok((amt_read, value.to_string())) } /// Parse from String to u8 and write @@ -871,7 +871,7 @@ struct Test { let data: Vec = vec![0x01, 0x02]; -let (rest, value) = Test::from_bytes((&data[..], 0)).unwrap(); +let (amt_read, value) = Test::from_bytes((&data[..], 0)).unwrap(); assert_eq!(value.a, 0x01); assert_eq!(value.sub.b, 0x01 + 0x02) ``` @@ -937,7 +937,7 @@ struct Test { let data: Vec = vec![0x01, 0x02]; // Use with context from `Test` -let (rest, value) = Test::from_bytes((&data[..], 0)).unwrap(); +let (amt_Read, value) = Test::from_bytes((&data[..], 0)).unwrap(); assert_eq!(value.a, 0x01); assert_eq!(value.sub.b, 0x01 + 0x02); @@ -945,7 +945,7 @@ assert_eq!(value.sub.b, 0x01 + 0x02); // Note: `from_bytes` is now available on `SubType` let data: Vec = vec![0x02]; -let (rest, value) = Subtype::from_bytes((&data[..], 0)).unwrap(); +let (amt_read, value) = Subtype::from_bytes((&data[..], 0)).unwrap(); assert_eq!(value.b, 0x01 + 0x02) ``` @@ -1019,7 +1019,7 @@ enum DekuTest { let data: Vec = vec![0x01, 0xFF, 0x02, 0xAB, 0xEF, 0xBE]; -let (rest, value) = DekuTest::from_bytes((data.as_ref(), 0)).unwrap(); +let (amt_read, value) = DekuTest::from_bytes((data.as_ref(), 0)).unwrap(); assert_eq!( DekuTest::VariantA(0xFF), @@ -1029,7 +1029,7 @@ assert_eq!( let variant_bytes: Vec = value.try_into().unwrap(); assert_eq!(vec![0x01, 0xFF], variant_bytes); -let (rest, value) = DekuTest::from_bytes(rest).unwrap(); +let (amt_read, value) = DekuTest::from_bytes((data.as_ref(), amt_read)).unwrap(); assert_eq!( DekuTest::VariantB(0xAB, 0xBEEF), @@ -1053,7 +1053,7 @@ enum DekuTest { let data: Vec = vec![0x01, 0x02]; -let (rest, value) = DekuTest::from_bytes((data.as_ref(), 0)).unwrap(); +let (amt_read, value) = DekuTest::from_bytes((data.as_ref(), 0)).unwrap(); assert_eq!( DekuTest::VariantA, @@ -1063,7 +1063,7 @@ assert_eq!( let variant_bytes: Vec = value.try_into().unwrap(); assert_eq!(vec![0x01], variant_bytes); -let (rest, value) = DekuTest::from_bytes(rest).unwrap(); +let (rest, value) = DekuTest::from_bytes((data.as_ref(), amt_read)).unwrap(); assert_eq!( DekuTest::VariantB, @@ -1099,7 +1099,7 @@ enum DekuTest { let data: Vec = vec![0x03, 0xFF]; -let (rest, value) = DekuTest::from_bytes((data.as_ref(), 0)).unwrap(); +let (amt_read, value) = DekuTest::from_bytes((data.as_ref(), 0)).unwrap(); assert_eq!( DekuTest::VariantB { id: 0x03 }, @@ -1109,7 +1109,7 @@ assert_eq!( let variant_bytes: Vec = value.try_into().unwrap(); assert_eq!(vec![0x03], variant_bytes); -let (rest, value) = DekuTest::from_bytes(rest).unwrap(); +let (rest, value) = DekuTest::from_bytes((data.as_ref(), amt_read)).unwrap(); assert_eq!( DekuTest::VariantC(0xFF), @@ -1143,7 +1143,7 @@ enum DekuTest { let data: Vec = vec![0b1001_0110, 0xFF]; -let (rest, value) = DekuTest::from_bytes((&data, 0)).unwrap(); +let (amt_read, value) = DekuTest::from_bytes((&data, 0)).unwrap(); assert_eq!( DekuTest::VariantA(0b0110, 0xFF), diff --git a/src/ctx.rs b/src/ctx.rs index db2a1e04..84ad4dc6 100644 --- a/src/ctx.rs +++ b/src/ctx.rs @@ -58,6 +58,7 @@ impl FromStr for Endian { /// # Examples /// ```rust /// use std::str::FromStr; + /// /// use deku::ctx::Endian; /// assert_eq!(FromStr::from_str("little"), Ok(Endian::Little)); /// assert_eq!(FromStr::from_str("big"), Ok(Endian::Big)); diff --git a/src/error.rs b/src/error.rs index bfeabf96..061f58dc 100644 --- a/src/error.rs +++ b/src/error.rs @@ -2,7 +2,8 @@ #![cfg(feature = "alloc")] -use alloc::{format, string::String}; +use alloc::format; +use alloc::string::String; /// Number of bits needed to retry parsing #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/src/impls/bool.rs b/src/impls/bool.rs index 478b5769..b413c417 100644 --- a/src/impls/bool.rs +++ b/src/impls/bool.rs @@ -1,9 +1,10 @@ -use crate::{DekuError, DekuRead, DekuWrite}; -use bitvec::prelude::*; - #[cfg(feature = "alloc")] use alloc::format; +use bitvec::prelude::*; + +use crate::{DekuError, DekuRead, DekuWrite}; + impl<'a, Ctx> DekuRead<'a, Ctx> for bool where Ctx: Copy, @@ -11,11 +12,8 @@ where { /// wrapper around u8::read with consideration to context, such as bit size /// true if the result of the read is `1`, false if `0` and error otherwise - fn read( - input: &'a BitSlice, - inner_ctx: Ctx, - ) -> Result<(&'a BitSlice, Self), DekuError> { - let (rest, val) = u8::read(input, inner_ctx)?; + fn read(input: &'a BitSlice, inner_ctx: Ctx) -> Result<(usize, Self), DekuError> { + let (amt_read, val) = u8::read(input, inner_ctx)?; let ret = match val { 0x01 => Ok(true), @@ -23,7 +21,7 @@ where _ => Err(DekuError::Parse(format!("cannot parse bool value: {val}",))), }?; - Ok((rest, ret)) + Ok((amt_read, ret)) } } @@ -42,10 +40,11 @@ where #[cfg(test)] mod tests { - use super::*; use hexlit::hex; use rstest::rstest; + use super::*; + #[rstest(input, expected, case(&hex!("00"), false), case(&hex!("01"), true), @@ -55,9 +54,9 @@ mod tests { )] fn test_bool(input: &[u8], expected: bool) { let bit_slice = input.view_bits::(); - let (rest, res_read) = bool::read(bit_slice, ()).unwrap(); + let (amt_read, res_read) = bool::read(bit_slice, ()).unwrap(); assert_eq!(expected, res_read); - assert!(rest.is_empty()); + assert_eq!(amt_read, 8); let mut res_write = bitvec![u8, Msb0;]; res_read.write(&mut res_write, ()).unwrap(); @@ -69,9 +68,9 @@ mod tests { let input = &[0b01_000000]; let bit_slice = input.view_bits::(); - let (rest, res_read) = bool::read(bit_slice, crate::ctx::BitSize(2)).unwrap(); + let (amt_read, res_read) = bool::read(bit_slice, crate::ctx::BitSize(2)).unwrap(); assert!(res_read); - assert_eq!(6, rest.len()); + assert_eq!(amt_read, 2); let mut res_write = bitvec![u8, Msb0;]; res_read.write(&mut res_write, ()).unwrap(); diff --git a/src/impls/boxed.rs b/src/impls/boxed.rs index 9ce5465e..74e798dc 100644 --- a/src/impls/boxed.rs +++ b/src/impls/boxed.rs @@ -1,22 +1,23 @@ -use crate::{ctx::Limit, DekuError, DekuRead, DekuWrite}; -use alloc::{boxed::Box, vec::Vec}; +use alloc::boxed::Box; +use alloc::vec::Vec; + use bitvec::prelude::*; +use crate::ctx::Limit; +use crate::{DekuError, DekuRead, DekuWrite}; + impl<'a, T, Ctx> DekuRead<'a, Ctx> for Box where T: DekuRead<'a, Ctx>, Ctx: Copy, { /// Read a T from input and store as Box - fn read( - input: &'a BitSlice, - inner_ctx: Ctx, - ) -> Result<(&'a BitSlice, Self), DekuError> + fn read(input: &'a BitSlice, inner_ctx: Ctx) -> Result<(usize, Self), DekuError> where Self: Sized, { - let (rest, val) = ::read(input, inner_ctx)?; - Ok((rest, Box::new(val))) + let (amt_read, val) = ::read(input, inner_ctx)?; + Ok((amt_read, Box::new(val))) } } @@ -41,13 +42,13 @@ where fn read( input: &'a BitSlice, (limit, inner_ctx): (Limit, Ctx), - ) -> Result<(&'a BitSlice, Self), DekuError> + ) -> Result<(usize, Self), DekuError> where Self: Sized, { // use Vec's implementation and convert to Box<[T]> - let (rest, val) = >::read(input, (limit, inner_ctx))?; - Ok((rest, val.into_boxed_slice())) + let (amt_read, val) = >::read(input, (limit, inner_ctx))?; + Ok((amt_read, val.into_boxed_slice())) } } @@ -67,10 +68,11 @@ where #[cfg(test)] mod tests { + use rstest::rstest; + use super::*; use crate::ctx::*; use crate::native_endian; - use rstest::rstest; #[rstest(input, expected, expected_rest, case( @@ -81,9 +83,9 @@ mod tests { )] fn test_boxed(input: &[u8], expected: Box, expected_rest: &BitSlice) { let bit_slice = input.view_bits::(); - let (rest, res_read) = >::read(bit_slice, ()).unwrap(); + let (amt_read, res_read) = >::read(bit_slice, ()).unwrap(); assert_eq!(expected, res_read); - assert_eq!(expected_rest, rest); + assert_eq!(expected_rest, bit_slice[amt_read..]); let mut res_write = bitvec![u8, Msb0;]; res_read.write(&mut res_write, ()).unwrap(); @@ -113,10 +115,10 @@ mod tests { // Unwrap here because all test cases are `Some`. let bit_size = bit_size.unwrap(); - let (rest, res_read) = + let (amt_read, res_read) = >::read(bit_slice, (limit, (endian, BitSize(bit_size)))).unwrap(); assert_eq!(expected, res_read); - assert_eq!(expected_rest, rest); + assert_eq!(expected_rest, bit_slice[amt_read..]); let mut res_write = bitvec![u8, Msb0;]; res_read diff --git a/src/impls/cow.rs b/src/impls/cow.rs index e685aac2..c48cb75f 100644 --- a/src/impls/cow.rs +++ b/src/impls/cow.rs @@ -1,22 +1,21 @@ -use crate::{DekuError, DekuRead, DekuWrite}; -use bitvec::prelude::*; use std::borrow::{Borrow, Cow}; +use bitvec::prelude::*; + +use crate::{DekuError, DekuRead, DekuWrite}; + impl<'a, T, Ctx> DekuRead<'a, Ctx> for Cow<'a, T> where T: DekuRead<'a, Ctx> + Clone, Ctx: Copy, { /// Read a T from input and store as Cow - fn read( - input: &'a BitSlice, - inner_ctx: Ctx, - ) -> Result<(&'a BitSlice, Self), DekuError> + fn read(input: &'a BitSlice, inner_ctx: Ctx) -> Result<(usize, Self), DekuError> where Self: Sized, { - let (rest, val) = ::read(input, inner_ctx)?; - Ok((rest, Cow::Owned(val))) + let (amt_read, val) = ::read(input, inner_ctx)?; + Ok((amt_read, Cow::Owned(val))) } } @@ -33,9 +32,10 @@ where #[cfg(test)] mod tests { + use rstest::rstest; + use super::*; use crate::native_endian; - use rstest::rstest; #[rstest(input, expected, expected_rest, case( @@ -46,9 +46,9 @@ mod tests { )] fn test_cow(input: &[u8], expected: Cow, expected_rest: &BitSlice) { let bit_slice = input.view_bits::(); - let (rest, res_read) = >::read(bit_slice, ()).unwrap(); + let (amt_read, res_read) = >::read(bit_slice, ()).unwrap(); assert_eq!(expected, res_read); - assert_eq!(expected_rest, rest); + assert_eq!(expected_rest, bit_slice[amt_read..]); let mut res_write = bitvec![u8, Msb0;]; res_read.write(&mut res_write, ()).unwrap(); diff --git a/src/impls/cstring.rs b/src/impls/cstring.rs index 692394fe..cddd943f 100644 --- a/src/impls/cstring.rs +++ b/src/impls/cstring.rs @@ -1,7 +1,10 @@ -use crate::{ctx::*, DekuError, DekuRead, DekuWrite}; -use bitvec::prelude::*; use std::ffi::CString; +use bitvec::prelude::*; + +use crate::ctx::*; +use crate::{DekuError, DekuRead, DekuWrite}; + impl DekuWrite for CString where u8: DekuWrite, @@ -16,14 +19,11 @@ impl<'a, Ctx: Copy> DekuRead<'a, Ctx> for CString where u8: DekuRead<'a, Ctx>, { - fn read( - input: &'a BitSlice, - ctx: Ctx, - ) -> Result<(&'a BitSlice, Self), DekuError> + fn read(input: &'a BitSlice, ctx: Ctx) -> Result<(usize, Self), DekuError> where Self: Sized, { - let (rest, mut bytes) = Vec::read(input, (Limit::from(|b: &u8| *b == 0x00), ctx))?; + let (amt_read, mut bytes) = Vec::read(input, (Limit::from(|b: &u8| *b == 0x00), ctx))?; // TODO: use from_vec_with_nul instead once stable @@ -36,15 +36,16 @@ where let value = CString::new(bytes) .map_err(|e| DekuError::Parse(format!("Failed to convert Vec to CString: {e}")))?; - Ok((rest, value)) + Ok((amt_read, value)) } } #[cfg(test)] mod tests { - use super::*; use rstest::rstest; + use super::*; + #[rstest(input, expected, expected_rest, case( &[b't', b'e', b's', b't', b'\0'], @@ -62,9 +63,9 @@ mod tests { )] fn test_cstring(input: &[u8], expected: CString, expected_rest: &BitSlice) { let bit_slice = input.view_bits::(); - let (rest, res_read) = CString::read(bit_slice, ()).unwrap(); + let (amt_read, res_read) = CString::read(bit_slice, ()).unwrap(); assert_eq!(expected, res_read); - assert_eq!(expected_rest, rest); + assert_eq!(expected_rest, bit_slice[amt_read..]); let mut res_write = bitvec![u8, Msb0;]; res_read.write(&mut res_write, ()).unwrap(); diff --git a/src/impls/hashmap.rs b/src/impls/hashmap.rs index 4a632755..07ba2601 100644 --- a/src/impls/hashmap.rs +++ b/src/impls/hashmap.rs @@ -1,8 +1,11 @@ -use crate::{ctx::*, DekuError, DekuRead, DekuWrite}; -use bitvec::prelude::*; use std::collections::HashMap; use std::hash::{BuildHasher, Hash}; +use bitvec::prelude::*; + +use crate::ctx::*; +use crate::{DekuError, DekuRead, DekuWrite}; + /// Read `K, V`s into a hashmap until a given predicate returns true /// * `capacity` - an optional capacity to pre-allocate the hashmap with /// * `ctx` - The context required by `K, V`. It will be passed to every `K, V` when constructing. @@ -11,45 +14,47 @@ use std::hash::{BuildHasher, Hash}; /// and a borrow of the latest value to have been read. It should return `true` if reading /// should now stop, and `false` otherwise #[allow(clippy::type_complexity)] -fn read_hashmap_with_predicate< - 'a, +fn read_hashmap_with_predicate<'a, K, V, S, Ctx, Predicate>( + input: &'a BitSlice, + capacity: Option, + ctx: Ctx, + mut predicate: Predicate, +) -> Result<(usize, HashMap), DekuError> +where K: DekuRead<'a, Ctx> + Eq + Hash, V: DekuRead<'a, Ctx>, S: BuildHasher + Default, Ctx: Copy, Predicate: FnMut(usize, &(K, V)) -> bool, ->( - input: &'a BitSlice, - capacity: Option, - ctx: Ctx, - mut predicate: Predicate, -) -> Result<(&'a BitSlice, HashMap), DekuError> { +{ let mut res = HashMap::with_capacity_and_hasher(capacity.unwrap_or(0), S::default()); let mut rest = input; let mut found_predicate = false; + let mut total_read = 0; + while !found_predicate { - let (new_rest, kv) = <(K, V)>::read(rest, ctx)?; + let (amt_read, kv) = <(K, V)>::read(rest, ctx)?; + rest = &rest[amt_read..]; found_predicate = predicate( - unsafe { new_rest.as_bitptr().offset_from(input.as_bitptr()) } as usize, + unsafe { rest.as_bitptr().offset_from(input.as_bitptr()) } as usize, &kv, ); res.insert(kv.0, kv.1); - rest = new_rest; + total_read += amt_read; } - Ok((rest, res)) + Ok((total_read, res)) } -impl< - 'a, - K: DekuRead<'a, Ctx> + Eq + Hash, - V: DekuRead<'a, Ctx>, - S: BuildHasher + Default, - Ctx: Copy, - Predicate: FnMut(&(K, V)) -> bool, - > DekuRead<'a, (Limit<(K, V), Predicate>, Ctx)> for HashMap +impl<'a, K, V, S, Ctx, Predicate> DekuRead<'a, (Limit<(K, V), Predicate>, Ctx)> for HashMap +where + K: DekuRead<'a, Ctx> + Eq + Hash, + V: DekuRead<'a, Ctx>, + S: BuildHasher + Default, + Ctx: Copy, + Predicate: FnMut(&(K, V)) -> bool, { /// Read `K, V`s until the given limit /// * `limit` - the limiting factor on the amount of `K, V`s to read @@ -61,8 +66,9 @@ impl< /// # use deku::bitvec::BitView; /// # use std::collections::HashMap; /// let input: Vec = vec![100, 1, 2, 3, 4]; - /// let (rest, map) = HashMap::::read(input.view_bits(), (1.into(), Endian::Little)).unwrap(); - /// assert!(rest.is_empty()); + /// let (amt_read, map) = + /// HashMap::::read(input.view_bits(), (1.into(), Endian::Little)).unwrap(); + /// assert_eq!((amt_read / 8), 5); /// let mut expected = HashMap::::default(); /// expected.insert(100, 0x04030201); /// assert_eq!(expected, map) @@ -70,7 +76,7 @@ impl< fn read( input: &'a BitSlice, (limit, inner_ctx): (Limit<(K, V), Predicate>, Ctx), - ) -> Result<(&'a BitSlice, Self), DekuError> + ) -> Result<(usize, Self), DekuError> where Self: Sized, { @@ -79,7 +85,7 @@ impl< Limit::Count(mut count) => { // Handle the trivial case of reading an empty hashmap if count == 0 { - return Ok((input, HashMap::::default())); + return Ok((0, HashMap::::default())); } // Otherwise, read until we have read `count` elements @@ -102,7 +108,7 @@ impl< }) } - // Read until a given quantity of bits have been read + // Read until a given quantity of byte bits have been read Limit::ByteSize(size) => { let bit_size = size.0 * 8; read_hashmap_with_predicate(input, None, inner_ctx, move |read_bits, _| { @@ -113,19 +119,18 @@ impl< } } -impl< - 'a, - K: DekuRead<'a> + Eq + Hash, - V: DekuRead<'a>, - S: BuildHasher + Default, - Predicate: FnMut(&(K, V)) -> bool, - > DekuRead<'a, Limit<(K, V), Predicate>> for HashMap +impl<'a, K, V, S, Predicate> DekuRead<'a, Limit<(K, V), Predicate>> for HashMap +where + K: DekuRead<'a> + Eq + Hash, + V: DekuRead<'a>, + S: BuildHasher + Default, + Predicate: FnMut(&(K, V)) -> bool, { /// Read `K, V`s until the given limit from input for types which don't require context. fn read( input: &'a BitSlice, limit: Limit<(K, V), Predicate>, - ) -> Result<(&'a BitSlice, Self), DekuError> + ) -> Result<(usize, Self), DekuError> where Self: Sized, { @@ -161,10 +166,11 @@ impl, V: DekuWrite, S, Ctx: Copy> DekuWrite for Hash #[cfg(test)] mod tests { - use super::*; use rstest::rstest; use rustc_hash::FxHashMap; + use super::*; + // Macro to create a deterministic HashMap for tests // This is needed for tests since the default HashMap Hasher // RandomState will Hash the keys different for each run of the test cases @@ -212,7 +218,7 @@ mod tests { ) { let bit_slice = input.view_bits::(); - let (rest, res_read) = match bit_size { + let (amt_read, res_read) = match bit_size { Some(bit_size) => { FxHashMap::::read(bit_slice, (limit, (endian, BitSize(bit_size)))).unwrap() } @@ -220,7 +226,7 @@ mod tests { }; assert_eq!(expected, res_read); - assert_eq!(expected_rest, rest); + assert_eq!(expected_rest, bit_slice[amt_read..]); } #[rstest(input, endian, expected, @@ -251,9 +257,9 @@ mod tests { ) { let bit_slice = input.view_bits::(); - let (rest, res_read) = FxHashMap::::read(bit_slice, (limit, endian)).unwrap(); + let (amt_read, res_read) = FxHashMap::::read(bit_slice, (limit, endian)).unwrap(); assert_eq!(expected, res_read); - assert_eq!(expected_rest, rest); + assert_eq!(expected_rest, bit_slice[amt_read..]); let mut res_write = bitvec![u8, Msb0;]; res_read.write(&mut res_write, endian).unwrap(); diff --git a/src/impls/hashset.rs b/src/impls/hashset.rs index eb21532e..d3333373 100644 --- a/src/impls/hashset.rs +++ b/src/impls/hashset.rs @@ -1,8 +1,11 @@ -use crate::{ctx::*, DekuError, DekuRead, DekuWrite}; -use bitvec::prelude::*; use std::collections::HashSet; use std::hash::{BuildHasher, Hash}; +use bitvec::prelude::*; + +use crate::ctx::*; +use crate::{DekuError, DekuRead, DekuWrite}; + /// Read `T`s into a hashset until a given predicate returns true /// * `capacity` - an optional capacity to pre-allocate the hashset with /// * `ctx` - The context required by `T`. It will be passed to every `T` when constructing. @@ -11,43 +14,44 @@ use std::hash::{BuildHasher, Hash}; /// and a borrow of the latest value to have been read. It should return `true` if reading /// should now stop, and `false` otherwise #[allow(clippy::type_complexity)] -fn read_hashset_with_predicate< - 'a, - T: DekuRead<'a, Ctx> + Eq + Hash, - S: BuildHasher + Default, - Ctx: Copy, - Predicate: FnMut(usize, &T) -> bool, ->( +fn read_hashset_with_predicate<'a, T, S, Ctx, Predicate>( input: &'a BitSlice, capacity: Option, ctx: Ctx, mut predicate: Predicate, -) -> Result<(&'a BitSlice, HashSet), DekuError> { +) -> Result<(usize, HashSet), DekuError> +where + T: DekuRead<'a, Ctx> + Eq + Hash, + S: BuildHasher + Default, + Ctx: Copy, + Predicate: FnMut(usize, &T) -> bool, +{ let mut res = HashSet::with_capacity_and_hasher(capacity.unwrap_or(0), S::default()); let mut rest = input; let mut found_predicate = false; + let mut total_read = 0; while !found_predicate { - let (new_rest, val) = ::read(rest, ctx)?; + let (amt_read, val) = ::read(rest, ctx)?; + rest = &rest[amt_read..]; found_predicate = predicate( - unsafe { new_rest.as_bitptr().offset_from(input.as_bitptr()) } as usize, + unsafe { rest.as_bitptr().offset_from(input.as_bitptr()) } as usize, &val, ); res.insert(val); - rest = new_rest; + total_read += amt_read; } - Ok((rest, res)) + Ok((total_read, res)) } -impl< - 'a, - T: DekuRead<'a, Ctx> + Eq + Hash, - S: BuildHasher + Default, - Ctx: Copy, - Predicate: FnMut(&T) -> bool, - > DekuRead<'a, (Limit, Ctx)> for HashSet +impl<'a, T, S, Ctx, Predicate> DekuRead<'a, (Limit, Ctx)> for HashSet +where + T: DekuRead<'a, Ctx> + Eq + Hash, + S: BuildHasher + Default, + Ctx: Copy, + Predicate: FnMut(&T) -> bool, { /// Read `T`s until the given limit /// * `limit` - the limiting factor on the amount of `T`s to read @@ -60,14 +64,15 @@ impl< /// # use std::collections::HashSet; /// let input = vec![1u8, 2, 3, 4]; /// let expected: HashSet = vec![0x04030201].into_iter().collect(); - /// let (rest, set) = HashSet::::read(input.view_bits(), (1.into(), Endian::Little)).unwrap(); - /// assert!(rest.is_empty()); + /// let (amt_read, set) = + /// HashSet::::read(input.view_bits(), (1.into(), Endian::Little)).unwrap(); + /// assert_eq!(amt_read, 32); /// assert_eq!(expected, set) /// ``` fn read( input: &'a BitSlice, (limit, inner_ctx): (Limit, Ctx), - ) -> Result<(&'a BitSlice, Self), DekuError> + ) -> Result<(usize, Self), DekuError> where Self: Sized, { @@ -76,7 +81,7 @@ impl< Limit::Count(mut count) => { // Handle the trivial case of reading an empty hashset if count == 0 { - return Ok((input, HashSet::::default())); + return Ok((0, HashSet::::default())); } // Otherwise, read until we have read `count` elements @@ -119,7 +124,7 @@ impl<'a, T: DekuRead<'a> + Eq + Hash, S: BuildHasher + Default, Predicate: FnMut fn read( input: &'a BitSlice, limit: Limit, - ) -> Result<(&'a BitSlice, Self), DekuError> + ) -> Result<(usize, Self), DekuError> where Self: Sized, { @@ -153,10 +158,11 @@ impl, S, Ctx: Copy> DekuWrite for HashSet { #[cfg(test)] mod tests { - use super::*; use rstest::rstest; use rustc_hash::FxHashSet; + use super::*; + #[rstest(input, endian, bit_size, limit, expected, expected_rest, case::count_0([0xAA].as_ref(), Endian::Little, Some(8), 0.into(), FxHashSet::default(), bits![u8, Msb0; 1, 0, 1, 0, 1, 0, 1, 0]), case::count_1([0xAA, 0xBB].as_ref(), Endian::Little, Some(8), 1.into(), vec![0xAA].into_iter().collect(), bits![u8, Msb0; 1, 0, 1, 1, 1, 0, 1, 1]), @@ -187,7 +193,7 @@ mod tests { ) { let bit_slice = input.view_bits::(); - let (rest, res_read) = match bit_size { + let (amt_read, res_read) = match bit_size { Some(bit_size) => { FxHashSet::::read(bit_slice, (limit, (endian, BitSize(bit_size)))).unwrap() } @@ -195,7 +201,7 @@ mod tests { }; assert_eq!(expected, res_read); - assert_eq!(expected_rest, rest); + assert_eq!(expected_rest, bit_slice[amt_read..]); } #[rstest(input, endian, expected, @@ -230,10 +236,10 @@ mod tests { // Unwrap here because all test cases are `Some`. let bit_size = bit_size.unwrap(); - let (rest, res_read) = + let (amt_read, res_read) = FxHashSet::::read(bit_slice, (limit, (endian, BitSize(bit_size)))).unwrap(); assert_eq!(expected, res_read); - assert_eq!(expected_rest, rest); + assert_eq!(expected_rest, bit_slice[amt_read..]); let mut res_write = bitvec![u8, Msb0;]; res_read diff --git a/src/impls/ipaddr.rs b/src/impls/ipaddr.rs index 304ac8fd..63cc1882 100644 --- a/src/impls/ipaddr.rs +++ b/src/impls/ipaddr.rs @@ -1,20 +1,19 @@ -use crate::{DekuError, DekuRead, DekuWrite}; -use bitvec::prelude::*; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; +use bitvec::prelude::*; + +use crate::{DekuError, DekuRead, DekuWrite}; + impl<'a, Ctx> DekuRead<'a, Ctx> for Ipv4Addr where u32: DekuRead<'a, Ctx>, { - fn read( - input: &'a BitSlice, - ctx: Ctx, - ) -> Result<(&'a BitSlice, Self), DekuError> + fn read(input: &'a BitSlice, ctx: Ctx) -> Result<(usize, Self), DekuError> where Self: Sized, { - let (rest, ip) = u32::read(input, ctx)?; - Ok((rest, ip.into())) + let (amt_read, ip) = u32::read(input, ctx)?; + Ok((amt_read, ip.into())) } } @@ -32,15 +31,12 @@ impl<'a, Ctx> DekuRead<'a, Ctx> for Ipv6Addr where u128: DekuRead<'a, Ctx>, { - fn read( - input: &'a BitSlice, - ctx: Ctx, - ) -> Result<(&'a BitSlice, Self), DekuError> + fn read(input: &'a BitSlice, ctx: Ctx) -> Result<(usize, Self), DekuError> where Self: Sized, { - let (rest, ip) = u128::read(input, ctx)?; - Ok((rest, ip.into())) + let (amt_read, ip) = u128::read(input, ctx)?; + Ok((amt_read, ip.into())) } } @@ -69,9 +65,10 @@ where #[cfg(test)] mod tests { + use rstest::rstest; + use super::*; use crate::ctx::Endian; - use rstest::rstest; #[rstest(input, endian, expected, expected_rest, case::normal_le([237, 160, 254, 145].as_ref(), Endian::Little, Ipv4Addr::new(145, 254, 160, 237), bits![u8, Msb0;]), @@ -85,9 +82,9 @@ mod tests { ) { let bit_slice = input.view_bits::(); - let (rest, res_read) = Ipv4Addr::read(bit_slice, endian).unwrap(); + let (amt_read, res_read) = Ipv4Addr::read(bit_slice, endian).unwrap(); assert_eq!(expected, res_read); - assert_eq!(expected_rest, rest); + assert_eq!(expected_rest, bit_slice[amt_read..]); let mut res_write = bitvec![u8, Msb0;]; res_read.write(&mut res_write, endian).unwrap(); @@ -106,9 +103,9 @@ mod tests { ) { let bit_slice = input.view_bits::(); - let (rest, res_read) = Ipv6Addr::read(bit_slice, endian).unwrap(); + let (amt_read, res_read) = Ipv6Addr::read(bit_slice, endian).unwrap(); assert_eq!(expected, res_read); - assert_eq!(expected_rest, rest); + assert_eq!(expected_rest, bit_slice[amt_read..]); let mut res_write = bitvec![u8, Msb0;]; res_read.write(&mut res_write, endian).unwrap(); @@ -127,7 +124,7 @@ mod tests { ip_addr.write(&mut ret_write, Endian::Little).unwrap(); assert_eq!( vec![ - 0xFF, 0x02, 0x0A, 0xC0, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0x02, 0x0a, 0xc0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ], ret_write.into_vec() diff --git a/src/impls/nonzero.rs b/src/impls/nonzero.rs index 33a5c2bf..d0e3f7ff 100644 --- a/src/impls/nonzero.rs +++ b/src/impls/nonzero.rs @@ -1,9 +1,11 @@ -use crate::{ctx::*, DekuError, DekuRead, DekuWrite}; -use bitvec::prelude::*; -use core::num::*; - #[cfg(feature = "alloc")] use alloc::format; +use core::num::*; + +use bitvec::prelude::*; + +use crate::ctx::*; +use crate::{DekuError, DekuRead, DekuWrite}; macro_rules! ImplDekuTraitsCtx { ($typ:ty, $readtype:ty, $ctx_arg:tt, $ctx_type:tt) => { @@ -11,16 +13,16 @@ macro_rules! ImplDekuTraitsCtx { fn read( input: &BitSlice, $ctx_arg: $ctx_type, - ) -> Result<(&BitSlice, Self), DekuError> + ) -> Result<(usize, Self), DekuError> where Self: Sized, { - let (rest, value) = <$readtype>::read(input, $ctx_arg)?; + let (amt_read, value) = <$readtype>::read(input, $ctx_arg)?; let value = <$typ>::new(value); match value { None => Err(DekuError::Parse(format!("NonZero assertion"))), - Some(v) => Ok((rest, v)), + Some(v) => Ok((amt_read, v)), } } } @@ -62,10 +64,11 @@ ImplDekuTraits!(NonZeroIsize, isize); #[cfg(test)] mod tests { - use super::*; use hexlit::hex; use rstest::rstest; + use super::*; + #[rstest(input, expected, case(&hex!("FF"), NonZeroU8::new(0xFF).unwrap()), @@ -74,9 +77,9 @@ mod tests { )] fn test_non_zero(input: &[u8], expected: NonZeroU8) { let bit_slice = input.view_bits::(); - let (rest, res_read) = NonZeroU8::read(bit_slice, ()).unwrap(); + let (amt_read, res_read) = NonZeroU8::read(bit_slice, ()).unwrap(); assert_eq!(expected, res_read); - assert!(rest.is_empty()); + assert!(bit_slice[amt_read..].is_empty()); let mut res_write = bitvec![u8, Msb0;]; res_read.write(&mut res_write, ()).unwrap(); diff --git a/src/impls/option.rs b/src/impls/option.rs index 24096071..a747b7c3 100644 --- a/src/impls/option.rs +++ b/src/impls/option.rs @@ -1,6 +1,7 @@ -use crate::{DekuError, DekuRead, DekuWrite}; use bitvec::prelude::*; +use crate::{DekuError, DekuRead, DekuWrite}; + impl<'a, T: DekuRead<'a, Ctx>, Ctx: Copy> DekuRead<'a, Ctx> for Option { /// Read a T from input and store as Some(T) /// * `inner_ctx` - The context required by `T`. It will be passed to every `T`s when constructing. @@ -10,19 +11,16 @@ impl<'a, T: DekuRead<'a, Ctx>, Ctx: Copy> DekuRead<'a, Ctx> for Option { /// # use deku::DekuRead; /// # use deku::bitvec::BitView; /// let input = vec![1u8, 2, 3, 4]; - /// let (rest, v) = Option::::read(input.view_bits(), Endian::Little).unwrap(); - /// assert!(rest.is_empty()); + /// let (amt_read, v) = Option::::read(input.view_bits(), Endian::Little).unwrap(); + /// assert_eq!(amt_read, 32); /// assert_eq!(v, Some(0x04030201)) /// ``` - fn read( - input: &'a BitSlice, - inner_ctx: Ctx, - ) -> Result<(&'a BitSlice, Self), DekuError> + fn read(input: &'a BitSlice, inner_ctx: Ctx) -> Result<(usize, Self), DekuError> where Self: Sized, { - let (rest, val) = ::read(input, inner_ctx)?; - Ok((rest, Some(val))) + let (amt_read, val) = ::read(input, inner_ctx)?; + Ok((amt_read, Some(val))) } } diff --git a/src/impls/primitive.rs b/src/impls/primitive.rs index 8dfdfd0d..7168b8ee 100644 --- a/src/impls/primitive.rs +++ b/src/impls/primitive.rs @@ -1,28 +1,27 @@ -use crate::{ctx::*, DekuError, DekuRead, DekuWrite}; -use bitvec::prelude::*; -use core::convert::TryInto; - #[cfg(feature = "alloc")] use alloc::format; +use core::convert::TryInto; + +use bitvec::prelude::*; + +use crate::ctx::*; +use crate::prelude::NeedSize; +use crate::{DekuError, DekuRead, DekuWrite}; // specialize u8 for ByteSize impl DekuRead<'_, (Endian, ByteSize)> for u8 { fn read( input: &BitSlice, (_, _): (Endian, ByteSize), - ) -> Result<(&BitSlice, Self), DekuError> { + ) -> Result<(usize, Self), DekuError> { const MAX_TYPE_BITS: usize = BitSize::of::().0; if input.len() < MAX_TYPE_BITS { - return Err(DekuError::Incomplete(crate::error::NeedSize::new( - MAX_TYPE_BITS, - ))); + return Err(DekuError::Incomplete(NeedSize::new(MAX_TYPE_BITS))); } - // SAFETY: We already check that input.len() < bit_size above - let (bit_slice, rest) = unsafe { input.split_at_unchecked(MAX_TYPE_BITS) }; - - let value = bit_slice.load::(); - Ok((rest, value)) + // PANIC: We already check that input.len() < bit_size above, so no panic will happen + let value = input[..MAX_TYPE_BITS].load::(); + Ok((MAX_TYPE_BITS, value)) } } @@ -32,7 +31,7 @@ macro_rules! ImplDekuReadBits { fn read( input: &BitSlice, (endian, size): (Endian, BitSize), - ) -> Result<(&BitSlice, Self), DekuError> { + ) -> Result<(usize, Self), DekuError> { const MAX_TYPE_BITS: usize = BitSize::of::<$typ>().0; let bit_size: usize = size.0; @@ -48,7 +47,8 @@ macro_rules! ImplDekuReadBits { return Err(DekuError::Incomplete(crate::error::NeedSize::new(bit_size))); } - let (bit_slice, rest) = input.split_at(bit_size); + // PANIC: We already check that input.len() < bit_size above, so no panic will happen + let bit_slice = &input[..bit_size]; let pad = 8 * ((bit_slice.len() + 7) / 8) - bit_slice.len(); @@ -63,53 +63,53 @@ macro_rules! ImplDekuReadBits { } else { <$typ>::from_be_bytes(bytes.try_into()?) }; - return Ok((rest, value)); + return Ok((bit_size, value)); } } - // Create a new BitVec from the slice and pad un-aligned chunks - // i.e. [10010110, 1110] -> [10010110, 00001110] - let bits: BitVec = { - let mut bits = BitVec::with_capacity(bit_slice.len() + pad); + // Create a new BitVec from the slice and pad un-aligned chunks + // i.e. [10010110, 1110] -> [10010110, 00001110] + let bits: BitVec = { + let mut bits = BitVec::with_capacity(bit_slice.len() + pad); - // Copy bits to new BitVec - bits.extend_from_bitslice(bit_slice); + // Copy bits to new BitVec + bits.extend_from_bitslice(&bit_slice); - // Force align - //i.e. [1110, 10010110] -> [11101001, 0110] - bits.force_align(); + // Force align + //i.e. [1110, 10010110] -> [11101001, 0110] + bits.force_align(); - // Some padding to next byte - let index = if input_is_le { - bits.len() - (8 - pad) - } else { - 0 - }; - for _ in 0..pad { - bits.insert(index, false); - } + // Some padding to next byte + let index = if input_is_le { + bits.len() - (8 - pad) + } else { + 0 + }; + for _ in 0..pad { + bits.insert(index, false); + } - // Pad up-to size of type - for _ in 0..(MAX_TYPE_BITS - bits.len()) { - if input_is_le { - bits.push(false); - } else { - bits.insert(0, false); - } + // Pad up-to size of type + for _ in 0..(MAX_TYPE_BITS - bits.len()) { + if input_is_le { + bits.push(false); + } else { + bits.insert(0, false); } + } - bits - }; + bits + }; - let bytes: &[u8] = bits.domain().region().unwrap().1; + let bytes: &[u8] = bits.domain().region().unwrap().1; - // Read value - let value = if input_is_le { - <$typ>::from_le_bytes(bytes.try_into()?) - } else { - <$typ>::from_be_bytes(bytes.try_into()?) - }; - Ok((rest, value)) + // Read value + let value = if input_is_le { + <$typ>::from_le_bytes(bytes.try_into()?) + } else { + <$typ>::from_be_bytes(bytes.try_into()?) + }; + Ok((bit_size, value)) } } }; @@ -121,7 +121,7 @@ macro_rules! ImplDekuReadBytes { fn read( input: &BitSlice, (endian, size): (Endian, ByteSize), - ) -> Result<(&BitSlice, Self), DekuError> { + ) -> Result<(usize, Self), DekuError> { const MAX_TYPE_BITS: usize = BitSize::of::<$typ>().0; let bit_size: usize = size.0 * 8; @@ -137,7 +137,7 @@ macro_rules! ImplDekuReadBytes { return Err(DekuError::Incomplete(crate::error::NeedSize::new(bit_size))); } - let (bit_slice, rest) = input.split_at(bit_size); + let bit_slice = &input[..bit_size]; let pad = 8 * ((bit_slice.len() + 7) / 8) - bit_slice.len(); @@ -156,7 +156,7 @@ macro_rules! ImplDekuReadBytes { let mut bits: BitVec = BitVec::with_capacity(bit_slice.len() + pad); // Copy bits to new BitVec - bits.extend_from_bitslice(bit_slice); + bits.extend_from_bitslice(&bit_slice); // Force align //i.e. [1110, 10010110] -> [11101001, 0110] @@ -180,7 +180,7 @@ macro_rules! ImplDekuReadBytes { res as $typ }; - Ok((rest, value)) + Ok((bit_size, value)) } } }; @@ -192,30 +192,30 @@ macro_rules! ImplDekuReadSignExtend { fn read( input: &BitSlice, (endian, size): (Endian, ByteSize), - ) -> Result<(&BitSlice, Self), DekuError> { - let (rest, value) = + ) -> Result<(usize, Self), DekuError> { + let (amt_read, value) = <$inner as DekuRead<'_, (Endian, ByteSize)>>::read(input, (endian, size))?; const MAX_TYPE_BITS: usize = BitSize::of::<$typ>().0; let bit_size = size.0 * 8; let shift = MAX_TYPE_BITS - bit_size; let value = (value as $typ) << shift >> shift; - Ok((rest, value)) + Ok((amt_read, value)) } } impl DekuRead<'_, (Endian, BitSize)> for $typ { fn read( input: &BitSlice, (endian, size): (Endian, BitSize), - ) -> Result<(&BitSlice, Self), DekuError> { - let (rest, value) = + ) -> Result<(usize, Self), DekuError> { + let (amt_read, value) = <$inner as DekuRead<'_, (Endian, BitSize)>>::read(input, (endian, size))?; const MAX_TYPE_BITS: usize = BitSize::of::<$typ>().0; let bit_size = size.0; let shift = MAX_TYPE_BITS - bit_size; let value = (value as $typ) << shift >> shift; - Ok((rest, value)) + Ok((amt_read, value)) } } }; @@ -228,7 +228,7 @@ macro_rules! ForwardDekuRead { fn read( input: &BitSlice, endian: Endian, - ) -> Result<(&BitSlice, Self), DekuError> { + ) -> Result<(usize, Self), DekuError> { let bit_size = BitSize::of::<$typ>(); // Since we don't have a #[bits] or [bytes], check if we can use bytes for perf @@ -245,7 +245,7 @@ macro_rules! ForwardDekuRead { fn read( input: &BitSlice, byte_size: ByteSize, - ) -> Result<(&BitSlice, Self), DekuError> { + ) -> Result<(usize, Self), DekuError> { let endian = Endian::default(); <$typ>::read(input, (endian, byte_size)) @@ -257,7 +257,7 @@ macro_rules! ForwardDekuRead { fn read( input: &BitSlice, bit_size: BitSize, - ) -> Result<(&BitSlice, Self), DekuError> { + ) -> Result<(usize, Self), DekuError> { let endian = Endian::default(); // check if we can use ByteSize for performance @@ -270,10 +270,7 @@ macro_rules! ForwardDekuRead { } impl DekuRead<'_> for $typ { - fn read( - input: &BitSlice, - _: (), - ) -> Result<(&BitSlice, Self), DekuError> { + fn read(input: &BitSlice, _: ()) -> Result<(usize, Self), DekuError> { <$typ>::read(input, Endian::default()) } } @@ -483,9 +480,10 @@ ImplDekuTraitsBytes!(f64, u64); #[cfg(test)] mod tests { + use rstest::rstest; + use super::*; use crate::native_endian; - use rstest::rstest; static ENDIAN: Endian = Endian::new(); @@ -505,87 +503,87 @@ mod tests { }; } - TestPrimitive!(test_u8, u8, vec![0xAAu8], 0xAAu8); + TestPrimitive!(test_u8, u8, vec![0xaau8], 0xaau8); TestPrimitive!( test_u16, u16, - vec![0xABu8, 0xCD], - native_endian!(0xCDAB_u16) + vec![0xabu8, 0xcd], + native_endian!(0xcdab_u16) ); TestPrimitive!( test_u32, u32, - vec![0xABu8, 0xCD, 0xEF, 0xBE], - native_endian!(0xBEEFCDAB_u32) + vec![0xabu8, 0xcd, 0xef, 0xbe], + native_endian!(0xbeefcdab_u32) ); TestPrimitive!( test_u64, u64, - vec![0xABu8, 0xCD, 0xEF, 0xBE, 0xAB, 0xCD, 0xFE, 0xC0], - native_endian!(0xC0FECDABBEEFCDAB_u64) + vec![0xabu8, 0xcd, 0xef, 0xbe, 0xab, 0xcd, 0xfe, 0xc0], + native_endian!(0xc0fecdabbeefcdab_u64) ); TestPrimitive!( test_u128, u128, vec![ - 0xABu8, 0xCD, 0xEF, 0xBE, 0xAB, 0xCD, 0xFE, 0xC0, 0xAB, 0xCD, 0xEF, 0xBE, 0xAB, 0xCD, - 0xFE, 0xC0 + 0xabu8, 0xcd, 0xef, 0xbe, 0xab, 0xcd, 0xfe, 0xc0, 0xab, 0xcd, 0xef, 0xbe, 0xab, 0xcd, + 0xfe, 0xc0 ], - native_endian!(0xC0FECDABBEEFCDABC0FECDABBEEFCDAB_u128) + native_endian!(0xc0fecdabbeefcdabc0fecdabbeefcdab_u128) ); TestPrimitive!( test_usize, usize, - vec![0xABu8, 0xCD, 0xEF, 0xBE, 0xAB, 0xCD, 0xFE, 0xC0], + vec![0xabu8, 0xcd, 0xef, 0xbe, 0xab, 0xcd, 0xfe, 0xc0], if core::mem::size_of::() == 8 { - native_endian!(0xC0FECDABBEEFCDAB_usize) + native_endian!(0xc0fecdabbeefcdab_usize) } else { - native_endian!(0xBEEFCDAB_usize) + native_endian!(0xbeefcdab_usize) } ); - TestPrimitive!(test_i8, i8, vec![0xFBu8], -5); - TestPrimitive!(test_i16, i16, vec![0xFDu8, 0xFE], native_endian!(-259_i16)); + TestPrimitive!(test_i8, i8, vec![0xfbu8], -5); + TestPrimitive!(test_i16, i16, vec![0xfdu8, 0xfe], native_endian!(-259_i16)); TestPrimitive!( test_i32, i32, - vec![0x02u8, 0x3F, 0x01, 0xEF], - native_endian!(-0x10FEC0FE_i32) + vec![0x02u8, 0x3f, 0x01, 0xef], + native_endian!(-0x10fec0fe_i32) ); TestPrimitive!( test_i64, i64, - vec![0x02u8, 0x3F, 0x01, 0xEF, 0x01, 0x3F, 0x01, 0xEF], - native_endian!(-0x10FEC0FE10FEC0FE_i64) + vec![0x02u8, 0x3f, 0x01, 0xef, 0x01, 0x3f, 0x01, 0xef], + native_endian!(-0x10fec0fe10fec0fe_i64) ); TestPrimitive!( test_i128, i128, vec![ - 0x02u8, 0x3F, 0x01, 0xEF, 0x01, 0x3F, 0x01, 0xEF, 0x01, 0x3F, 0x01, 0xEF, 0x01, 0x3F, - 0x01, 0xEF + 0x02u8, 0x3f, 0x01, 0xef, 0x01, 0x3f, 0x01, 0xef, 0x01, 0x3f, 0x01, 0xef, 0x01, 0x3f, + 0x01, 0xef ], - native_endian!(-0x10FEC0FE10FEC0FE10FEC0FE10FEC0FE_i128) + native_endian!(-0x10fec0fe10fec0fe10fec0fe10fec0fe_i128) ); TestPrimitive!( test_isize, isize, - vec![0x02u8, 0x3F, 0x01, 0xEF, 0x01, 0x3F, 0x01, 0xEF], + vec![0x02u8, 0x3f, 0x01, 0xef, 0x01, 0x3f, 0x01, 0xef], if core::mem::size_of::() == 8 { - native_endian!(-0x10FEC0FE10FEC0FE_isize) + native_endian!(-0x10fec0fe10fec0fe_isize) } else { - native_endian!(-0x10FEC0FE_isize) + native_endian!(-0x10fec0fe_isize) } ); TestPrimitive!( test_f32, f32, - vec![0xA6u8, 0x9B, 0xC4, 0xBB], + vec![0xa6u8, 0x9b, 0xc4, 0xbb], native_endian!(-0.006_f32) ); TestPrimitive!( test_f64, f64, - vec![0xFAu8, 0x7E, 0x6A, 0xBC, 0x74, 0x93, 0x78, 0xBF], + vec![0xfau8, 0x7e, 0x6a, 0xbc, 0x74, 0x93, 0x78, 0xbf], native_endian!(-0.006_f64) ); @@ -610,13 +608,13 @@ mod tests { ) { let bit_slice = input.view_bits::(); - let (rest, res_read) = match bit_size { + let (amt_read, res_read) = match bit_size { Some(bit_size) => u32::read(bit_slice, (endian, BitSize(bit_size))).unwrap(), None => u32::read(bit_slice, endian).unwrap(), }; assert_eq!(expected, res_read); - assert_eq!(expected_rest, rest); + assert_eq!(expected_rest, bit_slice[amt_read..]); } #[rstest(input, endian, bit_size, expected, @@ -651,12 +649,12 @@ mod tests { ) { let bit_slice = input.view_bits::(); - let (rest, res_read) = match bit_size { + let (amt_read, res_read) = match bit_size { Some(bit_size) => u32::read(bit_slice, (endian, BitSize(bit_size))).unwrap(), None => u32::read(bit_slice, endian).unwrap(), }; assert_eq!(expected, res_read); - assert_eq!(expected_rest, rest); + assert_eq!(expected_rest, bit_slice[amt_read..]); let mut res_write = bitvec![u8, Msb0;]; match bit_size { @@ -675,10 +673,10 @@ mod tests { fn $test_name() { let bit_slice = [0b10101_000].view_bits::(); - let (rest, res_read) = <$typ>::read(bit_slice, (Endian::Little, BitSize(5))).unwrap(); + let (amt_read, res_read) = <$typ>::read(bit_slice, (Endian::Little, BitSize(5))).unwrap(); assert_eq!(-11, res_read); - assert_eq!(bits![u8, Msb0; 0, 0, 0], rest); + assert_eq!(bits![u8, Msb0; 0, 0, 0], bit_slice[amt_read..]); } }; } diff --git a/src/impls/slice.rs b/src/impls/slice.rs index bd01b090..8a92d4ae 100644 --- a/src/impls/slice.rs +++ b/src/impls/slice.rs @@ -1,29 +1,35 @@ //! Implementations of DekuRead and DekuWrite for [T; N] where 0 < N <= 32 -use crate::{ctx::Limit, DekuError, DekuRead, DekuWrite}; use bitvec::prelude::*; pub use deku_derive::*; +use crate::ctx::Limit; +use crate::{DekuError, DekuRead, DekuWrite}; + /// Read `u8`s and returns a byte slice up until a given predicate returns true /// * `ctx` - The context required by `u8`. It will be passed to every `u8` when constructing. /// * `predicate` - the predicate that decides when to stop reading `u8`s /// The predicate takes two parameters: the number of bits that have been read so far, /// and a borrow of the latest value to have been read. It should return `true` if reading /// should now stop, and `false` otherwise -fn read_slice_with_predicate<'a, Ctx: Copy, Predicate: FnMut(usize, &u8) -> bool>( +fn read_slice_with_predicate<'a, Ctx, Predicate>( input: &'a BitSlice, ctx: Ctx, mut predicate: Predicate, -) -> Result<(&'a BitSlice, &[u8]), DekuError> +) -> Result<(usize, &[u8]), DekuError> where u8: DekuRead<'a, Ctx>, + Ctx: Copy, + Predicate: FnMut(usize, &u8) -> bool, { let mut rest = input; let mut value; + let mut total_read = 0; loop { - let (new_rest, val) = u8::read(rest, ctx)?; - rest = new_rest; + let (amt_read, val) = u8::read(rest, ctx)?; + rest = &rest[amt_read..]; + total_read += amt_read; let read_idx = unsafe { rest.as_bitptr().offset_from(input.as_bitptr()) } as usize; value = input[..read_idx].domain().region().unwrap().1; @@ -33,13 +39,14 @@ where } } - Ok((rest, value)) + Ok((total_read, value)) } -impl<'a, Ctx: Copy, Predicate: FnMut(&u8) -> bool> DekuRead<'a, (Limit, Ctx)> - for &'a [u8] +impl<'a, Ctx, Predicate> DekuRead<'a, (Limit, Ctx)> for &'a [u8] where u8: DekuRead<'a, Ctx>, + Ctx: Copy, + Predicate: FnMut(&u8) -> bool, { /// Read `u8`s until the given limit /// * `limit` - the limiting factor on the amount of `u8`s to read @@ -50,20 +57,20 @@ where /// # use deku::DekuRead; /// # use bitvec::view::BitView; /// let input = vec![1u8, 2, 3, 4]; - /// let (rest, v) = <&[u8]>::read(input.view_bits(), (4.into(), Endian::Little)).unwrap(); - /// assert!(rest.is_empty()); + /// let (amt_read, v) = <&[u8]>::read(input.view_bits(), (4.into(), Endian::Little)).unwrap(); + /// assert_eq!(amt_read, 32); /// assert_eq!(&[1u8, 2, 3, 4], v) /// ``` fn read( input: &'a BitSlice, (limit, inner_ctx): (Limit, Ctx), - ) -> Result<(&'a BitSlice, Self), DekuError> { + ) -> Result<(usize, Self), DekuError> { match limit { // Read a given count of elements Limit::Count(mut count) => { // Handle the trivial case of reading an empty slice if count == 0 { - return Ok((input, &input.domain().region().unwrap().1[..0])); + return Ok((0, &input.domain().region().unwrap().1[..0])); } // Otherwise, read until we have read `count` elements @@ -124,19 +131,21 @@ mod pre_const_generics_impl { fn read( input: &'a BitSlice, ctx: Ctx, - ) -> Result<(&'a BitSlice, Self), DekuError> + ) -> Result<(usize, Self), DekuError> where Self: Sized, { let mut slice: [$typ; $count] = Default::default(); let mut rest = input; + let mut total_read = 0; for i in 0..$count { - let (new_rest, value) = <$typ>::read(rest, ctx)?; + let (amt_read, value) = <$typ>::read(rest, ctx)?; slice[i] = value; - rest = new_rest; + rest = new_rest[amt_read..]; + total_read += amt_read; } - Ok((rest, slice)) + Ok((total_read, slice)) } } @@ -173,18 +182,15 @@ mod pre_const_generics_impl { #[cfg(feature = "const_generics")] mod const_generics_impl { - use super::*; - use core::mem::MaybeUninit; + use super::*; + impl<'a, Ctx: Copy, T, const N: usize> DekuRead<'a, Ctx> for [T; N] where T: DekuRead<'a, Ctx>, { - fn read( - input: &'a BitSlice, - ctx: Ctx, - ) -> Result<(&'a BitSlice, Self), DekuError> + fn read(input: &'a BitSlice, ctx: Ctx) -> Result<(usize, Self), DekuError> where Self: Sized, { @@ -193,8 +199,9 @@ mod const_generics_impl { // and never return it in case of error let mut slice: [MaybeUninit; N] = unsafe { MaybeUninit::uninit().assume_init() }; let mut rest = input; + let mut total_read = 0; for (n, item) in slice.iter_mut().enumerate() { - let (new_rest, value) = match T::read(rest, ctx) { + let (amt_read, value) = match T::read(rest, ctx) { Ok(it) => it, Err(err) => { // For each item in the array, drop if we allocated it. @@ -207,13 +214,15 @@ mod const_generics_impl { } }; item.write(value); - rest = new_rest; + rest = &rest[amt_read..]; + total_read += amt_read; } - Ok((rest, unsafe { + let val = unsafe { // TODO: array_assume_init: https://github.com/rust-lang/rust/issues/80908 (&slice as *const _ as *const [T; N]).read() - })) + }; + Ok((total_read, val)) } } @@ -244,10 +253,10 @@ mod const_generics_impl { #[cfg(test)] mod tests { - use super::*; + use rstest::rstest; + use super::*; use crate::ctx::Endian; - use rstest::rstest; #[rstest(input,endian,expected,expected_rest, case::normal_le([0xDD, 0xCC, 0xBB, 0xAA].as_ref(), Endian::Little, [0xCCDD, 0xAABB], bits![u8, Msb0;]), @@ -261,9 +270,9 @@ mod tests { ) { let bit_slice = input.view_bits::(); - let (rest, res_read) = <[u16; 2]>::read(bit_slice, endian).unwrap(); + let (amt_read, res_read) = <[u16; 2]>::read(bit_slice, endian).unwrap(); assert_eq!(expected, res_read); - assert_eq!(expected_rest, rest); + assert_eq!(expected_rest, bit_slice[amt_read..]); } #[rstest(input,endian,expected, @@ -305,9 +314,9 @@ mod tests { ) { let bit_slice = input.view_bits::(); - let (rest, res_read) = <[[u16; 2]; 2]>::read(bit_slice, endian).unwrap(); + let (amt_read, res_read) = <[[u16; 2]; 2]>::read(bit_slice, endian).unwrap(); assert_eq!(expected, res_read); - assert_eq!(expected_rest, rest); + assert_eq!(expected_rest, bit_slice[amt_read..]); } #[cfg(feature = "const_generics")] diff --git a/src/impls/tuple.rs b/src/impls/tuple.rs index 9872c77d..da0fe5be 100644 --- a/src/impls/tuple.rs +++ b/src/impls/tuple.rs @@ -1,8 +1,9 @@ //! Implementations of DekuRead and DekuWrite for tuples of length 1 to 11 -use crate::{DekuError, DekuRead, DekuWrite}; use bitvec::prelude::*; +use crate::{DekuError, DekuRead, DekuWrite}; + // Trait to help us build intermediate tuples while DekuRead'ing each element // from the tuple trait Append { @@ -39,18 +40,21 @@ macro_rules! ImplDekuTupleTraits { fn read( input: &'a BitSlice, ctx: Ctx, - ) -> Result<(&'a BitSlice, Self), DekuError> + ) -> Result<(usize, Self), DekuError> where Self: Sized, { let tuple = (); - let mut rest = input; + let mut _rest = input; + let mut total_read = 0; $( - let read = <$T>::read(rest, ctx)?; - rest = read.0; - let tuple = tuple.append(read.1); + let (amt_read, val) = <$T>::read(_rest, ctx)?; + let tuple = tuple.append(val); + + total_read += amt_read; + _rest = &_rest[amt_read..]; )+ - Ok((rest, tuple)) + Ok((total_read, tuple)) } } @@ -82,12 +86,13 @@ ImplDekuTupleTraits! { A, B, C, D, E, F, G, H, I, J, K, } #[cfg(test)] mod tests { - use super::*; - use crate::native_endian; use core::fmt::Debug; use rstest::rstest; + use super::*; + use crate::native_endian; + #[rstest(input, expected, expected_rest, case::length_1([0xef, 0xbe, 0xad, 0xde].as_ref(), (native_endian!(0xdeadbeef_u32),), bits![u8, Msb0;]), case::length_2([1, 0x24, 0x98, 0x82, 0].as_ref(), (true, native_endian!(0x829824_u32)), bits![u8, Msb0;]), @@ -99,9 +104,9 @@ mod tests { T: DekuRead<'a> + Sized + PartialEq + Debug, { let bit_slice = input.view_bits::(); - let (rest, res_read) = ::read(bit_slice, ()).unwrap(); + let (amt_read, res_read) = ::read(bit_slice, ()).unwrap(); assert_eq!(expected, res_read); - assert_eq!(expected_rest, rest); + assert_eq!(expected_rest, bit_slice[amt_read..]); } #[rstest(input, expected, diff --git a/src/impls/unit.rs b/src/impls/unit.rs index 710f3d72..ea7d999b 100644 --- a/src/impls/unit.rs +++ b/src/impls/unit.rs @@ -1,16 +1,14 @@ -use crate::{DekuError, DekuRead, DekuWrite}; use bitvec::prelude::*; +use crate::{DekuError, DekuRead, DekuWrite}; + impl DekuRead<'_, Ctx> for () { /// NOP on read - fn read( - input: &BitSlice, - _inner_ctx: Ctx, - ) -> Result<(&BitSlice, Self), DekuError> + fn read(_input: &BitSlice, _inner_ctx: Ctx) -> Result<(usize, Self), DekuError> where Self: Sized, { - Ok((input, ())) + Ok((0, ())) } } @@ -23,9 +21,10 @@ impl DekuWrite for () { #[cfg(test)] mod tests { - use super::*; use hexlit::hex; + use super::*; + #[test] #[allow(clippy::unit_arg)] #[allow(clippy::unit_cmp)] @@ -33,9 +32,9 @@ mod tests { let input = &hex!("FF"); let bit_slice = input.view_bits::(); - let (rest, res_read) = <()>::read(bit_slice, ()).unwrap(); + let (amt_read, res_read) = <()>::read(bit_slice, ()).unwrap(); assert_eq!((), res_read); - assert_eq!(bit_slice, rest); + assert_eq!(amt_read, 0); let mut res_write = bitvec![u8, Msb0;]; res_read.write(&mut res_write, ()).unwrap(); diff --git a/src/impls/vec.rs b/src/impls/vec.rs index 7f158f4a..03c2bf70 100644 --- a/src/impls/vec.rs +++ b/src/impls/vec.rs @@ -1,9 +1,11 @@ -use crate::{ctx::*, DekuError, DekuRead, DekuWrite}; -use bitvec::prelude::*; - #[cfg(feature = "alloc")] use alloc::vec::Vec; +use bitvec::prelude::*; + +use crate::ctx::*; +use crate::{DekuError, DekuRead, DekuWrite}; + /// Read `T`s into a vec until a given predicate returns true /// * `capacity` - an optional capacity to pre-allocate the vector with /// * `ctx` - The context required by `T`. It will be passed to every `T` when constructing. @@ -11,25 +13,27 @@ use alloc::vec::Vec; /// The predicate takes two parameters: the number of bits that have been read so far, /// and a borrow of the latest value to have been read. It should return `true` if reading /// should now stop, and `false` otherwise -fn read_vec_with_predicate< - 'a, - T: DekuRead<'a, Ctx>, - Ctx: Copy, - Predicate: FnMut(usize, &T) -> bool, ->( +fn read_vec_with_predicate<'a, T, Ctx, Predicate>( input: &'a BitSlice, capacity: Option, ctx: Ctx, mut predicate: Predicate, -) -> Result<(&'a BitSlice, Vec), DekuError> { +) -> Result<(usize, Vec), DekuError> +where + T: DekuRead<'a, Ctx>, + Ctx: Copy, + Predicate: FnMut(usize, &T) -> bool, +{ let mut res = capacity.map_or_else(Vec::new, Vec::with_capacity); let mut rest = input; + let mut total_read = 0; loop { - let (new_rest, val) = ::read(rest, ctx)?; + let (amt_read, val) = ::read(rest, ctx)?; res.push(val); - rest = new_rest; + rest = &rest[amt_read..]; + total_read += amt_read; // This unwrap is safe as we are pushing to the vec immediately before it, // so there will always be a last element @@ -41,11 +45,14 @@ fn read_vec_with_predicate< } } - Ok((rest, res)) + Ok((total_read, res)) } -impl<'a, T: DekuRead<'a, Ctx>, Ctx: Copy, Predicate: FnMut(&T) -> bool> - DekuRead<'a, (Limit, Ctx)> for Vec +impl<'a, T, Ctx, Predicate> DekuRead<'a, (Limit, Ctx)> for Vec +where + T: DekuRead<'a, Ctx>, + Ctx: Copy, + Predicate: FnMut(&T) -> bool, { /// Read `T`s until the given limit /// * `limit` - the limiting factor on the amount of `T`s to read @@ -56,14 +63,14 @@ impl<'a, T: DekuRead<'a, Ctx>, Ctx: Copy, Predicate: FnMut(&T) -> bool> /// # use deku::DekuRead; /// # use deku::bitvec::BitView; /// let input = vec![1u8, 2, 3, 4]; - /// let (rest, v) = Vec::::read(input.view_bits(), (1.into(), Endian::Little)).unwrap(); - /// assert!(rest.is_empty()); + /// let (amt_read, v) = Vec::::read(input.view_bits(), (1.into(), Endian::Little)).unwrap(); + /// assert_eq!(amt_read, 32); /// assert_eq!(vec![0x04030201], v) /// ``` fn read( input: &'a BitSlice, (limit, inner_ctx): (Limit, Ctx), - ) -> Result<(&'a BitSlice, Self), DekuError> + ) -> Result<(usize, Self), DekuError> where Self: Sized, { @@ -72,7 +79,7 @@ impl<'a, T: DekuRead<'a, Ctx>, Ctx: Copy, Predicate: FnMut(&T) -> bool> Limit::Count(mut count) => { // Handle the trivial case of reading an empty vector if count == 0 { - return Ok((input, Vec::new())); + return Ok((0, Vec::new())); } // Otherwise, read until we have read `count` elements @@ -113,7 +120,7 @@ impl<'a, T: DekuRead<'a>, Predicate: FnMut(&T) -> bool> DekuRead<'a, Limit, limit: Limit, - ) -> Result<(&'a BitSlice, Self), DekuError> + ) -> Result<(usize, Self), DekuError> where Self: Sized, { @@ -143,9 +150,10 @@ impl, Ctx: Copy> DekuWrite for Vec { #[cfg(test)] mod tests { - use super::*; use rstest::rstest; + use super::*; + #[rstest(input,endian,bit_size,limit,expected,expected_rest, case::count_0([0xAA].as_ref(), Endian::Little, Some(8), 0.into(), vec![], bits![u8, Msb0; 1, 0, 1, 0, 1, 0, 1, 0]), case::count_1([0xAA, 0xBB].as_ref(), Endian::Little, Some(8), 1.into(), vec![0xAA], bits![u8, Msb0; 1, 0, 1, 1, 1, 0, 1, 1]), @@ -176,7 +184,7 @@ mod tests { ) { let bit_slice = input.view_bits::(); - let (rest, res_read) = match bit_size { + let (amt_read, res_read) = match bit_size { Some(bit_size) => { Vec::::read(bit_slice, (limit, (endian, BitSize(bit_size)))).unwrap() } @@ -184,7 +192,7 @@ mod tests { }; assert_eq!(expected, res_read); - assert_eq!(expected_rest, rest); + assert_eq!(expected_rest, bit_slice[amt_read..]); } #[rstest(input, endian, expected, @@ -219,10 +227,10 @@ mod tests { // Unwrap here because all test cases are `Some`. let bit_size = bit_size.unwrap(); - let (rest, res_read) = + let (amt_read, res_read) = Vec::::read(bit_slice, (limit, (endian, BitSize(bit_size)))).unwrap(); assert_eq!(expected, res_read); - assert_eq!(expected_rest, rest); + assert_eq!(expected_rest, bit_slice[amt_read..]); let mut res_write = bitvec![u8, Msb0;]; res_read diff --git a/src/lib.rs b/src/lib.rs index 39f341b1..97819920 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,7 +42,7 @@ struct DekuTest { } let data: Vec = vec![0b0110_1001, 0xBE, 0xEF]; -let (_rest, mut val) = DekuTest::from_bytes((data.as_ref(), 0)).unwrap(); +let (_amt_read, mut val) = DekuTest::from_bytes((data.as_ref(), 0)).unwrap(); assert_eq!(DekuTest { field_a: 0b0110, field_b: 0b1001, @@ -75,7 +75,7 @@ struct DekuHeader(u8); struct DekuData(u16); let data: Vec = vec![0xAA, 0xEF, 0xBE]; -let (_rest, mut val) = DekuTest::from_bytes((data.as_ref(), 0)).unwrap(); +let (_amt_read, mut val) = DekuTest::from_bytes((data.as_ref(), 0)).unwrap(); assert_eq!(DekuTest { header: DekuHeader(0xAA), data: DekuData(0xBEEF), @@ -109,7 +109,7 @@ struct DekuTest { } let data: Vec = vec![0x02, 0xBE, 0xEF, 0xFF, 0xFF]; -let (_rest, mut val) = DekuTest::from_bytes((data.as_ref(), 0)).unwrap(); +let (_amt_read, mut val) = DekuTest::from_bytes((data.as_ref(), 0)).unwrap(); assert_eq!(DekuTest { count: 0x02, data: vec![0xBE, 0xEF] @@ -176,10 +176,10 @@ enum DekuTest { let data: Vec = vec![0x01, 0x02, 0xEF, 0xBE]; -let (rest, val) = DekuTest::from_bytes((data.as_ref(), 0)).unwrap(); +let (amt_read, val) = DekuTest::from_bytes((data.as_ref(), 0)).unwrap(); assert_eq!(DekuTest::VariantA , val); -let (rest, val) = DekuTest::from_bytes(rest).unwrap(); +let (amt_read, val) = DekuTest::from_bytes((data.as_ref(), amt_read)).unwrap(); assert_eq!(DekuTest::VariantB(0xBEEF) , val); ``` @@ -210,7 +210,7 @@ struct Root { let data: Vec = vec![0x01, 0x02]; -let (rest, value) = Root::from_bytes((&data[..], 0)).unwrap(); +let (amt_read, value) = Root::from_bytes((&data[..], 0)).unwrap(); assert_eq!(value.a, 0x01); assert_eq!(value.sub.b, 0x01 + 0x02) ``` @@ -295,11 +295,11 @@ pub trait DekuRead<'a, Ctx = ()> { /// * **ctx** - A context required by context-sensitive reading. A unit type `()` means no context /// needed. /// - /// Returns the remaining bits after parsing in addition to Self. + /// Returns the amount of bits read after parsing in addition to Self. fn read( input: &'a bitvec::BitSlice, ctx: Ctx, - ) -> Result<(&'a bitvec::BitSlice, Self), DekuError> + ) -> Result<(usize, Self), DekuError> where Self: Sized; } @@ -310,8 +310,8 @@ pub trait DekuContainerRead<'a>: DekuRead<'a, ()> { /// Read bytes and construct type /// * **input** - Input given as data and bit offset /// - /// Returns the remaining bytes and bit offset after parsing in addition to Self. - fn from_bytes(input: (&'a [u8], usize)) -> Result<((&'a [u8], usize), Self), DekuError> + /// Returns the amount of bits read after parsing in addition to Self. + fn from_bytes(input: (&'a [u8], usize)) -> Result<(usize, Self), DekuError> where Self: Sized; } diff --git a/src/prelude.rs b/src/prelude.rs index 2511a0c6..3ac88025 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -2,7 +2,8 @@ [What is a prelude?](std::prelude) */ +pub use crate::error::{DekuError, NeedSize}; pub use crate::{ - deku_derive, error::DekuError, error::NeedSize, DekuContainerRead, DekuContainerWrite, - DekuEnumExt, DekuRead, DekuUpdate, DekuWrite, + deku_derive, DekuContainerRead, DekuContainerWrite, DekuEnumExt, DekuRead, DekuUpdate, + DekuWrite, }; diff --git a/tests/test_alloc.rs b/tests/test_alloc.rs index 83c8806e..e61294b5 100644 --- a/tests/test_alloc.rs +++ b/tests/test_alloc.rs @@ -45,10 +45,12 @@ struct TestDeku { } mod tests { - use super::*; + use std::convert::TryFrom; + use alloc_counter::count_alloc; use hexlit::hex; - use std::convert::TryFrom; + + use super::*; #[test] #[cfg_attr(miri, ignore)] diff --git a/tests/test_attributes/test_assert.rs b/tests/test_attributes/test_assert.rs index 134a9c13..51efeff3 100644 --- a/tests/test_attributes/test_assert.rs +++ b/tests/test_attributes/test_assert.rs @@ -1,7 +1,8 @@ +use std::convert::{TryFrom, TryInto}; + use deku::prelude::*; use hexlit::hex; use rstest::rstest; -use std::convert::{TryFrom, TryInto}; #[derive(Default, PartialEq, Debug, DekuRead, DekuWrite)] struct TestStruct { diff --git a/tests/test_attributes/test_assert_eq.rs b/tests/test_attributes/test_assert_eq.rs index cdab14be..6cb3ab59 100644 --- a/tests/test_attributes/test_assert_eq.rs +++ b/tests/test_attributes/test_assert_eq.rs @@ -1,7 +1,8 @@ +use std::convert::{TryFrom, TryInto}; + use deku::prelude::*; use hexlit::hex; use rstest::rstest; -use std::convert::{TryFrom, TryInto}; #[derive(Default, PartialEq, Debug, DekuRead, DekuWrite)] struct TestStruct { diff --git a/tests/test_attributes/test_cond.rs b/tests/test_attributes/test_cond.rs index feac39ea..0e27b13e 100644 --- a/tests/test_attributes/test_cond.rs +++ b/tests/test_attributes/test_cond.rs @@ -1,6 +1,7 @@ -use deku::prelude::*; use std::convert::{TryFrom, TryInto}; +use deku::prelude::*; + #[test] fn test_cond_deku() { #[derive(PartialEq, Debug, DekuRead, DekuWrite)] diff --git a/tests/test_attributes/test_ctx.rs b/tests/test_attributes/test_ctx.rs index 46f0c47e..abc1030c 100644 --- a/tests/test_attributes/test_ctx.rs +++ b/tests/test_attributes/test_ctx.rs @@ -1,7 +1,8 @@ +use std::convert::{TryFrom, TryInto}; + use bitvec::bitvec; use deku::bitvec::{BitView, Msb0}; use deku::prelude::*; -use std::convert::{TryFrom, TryInto}; /// General smoke tests for ctx /// TODO: These should be divided into smaller units @@ -60,8 +61,9 @@ fn test_top_level_ctx_enum() { } let test_data = [0x01_u8, 0x03]; - let (rest, ret_read) = TopLevelCtxEnum::read(test_data.view_bits(), (1, 2)).unwrap(); - assert!(rest.is_empty()); + let bit_slice = test_data.view_bits(); + let (amt_read, ret_read) = TopLevelCtxEnum::read(bit_slice, (1, 2)).unwrap(); + assert!(bit_slice[amt_read..].is_empty()); assert_eq!(ret_read, TopLevelCtxEnum::VariantA(0x06)); let mut ret_write = bitvec![u8, Msb0;]; @@ -94,8 +96,9 @@ fn test_top_level_ctx_enum_default() { assert_eq!(test_data.to_vec(), ret_write); // Use context - let (rest, ret_read) = TopLevelCtxEnumDefault::read(test_data.view_bits(), (1, 2)).unwrap(); - assert!(rest.is_empty()); + let bit_slice = test_data.view_bits(); + let (amt_read, ret_read) = TopLevelCtxEnumDefault::read(bit_slice, (1, 2)).unwrap(); + assert!(bit_slice[amt_read..].is_empty()); assert_eq!(ret_read, TopLevelCtxEnumDefault::VariantA(0x06)); let mut ret_write = bitvec![u8, Msb0;]; ret_read.write(&mut ret_write, (1, 2)).unwrap(); @@ -212,8 +215,9 @@ fn test_ctx_default_struct() { assert_eq!(ret_write, test_data); // Use context - let (rest, ret_read) = TopLevelCtxStructDefault::read(test_data.view_bits(), (1, 2)).unwrap(); - assert!(rest.is_empty()); + let bit_slice = test_data.view_bits(); + let (amt_read, ret_read) = TopLevelCtxStructDefault::read(bit_slice, (1, 2)).unwrap(); + assert_eq!(bit_slice.len(), amt_read); assert_eq!(expected, ret_read); let mut ret_write = bitvec![u8, Msb0;]; ret_read.write(&mut ret_write, (1, 2)).unwrap(); @@ -240,7 +244,7 @@ fn test_enum_endian_ctx() { assert_eq!( EnumTypeEndian { - t: EnumTypeEndianCtx::VarA(0xFF) + t: EnumTypeEndianCtx::VarA(0xff) }, ret_read ); diff --git a/tests/test_attributes/test_limits/test_bits_read.rs b/tests/test_attributes/test_limits/test_bits_read.rs index a23ddebd..3b9fb72a 100644 --- a/tests/test_attributes/test_limits/test_bits_read.rs +++ b/tests/test_attributes/test_limits/test_bits_read.rs @@ -1,6 +1,7 @@ +use std::convert::{TryFrom, TryInto}; + use deku::prelude::*; use rstest::rstest; -use std::convert::{TryFrom, TryInto}; mod test_slice { use super::*; @@ -13,7 +14,7 @@ mod test_slice { data: &'a [u8], } - let test_data: Vec = [0xAA, 0xBB].to_vec(); + let test_data: Vec = [0xaa, 0xbb].to_vec(); let ret_read = TestStruct::try_from(test_data.as_ref()).unwrap(); assert_eq!( @@ -45,7 +46,7 @@ mod test_slice { data: &'a [u8], } - let test_data: Vec = [input_bits, 0xAA, 0xBB].to_vec(); + let test_data: Vec = [input_bits, 0xaa, 0xbb].to_vec(); let ret_read = TestStruct::try_from(test_data.as_ref()).unwrap(); assert_eq!( @@ -72,14 +73,14 @@ mod test_vec { data: Vec, } - let test_data: Vec = [0xAA, 0xBB].to_vec(); + let test_data: Vec = [0xaa, 0xbb].to_vec(); let ret_read = TestStruct::try_from(test_data.as_ref()).unwrap(); assert_eq!( TestStruct { // We should read 16 bits, not 16 elements, // thus resulting in a single u16 element - data: vec![0xBBAA] + data: vec![0xbbaa] }, ret_read ); @@ -106,7 +107,7 @@ mod test_vec { data: Vec, } - let test_data: Vec = [input_bits, 0xAA, 0xBB].to_vec(); + let test_data: Vec = [input_bits, 0xaa, 0xbb].to_vec(); let ret_read = TestStruct::try_from(test_data.as_ref()).unwrap(); assert_eq!( @@ -115,7 +116,7 @@ mod test_vec { // We should read 16 bits, not 16 elements, // thus resulting in a single u16 element - data: vec![0xBBAA] + data: vec![0xbbaa] }, ret_read ); diff --git a/tests/test_attributes/test_limits/test_bytes_read.rs b/tests/test_attributes/test_limits/test_bytes_read.rs index 38ffa1c6..d107abce 100644 --- a/tests/test_attributes/test_limits/test_bytes_read.rs +++ b/tests/test_attributes/test_limits/test_bytes_read.rs @@ -1,6 +1,7 @@ +use std::convert::{TryFrom, TryInto}; + use deku::prelude::*; use rstest::rstest; -use std::convert::{TryFrom, TryInto}; mod test_slice { use super::*; @@ -13,7 +14,7 @@ mod test_slice { data: &'a [u8], } - let test_data: Vec = [0xAA, 0xBB].to_vec(); + let test_data: Vec = [0xaa, 0xbb].to_vec(); let ret_read = TestStruct::try_from(test_data.as_ref()).unwrap(); assert_eq!( @@ -42,7 +43,7 @@ mod test_slice { data: &'a [u8], } - let test_data: Vec = [input_bytes, 0xAA, 0xBB].to_vec(); + let test_data: Vec = [input_bytes, 0xaa, 0xbb].to_vec(); let ret_read = TestStruct::try_from(test_data.as_ref()).unwrap(); assert_eq!( @@ -69,14 +70,14 @@ mod test_vec { data: Vec, } - let test_data: Vec = [0xAA, 0xBB].to_vec(); + let test_data: Vec = [0xaa, 0xbb].to_vec(); let ret_read = TestStruct::try_from(test_data.as_ref()).unwrap(); assert_eq!( TestStruct { // We should read two bytes, not two elements, // thus resulting in a single u16 element - data: vec![0xBBAA] + data: vec![0xbbaa] }, ret_read ); @@ -100,7 +101,7 @@ mod test_vec { data: Vec, } - let test_data: Vec = [input_bytes, 0xAA, 0xBB].to_vec(); + let test_data: Vec = [input_bytes, 0xaa, 0xbb].to_vec(); let ret_read = TestStruct::try_from(test_data.as_ref()).unwrap(); assert_eq!( @@ -109,7 +110,7 @@ mod test_vec { // We should read two bytes, not two elements, // thus resulting in a single u16 element - data: vec![0xBBAA] + data: vec![0xbbaa] }, ret_read ); diff --git a/tests/test_attributes/test_limits/test_count.rs b/tests/test_attributes/test_limits/test_count.rs index 0eb8ef53..f950476e 100644 --- a/tests/test_attributes/test_limits/test_count.rs +++ b/tests/test_attributes/test_limits/test_count.rs @@ -1,6 +1,7 @@ -use deku::prelude::*; use std::convert::{TryFrom, TryInto}; +use deku::prelude::*; + mod test_slice { use super::*; @@ -12,7 +13,7 @@ mod test_slice { data: &'a [u8], } - let test_data: Vec = [0xAA, 0xBB].to_vec(); + let test_data: Vec = [0xaa, 0xbb].to_vec(); let ret_read = TestStruct::try_from(test_data.as_ref()).unwrap(); assert_eq!( @@ -35,7 +36,7 @@ mod test_slice { data: &'a [u8], } - let test_data: Vec = [0x02, 0xAA, 0xBB].to_vec(); + let test_data: Vec = [0x02, 0xaa, 0xbb].to_vec(); let ret_read = TestStruct::try_from(test_data.as_ref()).unwrap(); assert_eq!( @@ -60,7 +61,7 @@ mod test_slice { data: &'a [u8], } - let test_data: Vec = [0x03, 0xAA, 0xBB].to_vec(); + let test_data: Vec = [0x03, 0xaa, 0xbb].to_vec(); let _ret_read = TestStruct::try_from(test_data.as_ref()).unwrap(); } @@ -77,12 +78,12 @@ mod test_vec { data: Vec, } - let test_data: Vec = [0xAA, 0xBB].to_vec(); + let test_data: Vec = [0xaa, 0xbb].to_vec(); let ret_read = TestStruct::try_from(test_data.as_ref()).unwrap(); assert_eq!( TestStruct { - data: vec![0xAA, 0xBB] + data: vec![0xaa, 0xbb] }, ret_read ); @@ -100,13 +101,13 @@ mod test_vec { data: Vec, } - let test_data: Vec = [0x02, 0xAA, 0xBB].to_vec(); + let test_data: Vec = [0x02, 0xaa, 0xbb].to_vec(); let ret_read = TestStruct::try_from(test_data.as_ref()).unwrap(); assert_eq!( TestStruct { count: 0x02, - data: vec![0xAA, 0xBB] + data: vec![0xaa, 0xbb] }, ret_read ); @@ -125,7 +126,7 @@ mod test_vec { data: Vec, } - let test_data: Vec = [0x03, 0xAA, 0xBB].to_vec(); + let test_data: Vec = [0x03, 0xaa, 0xbb].to_vec(); let _ret_read = TestStruct::try_from(test_data.as_ref()).unwrap(); } diff --git a/tests/test_attributes/test_limits/test_until.rs b/tests/test_attributes/test_limits/test_until.rs index f88a3d5e..4285f588 100644 --- a/tests/test_attributes/test_limits/test_until.rs +++ b/tests/test_attributes/test_limits/test_until.rs @@ -1,6 +1,7 @@ -use deku::prelude::*; use std::convert::{TryFrom, TryInto}; +use deku::prelude::*; + mod test_slice { use super::*; @@ -12,7 +13,7 @@ mod test_slice { data: &'a [u8], } - let test_data: Vec = [0xAA, 0xBB].to_vec(); + let test_data: Vec = [0xaa, 0xbb].to_vec(); let ret_read = TestStruct::try_from(test_data.as_ref()).unwrap(); assert_eq!( @@ -36,12 +37,12 @@ mod test_slice { data: &'a [u8], } - let test_data: Vec = [0xBB, 0xAA, 0xBB].to_vec(); + let test_data: Vec = [0xbb, 0xaa, 0xbb].to_vec(); let ret_read = TestStruct::try_from(test_data.as_ref()).unwrap(); assert_eq!( TestStruct { - until: 0xBB, + until: 0xbb, data: &test_data[1..] }, ret_read @@ -62,7 +63,7 @@ mod test_slice { data: &'a [u8], } - let test_data: Vec = [0xCC, 0xAA, 0xBB].to_vec(); + let test_data: Vec = [0xcc, 0xaa, 0xbb].to_vec(); let _ret_read = TestStruct::try_from(test_data.as_ref()).unwrap(); } @@ -79,12 +80,12 @@ mod test_vec { data: Vec, } - let test_data: Vec = [0xAA, 0xBB].to_vec(); + let test_data: Vec = [0xaa, 0xbb].to_vec(); let ret_read = TestStruct::try_from(test_data.as_ref()).unwrap(); assert_eq!( TestStruct { - data: vec![0xAA, 0xBB] + data: vec![0xaa, 0xbb] }, ret_read ); @@ -103,13 +104,13 @@ mod test_vec { data: Vec, } - let test_data: Vec = [0xBB, 0xAA, 0xBB].to_vec(); + let test_data: Vec = [0xbb, 0xaa, 0xbb].to_vec(); let ret_read = TestStruct::try_from(test_data.as_ref()).unwrap(); assert_eq!( TestStruct { - until: 0xBB, - data: vec![0xAA, 0xBB] + until: 0xbb, + data: vec![0xaa, 0xbb] }, ret_read ); @@ -129,7 +130,7 @@ mod test_vec { data: Vec, } - let test_data: Vec = [0xCC, 0xAA, 0xBB].to_vec(); + let test_data: Vec = [0xcc, 0xaa, 0xbb].to_vec(); let _ret_read = TestStruct::try_from(test_data.as_ref()).unwrap(); } diff --git a/tests/test_attributes/test_map.rs b/tests/test_attributes/test_map.rs index 90329e59..e6d693e8 100644 --- a/tests/test_attributes/test_map.rs +++ b/tests/test_attributes/test_map.rs @@ -1,6 +1,7 @@ -use deku::prelude::*; use std::convert::TryFrom; +use deku::prelude::*; + #[test] fn test_map() { #[derive(PartialEq, Debug, DekuRead)] diff --git a/tests/test_attributes/test_padding/mod.rs b/tests/test_attributes/test_padding/mod.rs index a54bd259..8ac00f36 100644 --- a/tests/test_attributes/test_padding/mod.rs +++ b/tests/test_attributes/test_padding/mod.rs @@ -1,6 +1,7 @@ -use deku::prelude::*; use std::convert::{TryFrom, TryInto}; +use deku::prelude::*; + mod test_pad_bits_after; mod test_pad_bits_before; mod test_pad_bytes_after; @@ -17,20 +18,20 @@ fn test_pad_bits_before_and_pad_bytes_before() { field_b: u8, } - let data: Vec = vec![0b10_000000, 0xAA, 0xBB]; + let data: Vec = vec![0b10_000000, 0xaa, 0xbb]; let ret_read = TestStruct::try_from(data.as_ref()).unwrap(); assert_eq!( TestStruct { field_a: 0b10, - field_b: 0xBB, + field_b: 0xbb, }, ret_read ); let ret_write: Vec = ret_read.try_into().unwrap(); - assert_eq!(vec![0b10_000000, 0x00, 0xBB], ret_write); + assert_eq!(vec![0b10_000000, 0x00, 0xbb], ret_write); } #[test] @@ -42,18 +43,18 @@ fn test_pad_bits_after_and_pad_bytes_after() { field_b: u8, } - let data: Vec = vec![0b10_000000, 0xAA, 0xBB]; + let data: Vec = vec![0b10_000000, 0xaa, 0xbb]; let ret_read = TestStruct::try_from(data.as_ref()).unwrap(); assert_eq!( TestStruct { field_a: 0b10, - field_b: 0xBB, + field_b: 0xbb, }, ret_read ); let ret_write: Vec = ret_read.try_into().unwrap(); - assert_eq!(vec![0b10_000000, 0x00, 0xBB], ret_write); + assert_eq!(vec![0b10_000000, 0x00, 0xbb], ret_write); } diff --git a/tests/test_attributes/test_padding/test_pad_bits_after.rs b/tests/test_attributes/test_padding/test_pad_bits_after.rs index cea1887a..dc751e01 100644 --- a/tests/test_attributes/test_padding/test_pad_bits_after.rs +++ b/tests/test_attributes/test_padding/test_pad_bits_after.rs @@ -1,6 +1,7 @@ -use deku::prelude::*; use std::convert::{TryFrom, TryInto}; +use deku::prelude::*; + #[test] fn test_pad_bits_after() { #[derive(PartialEq, Debug, DekuRead, DekuWrite)] diff --git a/tests/test_attributes/test_padding/test_pad_bits_before.rs b/tests/test_attributes/test_padding/test_pad_bits_before.rs index 9c872aa7..a82150eb 100644 --- a/tests/test_attributes/test_padding/test_pad_bits_before.rs +++ b/tests/test_attributes/test_padding/test_pad_bits_before.rs @@ -1,6 +1,7 @@ -use deku::prelude::*; use std::convert::{TryFrom, TryInto}; +use deku::prelude::*; + #[test] fn test_pad_bits_before() { #[derive(PartialEq, Debug, DekuRead, DekuWrite)] diff --git a/tests/test_attributes/test_padding/test_pad_bytes_after.rs b/tests/test_attributes/test_padding/test_pad_bytes_after.rs index 787eb60d..c0ea0171 100644 --- a/tests/test_attributes/test_padding/test_pad_bytes_after.rs +++ b/tests/test_attributes/test_padding/test_pad_bytes_after.rs @@ -1,6 +1,7 @@ -use deku::prelude::*; use std::convert::{TryFrom, TryInto}; +use deku::prelude::*; + #[test] fn test_pad_bytes_after() { #[derive(PartialEq, Debug, DekuRead, DekuWrite)] @@ -10,20 +11,20 @@ fn test_pad_bytes_after() { field_b: u8, } - let data: Vec = vec![0xAA, 0xBB, 0xCC, 0xDD]; + let data: Vec = vec![0xaa, 0xbb, 0xcc, 0xdd]; let ret_read = TestStruct::try_from(data.as_ref()).unwrap(); assert_eq!( TestStruct { - field_a: 0xAA, - field_b: 0xDD, + field_a: 0xaa, + field_b: 0xdd, }, ret_read ); let ret_write: Vec = ret_read.try_into().unwrap(); - assert_eq!(vec![0xAA, 0x00, 0x00, 0xDD], ret_write); + assert_eq!(vec![0xaa, 0x00, 0x00, 0xdd], ret_write); } #[test] @@ -36,7 +37,7 @@ fn test_pad_bytes_after_not_enough() { field_b: u8, } - let data: Vec = vec![0xAA, 0xBB, 0xCC, 0xDD]; + let data: Vec = vec![0xaa, 0xbb, 0xcc, 0xdd]; let _ret_read = TestStruct::try_from(data.as_ref()).unwrap(); } @@ -53,7 +54,7 @@ fn test_pad_bytes_after_read_err() { field_b: u8, } - let data: Vec = vec![0xAA, 0xBB, 0xCC, 0xDD]; + let data: Vec = vec![0xaa, 0xbb, 0xcc, 0xdd]; let _ret_read = TestStruct::try_from(data.as_ref()).unwrap(); } @@ -71,8 +72,8 @@ fn test_pad_bytes_after_write_err() { } let data = TestStruct { - field_a: 0xAA, - field_b: 0xDD, + field_a: 0xaa, + field_b: 0xdd, }; let _ret_write: Vec = data.try_into().unwrap(); diff --git a/tests/test_attributes/test_padding/test_pad_bytes_before.rs b/tests/test_attributes/test_padding/test_pad_bytes_before.rs index 7d53d67a..636a73eb 100644 --- a/tests/test_attributes/test_padding/test_pad_bytes_before.rs +++ b/tests/test_attributes/test_padding/test_pad_bytes_before.rs @@ -1,6 +1,7 @@ -use deku::prelude::*; use std::convert::{TryFrom, TryInto}; +use deku::prelude::*; + #[test] fn test_pad_bytes_before() { #[derive(PartialEq, Debug, DekuRead, DekuWrite)] @@ -10,20 +11,20 @@ fn test_pad_bytes_before() { field_b: u8, } - let data: Vec = vec![0xAA, 0xBB, 0xCC, 0xDD]; + let data: Vec = vec![0xaa, 0xbb, 0xcc, 0xdd]; let ret_read = TestStruct::try_from(data.as_ref()).unwrap(); assert_eq!( TestStruct { - field_a: 0xAA, - field_b: 0xDD, + field_a: 0xaa, + field_b: 0xdd, }, ret_read ); let ret_write: Vec = ret_read.try_into().unwrap(); - assert_eq!(vec![0xAA, 0x00, 0x00, 0xDD], ret_write); + assert_eq!(vec![0xaa, 0x00, 0x00, 0xdd], ret_write); } #[test] @@ -36,7 +37,7 @@ fn test_pad_bytes_before_not_enough() { field_b: u8, } - let data: Vec = vec![0xAA]; + let data: Vec = vec![0xaa]; let _ret_read = TestStruct::try_from(data.as_ref()).unwrap(); } @@ -53,7 +54,7 @@ fn test_pad_bytes_before_read_err() { field_b: u8, } - let data: Vec = vec![0xAA, 0xBB, 0xCC, 0xDD]; + let data: Vec = vec![0xaa, 0xbb, 0xcc, 0xdd]; let _ret_read = TestStruct::try_from(data.as_ref()).unwrap(); } @@ -71,8 +72,8 @@ fn test_pad_bytes_before_write_err() { } let data = TestStruct { - field_a: 0xAA, - field_b: 0xDD, + field_a: 0xaa, + field_b: 0xdd, }; let _ret_write: Vec = data.try_into().unwrap(); diff --git a/tests/test_attributes/test_skip.rs b/tests/test_attributes/test_skip.rs index a554e9ac..e9dc0559 100644 --- a/tests/test_attributes/test_skip.rs +++ b/tests/test_attributes/test_skip.rs @@ -1,6 +1,7 @@ -use deku::prelude::*; use std::convert::{TryFrom, TryInto}; +use deku::prelude::*; + /// Skip #[test] fn test_skip() { diff --git a/tests/test_attributes/test_temp.rs b/tests/test_attributes/test_temp.rs index 3893ad96..e86e2f98 100644 --- a/tests/test_attributes/test_temp.rs +++ b/tests/test_attributes/test_temp.rs @@ -1,6 +1,7 @@ -use deku::prelude::*; use std::convert::{TryFrom, TryInto}; +use deku::prelude::*; + #[test] fn test_temp_field_write() { #[deku_derive(DekuRead, DekuWrite)] @@ -114,7 +115,7 @@ fn test_temp_enum_field() { }, } - let test_data: Vec = [0xAB, 0x01, 0x02].to_vec(); + let test_data: Vec = [0xab, 0x01, 0x02].to_vec(); let ret_read = TestEnum::try_from(test_data.as_ref()).unwrap(); assert_eq!( @@ -125,7 +126,7 @@ fn test_temp_enum_field() { ); let ret_write: Vec = ret_read.try_into().unwrap(); - assert_eq!(vec![0xAB, 0x02], ret_write); + assert_eq!(vec![0xab, 0x02], ret_write); } #[test] @@ -148,7 +149,7 @@ fn test_temp_enum_field_write() { VarB(u8), } - let test_data: Vec = [0xAB, 0x01, 0x02].to_vec(); + let test_data: Vec = [0xab, 0x01, 0x02].to_vec(); let ret_write: Vec = TestEnum::VarA { field_b: vec![0x02], } @@ -156,7 +157,7 @@ fn test_temp_enum_field_write() { .unwrap(); assert_eq!(test_data, ret_write); - let test_data: Vec = [0xBA, 0x10].to_vec(); + let test_data: Vec = [0xba, 0x10].to_vec(); let ret_write: Vec = TestEnum::VarB(0x10).to_bytes().unwrap(); assert_eq!(test_data, ret_write); } diff --git a/tests/test_attributes/test_update.rs b/tests/test_attributes/test_update.rs index 19dcb69d..1faf9df2 100644 --- a/tests/test_attributes/test_update.rs +++ b/tests/test_attributes/test_update.rs @@ -1,6 +1,7 @@ -use deku::prelude::*; use std::convert::{TryFrom, TryInto}; +use deku::prelude::*; + /// Update field value #[test] fn test_update() { @@ -36,20 +37,20 @@ fn test_update_from_field() { } // Update the value of `count` to the length of `data` - let test_data: Vec = [0x02, 0xAA, 0xBB].to_vec(); + let test_data: Vec = [0x02, 0xaa, 0xbb].to_vec(); // Read let mut ret_read = TestStruct::try_from(test_data.as_ref()).unwrap(); assert_eq!( TestStruct { count: 0x02, - data: vec![0xAA, 0xBB] + data: vec![0xaa, 0xbb] }, ret_read ); // Add an item to the vec - ret_read.data.push(0xFF); + ret_read.data.push(0xff); // `count` field should now be increased ret_read.update().unwrap(); @@ -57,7 +58,7 @@ fn test_update_from_field() { // Write let ret_write: Vec = ret_read.try_into().unwrap(); - assert_eq!([0x03, 0xAA, 0xBB, 0xFF].to_vec(), ret_write); + assert_eq!([0x03, 0xaa, 0xbb, 0xff].to_vec(), ret_write); } /// Update error diff --git a/tests/test_catch_all.rs b/tests/test_catch_all.rs index a068f86e..37946f22 100644 --- a/tests/test_catch_all.rs +++ b/tests/test_catch_all.rs @@ -1,8 +1,8 @@ #[cfg(test)] mod test { + use std::convert::{TryFrom, TryInto}; + use deku::prelude::*; - use std::convert::TryFrom; - use std::convert::TryInto; /// Basic test struct #[derive(Clone, Copy, PartialEq, Eq, Debug, DekuWrite, DekuRead)] diff --git a/tests/test_compile/cases/internal_variables.rs b/tests/test_compile/cases/internal_variables.rs index 5a78923a..4e5d1930 100644 --- a/tests/test_compile/cases/internal_variables.rs +++ b/tests/test_compile/cases/internal_variables.rs @@ -53,8 +53,8 @@ struct TestMap { fn dummy_reader( offset: usize, rest: &BitSlice, -) -> Result<(&BitSlice, usize), DekuError> { - Ok((rest, offset)) +) -> Result<(usize, usize), DekuError> { + Ok((0, offset)) } #[derive(DekuRead, DekuWrite)] struct TestReader { diff --git a/tests/test_compile/cases/unknown_endian.stderr b/tests/test_compile/cases/unknown_endian.stderr index f6277a95..bfb919e8 100644 --- a/tests/test_compile/cases/unknown_endian.stderr +++ b/tests/test_compile/cases/unknown_endian.stderr @@ -1,5 +1,5 @@ error[E0425]: cannot find value `variable` in this scope - --> $DIR/unknown_endian.rs:3:10 + --> tests/test_compile/cases/unknown_endian.rs:3:10 | 3 | #[derive(DekuRead)] | ^^^^^^^^ not found in this scope @@ -7,7 +7,7 @@ error[E0425]: cannot find value `variable` in this scope = note: this error originates in the derive macro `DekuRead` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0425]: cannot find value `variable` in this scope - --> $DIR/unknown_endian.rs:9:10 + --> tests/test_compile/cases/unknown_endian.rs:9:10 | 9 | #[derive(DekuRead)] | ^^^^^^^^ not found in this scope @@ -15,7 +15,7 @@ error[E0425]: cannot find value `variable` in this scope = note: this error originates in the derive macro `DekuRead` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0425]: cannot find value `variable` in this scope - --> $DIR/unknown_endian.rs:15:10 + --> tests/test_compile/cases/unknown_endian.rs:15:10 | 15 | #[derive(DekuRead)] | ^^^^^^^^ not found in this scope @@ -23,27 +23,15 @@ error[E0425]: cannot find value `variable` in this scope = note: this error originates in the derive macro `DekuRead` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0425]: cannot find value `variable` in this scope - --> $DIR/unknown_endian.rs:19:10 + --> tests/test_compile/cases/unknown_endian.rs:19:10 | 19 | #[derive(DekuRead)] | ^^^^^^^^ not found in this scope | = note: this error originates in the derive macro `DekuRead` (in Nightly builds, run with -Z macro-backtrace for more info) -warning: unreachable statement - --> $DIR/unknown_endian.rs:15:10 - | -15 | #[derive(DekuRead)] - | ^^^^^^^^ - | | - | unreachable statement - | any code following this `match` expression is unreachable, as all arms diverge - | - = note: `#[warn(unreachable_code)]` on by default - = note: this warning originates in the derive macro `DekuRead` (in Nightly builds, run with -Z macro-backtrace for more info) - warning: unreachable expression - --> $DIR/unknown_endian.rs:15:10 + --> tests/test_compile/cases/unknown_endian.rs:15:10 | 15 | #[derive(DekuRead)] | ^^^^^^^^ @@ -51,4 +39,5 @@ warning: unreachable expression | unreachable expression | any code following this `match` expression is unreachable, as all arms diverge | + = note: `#[warn(unreachable_code)]` on by default = note: this warning originates in the derive macro `DekuRead` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/test_enum.rs b/tests/test_enum.rs index f652f298..5c9fd50c 100644 --- a/tests/test_enum.rs +++ b/tests/test_enum.rs @@ -1,7 +1,8 @@ +use std::convert::{TryFrom, TryInto}; + use deku::prelude::*; use hexlit::hex; use rstest::*; -use std::convert::{TryFrom, TryInto}; /// General smoke tests for enums /// TODO: These should be divided into smaller tests diff --git a/tests/test_from_bytes.rs b/tests/test_from_bytes.rs index dd14d587..88eaaa46 100644 --- a/tests/test_from_bytes.rs +++ b/tests/test_from_bytes.rs @@ -6,26 +6,26 @@ fn test_from_bytes_struct() { struct TestDeku(#[deku(bits = 4)] u8); let test_data: Vec = [0b0110_0110u8, 0b0101_1010u8].to_vec(); + let mut total_read = 0; - let ((rest, i), ret_read) = TestDeku::from_bytes((&test_data, 0)).unwrap(); + let (amt_read, ret_read) = TestDeku::from_bytes((&test_data, 0)).unwrap(); + total_read += amt_read; + assert_eq!(amt_read, 4); assert_eq!(TestDeku(0b0110), ret_read); - assert_eq!(2, rest.len()); - assert_eq!(4, i); - let ((rest, i), ret_read) = TestDeku::from_bytes((rest, i)).unwrap(); + let (amt_read, ret_read) = TestDeku::from_bytes((&test_data, total_read)).unwrap(); + total_read += amt_read; + assert_eq!(amt_read, 4); assert_eq!(TestDeku(0b0110), ret_read); - assert_eq!(1, rest.len()); - assert_eq!(0, i); - let ((rest, i), ret_read) = TestDeku::from_bytes((rest, i)).unwrap(); + let (amt_read, ret_read) = TestDeku::from_bytes((&test_data, total_read)).unwrap(); + total_read += amt_read; + assert_eq!(amt_read, 4); assert_eq!(TestDeku(0b0101), ret_read); - assert_eq!(1, rest.len()); - assert_eq!(4, i); - let ((rest, i), ret_read) = TestDeku::from_bytes((rest, i)).unwrap(); + let (amt_read, ret_read) = TestDeku::from_bytes((&test_data, total_read)).unwrap(); + assert_eq!(amt_read, 4); assert_eq!(TestDeku(0b1010), ret_read); - assert_eq!(0, rest.len()); - assert_eq!(0, i); } #[test] @@ -41,14 +41,11 @@ fn test_from_bytes_enum() { let test_data: Vec = [0b0110_0110u8, 0b0101_1010u8].to_vec(); - let ((rest, i), ret_read) = TestDeku::from_bytes((&test_data, 0)).unwrap(); + let (amt_read, ret_read) = TestDeku::from_bytes((&test_data, 0)).unwrap(); + assert_eq!(amt_read, 8); assert_eq!(TestDeku::VariantA(0b0110), ret_read); - assert_eq!(1, rest.len()); - assert_eq!(0, i); - let ((rest, i), ret_read) = TestDeku::from_bytes((rest, i)).unwrap(); + let (amt_read, ret_read) = TestDeku::from_bytes((&test_data, amt_read)).unwrap(); + assert_eq!(amt_read, 6); assert_eq!(TestDeku::VariantB(0b10), ret_read); - assert_eq!(1, rest.len()); - assert_eq!(6, i); - assert_eq!(0b0101_1010u8, rest[0]); } diff --git a/tests/test_generic.rs b/tests/test_generic.rs index 6151c223..4cdd2ff5 100644 --- a/tests/test_generic.rs +++ b/tests/test_generic.rs @@ -1,6 +1,7 @@ -use deku::prelude::*; use std::convert::{TryFrom, TryInto}; +use deku::prelude::*; + #[test] fn test_generic_struct() { #[derive(PartialEq, Debug, DekuRead, DekuWrite)] diff --git a/tests/test_magic.rs b/tests/test_magic.rs index dbf8240f..f3c8984d 100644 --- a/tests/test_magic.rs +++ b/tests/test_magic.rs @@ -1,7 +1,8 @@ +use std::convert::{TryFrom, TryInto}; + use deku::prelude::*; use hexlit::hex; use rstest::rstest; -use std::convert::{TryFrom, TryInto}; #[rstest(input, case(&hex!("64656b75")), diff --git a/tests/test_regression.rs b/tests/test_regression.rs index 4314414e..9f18c9c7 100644 --- a/tests/test_regression.rs +++ b/tests/test_regression.rs @@ -126,7 +126,7 @@ mod issue_282 { // https://github.com/sharksforarms/deku/issues/292 #[test] fn test_regression_292() { - let test_data: &[u8] = [0x0F, 0xF0].as_ref(); + let test_data: &[u8] = [0x0f, 0xf0].as_ref(); #[derive(Debug, PartialEq, DekuRead)] #[deku(endian = "little")] diff --git a/tests/test_struct.rs b/tests/test_struct.rs index c620af5d..69e03d79 100644 --- a/tests/test_struct.rs +++ b/tests/test_struct.rs @@ -1,8 +1,9 @@ #![allow(clippy::unusual_byte_groupings)] -use deku::prelude::*; use std::convert::{TryFrom, TryInto}; +use deku::prelude::*; + mod test_common; /// General smoke tests for structs @@ -53,18 +54,18 @@ fn test_unnamed_struct() { ); let test_data: Vec = [ - 0xFF, + 0xff, 0b1001_0110, - 0xAA, - 0xBB, - 0xCC, - 0xDD, + 0xaa, + 0xbb, + 0xcc, + 0xdd, 0b1001_0110, - 0xCC, - 0xDD, + 0xcc, + 0xdd, 0x02, - 0xBE, - 0xEF, + 0xbe, + 0xef, ] .to_vec(); @@ -72,20 +73,20 @@ fn test_unnamed_struct() { let ret_read = TestUnamedStruct::try_from(test_data.as_ref()).unwrap(); assert_eq!( TestUnamedStruct( - 0xFF, + 0xff, 0b0000_0010, 0b0001_0110, - native_endian!(0xBBAAu16), - 0xCCDDu16, + native_endian!(0xbbaau16), + 0xccddu16, NestedDeku { nest_a: 0b00_100101, nest_b: 0b10, inner: DoubleNestedDeku { - data: native_endian!(0xDDCCu16) + data: native_endian!(0xddccu16) } }, 0x02, - vec![0xBE, 0xEF], + vec![0xbe, 0xef], ), ret_read ); @@ -116,18 +117,18 @@ fn test_named_struct() { } let test_data: Vec = [ - 0xFF, + 0xff, 0b1001_0110, - 0xAA, - 0xBB, - 0xCC, - 0xDD, + 0xaa, + 0xbb, + 0xcc, + 0xdd, 0b1001_0110, - 0xCC, - 0xDD, + 0xcc, + 0xdd, 0x02, - 0xBE, - 0xEF, + 0xbe, + 0xef, ] .to_vec(); @@ -135,20 +136,20 @@ fn test_named_struct() { let ret_read = TestStruct::try_from(test_data.as_ref()).unwrap(); assert_eq!( TestStruct { - field_a: 0xFF, + field_a: 0xff, field_b: 0b0000_0010, field_c: 0b0001_0110, - field_d: native_endian!(0xBBAAu16), - field_e: 0xCCDDu16, + field_d: native_endian!(0xbbaau16), + field_e: 0xccddu16, field_f: NestedDeku { nest_a: 0b00_100101, nest_b: 0b10, inner: DoubleNestedDeku { - data: native_endian!(0xDDCCu16) + data: native_endian!(0xddccu16) } }, vec_len: 0x02, - vec_data: vec![0xBE, 0xEF] + vec_data: vec![0xbe, 0xef] }, ret_read ); @@ -165,11 +166,11 @@ fn test_raw_identifiers_struct() { pub r#type: u8, } - let test_data: Vec = [0xFF].to_vec(); + let test_data: Vec = [0xff].to_vec(); // Read let ret_read = TestStruct::try_from(test_data.as_ref()).unwrap(); - assert_eq!(TestStruct { r#type: 0xFF }, ret_read); + assert_eq!(TestStruct { r#type: 0xff }, ret_read); // Write let ret_write: Vec = ret_read.try_into().unwrap(); From 32dc0a07f2bc83e421e06b463132fefef73806ee Mon Sep 17 00:00:00 2001 From: wcampbell Date: Wed, 14 Jun 2023 23:48:27 -0400 Subject: [PATCH 03/30] Further improve DekuRead performance Gain another %5 increase in performance from just keeping __deku_total_read and use that for the BitSlice reference instead of assigning a new BitSlice every new offset --- deku-derive/src/lib.rs | 2 +- deku-derive/src/macros/deku_read.rs | 21 ++++++++------------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/deku-derive/src/lib.rs b/deku-derive/src/lib.rs index 35c68ab2..402663ca 100644 --- a/deku-derive/src/lib.rs +++ b/deku-derive/src/lib.rs @@ -670,7 +670,7 @@ fn apply_replacements(input: &syn::LitStr) -> Result, Repla .replace("deku::input", "__deku_input") // part of the public API `from_bytes` .replace("deku::input_bits", "__deku_input_bits") // part of the public API `read` .replace("deku::output", "__deku_output") // part of the public API `write` - .replace("deku::rest", "__deku_rest") + .replace("deku::rest", "&__deku_rest[__deku_total_read..]") .replace("deku::bit_offset", "__deku_bit_offset") .replace("deku::byte_offset", "__deku_byte_offset"); diff --git a/deku-derive/src/macros/deku_read.rs b/deku-derive/src/macros/deku_read.rs index 0e1e25a6..50899595 100644 --- a/deku-derive/src/macros/deku_read.rs +++ b/deku-derive/src/macros/deku_read.rs @@ -226,7 +226,6 @@ fn emit_enum(input: &DekuData) -> Result { // if we're consuming an id, set the rest to new_rest before reading the variant let new_rest = if consume_id { quote! { - __deku_rest = &__deku_rest[__deku_amt_read..]; __deku_total_read += __deku_amt_read; } } else { @@ -291,7 +290,7 @@ fn emit_enum(input: &DekuData) -> Result { } } else if id_type.is_some() { quote! { - let (__deku_amt_read, __deku_variant_id) = <#id_type>::read(__deku_rest, (#id_args))?; + let (__deku_amt_read, __deku_variant_id) = <#id_type>::read(&__deku_rest[__deku_total_read..], (#id_args))?; } } else { // either `id` or `type` needs to be specified @@ -409,12 +408,11 @@ fn emit_magic_read(input: &DekuData) -> TokenStream { let __deku_magic = #magic; for __deku_byte in __deku_magic { - let (__deku_amt_read, __deku_read_byte) = u8::read(__deku_rest, ())?; + let (__deku_amt_read, __deku_read_byte) = u8::read(&__deku_rest[__deku_total_read..], ())?; if *__deku_byte != __deku_read_byte { return Err(::#crate_::DekuError::Parse(format!("Missing magic value {:?}", #magic))); } - __deku_rest = &__deku_rest[__deku_amt_read..]; __deku_total_read += __deku_amt_read; } } @@ -490,9 +488,7 @@ fn emit_padding(bit_size: &TokenStream) -> TokenStream { )) )?; - if __deku_rest.len() >= __deku_pad { - let (__deku_padded_bits, __deku_new_rest) = __deku_rest.split_at(__deku_pad); - __deku_rest = __deku_new_rest; + if __deku_rest[__deku_total_read..].len() >= __deku_pad { __deku_total_read += __deku_pad; } else { return Err(::#crate_::DekuError::Incomplete(::#crate_::error::NeedSize::new(__deku_pad))); @@ -614,29 +610,29 @@ fn emit_field_read( quote! { { use core::borrow::Borrow; - #type_as_deku_read::read(__deku_rest, (::#crate_::ctx::Limit::new_count(usize::try_from(*((#field_count).borrow()))?), (#read_args))) + #type_as_deku_read::read(&__deku_rest[__deku_total_read..], (::#crate_::ctx::Limit::new_count(usize::try_from(*((#field_count).borrow()))?), (#read_args))) } } } else if let Some(field_bits) = &f.bits_read { quote! { { use core::borrow::Borrow; - #type_as_deku_read::read(__deku_rest, (::#crate_::ctx::Limit::new_bit_size(::#crate_::ctx::BitSize(usize::try_from(*((#field_bits).borrow()))?)), (#read_args))) + #type_as_deku_read::read(&__deku_rest[__deku_total_read..], (::#crate_::ctx::Limit::new_bit_size(::#crate_::ctx::BitSize(usize::try_from(*((#field_bits).borrow()))?)), (#read_args))) } } } else if let Some(field_bytes) = &f.bytes_read { quote! { { use core::borrow::Borrow; - #type_as_deku_read::read(__deku_rest, (::#crate_::ctx::Limit::new_byte_size(::#crate_::ctx::ByteSize(usize::try_from(*((#field_bytes).borrow()))?)), (#read_args))) + #type_as_deku_read::read(&__deku_rest[__deku_total_read..], (::#crate_::ctx::Limit::new_byte_size(::#crate_::ctx::ByteSize(usize::try_from(*((#field_bytes).borrow()))?)), (#read_args))) } } } else if let Some(field_until) = &f.until { // We wrap the input into another closure here to enforce that it is actually a callable // Otherwise, an incorrectly passed-in integer could unexpectedly convert into a `Count` limit - quote! {#type_as_deku_read::read(__deku_rest, (::#crate_::ctx::Limit::new_until(#field_until), (#read_args)))} + quote! {#type_as_deku_read::read(&__deku_rest[__deku_total_read..], (::#crate_::ctx::Limit::new_until(#field_until), (#read_args)))} } else { - quote! {#type_as_deku_read::read(__deku_rest, (#read_args))} + quote! {#type_as_deku_read::read(&__deku_rest[__deku_total_read..], (#read_args))} } }; @@ -655,7 +651,6 @@ fn emit_field_read( let (__deku_amt_read, __deku_value) = #field_read_func?; let __deku_value: #field_type = #field_map(__deku_value)?; - __deku_rest = &__deku_rest[__deku_amt_read..]; __deku_total_read += __deku_amt_read; __deku_value From 0c40c1a39d85469a93d57a307f663d4a91d72614 Mon Sep 17 00:00:00 2001 From: wcampbell Date: Mon, 31 Jul 2023 22:40:16 -0400 Subject: [PATCH 04/30] wip --- deku-derive/src/macros/deku_read.rs | 95 ++++++++++++++--------------- examples/example.rs | 18 +++++- src/container.rs | 66 ++++++++++++++++++++ src/impls/bool.rs | 19 +++++- src/impls/boxed.rs | 19 ++++++ src/impls/cow.rs | 10 ++- src/impls/cstring.rs | 21 +++++++ src/impls/ipaddr.rs | 18 +++++- src/impls/nonzero.rs | 14 +++++ src/impls/option.rs | 9 +++ src/impls/primitive.rs | 86 ++++++++++++++++++++++++++ src/impls/unit.rs | 8 +++ src/lib.rs | 13 ++++ 13 files changed, 341 insertions(+), 55 deletions(-) create mode 100644 src/container.rs diff --git a/deku-derive/src/macros/deku_read.rs b/deku-derive/src/macros/deku_read.rs index 50899595..067634cb 100644 --- a/deku-derive/src/macros/deku_read.rs +++ b/deku-derive/src/macros/deku_read.rs @@ -57,43 +57,43 @@ fn emit_struct(input: &DekuData) -> Result { let initialize_struct = super::gen_struct_init(is_named_struct, internal_fields); - // Implement `DekuContainerRead` for types that don't need a context - if input.ctx.is_none() || (input.ctx.is_some() && input.ctx_default.is_some()) { - let from_bytes_body = wrap_default_ctx( - quote! { - use core::convert::TryFrom; - use ::#crate_::bitvec::BitView; - let __deku_input_bits = __deku_input.0.view_bits::<::#crate_::bitvec::Msb0>(); - let mut __deku_rest = &__deku_input_bits[__deku_input.1..]; - let mut __deku_total_read = 0; - - #magic_read - - #(#field_reads)* - let __deku_value = #initialize_struct; - - Ok((__deku_total_read, __deku_value)) - }, - &input.ctx, - &input.ctx_default, - ); - - tokens.extend(emit_try_from(&imp, &lifetime, &ident, wher)); - - tokens.extend(emit_from_bytes( - &imp, - &lifetime, - &ident, - wher, - from_bytes_body, - )); - } + //// Implement `DekuContainerRead` for types that don't need a context + //if input.ctx.is_none() || (input.ctx.is_some() && input.ctx_default.is_some()) { + // let from_bytes_body = wrap_default_ctx( + // quote! { + // use core::convert::TryFrom; + // use ::#crate_::bitvec::BitView; + // let __deku_input_bits = __deku_input.0.view_bits::<::#crate_::bitvec::Msb0>(); + // let mut __deku_rest = &__deku_input_bits[__deku_input.1..]; + // let mut __deku_total_read = 0; + + // #magic_read + + // #(#field_reads)* + // let __deku_value = #initialize_struct; + + // Ok((__deku_total_read, __deku_value)) + // }, + // &input.ctx, + // &input.ctx_default, + // ); + + // tokens.extend(emit_try_from(&imp, &lifetime, &ident, wher)); + + // tokens.extend(emit_from_bytes( + // &imp, + // &lifetime, + // &ident, + // wher, + // from_bytes_body, + // )); + //} let (ctx_types, ctx_arg) = gen_ctx_types_and_arg(input.ctx.as_ref())?; let read_body = quote! { use core::convert::TryFrom; - let mut __deku_rest = __deku_input_bits; + //let mut __deku_rest = __deku_input_bits; let mut __deku_total_read = 0; #magic_read @@ -106,7 +106,7 @@ fn emit_struct(input: &DekuData) -> Result { tokens.extend(quote! { impl #imp ::#crate_::DekuRead<#lifetime, #ctx_types> for #ident #wher { - fn read(__deku_input_bits: &#lifetime ::#crate_::bitvec::BitSlice, #ctx_arg) -> core::result::Result<(usize, Self), ::#crate_::DekuError> { + fn from_reader(container: &#lifetime mut ::#crate_::container::Container, #ctx_arg) -> core::result::Result { #read_body } } @@ -117,7 +117,7 @@ fn emit_struct(input: &DekuData) -> Result { tokens.extend(quote! { impl #imp ::#crate_::DekuRead<#lifetime> for #ident #wher { - fn read(__deku_input_bits: &#lifetime ::#crate_::bitvec::BitSlice, _: ()) -> core::result::Result<(usize, Self), ::#crate_::DekuError> { + fn from_reader(container: &#lifetime mut ::#crate_::container::Container, _: ()) -> core::result::Result { #read_body } } @@ -226,7 +226,7 @@ fn emit_enum(input: &DekuData) -> Result { // if we're consuming an id, set the rest to new_rest before reading the variant let new_rest = if consume_id { quote! { - __deku_total_read += __deku_amt_read; + //__deku_total_read += __deku_amt_read; } } else { quote! {} @@ -290,7 +290,7 @@ fn emit_enum(input: &DekuData) -> Result { } } else if id_type.is_some() { quote! { - let (__deku_amt_read, __deku_variant_id) = <#id_type>::read(&__deku_rest[__deku_total_read..], (#id_args))?; + let (__deku_amt_read, __deku_variant_id) = <#id_type>::from_reader(container, (#id_args))?; } } else { // either `id` or `type` needs to be specified @@ -354,7 +354,7 @@ fn emit_enum(input: &DekuData) -> Result { tokens.extend(quote! { #[allow(non_snake_case)] impl #imp ::#crate_::DekuRead<#lifetime, #ctx_types> for #ident #wher { - fn read(__deku_input_bits: &#lifetime ::#crate_::bitvec::BitSlice, #ctx_arg) -> core::result::Result<(usize, Self), ::#crate_::DekuError> { + fn from_reader(container: &#lifetime mut ::#crate_::container::Container, #ctx_arg) -> core::result::Result { #read_body } } @@ -366,7 +366,7 @@ fn emit_enum(input: &DekuData) -> Result { tokens.extend(quote! { #[allow(non_snake_case)] impl #imp ::#crate_::DekuRead<#lifetime> for #ident #wher { - fn read(__deku_input_bits: &#lifetime ::#crate_::bitvec::BitSlice, _: ()) -> core::result::Result<(usize, Self), ::#crate_::DekuError> { + fn from_reader(container: &#lifetime mut ::#crate_::container::Container, _: ()) -> core::result::Result { #read_body } } @@ -408,12 +408,10 @@ fn emit_magic_read(input: &DekuData) -> TokenStream { let __deku_magic = #magic; for __deku_byte in __deku_magic { - let (__deku_amt_read, __deku_read_byte) = u8::read(&__deku_rest[__deku_total_read..], ())?; + let __deku_read_byte = u8::from_reader(&mut container, ())?; if *__deku_byte != __deku_read_byte { return Err(::#crate_::DekuError::Parse(format!("Missing magic value {:?}", #magic))); } - - __deku_total_read += __deku_amt_read; } } } else { @@ -610,29 +608,29 @@ fn emit_field_read( quote! { { use core::borrow::Borrow; - #type_as_deku_read::read(&__deku_rest[__deku_total_read..], (::#crate_::ctx::Limit::new_count(usize::try_from(*((#field_count).borrow()))?), (#read_args))) + #type_as_deku_read::from_reader(&mut container, (::#crate_::ctx::Limit::new_count(usize::try_from(*((#field_count).borrow()))?), (#read_args))) } } } else if let Some(field_bits) = &f.bits_read { quote! { { use core::borrow::Borrow; - #type_as_deku_read::read(&__deku_rest[__deku_total_read..], (::#crate_::ctx::Limit::new_bit_size(::#crate_::ctx::BitSize(usize::try_from(*((#field_bits).borrow()))?)), (#read_args))) + #type_as_deku_read::from_reader(container, (::#crate_::ctx::Limit::new_bit_size(::#crate_::ctx::BitSize(usize::try_from(*((#field_bits).borrow()))?)), (#read_args))) } } } else if let Some(field_bytes) = &f.bytes_read { quote! { { use core::borrow::Borrow; - #type_as_deku_read::read(&__deku_rest[__deku_total_read..], (::#crate_::ctx::Limit::new_byte_size(::#crate_::ctx::ByteSize(usize::try_from(*((#field_bytes).borrow()))?)), (#read_args))) + #type_as_deku_read::from_reader(container, (::#crate_::ctx::Limit::new_byte_size(::#crate_::ctx::ByteSize(usize::try_from(*((#field_bytes).borrow()))?)), (#read_args))) } } } else if let Some(field_until) = &f.until { // We wrap the input into another closure here to enforce that it is actually a callable // Otherwise, an incorrectly passed-in integer could unexpectedly convert into a `Count` limit - quote! {#type_as_deku_read::read(&__deku_rest[__deku_total_read..], (::#crate_::ctx::Limit::new_until(#field_until), (#read_args)))} + quote! {#type_as_deku_read::from_reader(container, (::#crate_::ctx::Limit::new_until(#field_until), (#read_args)))} } else { - quote! {#type_as_deku_read::read(&__deku_rest[__deku_total_read..], (#read_args))} + quote! {#type_as_deku_read::from_reader(container, (#read_args))} } }; @@ -648,11 +646,8 @@ fn emit_field_read( ); let field_read_normal = quote! { - let (__deku_amt_read, __deku_value) = #field_read_func?; + let __deku_value = #field_read_func?; let __deku_value: #field_type = #field_map(__deku_value)?; - - __deku_total_read += __deku_amt_read; - __deku_value }; diff --git a/examples/example.rs b/examples/example.rs index 9f29414a..f39afd1e 100644 --- a/examples/example.rs +++ b/examples/example.rs @@ -2,7 +2,11 @@ use std::convert::{TryFrom, TryInto}; -use deku::prelude::*; +use deku::{ + container::Container, + ctx::{BitSize, ByteSize, Endian}, + prelude::*, +}; #[derive(Debug, PartialEq, DekuRead, DekuWrite)] struct FieldF { @@ -49,8 +53,18 @@ fn main() { ] .as_ref(); - let test_deku = DekuTest::try_from(test_data).unwrap(); + let mut container = Container::new(std::io::Cursor::new(test_data.clone())); + let a = u8::from_reader(&mut container, (Endian::Little, ByteSize(1))); + let b = u8::from_reader(&mut container, (Endian::Little, BitSize(7))); + let c = u8::from_reader(&mut container, (Endian::Little, BitSize(1))); + let d = u16::from_reader(&mut container, (Endian::Big, BitSize(16))); + println!("{a:02x?}"); + println!("{b:02x?}"); + println!("{c:02x?}"); + println!("{d:02x?}"); + let test_deku = DekuTest::try_from(test_data).unwrap(); + println!("{test_deku:02x?}"); assert_eq!( DekuTest { field_a: 0xab, diff --git a/src/container.rs b/src/container.rs new file mode 100644 index 00000000..eee2c918 --- /dev/null +++ b/src/container.rs @@ -0,0 +1,66 @@ +use bitvec::prelude::*; +use std::io::Read; + +pub struct Container { + inner: R, + leftover: BitVec, +} + +impl Container { + pub fn new(inner: R) -> Self { + Self { + inner, + leftover: BitVec::new(), // with_capacity 8? + } + } + + pub fn read_bits(&mut self, amt: usize) -> std::io::Result> { + let mut ret = BitVec::with_capacity(amt); + + if amt < self.leftover.len() { + let used = self.leftover.split_off(amt); + ret.extend(&mut self.leftover); + self.leftover = used; + } else { + ret.extend(self.leftover.clone()); + + let bits_left = amt - self.leftover.len(); + let mut bytes_len = (bits_left / 8); + if (bits_left % 8) != 0 { + bytes_len += 1; + } + let mut buf = vec![0; bytes_len]; + self.inner.read_exact(&mut buf); + + let mut rest: BitVec = BitVec::try_from_slice(&buf).unwrap(); + let add = rest.split_off(bits_left); + ret.extend_from_bitslice(rest.as_bitslice()); + + self.leftover = add; + } + + Ok(ret) + } +} + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn test_container() { + use std::io::Cursor; + let buf = [0x12, 0x34]; + let buf = std::io::Cursor::new(buf); + + let mut container = Container::new(buf); + + let bits = container.read_bits(4).unwrap(); + println!("{}", bits); + let bits = container.read_bits(4).unwrap(); + println!("{}", bits); + let bits = container.read_bits(4).unwrap(); + println!("{}", bits); + let bits = container.read_bits(4).unwrap(); + println!("{}", bits); + } +} diff --git a/src/impls/bool.rs b/src/impls/bool.rs index b413c417..033c9a35 100644 --- a/src/impls/bool.rs +++ b/src/impls/bool.rs @@ -1,9 +1,11 @@ +use std::io::Read; + #[cfg(feature = "alloc")] use alloc::format; use bitvec::prelude::*; -use crate::{DekuError, DekuRead, DekuWrite}; +use crate::{DekuError, DekuRead, DekuWrite, container}; impl<'a, Ctx> DekuRead<'a, Ctx> for bool where @@ -23,6 +25,21 @@ where Ok((amt_read, ret)) } + + fn from_reader( + container: &mut crate::container::Container, + inner_ctx: Ctx, + ) -> Result { + let val = u8::from_reader(container, inner_ctx)?; + + let ret = match val { + 0x01 => Ok(true), + 0x00 => Ok(false), + _ => Err(DekuError::Parse(format!("cannot parse bool value: {val}",))), + }?; + + Ok(ret) + } } impl DekuWrite for bool diff --git a/src/impls/boxed.rs b/src/impls/boxed.rs index 74e798dc..49a54a35 100644 --- a/src/impls/boxed.rs +++ b/src/impls/boxed.rs @@ -1,3 +1,5 @@ +use std::io::Read; + use alloc::boxed::Box; use alloc::vec::Vec; @@ -19,6 +21,14 @@ where let (amt_read, val) = ::read(input, inner_ctx)?; Ok((amt_read, Box::new(val))) } + + fn from_reader( + container: &mut crate::container::Container, + inner_ctx: Ctx, + ) -> Result { + let val = ::from_reader(container, inner_ctx)?; + Ok(Box::new(val)) + } } impl DekuWrite for Box @@ -50,6 +60,15 @@ where let (amt_read, val) = >::read(input, (limit, inner_ctx))?; Ok((amt_read, val.into_boxed_slice())) } + + fn from_reader( + container: &mut crate::container::Container, + (limit, inner_ctx): (Limit, Ctx), + ) -> Result { + // use Vec's implementation and convert to Box<[T]> + let val = >::from_reader(container, (limit, inner_ctx))?; + Ok(val.into_boxed_slice()) + } } impl DekuWrite for Box<[T]> diff --git a/src/impls/cow.rs b/src/impls/cow.rs index c48cb75f..d1da2704 100644 --- a/src/impls/cow.rs +++ b/src/impls/cow.rs @@ -1,4 +1,4 @@ -use std::borrow::{Borrow, Cow}; +use std::{borrow::{Borrow, Cow}, io::Read}; use bitvec::prelude::*; @@ -17,6 +17,14 @@ where let (amt_read, val) = ::read(input, inner_ctx)?; Ok((amt_read, Cow::Owned(val))) } + + fn from_reader( + container: &mut crate::container::Container, + inner_ctx: Ctx, + ) -> Result { + let val = ::from_reader(container, inner_ctx)?; + Ok(Cow::Owned(val)) + } } impl DekuWrite for Cow<'_, T> diff --git a/src/impls/cstring.rs b/src/impls/cstring.rs index cddd943f..f0bc384d 100644 --- a/src/impls/cstring.rs +++ b/src/impls/cstring.rs @@ -1,4 +1,5 @@ use std::ffi::CString; +use std::io::Read; use bitvec::prelude::*; @@ -38,6 +39,26 @@ where Ok((amt_read, value)) } + + fn from_reader( + container: &mut crate::container::Container, + inner_ctx: Ctx, + ) -> Result { + let mut bytes = Vec::from_reader(container, (Limit::from(|b: &u8| *b == 0x00), inner_ctx))?; + + // TODO: use from_vec_with_nul instead once stable + + // Remove null byte + let nul_byte = bytes.pop(); + if nul_byte != Some(0x00) { + return Err(DekuError::Unexpected("Expected nul byte".to_string())); + } + + let value = CString::new(bytes) + .map_err(|e| DekuError::Parse(format!("Failed to convert Vec to CString: {e}")))?; + + Ok(value) + } } #[cfg(test)] diff --git a/src/impls/ipaddr.rs b/src/impls/ipaddr.rs index 63cc1882..e6162545 100644 --- a/src/impls/ipaddr.rs +++ b/src/impls/ipaddr.rs @@ -1,4 +1,4 @@ -use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; +use std::{net::{IpAddr, Ipv4Addr, Ipv6Addr}, io::Read}; use bitvec::prelude::*; @@ -15,6 +15,14 @@ where let (amt_read, ip) = u32::read(input, ctx)?; Ok((amt_read, ip.into())) } + + fn from_reader( + container: &mut crate::container::Container, + inner_ctx: Ctx, + ) -> Result { + let ip = u32::from_reader(container, inner_ctx)?; + Ok(ip.into()) + } } impl DekuWrite for Ipv4Addr @@ -38,6 +46,14 @@ where let (amt_read, ip) = u128::read(input, ctx)?; Ok((amt_read, ip.into())) } + + fn from_reader( + container: &mut crate::container::Container, + inner_ctx: Ctx, + ) -> Result { + let ip = u128::from_reader(container, inner_ctx)?; + Ok(ip.into()) + } } impl DekuWrite for Ipv6Addr diff --git a/src/impls/nonzero.rs b/src/impls/nonzero.rs index d0e3f7ff..f57ab34a 100644 --- a/src/impls/nonzero.rs +++ b/src/impls/nonzero.rs @@ -1,6 +1,7 @@ #[cfg(feature = "alloc")] use alloc::format; use core::num::*; +use std::io::Read; use bitvec::prelude::*; @@ -25,6 +26,19 @@ macro_rules! ImplDekuTraitsCtx { Some(v) => Ok((amt_read, v)), } } + + fn from_reader( + container: &mut crate::container::Container, + $ctx_arg: $ctx_type, + ) -> Result { + let value = <$readtype>::from_reader(container, $ctx_arg)?; + let value = <$typ>::new(value); + + match value { + None => Err(DekuError::Parse(format!("NonZero assertion"))), + Some(v) => Ok(v), + } + } } impl DekuWrite<$ctx_type> for $typ { diff --git a/src/impls/option.rs b/src/impls/option.rs index a747b7c3..cba6d245 100644 --- a/src/impls/option.rs +++ b/src/impls/option.rs @@ -1,4 +1,5 @@ use bitvec::prelude::*; +use std::io::Read; use crate::{DekuError, DekuRead, DekuWrite}; @@ -22,6 +23,14 @@ impl<'a, T: DekuRead<'a, Ctx>, Ctx: Copy> DekuRead<'a, Ctx> for Option { let (amt_read, val) = ::read(input, inner_ctx)?; Ok((amt_read, Some(val))) } + + fn from_reader( + container: &mut crate::container::Container, + inner_ctx: Ctx, + ) -> Result { + let val = ::from_reader(container, inner_ctx)?; + Ok(Some(val)) + } } impl, Ctx: Copy> DekuWrite for Option { diff --git a/src/impls/primitive.rs b/src/impls/primitive.rs index 7168b8ee..48cb21a6 100644 --- a/src/impls/primitive.rs +++ b/src/impls/primitive.rs @@ -3,6 +3,7 @@ use alloc::format; use core::convert::TryInto; use bitvec::prelude::*; +use std::io::Read; use crate::ctx::*; use crate::prelude::NeedSize; @@ -23,6 +24,15 @@ impl DekuRead<'_, (Endian, ByteSize)> for u8 { let value = input[..MAX_TYPE_BITS].load::(); Ok((MAX_TYPE_BITS, value)) } + + fn from_reader( + container: &mut crate::container::Container, + (endian, size): (Endian, ByteSize), + ) -> Result { + let mut bits = container.read_bits(8).unwrap(); + let a = ::read(&mut bits, (endian, size))?; + Ok(a.1) + } } macro_rules! ImplDekuReadBits { @@ -111,6 +121,15 @@ macro_rules! ImplDekuReadBits { }; Ok((bit_size, value)) } + + fn from_reader( + container: &mut crate::container::Container, + (endian, size): (Endian, BitSize), + ) -> Result<$typ, DekuError> { + let mut bits = container.read_bits(size.0).unwrap(); + let a = <$typ>::read(&mut bits, (endian, size))?; + Ok(a.1) + } } }; } @@ -182,6 +201,15 @@ macro_rules! ImplDekuReadBytes { Ok((bit_size, value)) } + + fn from_reader( + container: &mut crate::container::Container, + (endian, size): (Endian, ByteSize), + ) -> Result<$typ, DekuError> { + let mut bits = container.read_bits(size.0 * 8).unwrap(); + let a = <$typ>::read(&mut bits, (endian, size))?; + Ok(a.1) + } } }; } @@ -202,7 +230,17 @@ macro_rules! ImplDekuReadSignExtend { let value = (value as $typ) << shift >> shift; Ok((amt_read, value)) } + + fn from_reader( + container: &mut crate::container::Container, + (endian, size): (Endian, ByteSize), + ) -> Result<$typ, DekuError> { + let mut bits = container.read_bits(size.0 * 8).unwrap(); + let a = <$typ>::read(&mut bits, (endian, size))?; + Ok(a.1) + } } + impl DekuRead<'_, (Endian, BitSize)> for $typ { fn read( input: &BitSlice, @@ -217,6 +255,14 @@ macro_rules! ImplDekuReadSignExtend { let value = (value as $typ) << shift >> shift; Ok((amt_read, value)) } + fn from_reader( + container: &mut crate::container::Container, + (endian, size): (Endian, BitSize), + ) -> Result<$typ, DekuError> { + let mut bits = container.read_bits(size.0).unwrap(); + let a = <$typ>::read(&mut bits, (endian, size))?; + Ok(a.1) + } } }; } @@ -238,6 +284,17 @@ macro_rules! ForwardDekuRead { <$typ>::read(input, (endian, bit_size)) } } + + fn from_reader( + container: &mut crate::container::Container, + endian: Endian, + ) -> Result<$typ, DekuError> { + let bit_size = BitSize::of::<$typ>(); + + let mut bits = container.read_bits(bit_size.0).unwrap(); + let a = <$typ>::read(&mut bits, endian)?; + Ok(a.1) + } } // Only have `bit_size`, set `endian` to `Endian::default`. @@ -250,6 +307,17 @@ macro_rules! ForwardDekuRead { <$typ>::read(input, (endian, byte_size)) } + + fn from_reader( + container: &mut crate::container::Container, + byte_size: ByteSize, + ) -> Result<$typ, DekuError> { + let endian = Endian::default(); + + let mut bits = container.read_bits(byte_size.0 * 8).unwrap(); + let a = <$typ>::read(&mut bits, (endian, byte_size))?; + Ok(a.1) + } } // Only have `bit_size`, set `endian` to `Endian::default`. @@ -267,12 +335,30 @@ macro_rules! ForwardDekuRead { <$typ>::read(input, (endian, bit_size)) } } + + fn from_reader( + container: &mut crate::container::Container, + bit_size: BitSize, + ) -> Result<$typ, DekuError> { + let endian = Endian::default(); + + let mut bits = container.read_bits(bit_size.0).unwrap(); + let a = <$typ>::read(&mut bits, bit_size)?; + Ok(a.1) + } } impl DekuRead<'_> for $typ { fn read(input: &BitSlice, _: ()) -> Result<(usize, Self), DekuError> { <$typ>::read(input, Endian::default()) } + + fn from_reader( + container: &mut crate::container::Container, + _: (), + ) -> Result<$typ, DekuError> { + <$typ>::from_reader(container, Endian::default()) + } } }; } diff --git a/src/impls/unit.rs b/src/impls/unit.rs index ea7d999b..0df8791e 100644 --- a/src/impls/unit.rs +++ b/src/impls/unit.rs @@ -1,4 +1,5 @@ use bitvec::prelude::*; +use std::io::Read; use crate::{DekuError, DekuRead, DekuWrite}; @@ -10,6 +11,13 @@ impl DekuRead<'_, Ctx> for () { { Ok((0, ())) } + + fn from_reader( + container: &mut crate::container::Container, + _inner_ctx: Ctx, + ) -> Result { + Ok(()) + } } impl DekuWrite for () { diff --git a/src/lib.rs b/src/lib.rs index 97819920..dc2018e1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -269,6 +269,8 @@ pub struct EncodedString { #[cfg(feature = "alloc")] extern crate alloc; +use std::io::Read; + #[cfg(feature = "alloc")] use alloc::vec::Vec; @@ -281,6 +283,7 @@ pub mod bitvec { pub use deku_derive::*; pub mod attributes; +pub mod container; pub mod ctx; pub mod error; mod impls; @@ -302,6 +305,16 @@ pub trait DekuRead<'a, Ctx = ()> { ) -> Result<(usize, Self), DekuError> where Self: Sized; + + fn from_reader( + container: &mut crate::container::Container, + ctx: Ctx, + ) -> Result + where + Self: Sized, + { + todo!(); + } } /// "Reader" trait: implemented on DekuRead struct and enum containers. A `container` is a type which From f795279195793400d5d0dbdddee639a926f22d4f Mon Sep 17 00:00:00 2001 From: wcampbell Date: Tue, 1 Aug 2023 22:37:35 -0400 Subject: [PATCH 05/30] wip --- benches/deku.rs | 46 +++++--- deku-derive/src/macros/deku_read.rs | 174 +++++++++++++++------------- examples/enums.rs | 3 +- examples/example.rs | 12 +- examples/ipv4.rs | 3 +- src/container.rs | 27 ++++- src/impls/bool.rs | 2 +- src/impls/cow.rs | 5 +- src/impls/ipaddr.rs | 5 +- src/impls/primitive.rs | 86 +++++++++++--- src/impls/vec.rs | 96 +++++++++++++++ src/lib.rs | 5 +- 12 files changed, 332 insertions(+), 132 deletions(-) diff --git a/benches/deku.rs b/benches/deku.rs index f52791a8..963407db 100644 --- a/benches/deku.rs +++ b/benches/deku.rs @@ -1,4 +1,7 @@ +use std::io::Read; + use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use deku::container::Container; use deku::prelude::*; #[derive(Debug, PartialEq, DekuRead, DekuWrite)] @@ -10,8 +13,13 @@ struct DekuBits { } #[derive(Debug, PartialEq, DekuRead, DekuWrite)] -struct DekuByte { - data: u8, +struct DekuBytes { + // #[deku(bytes = "1")] <=== This should be emitted! + data_00: u8, + // #[deku(bytes = "2")] <=== This should be emitted! + data_01: u16, + // #[deku(bytes = "4")] <=== This should be emitted! + data_02: u32, } #[derive(Debug, PartialEq, DekuRead, DekuWrite)] @@ -38,24 +46,27 @@ struct DekuVec { data: Vec, } -fn deku_read_bits(input: &[u8]) { - let (_rest, _v) = DekuBits::from_bytes((input, 0)).unwrap(); +fn deku_read_bits(reader: impl Read) { + let mut container = Container::new(reader); + let _v = DekuBits::from_reader(&mut container, ()).unwrap(); } fn deku_write_bits(input: &DekuBits) { let _v = input.to_bytes().unwrap(); } -fn deku_read_byte(input: &[u8]) { - let (_rest, _v) = DekuByte::from_bytes((input, 0)).unwrap(); +fn deku_read_byte(reader: impl Read) { + let mut container = Container::new(reader); + let _v = DekuBytes::from_reader(&mut container, ()).unwrap(); } -fn deku_write_byte(input: &DekuByte) { +fn deku_write_byte(input: &DekuBytes) { let _v = input.to_bytes().unwrap(); } fn deku_read_enum(input: &[u8]) { - let (_rest, _v) = DekuEnum::from_bytes((input, 0)).unwrap(); + let mut container = Container::new(input); + let _v = DekuEnum::from_reader(&mut container, ()).unwrap(); } fn deku_write_enum(input: &DekuEnum) { @@ -63,7 +74,8 @@ fn deku_write_enum(input: &DekuEnum) { } fn deku_read_vec(input: &[u8]) { - let (_rest, _v) = DekuVec::from_bytes((input, 0)).unwrap(); + let mut container = Container::new(input); + let _v = DekuVec::from_reader(&mut container, ()).unwrap(); } fn deku_write_vec(input: &DekuVec) { @@ -71,7 +83,8 @@ fn deku_write_vec(input: &DekuVec) { } fn deku_read_vec_perf(input: &[u8]) { - let (_rest, _v) = DekuVecPerf::from_bytes((input, 0)).unwrap(); + let mut container = Container::new(std::io::Cursor::new(input)); + let _v = DekuVecPerf::from_reader(&mut container, ()).unwrap(); } fn deku_write_vec_perf(input: &DekuVecPerf) { @@ -79,14 +92,21 @@ fn deku_write_vec_perf(input: &DekuVecPerf) { } fn criterion_benchmark(c: &mut Criterion) { + let mut reader = std::io::repeat(0b101); c.bench_function("deku_read_byte", |b| { - b.iter(|| deku_read_byte(black_box([0x01].as_ref()))) + b.iter(|| deku_read_byte(black_box(&mut reader))) }); c.bench_function("deku_write_byte", |b| { - b.iter(|| deku_write_byte(black_box(&DekuByte { data: 0x01 }))) + b.iter(|| { + deku_write_byte(black_box(&DekuBytes { + data_00: 0x00, + data_01: 0x02, + data_02: 0x03, + })) + }) }); c.bench_function("deku_read_bits", |b| { - b.iter(|| deku_read_bits(black_box([0xf1].as_ref()))) + b.iter(|| deku_read_bits(black_box(&mut reader))) }); c.bench_function("deku_write_bits", |b| { b.iter(|| { diff --git a/deku-derive/src/macros/deku_read.rs b/deku-derive/src/macros/deku_read.rs index 067634cb..87cdcc5a 100644 --- a/deku-derive/src/macros/deku_read.rs +++ b/deku-derive/src/macros/deku_read.rs @@ -57,51 +57,51 @@ fn emit_struct(input: &DekuData) -> Result { let initialize_struct = super::gen_struct_init(is_named_struct, internal_fields); - //// Implement `DekuContainerRead` for types that don't need a context - //if input.ctx.is_none() || (input.ctx.is_some() && input.ctx_default.is_some()) { - // let from_bytes_body = wrap_default_ctx( - // quote! { - // use core::convert::TryFrom; - // use ::#crate_::bitvec::BitView; - // let __deku_input_bits = __deku_input.0.view_bits::<::#crate_::bitvec::Msb0>(); - // let mut __deku_rest = &__deku_input_bits[__deku_input.1..]; - // let mut __deku_total_read = 0; - - // #magic_read - - // #(#field_reads)* - // let __deku_value = #initialize_struct; - - // Ok((__deku_total_read, __deku_value)) - // }, - // &input.ctx, - // &input.ctx_default, - // ); - - // tokens.extend(emit_try_from(&imp, &lifetime, &ident, wher)); - - // tokens.extend(emit_from_bytes( - // &imp, - // &lifetime, - // &ident, - // wher, - // from_bytes_body, - // )); - //} + // Implement `DekuContainerRead` for types that don't need a context + if input.ctx.is_none() || (input.ctx.is_some() && input.ctx_default.is_some()) { + // let from_bytes_body = wrap_default_ctx( + // quote! { + // use core::convert::TryFrom; + // use ::#crate_::bitvec::BitView; + // let __deku_input_bits = __deku_input.0.view_bits::<::#crate_::bitvec::Msb0>(); + // let mut __deku_rest = &__deku_input_bits[__deku_input.1..]; + // let mut __deku_total_read = 0; + + // #magic_read + + // #(#field_reads)* + // let __deku_value = #initialize_struct; + + // Ok((__deku_total_read, __deku_value)) + // }, + // &input.ctx, + // &input.ctx_default, + // ); + + //tokens.extend(emit_try_from(&imp, &lifetime, &ident, wher)); + + // tokens.extend(emit_from_bytes( + // &imp, + // &lifetime, + // &ident, + // wher, + // from_bytes_body, + // )); + } let (ctx_types, ctx_arg) = gen_ctx_types_and_arg(input.ctx.as_ref())?; let read_body = quote! { use core::convert::TryFrom; //let mut __deku_rest = __deku_input_bits; - let mut __deku_total_read = 0; + //let mut __deku_total_read = 0; #magic_read #(#field_reads)* let __deku_value = #initialize_struct; - Ok((__deku_total_read, __deku_value)) + Ok(__deku_value) }; tokens.extend(quote! { @@ -223,18 +223,8 @@ fn emit_enum(input: &DekuData) -> Result { deku_ids.push(deku_id); } - // if we're consuming an id, set the rest to new_rest before reading the variant - let new_rest = if consume_id { - quote! { - //__deku_total_read += __deku_amt_read; - } - } else { - quote! {} - }; - quote! { { - #new_rest #(#field_reads)* Self :: #initialize_enum } @@ -290,7 +280,7 @@ fn emit_enum(input: &DekuData) -> Result { } } else if id_type.is_some() { quote! { - let (__deku_amt_read, __deku_variant_id) = <#id_type>::from_reader(container, (#id_args))?; + let __deku_variant_id = <#id_type>::from_reader(container, (#id_args))?; } } else { // either `id` or `type` needs to be specified @@ -309,46 +299,46 @@ fn emit_enum(input: &DekuData) -> Result { // Implement `DekuContainerRead` for types that don't need a context if input.ctx.is_none() || (input.ctx.is_some() && input.ctx_default.is_some()) { - let from_bytes_body = wrap_default_ctx( - quote! { - use core::convert::TryFrom; - use ::#crate_::bitvec::BitView; - let __deku_input_bits = __deku_input.0.view_bits::<::#crate_::bitvec::Msb0>(); - let mut __deku_rest = &__deku_input_bits[__deku_input.1..]; - let mut __deku_total_read = 0; - - #magic_read - - #variant_read - - Ok((__deku_total_read, __deku_value)) - }, - &input.ctx, - &input.ctx_default, - ); - - tokens.extend(emit_try_from(&imp, &lifetime, &ident, wher)); - - tokens.extend(emit_from_bytes( - &imp, - &lifetime, - &ident, - wher, - from_bytes_body, - )); + //let from_bytes_body = wrap_default_ctx( + // quote! { + // use core::convert::TryFrom; + // use ::#crate_::bitvec::BitView; + // let __deku_input_bits = __deku_input.0.view_bits::<::#crate_::bitvec::Msb0>(); + // let mut __deku_rest = &__deku_input_bits[__deku_input.1..]; + // let mut __deku_total_read = 0; + + // #magic_read + + // #variant_read + + // Ok((__deku_total_read, __deku_value)) + // }, + // &input.ctx, + // &input.ctx_default, + //); + + //tokens.extend(emit_try_from(&imp, &lifetime, &ident, wher)); + + //tokens.extend(emit_from_bytes( + // &imp, + // &lifetime, + // &ident, + // wher, + // from_bytes_body, + //)); } let (ctx_types, ctx_arg) = gen_ctx_types_and_arg(input.ctx.as_ref())?; let read_body = quote! { use core::convert::TryFrom; - let mut __deku_rest = __deku_input_bits; - let mut __deku_total_read = 0; + //let mut __deku_rest = __deku_input_bits; + //let mut __deku_total_read = 0; #magic_read #variant_read - Ok((__deku_total_read, __deku_value)) + Ok(__deku_value) }; tokens.extend(quote! { @@ -608,29 +598,53 @@ fn emit_field_read( quote! { { use core::borrow::Borrow; - #type_as_deku_read::from_reader(&mut container, (::#crate_::ctx::Limit::new_count(usize::try_from(*((#field_count).borrow()))?), (#read_args))) + #type_as_deku_read::from_reader + ( + container, + (::#crate_::ctx::Limit::new_count(usize::try_from(*((#field_count).borrow()))?), (#read_args)) + ) } } } else if let Some(field_bits) = &f.bits_read { quote! { { use core::borrow::Borrow; - #type_as_deku_read::from_reader(container, (::#crate_::ctx::Limit::new_bit_size(::#crate_::ctx::BitSize(usize::try_from(*((#field_bits).borrow()))?)), (#read_args))) + #type_as_deku_read::from_reader + ( + container, + (::#crate_::ctx::Limit::new_bit_size(::#crate_::ctx::BitSize(usize::try_from(*((#field_bits).borrow()))?)), (#read_args)) + ) } } } else if let Some(field_bytes) = &f.bytes_read { quote! { { use core::borrow::Borrow; - #type_as_deku_read::from_reader(container, (::#crate_::ctx::Limit::new_byte_size(::#crate_::ctx::ByteSize(usize::try_from(*((#field_bytes).borrow()))?)), (#read_args))) + #type_as_deku_read::from_reader + ( + container, + (::#crate_::ctx::Limit::new_byte_size(::#crate_::ctx::ByteSize(usize::try_from(*((#field_bytes).borrow()))?)), (#read_args)) + ) } } } else if let Some(field_until) = &f.until { // We wrap the input into another closure here to enforce that it is actually a callable // Otherwise, an incorrectly passed-in integer could unexpectedly convert into a `Count` limit - quote! {#type_as_deku_read::from_reader(container, (::#crate_::ctx::Limit::new_until(#field_until), (#read_args)))} + quote! { + #type_as_deku_read::from_reader + ( + container, + (::#crate_::ctx::Limit::new_until(#field_until), (#read_args)) + ) + } } else { - quote! {#type_as_deku_read::from_reader(container, (#read_args))} + quote! { + #type_as_deku_read::from_reader + ( + container, + (#read_args) + ) + } } }; @@ -647,7 +661,7 @@ fn emit_field_read( let field_read_normal = quote! { let __deku_value = #field_read_func?; - let __deku_value: #field_type = #field_map(__deku_value)?; + //let __deku_value: #field_type = #field_map(__deku_value)?; __deku_value }; diff --git a/examples/enums.rs b/examples/enums.rs index 522b9801..a817185d 100644 --- a/examples/enums.rs +++ b/examples/enums.rs @@ -29,7 +29,8 @@ enum DekuTest { fn main() { let test_data = hex!("03020102").to_vec(); - let deku_test = DekuTest::try_from(test_data.as_ref()).unwrap(); + let mut container = deku::container::Container::new(std::io::Cursor::new(test_data.clone())); + let deku_test = DekuTest::from_reader(&mut container, ()).unwrap(); assert_eq!( DekuTest::Var4 { diff --git a/examples/example.rs b/examples/example.rs index f39afd1e..8b7b0e13 100644 --- a/examples/example.rs +++ b/examples/example.rs @@ -53,17 +53,9 @@ fn main() { ] .as_ref(); - let mut container = Container::new(std::io::Cursor::new(test_data.clone())); - let a = u8::from_reader(&mut container, (Endian::Little, ByteSize(1))); - let b = u8::from_reader(&mut container, (Endian::Little, BitSize(7))); - let c = u8::from_reader(&mut container, (Endian::Little, BitSize(1))); - let d = u16::from_reader(&mut container, (Endian::Big, BitSize(16))); - println!("{a:02x?}"); - println!("{b:02x?}"); - println!("{c:02x?}"); - println!("{d:02x?}"); + let mut container = Container::new(std::io::Cursor::new(test_data)); + let test_deku = DekuTest::from_reader(&mut container, ()).unwrap(); - let test_deku = DekuTest::try_from(test_data).unwrap(); println!("{test_deku:02x?}"); assert_eq!( DekuTest { diff --git a/examples/ipv4.rs b/examples/ipv4.rs index ff3cf589..cfe371d2 100644 --- a/examples/ipv4.rs +++ b/examples/ipv4.rs @@ -51,7 +51,8 @@ pub struct Ipv4Header { fn main() { let test_data = hex!("4500004b0f490000801163a591fea0ed91fd02cb").to_vec(); - let ip_header = Ipv4Header::try_from(test_data.as_ref()).unwrap(); + let mut container = deku::container::Container::new(std::io::Cursor::new(test_data.clone())); + let ip_header = Ipv4Header::from_reader(&mut container, ()).unwrap(); assert_eq!( Ipv4Header { diff --git a/src/container.rs b/src/container.rs index eee2c918..03f931e0 100644 --- a/src/container.rs +++ b/src/container.rs @@ -1,16 +1,25 @@ use bitvec::prelude::*; use std::io::Read; +pub enum ContainerRet { + Bytes, + Bits(BitVec), +} + pub struct Container { inner: R, + // TODO; bitslice.len() == 8 leftover: BitVec, + pub(crate) bits_read: usize, } impl Container { + #[inline] pub fn new(inner: R) -> Self { Self { inner, leftover: BitVec::new(), // with_capacity 8? + bits_read: 0, } } @@ -39,8 +48,22 @@ impl Container { self.leftover = add; } + self.bits_read += ret.len(); Ok(ret) } + + // Attempt to read into bytes instead of bits + // + // 1. We must have no leftover bits, so that we are "aligned" + #[inline] + pub fn read_bytes(&mut self, amt: usize, buf: &mut [u8]) -> ContainerRet { + if self.leftover.is_empty() { + self.inner.read_exact(buf); + ContainerRet::Bytes + } else { + ContainerRet::Bits(self.read_bits(amt * 8).unwrap()) + } + } } #[cfg(test)] @@ -55,12 +78,8 @@ mod tests { let mut container = Container::new(buf); let bits = container.read_bits(4).unwrap(); - println!("{}", bits); let bits = container.read_bits(4).unwrap(); - println!("{}", bits); let bits = container.read_bits(4).unwrap(); - println!("{}", bits); let bits = container.read_bits(4).unwrap(); - println!("{}", bits); } } diff --git a/src/impls/bool.rs b/src/impls/bool.rs index 033c9a35..c8ebc736 100644 --- a/src/impls/bool.rs +++ b/src/impls/bool.rs @@ -5,7 +5,7 @@ use alloc::format; use bitvec::prelude::*; -use crate::{DekuError, DekuRead, DekuWrite, container}; +use crate::{container, DekuError, DekuRead, DekuWrite}; impl<'a, Ctx> DekuRead<'a, Ctx> for bool where diff --git a/src/impls/cow.rs b/src/impls/cow.rs index d1da2704..fe9edf86 100644 --- a/src/impls/cow.rs +++ b/src/impls/cow.rs @@ -1,4 +1,7 @@ -use std::{borrow::{Borrow, Cow}, io::Read}; +use std::{ + borrow::{Borrow, Cow}, + io::Read, +}; use bitvec::prelude::*; diff --git a/src/impls/ipaddr.rs b/src/impls/ipaddr.rs index e6162545..7a617487 100644 --- a/src/impls/ipaddr.rs +++ b/src/impls/ipaddr.rs @@ -1,4 +1,7 @@ -use std::{net::{IpAddr, Ipv4Addr, Ipv6Addr}, io::Read}; +use std::{ + io::Read, + net::{IpAddr, Ipv4Addr, Ipv6Addr}, +}; use bitvec::prelude::*; diff --git a/src/impls/primitive.rs b/src/impls/primitive.rs index 48cb21a6..e6d55efb 100644 --- a/src/impls/primitive.rs +++ b/src/impls/primitive.rs @@ -5,12 +5,14 @@ use core::convert::TryInto; use bitvec::prelude::*; use std::io::Read; +use crate::container::ContainerRet; use crate::ctx::*; use crate::prelude::NeedSize; use crate::{DekuError, DekuRead, DekuWrite}; // specialize u8 for ByteSize impl DekuRead<'_, (Endian, ByteSize)> for u8 { + #[inline] fn read( input: &BitSlice, (_, _): (Endian, ByteSize), @@ -25,19 +27,31 @@ impl DekuRead<'_, (Endian, ByteSize)> for u8 { Ok((MAX_TYPE_BITS, value)) } + // specialize not needed? + #[inline] fn from_reader( container: &mut crate::container::Container, (endian, size): (Endian, ByteSize), ) -> Result { - let mut bits = container.read_bits(8).unwrap(); - let a = ::read(&mut bits, (endian, size))?; - Ok(a.1) + let mut buf = [0; core::mem::size_of::()]; + let ret = container.read_bytes(size.0, &mut buf); + let a = match ret { + ContainerRet::Bits(mut bits) => { + let a = ::read(&bits, (endian, size))?; + a.1 + } + ContainerRet::Bytes => { + ::from_be_bytes(buf) + } + }; + Ok(a) } } macro_rules! ImplDekuReadBits { ($typ:ty, $inner:ty) => { impl DekuRead<'_, (Endian, BitSize)> for $typ { + #[inline] fn read( input: &BitSlice, (endian, size): (Endian, BitSize), @@ -122,12 +136,13 @@ macro_rules! ImplDekuReadBits { Ok((bit_size, value)) } + #[inline] fn from_reader( container: &mut crate::container::Container, (endian, size): (Endian, BitSize), ) -> Result<$typ, DekuError> { let mut bits = container.read_bits(size.0).unwrap(); - let a = <$typ>::read(&mut bits, (endian, size))?; + let a = <$typ>::read(&bits, (endian, size))?; Ok(a.1) } } @@ -137,6 +152,7 @@ macro_rules! ImplDekuReadBits { macro_rules! ImplDekuReadBytes { ($typ:ty, $inner:ty) => { impl DekuRead<'_, (Endian, ByteSize)> for $typ { + #[inline] fn read( input: &BitSlice, (endian, size): (Endian, ByteSize), @@ -202,13 +218,23 @@ macro_rules! ImplDekuReadBytes { Ok((bit_size, value)) } + #[inline] fn from_reader( container: &mut crate::container::Container, (endian, size): (Endian, ByteSize), ) -> Result<$typ, DekuError> { - let mut bits = container.read_bits(size.0 * 8).unwrap(); - let a = <$typ>::read(&mut bits, (endian, size))?; - Ok(a.1) + let mut buf = [0; core::mem::size_of::<$typ>()]; + let ret = container.read_bytes(size.0, &mut buf); + let a = match ret { + ContainerRet::Bits(mut bits) => { + let a = <$typ>::read(&bits, (endian, size))?; + a.1 + } + ContainerRet::Bytes => { + <$typ>::from_be_bytes(buf.try_into().unwrap()) + } + }; + Ok(a) } } }; @@ -217,6 +243,7 @@ macro_rules! ImplDekuReadBytes { macro_rules! ImplDekuReadSignExtend { ($typ:ty, $inner:ty) => { impl DekuRead<'_, (Endian, ByteSize)> for $typ { + #[inline] fn read( input: &BitSlice, (endian, size): (Endian, ByteSize), @@ -231,17 +258,20 @@ macro_rules! ImplDekuReadSignExtend { Ok((amt_read, value)) } + #[inline] fn from_reader( container: &mut crate::container::Container, (endian, size): (Endian, ByteSize), ) -> Result<$typ, DekuError> { + // TODO: specialize for reading byte aligned let mut bits = container.read_bits(size.0 * 8).unwrap(); - let a = <$typ>::read(&mut bits, (endian, size))?; + let a = <$typ>::read(&bits, (endian, size))?; Ok(a.1) } } impl DekuRead<'_, (Endian, BitSize)> for $typ { + #[inline] fn read( input: &BitSlice, (endian, size): (Endian, BitSize), @@ -255,12 +285,14 @@ macro_rules! ImplDekuReadSignExtend { let value = (value as $typ) << shift >> shift; Ok((amt_read, value)) } + + #[inline] fn from_reader( container: &mut crate::container::Container, (endian, size): (Endian, BitSize), ) -> Result<$typ, DekuError> { - let mut bits = container.read_bits(size.0).unwrap(); - let a = <$typ>::read(&mut bits, (endian, size))?; + let mut bits = container.read_bits(size.0 * 8).unwrap(); + let a = <$typ>::read(&bits, (endian, size))?; Ok(a.1) } } @@ -271,6 +303,7 @@ macro_rules! ForwardDekuRead { ($typ:ty) => { // Only have `endian`, set `bit_size` to `Size::of::()` impl DekuRead<'_, Endian> for $typ { + #[inline] fn read( input: &BitSlice, endian: Endian, @@ -285,20 +318,26 @@ macro_rules! ForwardDekuRead { } } + #[inline] fn from_reader( container: &mut crate::container::Container, endian: Endian, ) -> Result<$typ, DekuError> { let bit_size = BitSize::of::<$typ>(); - let mut bits = container.read_bits(bit_size.0).unwrap(); - let a = <$typ>::read(&mut bits, endian)?; - Ok(a.1) + // Since we don't have a #[bits] or [bytes], check if we can use bytes for perf + let a = if (bit_size.0 % 8) == 0 { + <$typ>::from_reader(container, (endian, ByteSize(bit_size.0 / 8)))? + } else { + <$typ>::from_reader(container, (endian, bit_size))? + }; + Ok(a) } } // Only have `bit_size`, set `endian` to `Endian::default`. impl DekuRead<'_, ByteSize> for $typ { + #[inline] fn read( input: &BitSlice, byte_size: ByteSize, @@ -308,20 +347,21 @@ macro_rules! ForwardDekuRead { <$typ>::read(input, (endian, byte_size)) } + #[inline] fn from_reader( container: &mut crate::container::Container, byte_size: ByteSize, ) -> Result<$typ, DekuError> { let endian = Endian::default(); - let mut bits = container.read_bits(byte_size.0 * 8).unwrap(); - let a = <$typ>::read(&mut bits, (endian, byte_size))?; - Ok(a.1) + let a = <$typ>::from_reader(container, (endian, byte_size))?; + Ok(a) } } // Only have `bit_size`, set `endian` to `Endian::default`. impl DekuRead<'_, BitSize> for $typ { + #[inline] fn read( input: &BitSlice, bit_size: BitSize, @@ -336,23 +376,25 @@ macro_rules! ForwardDekuRead { } } + #[inline] fn from_reader( container: &mut crate::container::Container, bit_size: BitSize, ) -> Result<$typ, DekuError> { let endian = Endian::default(); - let mut bits = container.read_bits(bit_size.0).unwrap(); - let a = <$typ>::read(&mut bits, bit_size)?; - Ok(a.1) + let a = <$typ>::from_reader(container, (endian, bit_size))?; + Ok(a) } } impl DekuRead<'_> for $typ { + #[inline] fn read(input: &BitSlice, _: ()) -> Result<(usize, Self), DekuError> { <$typ>::read(input, Endian::default()) } + #[inline] fn from_reader( container: &mut crate::container::Container, _: (), @@ -366,6 +408,7 @@ macro_rules! ForwardDekuRead { macro_rules! ImplDekuWrite { ($typ:ty) => { impl DekuWrite<(Endian, BitSize)> for $typ { + #[inline] fn write( &self, output: &mut BitVec, @@ -411,6 +454,7 @@ macro_rules! ImplDekuWrite { } impl DekuWrite<(Endian, ByteSize)> for $typ { + #[inline] fn write( &self, output: &mut BitVec, @@ -457,6 +501,7 @@ macro_rules! ImplDekuWrite { // Only have `endian`, return all input impl DekuWrite for $typ { + #[inline] fn write( &self, output: &mut BitVec, @@ -477,6 +522,7 @@ macro_rules! ForwardDekuWrite { ($typ:ty) => { // Only have `bit_size`, set `endian` to `Endian::default`. impl DekuWrite for $typ { + #[inline] fn write( &self, output: &mut BitVec, @@ -488,6 +534,7 @@ macro_rules! ForwardDekuWrite { // Only have `bit_size`, set `endian` to `Endian::default`. impl DekuWrite for $typ { + #[inline] fn write( &self, output: &mut BitVec, @@ -498,6 +545,7 @@ macro_rules! ForwardDekuWrite { } impl DekuWrite for $typ { + #[inline] fn write(&self, output: &mut BitVec, _: ()) -> Result<(), DekuError> { <$typ>::write(self, output, Endian::default()) } diff --git a/src/impls/vec.rs b/src/impls/vec.rs index 03c2bf70..c1914764 100644 --- a/src/impls/vec.rs +++ b/src/impls/vec.rs @@ -48,6 +48,42 @@ where Ok((total_read, res)) } +/// Read `T`s into a vec until a given predicate returns true +/// * `capacity` - an optional capacity to pre-allocate the vector with +/// * `ctx` - The context required by `T`. It will be passed to every `T` when constructing. +/// * `predicate` - the predicate that decides when to stop reading `T`s +/// The predicate takes two parameters: the number of bits that have been read so far, +/// and a borrow of the latest value to have been read. It should return `true` if reading +/// should now stop, and `false` otherwise +fn reader_vec_with_predicate<'a, T, Ctx, Predicate, R: std::io::Read>( + container: &mut crate::container::Container, + capacity: Option, + ctx: Ctx, + mut predicate: Predicate, +) -> Result, DekuError> +where + T: DekuRead<'a, Ctx>, + Ctx: Copy, + Predicate: FnMut(usize, &T) -> bool, +{ + let mut res = capacity.map_or_else(Vec::new, Vec::with_capacity); + + let mut start_read = container.bits_read; + + loop { + let val = ::from_reader(container, ctx)?; + res.push(val); + + // This unwrap is safe as we are pushing to the vec immediately before it, + // so there will always be a last element + if predicate(container.bits_read - start_read, res.last().unwrap()) { + break; + } + } + + Ok(res) +} + impl<'a, T, Ctx, Predicate> DekuRead<'a, (Limit, Ctx)> for Vec where T: DekuRead<'a, Ctx>, @@ -111,6 +147,66 @@ where } } } + + /// Read `T`s until the given limit + /// * `limit` - the limiting factor on the amount of `T`s to read + /// * `inner_ctx` - The context required by `T`. It will be passed to every `T`s when constructing. + /// # Examples + /// ```rust + /// # use deku::ctx::*; + /// # use deku::DekuRead; + /// # use deku::bitvec::BitView; + /// let input = vec![1u8, 2, 3, 4]; + /// let (amt_read, v) = Vec::::read(input.view_bits(), (1.into(), Endian::Little)).unwrap(); + /// assert_eq!(amt_read, 32); + /// assert_eq!(vec![0x04030201], v) + /// ``` + fn from_reader( + container: &mut crate::container::Container, + (limit, inner_ctx): (Limit, Ctx), + ) -> Result + where + Self: Sized, + { + match limit { + // Read a given count of elements + Limit::Count(mut count) => { + // Handle the trivial case of reading an empty vector + if count == 0 { + return Ok(Vec::new()); + } + + // Otherwise, read until we have read `count` elements + reader_vec_with_predicate(container, Some(count), inner_ctx, move |_, _| { + count -= 1; + count == 0 + }) + } + + // Read until a given predicate returns true + Limit::Until(mut predicate, _) => { + reader_vec_with_predicate(container, None, inner_ctx, move |_, value| { + predicate(value) + }) + } + + // Read until a given quantity of bits have been read + Limit::BitSize(size) => { + let bit_size = size.0; + reader_vec_with_predicate(container, None, inner_ctx, move |read_bits, _| { + read_bits == bit_size + }) + } + + // Read until a given quantity of bits have been read + Limit::ByteSize(size) => { + let bit_size = size.0 * 8; + reader_vec_with_predicate(container, None, inner_ctx, move |read_bits, _| { + read_bits == bit_size + }) + } + } + } } impl<'a, T: DekuRead<'a>, Predicate: FnMut(&T) -> bool> DekuRead<'a, Limit> diff --git a/src/lib.rs b/src/lib.rs index dc2018e1..e4dec3bb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -304,7 +304,10 @@ pub trait DekuRead<'a, Ctx = ()> { ctx: Ctx, ) -> Result<(usize, Self), DekuError> where - Self: Sized; + Self: Sized, + { + todo!(); + } fn from_reader( container: &mut crate::container::Container, From a8970762e91832c96139873aa37fa0d90e08c0e5 Mon Sep 17 00:00:00 2001 From: wcampbell Date: Wed, 2 Aug 2023 00:02:55 -0400 Subject: [PATCH 06/30] wip --- deku-derive/src/macros/deku_read.rs | 108 +++++++++++++-------------- examples/custom_reader_and_writer.rs | 4 +- examples/example.rs | 4 + src/container.rs | 2 +- src/impls/primitive.rs | 4 +- tests/test_attributes/test_ctx.rs | 4 +- 6 files changed, 62 insertions(+), 64 deletions(-) diff --git a/deku-derive/src/macros/deku_read.rs b/deku-derive/src/macros/deku_read.rs index 87cdcc5a..0d8b10b6 100644 --- a/deku-derive/src/macros/deku_read.rs +++ b/deku-derive/src/macros/deku_read.rs @@ -59,34 +59,32 @@ fn emit_struct(input: &DekuData) -> Result { // Implement `DekuContainerRead` for types that don't need a context if input.ctx.is_none() || (input.ctx.is_some() && input.ctx_default.is_some()) { - // let from_bytes_body = wrap_default_ctx( - // quote! { - // use core::convert::TryFrom; - // use ::#crate_::bitvec::BitView; - // let __deku_input_bits = __deku_input.0.view_bits::<::#crate_::bitvec::Msb0>(); - // let mut __deku_rest = &__deku_input_bits[__deku_input.1..]; - // let mut __deku_total_read = 0; - - // #magic_read - - // #(#field_reads)* - // let __deku_value = #initialize_struct; - - // Ok((__deku_total_read, __deku_value)) - // }, - // &input.ctx, - // &input.ctx_default, - // ); - - //tokens.extend(emit_try_from(&imp, &lifetime, &ident, wher)); - - // tokens.extend(emit_from_bytes( - // &imp, - // &lifetime, - // &ident, - // wher, - // from_bytes_body, - // )); + let from_bytes_body = wrap_default_ctx( + quote! { + use core::convert::TryFrom; + let container = &mut deku::container::Container::new(__deku_input.0); + let _ = container.read_bits(__deku_input.1); + + #magic_read + + #(#field_reads)* + let __deku_value = #initialize_struct; + + Ok((container.bits_read, __deku_value)) + }, + &input.ctx, + &input.ctx_default, + ); + + tokens.extend(emit_try_from(&imp, &lifetime, &ident, wher)); + + tokens.extend(emit_from_bytes( + &imp, + &lifetime, + &ident, + wher, + from_bytes_body, + )); } let (ctx_types, ctx_arg) = gen_ctx_types_and_arg(input.ctx.as_ref())?; @@ -299,33 +297,31 @@ fn emit_enum(input: &DekuData) -> Result { // Implement `DekuContainerRead` for types that don't need a context if input.ctx.is_none() || (input.ctx.is_some() && input.ctx_default.is_some()) { - //let from_bytes_body = wrap_default_ctx( - // quote! { - // use core::convert::TryFrom; - // use ::#crate_::bitvec::BitView; - // let __deku_input_bits = __deku_input.0.view_bits::<::#crate_::bitvec::Msb0>(); - // let mut __deku_rest = &__deku_input_bits[__deku_input.1..]; - // let mut __deku_total_read = 0; - - // #magic_read - - // #variant_read - - // Ok((__deku_total_read, __deku_value)) - // }, - // &input.ctx, - // &input.ctx_default, - //); - - //tokens.extend(emit_try_from(&imp, &lifetime, &ident, wher)); - - //tokens.extend(emit_from_bytes( - // &imp, - // &lifetime, - // &ident, - // wher, - // from_bytes_body, - //)); + let from_bytes_body = wrap_default_ctx( + quote! { + use core::convert::TryFrom; + let container = &mut deku::container::Container::new(__deku_input.0); + let _ = container.read_bits(__deku_input.1); + + #magic_read + + #variant_read + + Ok((container.bits_read, __deku_value)) + }, + &input.ctx, + &input.ctx_default, + ); + + tokens.extend(emit_try_from(&imp, &lifetime, &ident, wher)); + + tokens.extend(emit_from_bytes( + &imp, + &lifetime, + &ident, + wher, + from_bytes_body, + )); } let (ctx_types, ctx_arg) = gen_ctx_types_and_arg(input.ctx.as_ref())?; @@ -398,7 +394,7 @@ fn emit_magic_read(input: &DekuData) -> TokenStream { let __deku_magic = #magic; for __deku_byte in __deku_magic { - let __deku_read_byte = u8::from_reader(&mut container, ())?; + let __deku_read_byte = u8::from_reader(container, ())?; if *__deku_byte != __deku_read_byte { return Err(::#crate_::DekuError::Parse(format!("Missing magic value {:?}", #magic))); } diff --git a/examples/custom_reader_and_writer.rs b/examples/custom_reader_and_writer.rs index 099795c8..0bb8dbd4 100644 --- a/examples/custom_reader_and_writer.rs +++ b/examples/custom_reader_and_writer.rs @@ -8,7 +8,7 @@ fn bit_flipper_read( field_a: u8, rest: &BitSlice, bit_size: BitSize, -) -> Result<(usize, u8), DekuError> { +) -> Result { // Access to previously read fields println!("field_a = 0x{:X}", field_a); @@ -24,7 +24,7 @@ fn bit_flipper_read( // flip the bits on value if field_a is 0x01 let value = if field_a == 0x01 { !value } else { value }; - Ok((amt_read, value)) + Ok(value) } fn bit_flipper_write( diff --git a/examples/example.rs b/examples/example.rs index 8b7b0e13..526e9211 100644 --- a/examples/example.rs +++ b/examples/example.rs @@ -56,6 +56,10 @@ fn main() { let mut container = Container::new(std::io::Cursor::new(test_data)); let test_deku = DekuTest::from_reader(&mut container, ()).unwrap(); + let mut container = Container::new(std::io::Cursor::new(test_data)); + let test_deku_from_bytes = DekuTest::from_bytes((test_data, 0)).unwrap(); + assert_eq!(test_deku, test_deku_from_bytes.1); + println!("{test_deku:02x?}"); assert_eq!( DekuTest { diff --git a/src/container.rs b/src/container.rs index 03f931e0..7f84af2a 100644 --- a/src/container.rs +++ b/src/container.rs @@ -10,7 +10,7 @@ pub struct Container { inner: R, // TODO; bitslice.len() == 8 leftover: BitVec, - pub(crate) bits_read: usize, + pub bits_read: usize, } impl Container { diff --git a/src/impls/primitive.rs b/src/impls/primitive.rs index e6d55efb..6e42b849 100644 --- a/src/impls/primitive.rs +++ b/src/impls/primitive.rs @@ -40,9 +40,7 @@ impl DekuRead<'_, (Endian, ByteSize)> for u8 { let a = ::read(&bits, (endian, size))?; a.1 } - ContainerRet::Bytes => { - ::from_be_bytes(buf) - } + ContainerRet::Bytes => ::from_be_bytes(buf), }; Ok(a) } diff --git a/tests/test_attributes/test_ctx.rs b/tests/test_attributes/test_ctx.rs index abc1030c..43114f26 100644 --- a/tests/test_attributes/test_ctx.rs +++ b/tests/test_attributes/test_ctx.rs @@ -53,7 +53,7 @@ fn test_top_level_ctx_enum() { #[deku(id = "1")] VariantA( #[deku( - reader = "(|rest|{u8::read(rest,()).map(|(slice,c)|(slice,(a+b+c)))})(deku::rest)", + reader = "(|rest|{u8::read(rest,()).map(|(slice,c)|(slice,(a+b+c)))})", writer = "(|c|{u8::write(&(c-a-b), deku::output, ())})(field_0)" )] u8, @@ -79,7 +79,7 @@ fn test_top_level_ctx_enum_default() { #[deku(id = "1")] VariantA( #[deku( - reader = "(|rest|{u8::read(rest,()).map(|(slice,c)|(slice,(a+b+c)))})(deku::rest)", + reader = "(|rest|{u8::read(rest,()).map(|(slice,c)|(slice,(a+b+c)))})", writer = "(|c|{u8::write(&(c-a-b), deku::output, ())})(field_0)" )] u8, From ba06d8b8cecc5bacc58a17e3495961e7076a9050 Mon Sep 17 00:00:00 2001 From: wcampbell Date: Wed, 2 Aug 2023 20:21:03 -0400 Subject: [PATCH 07/30] wip --- deku-derive/src/lib.rs | 7 +-- deku-derive/src/macros/deku_read.rs | 29 +++++------ examples/custom_reader_and_writer.rs | 13 ++--- examples/example.rs | 1 + src/container.rs | 51 +++++++++---------- src/error.rs | 2 + src/impls/primitive.rs | 20 +++++--- src/impls/vec.rs | 2 +- src/prelude.rs | 4 +- tests/test_attributes/test_ctx.rs | 25 ++++----- .../test_compile/cases/internal_variables.rs | 12 ++--- 11 files changed, 85 insertions(+), 81 deletions(-) diff --git a/deku-derive/src/lib.rs b/deku-derive/src/lib.rs index 402663ca..e1fc07ff 100644 --- a/deku-derive/src/lib.rs +++ b/deku-derive/src/lib.rs @@ -667,10 +667,11 @@ fn apply_replacements(input: &syn::LitStr) -> Result, Repla } let input_str = input_value - .replace("deku::input", "__deku_input") // part of the public API `from_bytes` - .replace("deku::input_bits", "__deku_input_bits") // part of the public API `read` + // TODO: remove these? + //.replace("deku::input", "__deku_input") // part of the public API `from_bytes` + //.replace("deku::input_bits", "__deku_input_bits") // part of the public API `read` .replace("deku::output", "__deku_output") // part of the public API `write` - .replace("deku::rest", "&__deku_rest[__deku_total_read..]") + .replace("deku::reader", "container") .replace("deku::bit_offset", "__deku_bit_offset") .replace("deku::byte_offset", "__deku_byte_offset"); diff --git a/deku-derive/src/macros/deku_read.rs b/deku-derive/src/macros/deku_read.rs index 0d8b10b6..7d788dfc 100644 --- a/deku-derive/src/macros/deku_read.rs +++ b/deku-derive/src/macros/deku_read.rs @@ -63,7 +63,7 @@ fn emit_struct(input: &DekuData) -> Result { quote! { use core::convert::TryFrom; let container = &mut deku::container::Container::new(__deku_input.0); - let _ = container.read_bits(__deku_input.1); + let _ = container.read_bits(__deku_input.1)?; #magic_read @@ -104,7 +104,7 @@ fn emit_struct(input: &DekuData) -> Result { tokens.extend(quote! { impl #imp ::#crate_::DekuRead<#lifetime, #ctx_types> for #ident #wher { - fn from_reader(container: &#lifetime mut ::#crate_::container::Container, #ctx_arg) -> core::result::Result { + fn from_reader(container: &mut ::#crate_::container::Container, #ctx_arg) -> core::result::Result { #read_body } } @@ -115,7 +115,7 @@ fn emit_struct(input: &DekuData) -> Result { tokens.extend(quote! { impl #imp ::#crate_::DekuRead<#lifetime> for #ident #wher { - fn from_reader(container: &#lifetime mut ::#crate_::container::Container, _: ()) -> core::result::Result { + fn from_reader(container: &mut ::#crate_::container::Container, _: ()) -> core::result::Result { #read_body } } @@ -274,7 +274,7 @@ fn emit_enum(input: &DekuData) -> Result { let variant_id_read = if id.is_some() { quote! { - let (__deku_amt_read, __deku_variant_id) = (0, (#id)); + let __deku_variant_id = (#id); } } else if id_type.is_some() { quote! { @@ -301,7 +301,7 @@ fn emit_enum(input: &DekuData) -> Result { quote! { use core::convert::TryFrom; let container = &mut deku::container::Container::new(__deku_input.0); - let _ = container.read_bits(__deku_input.1); + let _ = container.read_bits(__deku_input.1)?; #magic_read @@ -340,7 +340,7 @@ fn emit_enum(input: &DekuData) -> Result { tokens.extend(quote! { #[allow(non_snake_case)] impl #imp ::#crate_::DekuRead<#lifetime, #ctx_types> for #ident #wher { - fn from_reader(container: &#lifetime mut ::#crate_::container::Container, #ctx_arg) -> core::result::Result { + fn from_reader(container: &mut ::#crate_::container::Container, #ctx_arg) -> core::result::Result { #read_body } } @@ -352,7 +352,7 @@ fn emit_enum(input: &DekuData) -> Result { tokens.extend(quote! { #[allow(non_snake_case)] impl #imp ::#crate_::DekuRead<#lifetime> for #ident #wher { - fn from_reader(container: &#lifetime mut ::#crate_::container::Container, _: ()) -> core::result::Result { + fn from_reader(container: &mut ::#crate_::container::Container, _: ()) -> core::result::Result { #read_body } } @@ -439,7 +439,7 @@ fn emit_bit_byte_offsets( .any(|v| token_contains_string(v, "__deku_byte_offset")) { Some(quote! { - let __deku_byte_offset = __deku_bit_offset / 8; + let __deku_byte_offset = container.bits_read / 8; }) } else { None @@ -451,7 +451,7 @@ fn emit_bit_byte_offsets( || byte_offset.is_some() { Some(quote! { - let __deku_bit_offset = usize::try_from(unsafe { __deku_rest.as_bitptr().offset_from(__deku_input_bits.as_bitptr()) } )?; + let __deku_bit_offset = container.bits_read; }) } else { None @@ -465,6 +465,7 @@ fn emit_padding(bit_size: &TokenStream) -> TokenStream { quote! { { use core::convert::TryFrom; + // TODO: I hope this consts in most cases? let __deku_pad = usize::try_from(#bit_size).map_err(|e| ::#crate_::DekuError::InvalidParam(format!( "Invalid padding param \"({})\": cannot convert to usize", @@ -472,11 +473,9 @@ fn emit_padding(bit_size: &TokenStream) -> TokenStream { )) )?; - if __deku_rest[__deku_total_read..].len() >= __deku_pad { - __deku_total_read += __deku_pad; - } else { - return Err(::#crate_::DekuError::Incomplete(::#crate_::error::NeedSize::new(__deku_pad))); - } + + // TODO: This could be bytes + container.read_bits(__deku_pad)?; } } } @@ -657,7 +656,7 @@ fn emit_field_read( let field_read_normal = quote! { let __deku_value = #field_read_func?; - //let __deku_value: #field_type = #field_map(__deku_value)?; + let __deku_value: #field_type = #field_map(__deku_value)?; __deku_value }; diff --git a/examples/custom_reader_and_writer.rs b/examples/custom_reader_and_writer.rs index 0bb8dbd4..d423e404 100644 --- a/examples/custom_reader_and_writer.rs +++ b/examples/custom_reader_and_writer.rs @@ -1,25 +1,22 @@ use std::convert::TryInto; -use deku::bitvec::{BitSlice, BitVec, Msb0}; +use deku::bitvec::{BitVec, Msb0}; use deku::ctx::BitSize; use deku::prelude::*; -fn bit_flipper_read( +fn bit_flipper_read( field_a: u8, - rest: &BitSlice, + container: &mut Container, bit_size: BitSize, ) -> Result { // Access to previously read fields println!("field_a = 0x{:X}", field_a); - // The current rest - println!("rest = {:?}", rest); - // Size of the current field println!("bit_size: {:?}", bit_size); // read field_b, calling original func - let (amt_read, value) = u8::read(rest, bit_size)?; + let value = u8::from_reader(container, bit_size)?; // flip the bits on value if field_a is 0x01 let value = if field_a == 0x01 { !value } else { value }; @@ -53,7 +50,7 @@ struct DekuTest { field_a: u8, #[deku( - reader = "bit_flipper_read(*field_a, deku::rest, BitSize(8))", + reader = "bit_flipper_read(*field_a, deku::reader, BitSize(8))", writer = "bit_flipper_write(*field_a, *field_b, deku::output, BitSize(8))" )] field_b: u8, diff --git a/examples/example.rs b/examples/example.rs index 526e9211..58fe725a 100644 --- a/examples/example.rs +++ b/examples/example.rs @@ -11,6 +11,7 @@ use deku::{ #[derive(Debug, PartialEq, DekuRead, DekuWrite)] struct FieldF { #[deku(bits = "6")] + #[deku(assert_eq = "6")] data: u8, } diff --git a/src/container.rs b/src/container.rs index 7f84af2a..07935411 100644 --- a/src/container.rs +++ b/src/container.rs @@ -1,5 +1,7 @@ use bitvec::prelude::*; -use std::io::Read; +use std::io::{self, Read}; + +use crate::{prelude::NeedSize, DekuError}; pub enum ContainerRet { Bytes, @@ -23,7 +25,11 @@ impl Container { } } - pub fn read_bits(&mut self, amt: usize) -> std::io::Result> { + #[inline] + pub fn read_bits(&mut self, amt: usize) -> Result, DekuError> { + if amt == 0 { + return Ok(BitVec::new()); + } let mut ret = BitVec::with_capacity(amt); if amt < self.leftover.len() { @@ -34,12 +40,16 @@ impl Container { ret.extend(self.leftover.clone()); let bits_left = amt - self.leftover.len(); - let mut bytes_len = (bits_left / 8); + let mut bytes_len = bits_left / 8; if (bits_left % 8) != 0 { bytes_len += 1; } let mut buf = vec![0; bytes_len]; - self.inner.read_exact(&mut buf); + if let Err(e) = self.inner.read_exact(&mut buf) { + if e.kind() == io::ErrorKind::UnexpectedEof { + return Err(DekuError::Incomplete(NeedSize::new(amt))); + } + } let mut rest: BitVec = BitVec::try_from_slice(&buf).unwrap(); let add = rest.split_off(bits_left); @@ -56,30 +66,19 @@ impl Container { // // 1. We must have no leftover bits, so that we are "aligned" #[inline] - pub fn read_bytes(&mut self, amt: usize, buf: &mut [u8]) -> ContainerRet { + pub fn read_bytes(&mut self, amt: usize, buf: &mut [u8]) -> Result { if self.leftover.is_empty() { - self.inner.read_exact(buf); - ContainerRet::Bytes + if let Err(e) = self.inner.read_exact(&mut buf[..amt]) { + if e.kind() == io::ErrorKind::UnexpectedEof { + return Err(DekuError::Incomplete(NeedSize::new(amt * 8))); + } + + // TODO: other errors? + } + self.bits_read += amt * 8; + Ok(ContainerRet::Bytes) } else { - ContainerRet::Bits(self.read_bits(amt * 8).unwrap()) + Ok(ContainerRet::Bits(self.read_bits(amt * 8)?)) } } } - -#[cfg(test)] -mod tests { - use super::*; - #[test] - fn test_container() { - use std::io::Cursor; - let buf = [0x12, 0x34]; - let buf = std::io::Cursor::new(buf); - - let mut container = Container::new(buf); - - let bits = container.read_bits(4).unwrap(); - let bits = container.read_bits(4).unwrap(); - let bits = container.read_bits(4).unwrap(); - let bits = container.read_bits(4).unwrap(); - } -} diff --git a/src/error.rs b/src/error.rs index 061f58dc..63143bed 100644 --- a/src/error.rs +++ b/src/error.rs @@ -6,6 +6,8 @@ use alloc::format; use alloc::string::String; /// Number of bits needed to retry parsing +/// +/// TODO: add bytes #[derive(Debug, Clone, PartialEq, Eq)] pub struct NeedSize { bits: usize, diff --git a/src/impls/primitive.rs b/src/impls/primitive.rs index 6e42b849..42ed671a 100644 --- a/src/impls/primitive.rs +++ b/src/impls/primitive.rs @@ -34,9 +34,9 @@ impl DekuRead<'_, (Endian, ByteSize)> for u8 { (endian, size): (Endian, ByteSize), ) -> Result { let mut buf = [0; core::mem::size_of::()]; - let ret = container.read_bytes(size.0, &mut buf); + let ret = container.read_bytes(size.0, &mut buf)?; let a = match ret { - ContainerRet::Bits(mut bits) => { + ContainerRet::Bits(bits) => { let a = ::read(&bits, (endian, size))?; a.1 } @@ -139,7 +139,7 @@ macro_rules! ImplDekuReadBits { container: &mut crate::container::Container, (endian, size): (Endian, BitSize), ) -> Result<$typ, DekuError> { - let mut bits = container.read_bits(size.0).unwrap(); + let bits = container.read_bits(size.0)?; let a = <$typ>::read(&bits, (endian, size))?; Ok(a.1) } @@ -222,14 +222,18 @@ macro_rules! ImplDekuReadBytes { (endian, size): (Endian, ByteSize), ) -> Result<$typ, DekuError> { let mut buf = [0; core::mem::size_of::<$typ>()]; - let ret = container.read_bytes(size.0, &mut buf); + let ret = container.read_bytes(size.0, &mut buf)?; let a = match ret { - ContainerRet::Bits(mut bits) => { + ContainerRet::Bits(bits) => { let a = <$typ>::read(&bits, (endian, size))?; a.1 } ContainerRet::Bytes => { - <$typ>::from_be_bytes(buf.try_into().unwrap()) + if endian.is_le() { + <$typ>::from_le_bytes(buf.try_into().unwrap()) + } else { + <$typ>::from_be_bytes(buf.try_into().unwrap()) + } } }; Ok(a) @@ -262,7 +266,7 @@ macro_rules! ImplDekuReadSignExtend { (endian, size): (Endian, ByteSize), ) -> Result<$typ, DekuError> { // TODO: specialize for reading byte aligned - let mut bits = container.read_bits(size.0 * 8).unwrap(); + let bits = container.read_bits(size.0 * 8)?; let a = <$typ>::read(&bits, (endian, size))?; Ok(a.1) } @@ -289,7 +293,7 @@ macro_rules! ImplDekuReadSignExtend { container: &mut crate::container::Container, (endian, size): (Endian, BitSize), ) -> Result<$typ, DekuError> { - let mut bits = container.read_bits(size.0 * 8).unwrap(); + let bits = container.read_bits(size.0 * 8)?; let a = <$typ>::read(&bits, (endian, size))?; Ok(a.1) } diff --git a/src/impls/vec.rs b/src/impls/vec.rs index c1914764..fe5289ce 100644 --- a/src/impls/vec.rs +++ b/src/impls/vec.rs @@ -68,7 +68,7 @@ where { let mut res = capacity.map_or_else(Vec::new, Vec::with_capacity); - let mut start_read = container.bits_read; + let start_read = container.bits_read; loop { let val = ::from_reader(container, ctx)?; diff --git a/src/prelude.rs b/src/prelude.rs index 3ac88025..11d6f6c6 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -4,6 +4,6 @@ */ pub use crate::error::{DekuError, NeedSize}; pub use crate::{ - deku_derive, DekuContainerRead, DekuContainerWrite, DekuEnumExt, DekuRead, DekuUpdate, - DekuWrite, + container::Container, deku_derive, DekuContainerRead, DekuContainerWrite, DekuEnumExt, + DekuRead, DekuUpdate, DekuWrite, }; diff --git a/tests/test_attributes/test_ctx.rs b/tests/test_attributes/test_ctx.rs index 43114f26..213f8b04 100644 --- a/tests/test_attributes/test_ctx.rs +++ b/tests/test_attributes/test_ctx.rs @@ -1,7 +1,9 @@ use std::convert::{TryFrom, TryInto}; +use std::io::Cursor; use bitvec::bitvec; use deku::bitvec::{BitView, Msb0}; +use deku::container::Container; use deku::prelude::*; /// General smoke tests for ctx @@ -13,7 +15,7 @@ fn test_ctx_struct() { #[deku(ctx = "a: u8, b: u8")] struct SubTypeNeedCtx { #[deku( - reader = "(|rest|{u8::read(rest,()).map(|(slice,c)|(slice,(a+b+c) as usize))})(deku::rest)", + reader = "(u8::from_reader(container,()).map(|c|(a+b+c) as usize))", writer = "(|c|{u8::write(&(c-a-b), deku::output, ())})(self.i as u8)" )] i: usize, @@ -53,7 +55,7 @@ fn test_top_level_ctx_enum() { #[deku(id = "1")] VariantA( #[deku( - reader = "(|rest|{u8::read(rest,()).map(|(slice,c)|(slice,(a+b+c)))})", + reader = "(u8::from_reader(container,()).map(|c|(a+b+c)))", writer = "(|c|{u8::write(&(c-a-b), deku::output, ())})(field_0)" )] u8, @@ -61,9 +63,8 @@ fn test_top_level_ctx_enum() { } let test_data = [0x01_u8, 0x03]; - let bit_slice = test_data.view_bits(); - let (amt_read, ret_read) = TopLevelCtxEnum::read(bit_slice, (1, 2)).unwrap(); - assert!(bit_slice[amt_read..].is_empty()); + let ret_read = + TopLevelCtxEnum::from_reader(&mut Container::new(Cursor::new(test_data)), (1, 2)).unwrap(); assert_eq!(ret_read, TopLevelCtxEnum::VariantA(0x06)); let mut ret_write = bitvec![u8, Msb0;]; @@ -79,7 +80,7 @@ fn test_top_level_ctx_enum_default() { #[deku(id = "1")] VariantA( #[deku( - reader = "(|rest|{u8::read(rest,()).map(|(slice,c)|(slice,(a+b+c)))})", + reader = "(u8::from_reader(container, ()).map(|c|(a+b+c)))", writer = "(|c|{u8::write(&(c-a-b), deku::output, ())})(field_0)" )] u8, @@ -96,9 +97,9 @@ fn test_top_level_ctx_enum_default() { assert_eq!(test_data.to_vec(), ret_write); // Use context - let bit_slice = test_data.view_bits(); - let (amt_read, ret_read) = TopLevelCtxEnumDefault::read(bit_slice, (1, 2)).unwrap(); - assert!(bit_slice[amt_read..].is_empty()); + let ret_read = + TopLevelCtxEnumDefault::from_reader(&mut Container::new(Cursor::new(test_data)), (1, 2)) + .unwrap(); assert_eq!(ret_read, TopLevelCtxEnumDefault::VariantA(0x06)); let mut ret_write = bitvec![u8, Msb0;]; ret_read.write(&mut ret_write, (1, 2)).unwrap(); @@ -215,9 +216,9 @@ fn test_ctx_default_struct() { assert_eq!(ret_write, test_data); // Use context - let bit_slice = test_data.view_bits(); - let (amt_read, ret_read) = TopLevelCtxStructDefault::read(bit_slice, (1, 2)).unwrap(); - assert_eq!(bit_slice.len(), amt_read); + let ret_read = + TopLevelCtxStructDefault::from_reader(&mut Container::new(Cursor::new(test_data)), (1, 2)) + .unwrap(); assert_eq!(expected, ret_read); let mut ret_write = bitvec![u8, Msb0;]; ret_read.write(&mut ret_write, (1, 2)).unwrap(); diff --git a/tests/test_compile/cases/internal_variables.rs b/tests/test_compile/cases/internal_variables.rs index 4e5d1930..c9aa76aa 100644 --- a/tests/test_compile/cases/internal_variables.rs +++ b/tests/test_compile/cases/internal_variables.rs @@ -1,5 +1,5 @@ use deku::prelude::*; -use deku::bitvec::{BitVec, BitSlice, Msb0}; +use deku::bitvec::{BitVec, Msb0}; #[derive(DekuRead, DekuWrite)] struct TestCount { @@ -50,16 +50,16 @@ struct TestMap { field_b: usize } -fn dummy_reader( +fn dummy_reader( offset: usize, - rest: &BitSlice, -) -> Result<(usize, usize), DekuError> { - Ok((0, offset)) + _reader: &mut Container, +) -> Result { + Ok(0) } #[derive(DekuRead, DekuWrite)] struct TestReader { field_a: u8, - #[deku(reader = "dummy_reader(deku::byte_offset, deku::rest)")] + #[deku(reader = "dummy_reader(deku::byte_offset, deku::reader)")] field_b: usize } From 4768d51143369edcd743992faaa94c3b7b80a4e8 Mon Sep 17 00:00:00 2001 From: wcampbell Date: Thu, 3 Aug 2023 19:55:10 -0400 Subject: [PATCH 08/30] Perf / Comments --- src/container.rs | 55 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 11 deletions(-) diff --git a/src/container.rs b/src/container.rs index 07935411..a07b05bc 100644 --- a/src/container.rs +++ b/src/container.rs @@ -3,19 +3,25 @@ use std::io::{self, Read}; use crate::{prelude::NeedSize, DekuError}; +/// Return from `read_bytes` pub enum ContainerRet { + /// Successfully read bytes Bytes, + /// Read Bits intead Bits(BitVec), } -pub struct Container { +/// Container to use with `from_reader` +pub struct Container { inner: R, - // TODO; bitslice.len() == 8 + /// bits stored from previous reads that didn't read to the end of a byte size leftover: BitVec, + /// Amount of bits read during the use of `read_bits` and `read_bytes`. pub bits_read: usize, } impl Container { + /// Create a new `Container` #[inline] pub fn new(inner: R) -> Self { Self { @@ -25,6 +31,15 @@ impl Container { } } + /// Attempt to read bits from `Container`. This will always return a `BitVec` and will + /// correctly add previously read and stored "leftover" bits from previous reads. + /// + /// # Guarantees + /// - The returned `BitVec` will have the size of `amt` + /// - `self.bits_read` will increase by `amt` + /// + /// # Params + /// `amt` - Amount of bits that will be read #[inline] pub fn read_bits(&mut self, amt: usize) -> Result, DekuError> { if amt == 0 { @@ -32,39 +47,57 @@ impl Container { } let mut ret = BitVec::with_capacity(amt); - if amt < self.leftover.len() { + if amt == self.leftover.len() { + // exact match, just use leftover + ret = self.leftover.clone(); + self.leftover.clear(); + } else if amt < self.leftover.len() { + // The entire bits we need to return have been already read previously from bytes but + // not all were read, return required leftover bits let used = self.leftover.split_off(amt); - ret.extend(&mut self.leftover); + ret.extend_from_bitslice(&self.leftover); self.leftover = used; } else { - ret.extend(self.leftover.clone()); + // previous read was not enought to satisfy the amt requirement, return all previously + // read bits + ret.extend_from_bitslice(&self.leftover); + // calulcate the amount of bytes we need to read to read enough bits let bits_left = amt - self.leftover.len(); let mut bytes_len = bits_left / 8; if (bits_left % 8) != 0 { bytes_len += 1; } + + // read in new bytes let mut buf = vec![0; bytes_len]; if let Err(e) = self.inner.read_exact(&mut buf) { if e.kind() == io::ErrorKind::UnexpectedEof { return Err(DekuError::Incomplete(NeedSize::new(amt))); } + + // TODO: other errors? } + // create bitslice and remove unused bits let mut rest: BitVec = BitVec::try_from_slice(&buf).unwrap(); - let add = rest.split_off(bits_left); - ret.extend_from_bitslice(rest.as_bitslice()); + let not_needed = rest.split_off(bits_left); + self.leftover = not_needed; - self.leftover = add; + // create return + ret.extend_from_bitslice(rest.as_bitslice()); } self.bits_read += ret.len(); Ok(ret) } - // Attempt to read into bytes instead of bits - // - // 1. We must have no leftover bits, so that we are "aligned" + /// Attempt to read bytes from `Container`. This will return `ContainerRet::Bytes` with a valid + /// `buf` of bytes if we have no "leftover" bytes and thus are byte aligned. If we are not byte + /// aligned, this will call `read_bits` and return `ContainerRet::Bits(_)` of size `amt` * 8. + /// + /// # Params + /// `amt` - Amount of bytes that will be read #[inline] pub fn read_bytes(&mut self, amt: usize, buf: &mut [u8]) -> Result { if self.leftover.is_empty() { From 27f19834c2c43e303e8bcd4303afe1ef6be8d6af Mon Sep 17 00:00:00 2001 From: wcampbell Date: Thu, 3 Aug 2023 19:58:39 -0400 Subject: [PATCH 09/30] Add check --- src/container.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/container.rs b/src/container.rs index a07b05bc..5c13aaa8 100644 --- a/src/container.rs +++ b/src/container.rs @@ -101,6 +101,9 @@ impl Container { #[inline] pub fn read_bytes(&mut self, amt: usize, buf: &mut [u8]) -> Result { if self.leftover.is_empty() { + if buf.len() < amt { + return Err(DekuError::Incomplete(NeedSize::new(amt * 8))); + } if let Err(e) = self.inner.read_exact(&mut buf[..amt]) { if e.kind() == io::ErrorKind::UnexpectedEof { return Err(DekuError::Incomplete(NeedSize::new(amt * 8))); From 2c5188429016153d881466077691f92f6975c095 Mon Sep 17 00:00:00 2001 From: wcampbell Date: Thu, 3 Aug 2023 22:17:25 -0400 Subject: [PATCH 10/30] Add example many for testing --- examples/many.rs | 30 ++++++++++++++++++++++++++++++ src/impls/vec.rs | 26 +++++++++++++------------- 2 files changed, 43 insertions(+), 13 deletions(-) create mode 100644 examples/many.rs diff --git a/examples/many.rs b/examples/many.rs new file mode 100644 index 00000000..88f96490 --- /dev/null +++ b/examples/many.rs @@ -0,0 +1,30 @@ +use deku::{bitvec::BitView, container, ctx::Limit, prelude::*, DekuRead, DekuWrite}; +use std::io::Write; + +#[derive(Debug, DekuRead, DekuWrite)] +struct Test { + pub a: u64, + pub b: u64, + pub c: u64, +} + +fn main() { + let input: Vec<_> = (0..10_0000) + .map(|i| Test { + a: i, + b: i + 1, + c: i + 2, + }) + .collect(); + let custom: Vec = input + .iter() + .flat_map(|x| x.to_bytes().unwrap().into_iter()) + .collect(); + let mut container = Container::new(std::io::Cursor::new(custom.clone())); + let ret = as DekuRead>>::from_reader( + &mut container, + Limit::new_count(10_0000), + ); + + println!("{:?}", ret); +} diff --git a/src/impls/vec.rs b/src/impls/vec.rs index fe5289ce..4bae4630 100644 --- a/src/impls/vec.rs +++ b/src/impls/vec.rs @@ -1,3 +1,5 @@ +use std::io::Read; + #[cfg(feature = "alloc")] use alloc::vec::Vec; @@ -148,19 +150,6 @@ where } } - /// Read `T`s until the given limit - /// * `limit` - the limiting factor on the amount of `T`s to read - /// * `inner_ctx` - The context required by `T`. It will be passed to every `T`s when constructing. - /// # Examples - /// ```rust - /// # use deku::ctx::*; - /// # use deku::DekuRead; - /// # use deku::bitvec::BitView; - /// let input = vec![1u8, 2, 3, 4]; - /// let (amt_read, v) = Vec::::read(input.view_bits(), (1.into(), Endian::Little)).unwrap(); - /// assert_eq!(amt_read, 32); - /// assert_eq!(vec![0x04030201], v) - /// ``` fn from_reader( container: &mut crate::container::Container, (limit, inner_ctx): (Limit, Ctx), @@ -222,6 +211,17 @@ impl<'a, T: DekuRead<'a>, Predicate: FnMut(&T) -> bool> DekuRead<'a, Limit( + container: &mut crate::container::Container, + limit: Limit, + ) -> Result + where + Self: Sized, + { + Vec::from_reader(container, (limit, ())) + } } impl, Ctx: Copy> DekuWrite for Vec { From 4ad52cbf9086674b678e9c5dd3816215c08d339a Mon Sep 17 00:00:00 2001 From: wcampbell Date: Fri, 4 Aug 2023 18:47:19 -0400 Subject: [PATCH 11/30] Mkae read_bits be able to not return * save that stack baby --- deku-derive/src/macros/deku_read.rs | 10 +++++++--- src/container.rs | 12 ++++++------ src/impls/primitive.rs | 25 +++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 9 deletions(-) diff --git a/deku-derive/src/macros/deku_read.rs b/deku-derive/src/macros/deku_read.rs index 7d788dfc..28af2869 100644 --- a/deku-derive/src/macros/deku_read.rs +++ b/deku-derive/src/macros/deku_read.rs @@ -63,7 +63,9 @@ fn emit_struct(input: &DekuData) -> Result { quote! { use core::convert::TryFrom; let container = &mut deku::container::Container::new(__deku_input.0); - let _ = container.read_bits(__deku_input.1)?; + if __deku_input.1 != 0 { + let _ = container.read_bits(__deku_input.1)?; + } #magic_read @@ -301,7 +303,9 @@ fn emit_enum(input: &DekuData) -> Result { quote! { use core::convert::TryFrom; let container = &mut deku::container::Container::new(__deku_input.0); - let _ = container.read_bits(__deku_input.1)?; + if __deku_input.1 != 0 { + let _ = container.read_bits(__deku_input.1)?; + } #magic_read @@ -475,7 +479,7 @@ fn emit_padding(bit_size: &TokenStream) -> TokenStream { // TODO: This could be bytes - container.read_bits(__deku_pad)?; + let _ = container.read_bits(__deku_pad)?; } } } diff --git a/src/container.rs b/src/container.rs index 5c13aaa8..387f4f04 100644 --- a/src/container.rs +++ b/src/container.rs @@ -8,7 +8,7 @@ pub enum ContainerRet { /// Successfully read bytes Bytes, /// Read Bits intead - Bits(BitVec), + Bits(Option>), } /// Container to use with `from_reader` @@ -35,15 +35,15 @@ impl Container { /// correctly add previously read and stored "leftover" bits from previous reads. /// /// # Guarantees - /// - The returned `BitVec` will have the size of `amt` - /// - `self.bits_read` will increase by `amt` + /// - if Some(bits), the returned `BitVec` will have the size of `amt` and + /// `self.bits_read` will increase by `amt` /// /// # Params /// `amt` - Amount of bits that will be read #[inline] - pub fn read_bits(&mut self, amt: usize) -> Result, DekuError> { + pub fn read_bits(&mut self, amt: usize) -> Result>, DekuError> { if amt == 0 { - return Ok(BitVec::new()); + return Ok(None); } let mut ret = BitVec::with_capacity(amt); @@ -89,7 +89,7 @@ impl Container { } self.bits_read += ret.len(); - Ok(ret) + Ok(Some(ret)) } /// Attempt to read bytes from `Container`. This will return `ContainerRet::Bytes` with a valid diff --git a/src/impls/primitive.rs b/src/impls/primitive.rs index 42ed671a..3ccc2a81 100644 --- a/src/impls/primitive.rs +++ b/src/impls/primitive.rs @@ -37,6 +37,11 @@ impl DekuRead<'_, (Endian, ByteSize)> for u8 { let ret = container.read_bytes(size.0, &mut buf)?; let a = match ret { ContainerRet::Bits(bits) => { + let Some(bits) = bits else { + return Err(DekuError::Parse(format!( + "no bits read from reader", + ))); + }; let a = ::read(&bits, (endian, size))?; a.1 } @@ -140,6 +145,11 @@ macro_rules! ImplDekuReadBits { (endian, size): (Endian, BitSize), ) -> Result<$typ, DekuError> { let bits = container.read_bits(size.0)?; + let Some(bits) = bits else { + return Err(DekuError::Parse(format!( + "no bits read from reader", + ))); + }; let a = <$typ>::read(&bits, (endian, size))?; Ok(a.1) } @@ -225,6 +235,11 @@ macro_rules! ImplDekuReadBytes { let ret = container.read_bytes(size.0, &mut buf)?; let a = match ret { ContainerRet::Bits(bits) => { + let Some(bits) = bits else { + return Err(DekuError::Parse(format!( + "no bits read from reader", + ))); + }; let a = <$typ>::read(&bits, (endian, size))?; a.1 } @@ -267,6 +282,11 @@ macro_rules! ImplDekuReadSignExtend { ) -> Result<$typ, DekuError> { // TODO: specialize for reading byte aligned let bits = container.read_bits(size.0 * 8)?; + let Some(bits) = bits else { + return Err(DekuError::Parse(format!( + "no bits read from reader", + ))); + }; let a = <$typ>::read(&bits, (endian, size))?; Ok(a.1) } @@ -294,6 +314,11 @@ macro_rules! ImplDekuReadSignExtend { (endian, size): (Endian, BitSize), ) -> Result<$typ, DekuError> { let bits = container.read_bits(size.0 * 8)?; + let Some(bits) = bits else { + return Err(DekuError::Parse(format!( + "no bits read from reader", + ))); + }; let a = <$typ>::read(&bits, (endian, size))?; Ok(a.1) } From 64e686853c2ce0126d244c06b41552acdf411917 Mon Sep 17 00:00:00 2001 From: wcampbell Date: Fri, 4 Aug 2023 18:47:46 -0400 Subject: [PATCH 12/30] Impl from_reader for [N; T] --- src/impls/slice.rs | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/impls/slice.rs b/src/impls/slice.rs index 8a92d4ae..daf4e29e 100644 --- a/src/impls/slice.rs +++ b/src/impls/slice.rs @@ -183,6 +183,7 @@ mod pre_const_generics_impl { #[cfg(feature = "const_generics")] mod const_generics_impl { use core::mem::MaybeUninit; + use std::io::Read; use super::*; @@ -224,6 +225,40 @@ mod const_generics_impl { }; Ok((total_read, val)) } + + fn from_reader( + container: &mut crate::container::Container, + ctx: Ctx, + ) -> Result + where + Self: Sized, + { + #[allow(clippy::uninit_assumed_init)] + // This is safe because we initialize the array immediately after, + // and never return it in case of error + let mut slice: [MaybeUninit; N] = unsafe { MaybeUninit::uninit().assume_init() }; + for (n, item) in slice.iter_mut().enumerate() { + let value = match T::from_reader(container, ctx) { + Ok(it) => it, + Err(err) => { + // For each item in the array, drop if we allocated it. + for item in &mut slice[0..n] { + unsafe { + item.assume_init_drop(); + } + } + return Err(err); + } + }; + item.write(value); + } + + let val = unsafe { + // TODO: array_assume_init: https://github.com/rust-lang/rust/issues/80908 + (&slice as *const _ as *const [T; N]).read() + }; + Ok(val) + } } impl DekuWrite for [T; N] From be496bfc4661bc779ef87f45b43341154d0a9181 Mon Sep 17 00:00:00 2001 From: wcampbell Date: Sat, 5 Aug 2023 15:19:38 -0400 Subject: [PATCH 13/30] Use acid_io for no_std Read without nightly --- Cargo.toml | 5 +++-- deku-derive/src/macros/deku_read.rs | 4 ++-- src/container.rs | 8 ++++---- src/impls/bool.rs | 2 +- src/impls/boxed.rs | 2 +- src/impls/cow.rs | 7 +++---- src/impls/cstring.rs | 2 +- src/impls/ipaddr.rs | 7 +++---- src/impls/nonzero.rs | 2 +- src/impls/option.rs | 2 +- src/impls/primitive.rs | 14 ++++---------- src/impls/unit.rs | 2 +- src/impls/vec.rs | 6 +++--- src/lib.rs | 2 +- 14 files changed, 29 insertions(+), 36 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 83b400af..e065288d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,8 +20,8 @@ members = [ [features] default = ["std", "const_generics"] -std = ["deku_derive/std", "bitvec/std", "alloc"] -alloc = ["bitvec/alloc"] +std = ["deku_derive/std", "bitvec/std", "alloc", "acid_io/std", "acid_io/alloc"] +alloc = ["bitvec/alloc", "acid_io/alloc"] logging = ["deku_derive/logging", "log"] const_generics = [] @@ -29,6 +29,7 @@ const_generics = [] deku_derive = { version = "^0.16.0", path = "deku-derive", default-features = false} bitvec = { version = "1.0.1", default-features = false } log = { version = "0.4.17", optional = true } +acid_io = { git = "https://github.com/dataphract/acid_io.git", default-features = false, features = ["alloc"] } [dev-dependencies] rstest = "0.16.0" diff --git a/deku-derive/src/macros/deku_read.rs b/deku-derive/src/macros/deku_read.rs index 28af2869..9528aa5e 100644 --- a/deku-derive/src/macros/deku_read.rs +++ b/deku-derive/src/macros/deku_read.rs @@ -106,7 +106,7 @@ fn emit_struct(input: &DekuData) -> Result { tokens.extend(quote! { impl #imp ::#crate_::DekuRead<#lifetime, #ctx_types> for #ident #wher { - fn from_reader(container: &mut ::#crate_::container::Container, #ctx_arg) -> core::result::Result { + fn from_reader(container: &mut ::#crate_::container::Container, #ctx_arg) -> core::result::Result { #read_body } } @@ -117,7 +117,7 @@ fn emit_struct(input: &DekuData) -> Result { tokens.extend(quote! { impl #imp ::#crate_::DekuRead<#lifetime> for #ident #wher { - fn from_reader(container: &mut ::#crate_::container::Container, _: ()) -> core::result::Result { + fn from_reader(container: &mut ::#crate_::container::Container, _: ()) -> core::result::Result { #read_body } } diff --git a/src/container.rs b/src/container.rs index 387f4f04..293dbbde 100644 --- a/src/container.rs +++ b/src/container.rs @@ -1,5 +1,5 @@ +use acid_io::{self, Read}; use bitvec::prelude::*; -use std::io::{self, Read}; use crate::{prelude::NeedSize, DekuError}; @@ -70,9 +70,9 @@ impl Container { } // read in new bytes - let mut buf = vec![0; bytes_len]; + let mut buf = alloc::vec![0; bytes_len]; if let Err(e) = self.inner.read_exact(&mut buf) { - if e.kind() == io::ErrorKind::UnexpectedEof { + if e.kind() == acid_io::ErrorKind::UnexpectedEof { return Err(DekuError::Incomplete(NeedSize::new(amt))); } @@ -105,7 +105,7 @@ impl Container { return Err(DekuError::Incomplete(NeedSize::new(amt * 8))); } if let Err(e) = self.inner.read_exact(&mut buf[..amt]) { - if e.kind() == io::ErrorKind::UnexpectedEof { + if e.kind() == acid_io::ErrorKind::UnexpectedEof { return Err(DekuError::Incomplete(NeedSize::new(amt * 8))); } diff --git a/src/impls/bool.rs b/src/impls/bool.rs index c8ebc736..7f7ed8d0 100644 --- a/src/impls/bool.rs +++ b/src/impls/bool.rs @@ -1,4 +1,4 @@ -use std::io::Read; +use acid_io::Read; #[cfg(feature = "alloc")] use alloc::format; diff --git a/src/impls/boxed.rs b/src/impls/boxed.rs index 49a54a35..9eae6c73 100644 --- a/src/impls/boxed.rs +++ b/src/impls/boxed.rs @@ -1,4 +1,4 @@ -use std::io::Read; +use acid_io::Read; use alloc::boxed::Box; use alloc::vec::Vec; diff --git a/src/impls/cow.rs b/src/impls/cow.rs index fe9edf86..fd777799 100644 --- a/src/impls/cow.rs +++ b/src/impls/cow.rs @@ -1,7 +1,6 @@ -use std::{ - borrow::{Borrow, Cow}, - io::Read, -}; +use std::borrow::{Borrow, Cow}; + +use acid_io::Read; use bitvec::prelude::*; diff --git a/src/impls/cstring.rs b/src/impls/cstring.rs index f0bc384d..646f971d 100644 --- a/src/impls/cstring.rs +++ b/src/impls/cstring.rs @@ -1,5 +1,5 @@ +use acid_io::Read; use std::ffi::CString; -use std::io::Read; use bitvec::prelude::*; diff --git a/src/impls/ipaddr.rs b/src/impls/ipaddr.rs index 7a617487..0dea668a 100644 --- a/src/impls/ipaddr.rs +++ b/src/impls/ipaddr.rs @@ -1,7 +1,6 @@ -use std::{ - io::Read, - net::{IpAddr, Ipv4Addr, Ipv6Addr}, -}; +use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + +use acid_io::Read; use bitvec::prelude::*; diff --git a/src/impls/nonzero.rs b/src/impls/nonzero.rs index f57ab34a..f8427427 100644 --- a/src/impls/nonzero.rs +++ b/src/impls/nonzero.rs @@ -1,7 +1,7 @@ +use acid_io::Read; #[cfg(feature = "alloc")] use alloc::format; use core::num::*; -use std::io::Read; use bitvec::prelude::*; diff --git a/src/impls/option.rs b/src/impls/option.rs index cba6d245..d875a7f9 100644 --- a/src/impls/option.rs +++ b/src/impls/option.rs @@ -1,5 +1,5 @@ +use acid_io::Read; use bitvec::prelude::*; -use std::io::Read; use crate::{DekuError, DekuRead, DekuWrite}; diff --git a/src/impls/primitive.rs b/src/impls/primitive.rs index 3ccc2a81..d107a13d 100644 --- a/src/impls/primitive.rs +++ b/src/impls/primitive.rs @@ -2,8 +2,8 @@ use alloc::format; use core::convert::TryInto; +use acid_io::Read; use bitvec::prelude::*; -use std::io::Read; use crate::container::ContainerRet; use crate::ctx::*; @@ -38,9 +38,7 @@ impl DekuRead<'_, (Endian, ByteSize)> for u8 { let a = match ret { ContainerRet::Bits(bits) => { let Some(bits) = bits else { - return Err(DekuError::Parse(format!( - "no bits read from reader", - ))); + return Err(DekuError::Parse(format!("no bits read from reader",))); }; let a = ::read(&bits, (endian, size))?; a.1 @@ -283,9 +281,7 @@ macro_rules! ImplDekuReadSignExtend { // TODO: specialize for reading byte aligned let bits = container.read_bits(size.0 * 8)?; let Some(bits) = bits else { - return Err(DekuError::Parse(format!( - "no bits read from reader", - ))); + return Err(DekuError::Parse(format!("no bits read from reader",))); }; let a = <$typ>::read(&bits, (endian, size))?; Ok(a.1) @@ -315,9 +311,7 @@ macro_rules! ImplDekuReadSignExtend { ) -> Result<$typ, DekuError> { let bits = container.read_bits(size.0 * 8)?; let Some(bits) = bits else { - return Err(DekuError::Parse(format!( - "no bits read from reader", - ))); + return Err(DekuError::Parse(format!("no bits read from reader",))); }; let a = <$typ>::read(&bits, (endian, size))?; Ok(a.1) diff --git a/src/impls/unit.rs b/src/impls/unit.rs index 0df8791e..728fbc19 100644 --- a/src/impls/unit.rs +++ b/src/impls/unit.rs @@ -1,5 +1,5 @@ +use acid_io::Read; use bitvec::prelude::*; -use std::io::Read; use crate::{DekuError, DekuRead, DekuWrite}; diff --git a/src/impls/vec.rs b/src/impls/vec.rs index 4bae4630..5fbc5e3e 100644 --- a/src/impls/vec.rs +++ b/src/impls/vec.rs @@ -1,4 +1,4 @@ -use std::io::Read; +use acid_io::Read; #[cfg(feature = "alloc")] use alloc::vec::Vec; @@ -57,7 +57,7 @@ where /// The predicate takes two parameters: the number of bits that have been read so far, /// and a borrow of the latest value to have been read. It should return `true` if reading /// should now stop, and `false` otherwise -fn reader_vec_with_predicate<'a, T, Ctx, Predicate, R: std::io::Read>( +fn reader_vec_with_predicate<'a, T, Ctx, Predicate, R: Read>( container: &mut crate::container::Container, capacity: Option, ctx: Ctx, @@ -150,7 +150,7 @@ where } } - fn from_reader( + fn from_reader( container: &mut crate::container::Container, (limit, inner_ctx): (Limit, Ctx), ) -> Result diff --git a/src/lib.rs b/src/lib.rs index e4dec3bb..017ec004 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -269,7 +269,7 @@ pub struct EncodedString { #[cfg(feature = "alloc")] extern crate alloc; -use std::io::Read; +use acid_io::Read; #[cfg(feature = "alloc")] use alloc::vec::Vec; From 6b621d400c068b731894e6cad72520a122f7e4c4 Mon Sep 17 00:00:00 2001 From: wcampbell Date: Sat, 5 Aug 2023 15:19:52 -0400 Subject: [PATCH 14/30] Remove unused --- deku-derive/src/macros/deku_read.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/deku-derive/src/macros/deku_read.rs b/deku-derive/src/macros/deku_read.rs index 9528aa5e..089c5afc 100644 --- a/deku-derive/src/macros/deku_read.rs +++ b/deku-derive/src/macros/deku_read.rs @@ -93,8 +93,6 @@ fn emit_struct(input: &DekuData) -> Result { let read_body = quote! { use core::convert::TryFrom; - //let mut __deku_rest = __deku_input_bits; - //let mut __deku_total_read = 0; #magic_read @@ -331,8 +329,6 @@ fn emit_enum(input: &DekuData) -> Result { let read_body = quote! { use core::convert::TryFrom; - //let mut __deku_rest = __deku_input_bits; - //let mut __deku_total_read = 0; #magic_read From d1960b2d387572b1a4dc9f466c8910a4d347c3b6 Mon Sep 17 00:00:00 2001 From: wcampbell Date: Sat, 5 Aug 2023 15:20:03 -0400 Subject: [PATCH 15/30] Remove slice support for not("const_generics") --- src/impls/slice.rs | 76 ---------------------------------------------- 1 file changed, 76 deletions(-) diff --git a/src/impls/slice.rs b/src/impls/slice.rs index daf4e29e..fd579ef0 100644 --- a/src/impls/slice.rs +++ b/src/impls/slice.rs @@ -104,82 +104,6 @@ where } } -#[cfg(not(feature = "const_generics"))] -mod pre_const_generics_impl { - use super::*; - - macro_rules! ImplDekuSliceTraits { - ($typ:ty; $($count:expr),+ $(,)?) => { - - impl DekuWrite for &[$typ] - where - $typ: DekuWrite, - { - fn write(&self, output: &mut BitVec, ctx: Ctx) -> Result<(), DekuError> { - for v in *self { - v.write(output, ctx)?; - } - Ok(()) - } - } - - $( - impl<'a, Ctx: Copy> DekuRead<'a, Ctx> for [$typ; $count] - where - $typ: DekuRead<'a, Ctx>, - { - fn read( - input: &'a BitSlice, - ctx: Ctx, - ) -> Result<(usize, Self), DekuError> - where - Self: Sized, - { - let mut slice: [$typ; $count] = Default::default(); - let mut rest = input; - let mut total_read = 0; - for i in 0..$count { - let (amt_read, value) = <$typ>::read(rest, ctx)?; - slice[i] = value; - rest = new_rest[amt_read..]; - total_read += amt_read; - } - - Ok((total_read, slice)) - } - } - - impl DekuWrite for [$typ; $count] - where - $typ: DekuWrite, - { - fn write(&self, output: &mut BitVec, ctx: Ctx) -> Result<(), DekuError> { - for v in self { - v.write(output, ctx)?; - } - Ok(()) - } - } - )+ - }; - } - - ImplDekuSliceTraits!(i8; 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); - ImplDekuSliceTraits!(i16; 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); - ImplDekuSliceTraits!(i32; 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); - ImplDekuSliceTraits!(i64; 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); - ImplDekuSliceTraits!(i128; 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); - ImplDekuSliceTraits!(isize; 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); - ImplDekuSliceTraits!(u8; 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); - ImplDekuSliceTraits!(u16; 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); - ImplDekuSliceTraits!(u32; 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); - ImplDekuSliceTraits!(u64; 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); - ImplDekuSliceTraits!(u128; 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); - ImplDekuSliceTraits!(usize; 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); - ImplDekuSliceTraits!(f32; 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); - ImplDekuSliceTraits!(f64; 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); -} - #[cfg(feature = "const_generics")] mod const_generics_impl { use core::mem::MaybeUninit; From a0e2e162231b4a5080da46a73463bfa07c1b8fd6 Mon Sep 17 00:00:00 2001 From: wcampbell Date: Sat, 5 Aug 2023 15:21:49 -0400 Subject: [PATCH 16/30] Use acid_io for ensure_no_std --- ensure_no_std/Cargo.toml | 2 ++ ensure_no_std/src/bin/main.rs | 30 ++++++++---------------------- 2 files changed, 10 insertions(+), 22 deletions(-) diff --git a/ensure_no_std/Cargo.toml b/ensure_no_std/Cargo.toml index a8da0522..34891b28 100644 --- a/ensure_no_std/Cargo.toml +++ b/ensure_no_std/Cargo.toml @@ -20,4 +20,6 @@ alloc = [] [dependencies] wee_alloc = "0.4" +acid_io = { git = "https://github.com/dataphract/acid_io.git", default-features = false, features = ["alloc"] } deku = { path = "../", default-features = false, features = ["alloc"] } + diff --git a/ensure_no_std/src/bin/main.rs b/ensure_no_std/src/bin/main.rs index f065f8c0..747dbec3 100644 --- a/ensure_no_std/src/bin/main.rs +++ b/ensure_no_std/src/bin/main.rs @@ -8,34 +8,20 @@ extern crate alloc; extern crate wee_alloc; -#[no_mangle] -#[allow(non_snake_case)] -fn _Unwind_Resume() {} +use acid_io::{Cursor, Read, Seek, SeekFrom, Write}; -#[global_allocator] -static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; - -// Need to provide a tiny `panic` implementation for `#![no_std]`. -// This translates into an `unreachable` instruction that will -// raise a `trap` the WebAssembly execution if we panic at runtime. -#[panic_handler] #[no_mangle] -unsafe fn panic(_info: &::core::panic::PanicInfo) -> ! { - ::core::intrinsics::abort(); +pub extern "C" fn _start() -> ! { + loop {} } -// Need to provide an allocation error handler which just aborts -// the execution with trap. -#[alloc_error_handler] -#[no_mangle] -unsafe fn oom(_: ::core::alloc::Layout) -> ! { - ::core::intrinsics::abort(); +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} } -// Needed for non-wasm targets. -#[lang = "eh_personality"] -#[no_mangle] -extern "C" fn eh_personality() {} +#[global_allocator] +static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; use alloc::{format, vec, vec::Vec}; use deku::prelude::*; From 49bd8438d9f31507f02228826d800944fe9d5441 Mon Sep 17 00:00:00 2001 From: wcampbell Date: Sat, 5 Aug 2023 16:21:32 -0400 Subject: [PATCH 17/30] fixup! Use acid_io for no_std Read without nightly --- deku-derive/src/macros/deku_read.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deku-derive/src/macros/deku_read.rs b/deku-derive/src/macros/deku_read.rs index 089c5afc..4db21d10 100644 --- a/deku-derive/src/macros/deku_read.rs +++ b/deku-derive/src/macros/deku_read.rs @@ -104,7 +104,7 @@ fn emit_struct(input: &DekuData) -> Result { tokens.extend(quote! { impl #imp ::#crate_::DekuRead<#lifetime, #ctx_types> for #ident #wher { - fn from_reader(container: &mut ::#crate_::container::Container, #ctx_arg) -> core::result::Result { + fn from_reader(container: &mut ::#crate_::container::Container, #ctx_arg) -> core::result::Result { #read_body } } From 8b42713226a63400e0b5edf69a4d7a04b1dec871 Mon Sep 17 00:00:00 2001 From: wcampbell Date: Sat, 5 Aug 2023 16:21:32 -0400 Subject: [PATCH 18/30] fixup! Use acid_io for no_std Read without nightly --- deku-derive/src/macros/deku_read.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deku-derive/src/macros/deku_read.rs b/deku-derive/src/macros/deku_read.rs index 4db21d10..c7500c54 100644 --- a/deku-derive/src/macros/deku_read.rs +++ b/deku-derive/src/macros/deku_read.rs @@ -115,7 +115,7 @@ fn emit_struct(input: &DekuData) -> Result { tokens.extend(quote! { impl #imp ::#crate_::DekuRead<#lifetime> for #ident #wher { - fn from_reader(container: &mut ::#crate_::container::Container, _: ()) -> core::result::Result { + fn from_reader(container: &mut ::#crate_::container::Container, _: ()) -> core::result::Result { #read_body } } From 9562a7f490d55f97b144709c459624ed8b0baeb1 Mon Sep 17 00:00:00 2001 From: wcampbell Date: Sat, 5 Aug 2023 16:21:32 -0400 Subject: [PATCH 19/30] fixup! Use acid_io for ensure_no_std --- ensure_no_std/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/ensure_no_std/Cargo.toml b/ensure_no_std/Cargo.toml index 34891b28..5b9f659a 100644 --- a/ensure_no_std/Cargo.toml +++ b/ensure_no_std/Cargo.toml @@ -20,6 +20,5 @@ alloc = [] [dependencies] wee_alloc = "0.4" -acid_io = { git = "https://github.com/dataphract/acid_io.git", default-features = false, features = ["alloc"] } deku = { path = "../", default-features = false, features = ["alloc"] } From 61659c8281d6a77fc0dd087e241ec60e6ad2a400 Mon Sep 17 00:00:00 2001 From: wcampbell Date: Sat, 5 Aug 2023 16:21:32 -0400 Subject: [PATCH 20/30] fixup! Use acid_io for ensure_no_std --- ensure_no_std/src/bin/main.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/ensure_no_std/src/bin/main.rs b/ensure_no_std/src/bin/main.rs index 747dbec3..0cc98570 100644 --- a/ensure_no_std/src/bin/main.rs +++ b/ensure_no_std/src/bin/main.rs @@ -8,8 +8,6 @@ extern crate alloc; extern crate wee_alloc; -use acid_io::{Cursor, Read, Seek, SeekFrom, Write}; - #[no_mangle] pub extern "C" fn _start() -> ! { loop {} From b300f902592fc470357f99d0209c0aca4e39c2ec Mon Sep 17 00:00:00 2001 From: wcampbell Date: Sat, 5 Aug 2023 16:21:57 -0400 Subject: [PATCH 21/30] fixup! Use acid_io for no_std Read without nightly --- ensure_no_std/src/bin/main.rs | 2 +- src/lib.rs | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ensure_no_std/src/bin/main.rs b/ensure_no_std/src/bin/main.rs index 0cc98570..a64da7c8 100644 --- a/ensure_no_std/src/bin/main.rs +++ b/ensure_no_std/src/bin/main.rs @@ -3,7 +3,7 @@ #![no_std] #![no_main] -#![feature(core_intrinsics, lang_items, alloc_error_handler)] +#![feature(core_intrinsics, alloc_error_handler)] extern crate alloc; extern crate wee_alloc; diff --git a/src/lib.rs b/src/lib.rs index 017ec004..02606f6a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -274,6 +274,11 @@ use acid_io::Read; #[cfg(feature = "alloc")] use alloc::vec::Vec; +/// re-export of bitvec +pub mod acid_io { + pub use acid_io::Read; +} + /// re-export of bitvec pub mod bitvec { pub use bitvec::prelude::*; From ffb38a7f54e75466f0945eab632ae00e8db462e7 Mon Sep 17 00:00:00 2001 From: wcampbell Date: Sat, 5 Aug 2023 16:23:09 -0400 Subject: [PATCH 22/30] Remove support for &[u8] --- src/impls/slice.rs | 98 ------------------- .../test_limits/test_bits_read.rs | 12 +-- .../test_limits/test_bytes_read.rs | 12 +-- .../test_attributes/test_limits/test_count.rs | 16 +-- .../test_attributes/test_limits/test_until.rs | 16 +-- tests/test_generic.rs | 22 ----- 6 files changed, 28 insertions(+), 148 deletions(-) diff --git a/src/impls/slice.rs b/src/impls/slice.rs index fd579ef0..ae718ef1 100644 --- a/src/impls/slice.rs +++ b/src/impls/slice.rs @@ -6,104 +6,6 @@ pub use deku_derive::*; use crate::ctx::Limit; use crate::{DekuError, DekuRead, DekuWrite}; -/// Read `u8`s and returns a byte slice up until a given predicate returns true -/// * `ctx` - The context required by `u8`. It will be passed to every `u8` when constructing. -/// * `predicate` - the predicate that decides when to stop reading `u8`s -/// The predicate takes two parameters: the number of bits that have been read so far, -/// and a borrow of the latest value to have been read. It should return `true` if reading -/// should now stop, and `false` otherwise -fn read_slice_with_predicate<'a, Ctx, Predicate>( - input: &'a BitSlice, - ctx: Ctx, - mut predicate: Predicate, -) -> Result<(usize, &[u8]), DekuError> -where - u8: DekuRead<'a, Ctx>, - Ctx: Copy, - Predicate: FnMut(usize, &u8) -> bool, -{ - let mut rest = input; - let mut value; - let mut total_read = 0; - - loop { - let (amt_read, val) = u8::read(rest, ctx)?; - rest = &rest[amt_read..]; - total_read += amt_read; - - let read_idx = unsafe { rest.as_bitptr().offset_from(input.as_bitptr()) } as usize; - value = input[..read_idx].domain().region().unwrap().1; - - if predicate(read_idx, &val) { - break; - } - } - - Ok((total_read, value)) -} - -impl<'a, Ctx, Predicate> DekuRead<'a, (Limit, Ctx)> for &'a [u8] -where - u8: DekuRead<'a, Ctx>, - Ctx: Copy, - Predicate: FnMut(&u8) -> bool, -{ - /// Read `u8`s until the given limit - /// * `limit` - the limiting factor on the amount of `u8`s to read - /// * `inner_ctx` - The context required by `u8`. It will be passed to every `u8`s when constructing. - /// # Examples - /// ```rust - /// # use deku::ctx::*; - /// # use deku::DekuRead; - /// # use bitvec::view::BitView; - /// let input = vec![1u8, 2, 3, 4]; - /// let (amt_read, v) = <&[u8]>::read(input.view_bits(), (4.into(), Endian::Little)).unwrap(); - /// assert_eq!(amt_read, 32); - /// assert_eq!(&[1u8, 2, 3, 4], v) - /// ``` - fn read( - input: &'a BitSlice, - (limit, inner_ctx): (Limit, Ctx), - ) -> Result<(usize, Self), DekuError> { - match limit { - // Read a given count of elements - Limit::Count(mut count) => { - // Handle the trivial case of reading an empty slice - if count == 0 { - return Ok((0, &input.domain().region().unwrap().1[..0])); - } - - // Otherwise, read until we have read `count` elements - read_slice_with_predicate(input, inner_ctx, move |_, _| { - count -= 1; - count == 0 - }) - } - - // Read until a given predicate returns true - Limit::Until(mut predicate, _) => { - read_slice_with_predicate(input, inner_ctx, move |_, value| predicate(value)) - } - - // Read until a given quantity of bits have been read - Limit::BitSize(size) => { - let bit_size = size.0; - read_slice_with_predicate(input, inner_ctx, move |read_bits, _| { - read_bits == bit_size - }) - } - - // Read until a given quantity of bytes have been read - Limit::ByteSize(size) => { - let bit_size = size.0 * 8; - read_slice_with_predicate(input, inner_ctx, move |read_bits, _| { - read_bits == bit_size - }) - } - } - } -} - #[cfg(feature = "const_generics")] mod const_generics_impl { use core::mem::MaybeUninit; diff --git a/tests/test_attributes/test_limits/test_bits_read.rs b/tests/test_attributes/test_limits/test_bits_read.rs index 3b9fb72a..e0772e02 100644 --- a/tests/test_attributes/test_limits/test_bits_read.rs +++ b/tests/test_attributes/test_limits/test_bits_read.rs @@ -9,9 +9,9 @@ mod test_slice { #[test] fn test_bits_read_static() { #[derive(PartialEq, Debug, DekuRead, DekuWrite)] - struct TestStruct<'a> { + struct TestStruct { #[deku(bits_read = "16")] - data: &'a [u8], + data: Vec, } let test_data: Vec = [0xaa, 0xbb].to_vec(); @@ -19,7 +19,7 @@ mod test_slice { let ret_read = TestStruct::try_from(test_data.as_ref()).unwrap(); assert_eq!( TestStruct { - data: test_data.as_ref() + data: test_data.to_vec() }, ret_read ); @@ -39,11 +39,11 @@ mod test_slice { )] fn test_bits_read_from_field(input_bits: u8) { #[derive(PartialEq, Debug, DekuRead, DekuWrite)] - struct TestStruct<'a> { + struct TestStruct { bits: u8, #[deku(bits_read = "bits")] - data: &'a [u8], + data: Vec, } let test_data: Vec = [input_bits, 0xaa, 0xbb].to_vec(); @@ -52,7 +52,7 @@ mod test_slice { assert_eq!( TestStruct { bits: 16, - data: &test_data[1..] + data: test_data[1..].to_vec(), }, ret_read ); diff --git a/tests/test_attributes/test_limits/test_bytes_read.rs b/tests/test_attributes/test_limits/test_bytes_read.rs index d107abce..66ea19e9 100644 --- a/tests/test_attributes/test_limits/test_bytes_read.rs +++ b/tests/test_attributes/test_limits/test_bytes_read.rs @@ -9,9 +9,9 @@ mod test_slice { #[test] fn test_bytes_read_static() { #[derive(PartialEq, Debug, DekuRead, DekuWrite)] - struct TestStruct<'a> { + struct TestStruct { #[deku(bytes_read = "2")] - data: &'a [u8], + data: Vec, } let test_data: Vec = [0xaa, 0xbb].to_vec(); @@ -19,7 +19,7 @@ mod test_slice { let ret_read = TestStruct::try_from(test_data.as_ref()).unwrap(); assert_eq!( TestStruct { - data: test_data.as_ref() + data: test_data.to_vec(), }, ret_read ); @@ -36,11 +36,11 @@ mod test_slice { )] fn test_bytes_read_from_field(input_bytes: u8) { #[derive(PartialEq, Debug, DekuRead, DekuWrite)] - struct TestStruct<'a> { + struct TestStruct { bytes: u8, #[deku(bytes_read = "bytes")] - data: &'a [u8], + data: Vec, } let test_data: Vec = [input_bytes, 0xaa, 0xbb].to_vec(); @@ -49,7 +49,7 @@ mod test_slice { assert_eq!( TestStruct { bytes: 0x02, - data: &test_data[1..] + data: test_data[1..].to_vec() }, ret_read ); diff --git a/tests/test_attributes/test_limits/test_count.rs b/tests/test_attributes/test_limits/test_count.rs index f950476e..606fe1fd 100644 --- a/tests/test_attributes/test_limits/test_count.rs +++ b/tests/test_attributes/test_limits/test_count.rs @@ -8,9 +8,9 @@ mod test_slice { #[test] fn test_count_static() { #[derive(PartialEq, Debug, DekuRead, DekuWrite)] - struct TestStruct<'a> { + struct TestStruct { #[deku(count = "2")] - data: &'a [u8], + data: Vec, } let test_data: Vec = [0xaa, 0xbb].to_vec(); @@ -18,7 +18,7 @@ mod test_slice { let ret_read = TestStruct::try_from(test_data.as_ref()).unwrap(); assert_eq!( TestStruct { - data: test_data.as_ref() + data: test_data.to_vec() }, ret_read ); @@ -30,10 +30,10 @@ mod test_slice { #[test] fn test_count_from_field() { #[derive(PartialEq, Debug, DekuRead, DekuWrite)] - struct TestStruct<'a> { + struct TestStruct { count: u8, #[deku(count = "count")] - data: &'a [u8], + data: Vec, } let test_data: Vec = [0x02, 0xaa, 0xbb].to_vec(); @@ -42,7 +42,7 @@ mod test_slice { assert_eq!( TestStruct { count: 0x02, - data: &test_data[1..] + data: test_data[1..].to_vec(), }, ret_read ); @@ -55,10 +55,10 @@ mod test_slice { #[should_panic(expected = "Incomplete(NeedSize { bits: 8 })")] fn test_count_error() { #[derive(PartialEq, Debug, DekuRead, DekuWrite)] - struct TestStruct<'a> { + struct TestStruct { count: u8, #[deku(count = "count")] - data: &'a [u8], + data: Vec, } let test_data: Vec = [0x03, 0xaa, 0xbb].to_vec(); diff --git a/tests/test_attributes/test_limits/test_until.rs b/tests/test_attributes/test_limits/test_until.rs index 4285f588..0f57da6c 100644 --- a/tests/test_attributes/test_limits/test_until.rs +++ b/tests/test_attributes/test_limits/test_until.rs @@ -8,9 +8,9 @@ mod test_slice { #[test] fn test_until_static() { #[derive(PartialEq, Debug, DekuRead, DekuWrite)] - struct TestStruct<'a> { + struct TestStruct { #[deku(until = "|v: &u8| *v == 0xBB")] - data: &'a [u8], + data: Vec, } let test_data: Vec = [0xaa, 0xbb].to_vec(); @@ -18,7 +18,7 @@ mod test_slice { let ret_read = TestStruct::try_from(test_data.as_ref()).unwrap(); assert_eq!( TestStruct { - data: test_data.as_ref() + data: test_data.to_vec() }, ret_read ); @@ -30,11 +30,11 @@ mod test_slice { #[test] fn test_until_from_field() { #[derive(PartialEq, Debug, DekuRead, DekuWrite)] - struct TestStruct<'a> { + struct TestStruct { until: u8, #[deku(until = "|v: &u8| *v == *until")] - data: &'a [u8], + data: Vec, } let test_data: Vec = [0xbb, 0xaa, 0xbb].to_vec(); @@ -43,7 +43,7 @@ mod test_slice { assert_eq!( TestStruct { until: 0xbb, - data: &test_data[1..] + data: test_data[1..].to_vec() }, ret_read ); @@ -56,11 +56,11 @@ mod test_slice { #[should_panic(expected = "Incomplete(NeedSize { bits: 8 })")] fn test_until_error() { #[derive(PartialEq, Debug, DekuRead, DekuWrite)] - struct TestStruct<'a> { + struct TestStruct { until: u8, #[deku(until = "|v: &u8| *v == *until")] - data: &'a [u8], + data: Vec, } let test_data: Vec = [0xcc, 0xaa, 0xbb].to_vec(); diff --git a/tests/test_generic.rs b/tests/test_generic.rs index 4cdd2ff5..d9492869 100644 --- a/tests/test_generic.rs +++ b/tests/test_generic.rs @@ -41,25 +41,3 @@ fn test_generic_enum() { let ret_write: Vec = ret_read.try_into().unwrap(); assert_eq!(test_data, ret_write); } - -#[test] -fn test_slice_struct() { - #[derive(PartialEq, Debug, DekuRead, DekuWrite)] - struct TestStruct<'a> { - #[deku(count = "2")] - field_a: &'a [u8], - } - - let test_data: Vec = [0x01, 0x02].to_vec(); - - let ret_read = TestStruct::try_from(test_data.as_ref()).unwrap(); - assert_eq!( - TestStruct { - field_a: test_data.as_ref() - }, - ret_read - ); - - let ret_write: Vec = ret_read.try_into().unwrap(); - assert_eq!(test_data, ret_write); -} From 1d94ada19638a690e687ea927b346d16b8da8458 Mon Sep 17 00:00:00 2001 From: wcampbell Date: Sat, 5 Aug 2023 16:23:21 -0400 Subject: [PATCH 23/30] Update TRYBUILD --- .../test_compile/cases/attribute_token_stream.stderr | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/test_compile/cases/attribute_token_stream.stderr b/tests/test_compile/cases/attribute_token_stream.stderr index 9e01d76e..2d9e7463 100644 --- a/tests/test_compile/cases/attribute_token_stream.stderr +++ b/tests/test_compile/cases/attribute_token_stream.stderr @@ -12,12 +12,12 @@ error[E0277]: can't compare `{integer}` with `bool` | = help: the trait `PartialEq` is not implemented for `{integer}` = help: the following other types implement trait `PartialEq`: - f32 - f64 - i128 + isize + i8 i16 i32 i64 - i8 - isize - and 6 others + i128 + usize + u8 + and $N others From a40735e3b4b2822e0b840d314de07d27dac6f227 Mon Sep 17 00:00:00 2001 From: wcampbell Date: Sat, 5 Aug 2023 16:23:55 -0400 Subject: [PATCH 24/30] Update test_alloc numbers --- tests/test_alloc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_alloc.rs b/tests/test_alloc.rs index e61294b5..91587794 100644 --- a/tests/test_alloc.rs +++ b/tests/test_alloc.rs @@ -62,7 +62,7 @@ mod tests { let _ = TestDeku::try_from(input.as_ref()).unwrap(); }) .0, - (4, 0, 4) + (9, 0, 9) ); } } From b50fe555d55af2d67d305f235de37e8257d50764 Mon Sep 17 00:00:00 2001 From: wcampbell Date: Sat, 5 Aug 2023 16:30:27 -0400 Subject: [PATCH 25/30] Stable rust has weird fmt on let-else --- src/impls/primitive.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/impls/primitive.rs b/src/impls/primitive.rs index d107a13d..c029b391 100644 --- a/src/impls/primitive.rs +++ b/src/impls/primitive.rs @@ -281,8 +281,8 @@ macro_rules! ImplDekuReadSignExtend { // TODO: specialize for reading byte aligned let bits = container.read_bits(size.0 * 8)?; let Some(bits) = bits else { - return Err(DekuError::Parse(format!("no bits read from reader",))); - }; + return Err(DekuError::Parse(format!("no bits read from reader",))); + }; let a = <$typ>::read(&bits, (endian, size))?; Ok(a.1) } @@ -311,8 +311,8 @@ macro_rules! ImplDekuReadSignExtend { ) -> Result<$typ, DekuError> { let bits = container.read_bits(size.0 * 8)?; let Some(bits) = bits else { - return Err(DekuError::Parse(format!("no bits read from reader",))); - }; + return Err(DekuError::Parse(format!("no bits read from reader",))); + }; let a = <$typ>::read(&bits, (endian, size))?; Ok(a.1) } From eb2ee3bcf2850a420a1ddc5b8e60ac5d98a900d0 Mon Sep 17 00:00:00 2001 From: wcampbell Date: Sat, 5 Aug 2023 16:32:45 -0400 Subject: [PATCH 26/30] fixup! Use acid_io for no_std Read without nightly --- src/lib.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 02606f6a..0cbe2536 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -269,8 +269,6 @@ pub struct EncodedString { #[cfg(feature = "alloc")] extern crate alloc; -use acid_io::Read; - #[cfg(feature = "alloc")] use alloc::vec::Vec; @@ -314,7 +312,7 @@ pub trait DekuRead<'a, Ctx = ()> { todo!(); } - fn from_reader( + fn from_reader( container: &mut crate::container::Container, ctx: Ctx, ) -> Result From ef1c1b5ac407f36d1511ccb23e1ecc12f6878767 Mon Sep 17 00:00:00 2001 From: wcampbell Date: Sat, 5 Aug 2023 20:01:37 -0400 Subject: [PATCH 27/30] Correctly read enums variants and fix from_bytes --- deku-derive/src/macros/deku_read.rs | 46 ++++++++++++++++++----------- src/container.rs | 11 +++++++ 2 files changed, 40 insertions(+), 17 deletions(-) diff --git a/deku-derive/src/macros/deku_read.rs b/deku-derive/src/macros/deku_read.rs index c7500c54..1af76ff4 100644 --- a/deku-derive/src/macros/deku_read.rs +++ b/deku-derive/src/macros/deku_read.rs @@ -45,7 +45,7 @@ fn emit_struct(input: &DekuData) -> Result { .and_then(|v| v.ident.as_ref()) .is_some(); - let (field_idents, field_reads) = emit_field_reads(input, &fields, &ident)?; + let (field_idents, field_reads) = emit_field_reads(input, &fields, &ident, false)?; // filter out temporary fields let field_idents = field_idents @@ -64,7 +64,7 @@ fn emit_struct(input: &DekuData) -> Result { use core::convert::TryFrom; let container = &mut deku::container::Container::new(__deku_input.0); if __deku_input.1 != 0 { - let _ = container.read_bits(__deku_input.1)?; + container.skip_bits(__deku_input.1)?; } #magic_read @@ -167,13 +167,15 @@ fn emit_enum(input: &DekuData) -> Result { .and_then(|v| v.ident.as_ref()) .is_some(); - let (consume_id, variant_id) = if let Some(variant_id) = &variant.id { + let (use_id, variant_id) = if let Some(variant_id) = &variant.id { match variant_id { - Id::TokenStream(v) => (true, quote! {&#v}.into_token_stream()), - Id::LitByteStr(v) => (true, v.into_token_stream()), + Id::TokenStream(v) => (false, quote! {&#v}.into_token_stream()), + Id::LitByteStr(v) => (false, v.into_token_stream()), } } else if let Some(variant_id_pat) = &variant.id_pat { - (false, variant_id_pat.clone()) + // if set, the first field read will not read from reader and instead + // be __deku_variant_id + (true, variant_id_pat.clone()) } else if has_discriminant { let ident = &variant.ident; let internal_ident = gen_internal_field_ident("e!(#ident)); @@ -200,7 +202,7 @@ fn emit_enum(input: &DekuData) -> Result { quote! { #variant_reader; } } else { let (field_idents, field_reads) = - emit_field_reads(input, &variant.fields.as_ref(), &ident)?; + emit_field_reads(input, &variant.fields.as_ref(), &ident, use_id)?; // filter out temporary fields let field_idents = field_idents @@ -302,7 +304,7 @@ fn emit_enum(input: &DekuData) -> Result { use core::convert::TryFrom; let container = &mut deku::container::Container::new(__deku_input.0); if __deku_input.1 != 0 { - let _ = container.read_bits(__deku_input.1)?; + container.skip_bits(__deku_input.1)?; } #magic_read @@ -414,12 +416,16 @@ fn emit_field_reads( input: &DekuData, fields: &Fields<&FieldData>, ident: &TokenStream, + use_id: bool, ) -> Result<(Vec, Vec), syn::Error> { let mut field_reads = Vec::with_capacity(fields.len()); let mut field_idents = Vec::with_capacity(fields.len()); + let mut use_id = use_id; + for (i, f) in fields.iter().enumerate() { - let (field_ident, field_read) = emit_field_read(input, i, f, ident)?; + let (field_ident, field_read) = emit_field_read(input, i, f, ident, use_id)?; + use_id = false; field_idents.push(FieldIdent { field_ident, is_temp: f.temp, @@ -485,6 +491,7 @@ fn emit_field_read( i: usize, f: &FieldData, ident: &TokenStream, + use_id: bool, ) -> Result<(TokenStream, TokenStream), syn::Error> { let crate_ = super::get_crate_name(); let field_type = &f.ty; @@ -564,7 +571,7 @@ fn emit_field_read( }; let field_read_func = if field_reader.is_some() { - quote! { #field_reader } + quote! { #field_reader? } } else { let read_args = gen_field_args( field_endian, @@ -589,7 +596,12 @@ fn emit_field_read( // use type directly quote!(<#field_type as ::#crate_::DekuRead<'_, _>>) }; - if let Some(field_count) = &f.count { + + if use_id { + quote! { + __deku_variant_id + } + } else if let Some(field_count) = &f.count { quote! { { use core::borrow::Borrow; @@ -597,7 +609,7 @@ fn emit_field_read( ( container, (::#crate_::ctx::Limit::new_count(usize::try_from(*((#field_count).borrow()))?), (#read_args)) - ) + )? } } } else if let Some(field_bits) = &f.bits_read { @@ -608,7 +620,7 @@ fn emit_field_read( ( container, (::#crate_::ctx::Limit::new_bit_size(::#crate_::ctx::BitSize(usize::try_from(*((#field_bits).borrow()))?)), (#read_args)) - ) + )? } } } else if let Some(field_bytes) = &f.bytes_read { @@ -619,7 +631,7 @@ fn emit_field_read( ( container, (::#crate_::ctx::Limit::new_byte_size(::#crate_::ctx::ByteSize(usize::try_from(*((#field_bytes).borrow()))?)), (#read_args)) - ) + )? } } } else if let Some(field_until) = &f.until { @@ -630,7 +642,7 @@ fn emit_field_read( ( container, (::#crate_::ctx::Limit::new_until(#field_until), (#read_args)) - ) + )? } } else { quote! { @@ -638,7 +650,7 @@ fn emit_field_read( ( container, (#read_args) - ) + )? } } }; @@ -655,7 +667,7 @@ fn emit_field_read( ); let field_read_normal = quote! { - let __deku_value = #field_read_func?; + let __deku_value = #field_read_func; let __deku_value: #field_type = #field_map(__deku_value)?; __deku_value }; diff --git a/src/container.rs b/src/container.rs index 293dbbde..c7eadff9 100644 --- a/src/container.rs +++ b/src/container.rs @@ -31,6 +31,17 @@ impl Container { } } + /// Used at the beginning of `from_bytes`. Will read the `amt` of bits, but + /// not increase bits_read. + #[inline] + pub fn skip_bits(&mut self, amt: usize) -> Result<(), DekuError> { + // Save, and keep the leftover bits since the read will most likely be less than a byte + self.read_bits(amt)?; + self.bits_read = 0; + + Ok(()) + } + /// Attempt to read bits from `Container`. This will always return a `BitVec` and will /// correctly add previously read and stored "leftover" bits from previous reads. /// From 766f246b7ac8ecb076bcb3cb3d7f733d2185b602 Mon Sep 17 00:00:00 2001 From: wcampbell Date: Sat, 5 Aug 2023 20:02:29 -0400 Subject: [PATCH 28/30] Fix issue 282 again --- src/impls/primitive.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/impls/primitive.rs b/src/impls/primitive.rs index c029b391..920f108e 100644 --- a/src/impls/primitive.rs +++ b/src/impls/primitive.rs @@ -245,6 +245,13 @@ macro_rules! ImplDekuReadBytes { if endian.is_le() { <$typ>::from_le_bytes(buf.try_into().unwrap()) } else { + if size.0 != core::mem::size_of::<$typ>() { + let padding = core::mem::size_of::<$typ>() - size.0; + buf.copy_within(0..size.0, padding); + for n in 0..padding { + buf[n] = 0; + } + } <$typ>::from_be_bytes(buf.try_into().unwrap()) } } From 45163c1275964f7bc6ef5df186c1fbe83b99ca54 Mon Sep 17 00:00:00 2001 From: wcampbell Date: Sat, 5 Aug 2023 20:05:18 -0400 Subject: [PATCH 29/30] fixup! Fix issue 282 again --- src/impls/primitive.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/impls/primitive.rs b/src/impls/primitive.rs index 920f108e..0708e6c1 100644 --- a/src/impls/primitive.rs +++ b/src/impls/primitive.rs @@ -248,9 +248,7 @@ macro_rules! ImplDekuReadBytes { if size.0 != core::mem::size_of::<$typ>() { let padding = core::mem::size_of::<$typ>() - size.0; buf.copy_within(0..size.0, padding); - for n in 0..padding { - buf[n] = 0; - } + buf[..padding].fill(0x00); } <$typ>::from_be_bytes(buf.try_into().unwrap()) } From b0f9a8d087efcc08350b99f3e5d65081ac92c9d3 Mon Sep 17 00:00:00 2001 From: wcampbell Date: Sun, 6 Aug 2023 00:04:04 -0400 Subject: [PATCH 30/30] Change container -> __deku_container --- deku-derive/src/lib.rs | 5 +-- deku-derive/src/macros/deku_read.rs | 42 +++++++++---------- examples/custom_reader_and_writer.rs | 2 +- src/attributes.rs | 12 +++--- src/lib.rs | 4 +- tests/test_attributes/test_ctx.rs | 6 +-- .../cases/attribute_token_stream.stderr | 10 ++--- .../test_compile/cases/internal_variables.rs | 34 +++++++-------- .../cases/internal_variables.stderr | 4 +- 9 files changed, 55 insertions(+), 64 deletions(-) diff --git a/deku-derive/src/lib.rs b/deku-derive/src/lib.rs index e1fc07ff..67c6ec84 100644 --- a/deku-derive/src/lib.rs +++ b/deku-derive/src/lib.rs @@ -667,11 +667,8 @@ fn apply_replacements(input: &syn::LitStr) -> Result, Repla } let input_str = input_value - // TODO: remove these? - //.replace("deku::input", "__deku_input") // part of the public API `from_bytes` - //.replace("deku::input_bits", "__deku_input_bits") // part of the public API `read` + .replace("deku::container", "__deku_container") .replace("deku::output", "__deku_output") // part of the public API `write` - .replace("deku::reader", "container") .replace("deku::bit_offset", "__deku_bit_offset") .replace("deku::byte_offset", "__deku_byte_offset"); diff --git a/deku-derive/src/macros/deku_read.rs b/deku-derive/src/macros/deku_read.rs index 1af76ff4..a7a2bea7 100644 --- a/deku-derive/src/macros/deku_read.rs +++ b/deku-derive/src/macros/deku_read.rs @@ -62,9 +62,9 @@ fn emit_struct(input: &DekuData) -> Result { let from_bytes_body = wrap_default_ctx( quote! { use core::convert::TryFrom; - let container = &mut deku::container::Container::new(__deku_input.0); + let __deku_container = &mut deku::container::Container::new(__deku_input.0); if __deku_input.1 != 0 { - container.skip_bits(__deku_input.1)?; + __deku_container.skip_bits(__deku_input.1)?; } #magic_read @@ -72,7 +72,7 @@ fn emit_struct(input: &DekuData) -> Result { #(#field_reads)* let __deku_value = #initialize_struct; - Ok((container.bits_read, __deku_value)) + Ok((__deku_container.bits_read, __deku_value)) }, &input.ctx, &input.ctx_default, @@ -104,7 +104,7 @@ fn emit_struct(input: &DekuData) -> Result { tokens.extend(quote! { impl #imp ::#crate_::DekuRead<#lifetime, #ctx_types> for #ident #wher { - fn from_reader(container: &mut ::#crate_::container::Container, #ctx_arg) -> core::result::Result { + fn from_reader(__deku_container: &mut ::#crate_::container::Container, #ctx_arg) -> core::result::Result { #read_body } } @@ -115,7 +115,7 @@ fn emit_struct(input: &DekuData) -> Result { tokens.extend(quote! { impl #imp ::#crate_::DekuRead<#lifetime> for #ident #wher { - fn from_reader(container: &mut ::#crate_::container::Container, _: ()) -> core::result::Result { + fn from_reader(__deku_container: &mut ::#crate_::container::Container, _: ()) -> core::result::Result { #read_body } } @@ -280,7 +280,7 @@ fn emit_enum(input: &DekuData) -> Result { } } else if id_type.is_some() { quote! { - let __deku_variant_id = <#id_type>::from_reader(container, (#id_args))?; + let __deku_variant_id = <#id_type>::from_reader(__deku_container, (#id_args))?; } } else { // either `id` or `type` needs to be specified @@ -302,16 +302,16 @@ fn emit_enum(input: &DekuData) -> Result { let from_bytes_body = wrap_default_ctx( quote! { use core::convert::TryFrom; - let container = &mut deku::container::Container::new(__deku_input.0); + let __deku_container = &mut deku::container::Container::new(__deku_input.0); if __deku_input.1 != 0 { - container.skip_bits(__deku_input.1)?; + __deku_container.skip_bits(__deku_input.1)?; } #magic_read #variant_read - Ok((container.bits_read, __deku_value)) + Ok((__deku_container.bits_read, __deku_value)) }, &input.ctx, &input.ctx_default, @@ -342,7 +342,7 @@ fn emit_enum(input: &DekuData) -> Result { tokens.extend(quote! { #[allow(non_snake_case)] impl #imp ::#crate_::DekuRead<#lifetime, #ctx_types> for #ident #wher { - fn from_reader(container: &mut ::#crate_::container::Container, #ctx_arg) -> core::result::Result { + fn from_reader(__deku_container: &mut ::#crate_::container::Container, #ctx_arg) -> core::result::Result { #read_body } } @@ -354,7 +354,7 @@ fn emit_enum(input: &DekuData) -> Result { tokens.extend(quote! { #[allow(non_snake_case)] impl #imp ::#crate_::DekuRead<#lifetime> for #ident #wher { - fn from_reader(container: &mut ::#crate_::container::Container, _: ()) -> core::result::Result { + fn from_reader(__deku_container: &mut ::#crate_::container::Container, _: ()) -> core::result::Result { #read_body } } @@ -396,7 +396,7 @@ fn emit_magic_read(input: &DekuData) -> TokenStream { let __deku_magic = #magic; for __deku_byte in __deku_magic { - let __deku_read_byte = u8::from_reader(container, ())?; + let __deku_read_byte = u8::from_reader(__deku_container, ())?; if *__deku_byte != __deku_read_byte { return Err(::#crate_::DekuError::Parse(format!("Missing magic value {:?}", #magic))); } @@ -445,7 +445,7 @@ fn emit_bit_byte_offsets( .any(|v| token_contains_string(v, "__deku_byte_offset")) { Some(quote! { - let __deku_byte_offset = container.bits_read / 8; + let __deku_byte_offset = __deku_container.bits_read / 8; }) } else { None @@ -457,7 +457,7 @@ fn emit_bit_byte_offsets( || byte_offset.is_some() { Some(quote! { - let __deku_bit_offset = container.bits_read; + let __deku_bit_offset = __deku_container.bits_read; }) } else { None @@ -481,7 +481,7 @@ fn emit_padding(bit_size: &TokenStream) -> TokenStream { // TODO: This could be bytes - let _ = container.read_bits(__deku_pad)?; + let _ = __deku_container.read_bits(__deku_pad)?; } } } @@ -580,7 +580,7 @@ fn emit_field_read( f.ctx.as_ref(), )?; - // The container limiting options are special, we need to generate `(limit, (other, ..))` for them. + // The __deku_container limiting options are special, we need to generate `(limit, (other, ..))` for them. // These have a problem where when it isn't a copy type, the field will be moved. // e.g. struct FooBar { // a: Baz // a type implement `Into` but not `Copy`. @@ -607,7 +607,7 @@ fn emit_field_read( use core::borrow::Borrow; #type_as_deku_read::from_reader ( - container, + __deku_container, (::#crate_::ctx::Limit::new_count(usize::try_from(*((#field_count).borrow()))?), (#read_args)) )? } @@ -618,7 +618,7 @@ fn emit_field_read( use core::borrow::Borrow; #type_as_deku_read::from_reader ( - container, + __deku_container, (::#crate_::ctx::Limit::new_bit_size(::#crate_::ctx::BitSize(usize::try_from(*((#field_bits).borrow()))?)), (#read_args)) )? } @@ -629,7 +629,7 @@ fn emit_field_read( use core::borrow::Borrow; #type_as_deku_read::from_reader ( - container, + __deku_container, (::#crate_::ctx::Limit::new_byte_size(::#crate_::ctx::ByteSize(usize::try_from(*((#field_bytes).borrow()))?)), (#read_args)) )? } @@ -640,7 +640,7 @@ fn emit_field_read( quote! { #type_as_deku_read::from_reader ( - container, + __deku_container, (::#crate_::ctx::Limit::new_until(#field_until), (#read_args)) )? } @@ -648,7 +648,7 @@ fn emit_field_read( quote! { #type_as_deku_read::from_reader ( - container, + __deku_container, (#read_args) )? } diff --git a/examples/custom_reader_and_writer.rs b/examples/custom_reader_and_writer.rs index d423e404..2e6f1e6f 100644 --- a/examples/custom_reader_and_writer.rs +++ b/examples/custom_reader_and_writer.rs @@ -50,7 +50,7 @@ struct DekuTest { field_a: u8, #[deku( - reader = "bit_flipper_read(*field_a, deku::reader, BitSize(8))", + reader = "bit_flipper_read(*field_a, deku::container, BitSize(8))", writer = "bit_flipper_write(*field_a, *field_b, deku::output, BitSize(8))" )] field_b: u8, diff --git a/src/attributes.rs b/src/attributes.rs index 41e72580..f73c0fd6 100644 --- a/src/attributes.rs +++ b/src/attributes.rs @@ -800,7 +800,7 @@ use deku::prelude::*; # #[derive(PartialEq, Debug, DekuRead, DekuWrite)] struct DekuTest { #[deku( - reader = "DekuTest::read(deku::rest)", + reader = "DekuTest::read(deku::container)", writer = "DekuTest::write(deku::output, &self.field_a)" )] field_a: String, @@ -808,11 +808,11 @@ struct DekuTest { impl DekuTest { /// Read and convert to String - fn read( - rest: &BitSlice, - ) -> Result<(usize, String), DekuError> { - let (amt_read, value) = u8::read(rest, ())?; - Ok((amt_read, value.to_string())) + fn read( + container: &mut deku::container::Container, + ) -> Result { + let value = u8::from_reader(container, ())?; + Ok(value.to_string()) } /// Parse from String to u8 and write diff --git a/src/lib.rs b/src/lib.rs index 0cbe2536..2584ffbf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -238,10 +238,8 @@ tokens such as `reader`, `writer`, `map`, `count`, etc. These are provided as a convenience to the user. Always included: -- `deku::input: (&[u8], usize)` - The initial input byte slice and bit offset -(available when using [from_bytes](crate::DekuContainerRead::from_bytes)) +- `deku::container: &Container` - Current [`deku::container::Container`] - `deku::input_bits: &BitSlice` - The initial input in bits -- `deku::rest: &BitSlice` - Remaining bits to read - `deku::output: &mut BitSlice` - The output bit stream Conditionally included if referenced: diff --git a/tests/test_attributes/test_ctx.rs b/tests/test_attributes/test_ctx.rs index 213f8b04..b6911f6a 100644 --- a/tests/test_attributes/test_ctx.rs +++ b/tests/test_attributes/test_ctx.rs @@ -15,7 +15,7 @@ fn test_ctx_struct() { #[deku(ctx = "a: u8, b: u8")] struct SubTypeNeedCtx { #[deku( - reader = "(u8::from_reader(container,()).map(|c|(a+b+c) as usize))", + reader = "(u8::from_reader(deku::container,()).map(|c|(a+b+c) as usize))", writer = "(|c|{u8::write(&(c-a-b), deku::output, ())})(self.i as u8)" )] i: usize, @@ -55,7 +55,7 @@ fn test_top_level_ctx_enum() { #[deku(id = "1")] VariantA( #[deku( - reader = "(u8::from_reader(container,()).map(|c|(a+b+c)))", + reader = "(u8::from_reader(deku::container,()).map(|c|(a+b+c)))", writer = "(|c|{u8::write(&(c-a-b), deku::output, ())})(field_0)" )] u8, @@ -80,7 +80,7 @@ fn test_top_level_ctx_enum_default() { #[deku(id = "1")] VariantA( #[deku( - reader = "(u8::from_reader(container, ()).map(|c|(a+b+c)))", + reader = "(u8::from_reader(deku::container, ()).map(|c|(a+b+c)))", writer = "(|c|{u8::write(&(c-a-b), deku::output, ())})(field_0)" )] u8, diff --git a/tests/test_compile/cases/attribute_token_stream.stderr b/tests/test_compile/cases/attribute_token_stream.stderr index 2d9e7463..780e20f8 100644 --- a/tests/test_compile/cases/attribute_token_stream.stderr +++ b/tests/test_compile/cases/attribute_token_stream.stderr @@ -12,12 +12,12 @@ error[E0277]: can't compare `{integer}` with `bool` | = help: the trait `PartialEq` is not implemented for `{integer}` = help: the following other types implement trait `PartialEq`: - isize - i8 + f32 + f64 + i128 i16 i32 i64 - i128 - usize - u8 + i8 + isize and $N others diff --git a/tests/test_compile/cases/internal_variables.rs b/tests/test_compile/cases/internal_variables.rs index c9aa76aa..42ab32e0 100644 --- a/tests/test_compile/cases/internal_variables.rs +++ b/tests/test_compile/cases/internal_variables.rs @@ -1,53 +1,53 @@ -use deku::prelude::*; use deku::bitvec::{BitVec, Msb0}; +use deku::prelude::*; #[derive(DekuRead, DekuWrite)] struct TestCount { field_a: u8, #[deku(count = "deku::byte_offset")] - field_b: Vec + field_b: Vec, } #[derive(DekuRead, DekuWrite)] struct TestBitRead { field_a: u8, #[deku(bits_read = "deku::bit_offset")] - field_b: Vec + field_b: Vec, } #[derive(DekuRead, DekuWrite)] struct TestBytesRead { field_a: u8, #[deku(bytes_read = "deku::bit_offset")] - field_b: Vec + field_b: Vec, } #[derive(DekuRead, DekuWrite)] struct TestUntil { field_a: u8, #[deku(until = "|v| *v as usize == deku::bit_offset")] - field_b: Vec + field_b: Vec, } #[derive(DekuRead, DekuWrite)] struct TestCond { field_a: u8, #[deku(cond = "deku::bit_offset == *field_a as usize")] - field_b: u8 + field_b: u8, } #[derive(DekuRead, DekuWrite)] struct TestDefault { field_a: u8, #[deku(skip, default = "deku::byte_offset")] - field_b: usize + field_b: usize, } #[derive(DekuRead, DekuWrite)] struct TestMap { field_a: u8, #[deku(map = "|v: u8| -> Result<_, DekuError> { Ok(v as usize + deku::byte_offset) }")] - field_b: usize + field_b: usize, } fn dummy_reader( @@ -59,39 +59,35 @@ fn dummy_reader( #[derive(DekuRead, DekuWrite)] struct TestReader { field_a: u8, - #[deku(reader = "dummy_reader(deku::byte_offset, deku::reader)")] - field_b: usize + #[deku(reader = "dummy_reader(deku::byte_offset, deku::container)")] + field_b: usize, } #[derive(DekuRead, DekuWrite)] #[deku(ctx = "_byte_size: usize, _bit_size: usize")] -struct ChildCtx { -} +struct ChildCtx {} #[derive(DekuRead, DekuWrite)] struct TestCtx { field_a: u8, #[deku(ctx = "deku::byte_offset, deku::bit_offset")] - field_b: ChildCtx + field_b: ChildCtx, } -fn dummy_writer( - _offset: usize, - _output: &mut BitVec, -) -> Result<(), DekuError> { +fn dummy_writer(_offset: usize, _output: &mut BitVec) -> Result<(), DekuError> { Ok(()) } #[derive(DekuRead, DekuWrite)] struct TestWriter { field_a: u8, #[deku(writer = "dummy_writer(deku::byte_offset, deku::output)")] - field_b: usize + field_b: usize, } #[derive(DekuRead, DekuWrite)] struct FailInternal { field_a: u8, #[deku(cond = "__deku_bit_offset == *field_a as usize")] - field_b: u8 + field_b: u8, } fn main() {} diff --git a/tests/test_compile/cases/internal_variables.stderr b/tests/test_compile/cases/internal_variables.stderr index 5460e6c1..891a145d 100644 --- a/tests/test_compile/cases/internal_variables.stderr +++ b/tests/test_compile/cases/internal_variables.stderr @@ -1,5 +1,5 @@ error: Unexpected meta-item format `attribute cannot contain `__deku_` these are internal variables. Please use the `deku::` instead.` - --> $DIR/internal_variables.rs:93:19 + --> tests/test_compile/cases/internal_variables.rs:89:19 | -93 | #[deku(cond = "__deku_bit_offset == *field_a as usize")] +89 | #[deku(cond = "__deku_bit_offset == *field_a as usize")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^