diff --git a/benches/deku.rs b/benches/deku.rs index 72106c36..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(|| { @@ -105,13 +125,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 +142,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..e1fc07ff 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; @@ -662,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") + .replace("deku::reader", "container") .replace("deku::bit_offset", "__deku_bit_offset") .replace("deku::byte_offset", "__deku_byte_offset"); @@ -1006,10 +1012,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..7d788dfc 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 { @@ -62,21 +62,15 @@ fn emit_struct(input: &DekuData) -> Result { 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_rest = &__deku_rest[__deku_input.1..]; + 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; - 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((container.bits_read, __deku_value)) }, &input.ctx, &input.ctx_default, @@ -97,19 +91,20 @@ fn emit_struct(input: &DekuData) -> Result { 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 #(#field_reads)* let __deku_value = #initialize_struct; - Ok((__deku_rest, __deku_value)) + Ok(__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 from_reader(container: &mut ::#crate_::container::Container, #ctx_arg) -> core::result::Result { #read_body } } @@ -120,7 +115,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 from_reader(container: &mut ::#crate_::container::Container, _: ()) -> core::result::Result { #read_body } } @@ -226,18 +221,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_rest = __deku_new_rest; - } - } else { - quote! {} - }; - quote! { { - #new_rest #(#field_reads)* Self :: #initialize_enum } @@ -289,11 +274,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_variant_id = (#id); } } else if id_type.is_some() { quote! { - let (__deku_new_rest, __deku_variant_id) = <#id_type>::read(__deku_rest, (#id_args))?; + let __deku_variant_id = <#id_type>::from_reader(container, (#id_args))?; } } else { // either `id` or `type` needs to be specified @@ -315,20 +300,14 @@ fn emit_enum(input: &DekuData) -> Result { 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_rest = &__deku_rest[__deku_input.1..]; + let container = &mut deku::container::Container::new(__deku_input.0); + let _ = container.read_bits(__deku_input.1)?; #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((container.bits_read, __deku_value)) }, &input.ctx, &input.ctx_default, @@ -348,19 +327,20 @@ fn emit_enum(input: &DekuData) -> Result { 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 #variant_read - Ok((__deku_rest, __deku_value)) + Ok(__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 from_reader(container: &mut ::#crate_::container::Container, #ctx_arg) -> core::result::Result { #read_body } } @@ -372,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 read(__deku_input_bits: &#lifetime ::#crate_::bitvec::BitSlice, _: ()) -> core::result::Result<(&#lifetime ::#crate_::bitvec::BitSlice, Self), ::#crate_::DekuError> { + fn from_reader(container: &mut ::#crate_::container::Container, _: ()) -> core::result::Result { #read_body } } @@ -414,12 +394,10 @@ 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_read_byte = u8::from_reader(container, ())?; if *__deku_byte != __deku_read_byte { return Err(::#crate_::DekuError::Parse(format!("Missing magic value {:?}", #magic))); } - - __deku_rest = __deku_new_rest; } } } else { @@ -461,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 @@ -473,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 @@ -487,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", @@ -494,12 +473,9 @@ 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; - } else { - return Err(::#crate_::DekuError::Incomplete(::#crate_::error::NeedSize::new(__deku_pad))); - } + + // TODO: This could be bytes + container.read_bits(__deku_pad)?; } } } @@ -617,29 +593,53 @@ 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::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::read(__deku_rest, (::#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, (::#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, (::#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, (#read_args))} + quote! { + #type_as_deku_read::from_reader + ( + container, + (#read_args) + ) + } } }; @@ -655,11 +655,8 @@ fn emit_field_read( ); let field_read_normal = quote! { - let (__deku_new_rest, __deku_value) = #field_read_func?; + let __deku_value = #field_read_func?; let __deku_value: #field_type = #field_map(__deku_value)?; - - __deku_rest = __deku_new_rest; - __deku_value }; @@ -732,7 +729,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 +749,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..d423e404 100644 --- a/examples/custom_reader_and_writer.rs +++ b/examples/custom_reader_and_writer.rs @@ -1,29 +1,27 @@ -use deku::bitvec::{BitSlice, BitVec, Msb0}; +use std::convert::TryInto; + +use deku::bitvec::{BitVec, Msb0}; use deku::ctx::BitSize; use deku::prelude::*; -use std::convert::TryInto; -fn bit_flipper_read( +fn bit_flipper_read( field_a: u8, - rest: &BitSlice, + container: &mut Container, bit_size: BitSize, -) -> Result<(&BitSlice, u8), DekuError> { +) -> 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 (rest, 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 }; - Ok((rest, value)) + Ok(value) } fn bit_flipper_write( @@ -52,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/enums.rs b/examples/enums.rs index f6a16a90..a817185d 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,12 +22,15 @@ 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() { 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/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..58fe725a 100644 --- a/examples/example.rs +++ b/examples/example.rs @@ -1,11 +1,17 @@ #![allow(clippy::unusual_byte_groupings)] -use deku::prelude::*; use std::convert::{TryFrom, TryInto}; +use deku::{ + container::Container, + ctx::{BitSize, ByteSize, Endian}, + prelude::*, +}; + #[derive(Debug, PartialEq, DekuRead, DekuWrite)] struct FieldF { #[deku(bits = "6")] + #[deku(assert_eq = "6")] data: u8, } @@ -15,7 +21,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,31 +41,37 @@ 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(); - let test_deku = DekuTest::try_from(test_data).unwrap(); + 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 { - 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..cfe371d2 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,15 +43,16 @@ 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() { 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/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/container.rs b/src/container.rs new file mode 100644 index 00000000..5c13aaa8 --- /dev/null +++ b/src/container.rs @@ -0,0 +1,120 @@ +use bitvec::prelude::*; +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), +} + +/// Container to use with `from_reader` +pub struct Container { + inner: R, + /// 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 { + inner, + leftover: BitVec::new(), // with_capacity 8? + bits_read: 0, + } + } + + /// 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 { + return Ok(BitVec::new()); + } + let mut ret = BitVec::with_capacity(amt); + + 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_from_bitslice(&self.leftover); + self.leftover = used; + } else { + // 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 not_needed = rest.split_off(bits_left); + self.leftover = not_needed; + + // create return + ret.extend_from_bitslice(rest.as_bitslice()); + } + + self.bits_read += ret.len(); + Ok(ret) + } + + /// 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() { + 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))); + } + + // TODO: other errors? + } + self.bits_read += amt * 8; + Ok(ContainerRet::Bytes) + } else { + Ok(ContainerRet::Bits(self.read_bits(amt * 8)?)) + } + } +} 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..63143bed 100644 --- a/src/error.rs +++ b/src/error.rs @@ -2,9 +2,12 @@ #![cfg(feature = "alloc")] -use alloc::{format, string::String}; +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/bool.rs b/src/impls/bool.rs index 478b5769..c8ebc736 100644 --- a/src/impls/bool.rs +++ b/src/impls/bool.rs @@ -1,9 +1,12 @@ -use crate::{DekuError, DekuRead, DekuWrite}; -use bitvec::prelude::*; +use std::io::Read; #[cfg(feature = "alloc")] use alloc::format; +use bitvec::prelude::*; + +use crate::{container, DekuError, DekuRead, DekuWrite}; + impl<'a, Ctx> DekuRead<'a, Ctx> for bool where Ctx: Copy, @@ -11,11 +14,23 @@ 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, + 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), + 0x00 => Ok(false), + _ => Err(DekuError::Parse(format!("cannot parse bool value: {val}",))), + }?; + + Ok((amt_read, ret)) + } + + fn from_reader( + container: &mut crate::container::Container, inner_ctx: Ctx, - ) -> Result<(&'a BitSlice, Self), DekuError> { - let (rest, val) = u8::read(input, inner_ctx)?; + ) -> Result { + let val = u8::from_reader(container, inner_ctx)?; let ret = match val { 0x01 => Ok(true), @@ -23,7 +38,7 @@ where _ => Err(DekuError::Parse(format!("cannot parse bool value: {val}",))), }?; - Ok((rest, ret)) + Ok(ret) } } @@ -42,10 +57,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 +71,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 +85,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..49a54a35 100644 --- a/src/impls/boxed.rs +++ b/src/impls/boxed.rs @@ -1,22 +1,33 @@ -use crate::{ctx::Limit, DekuError, DekuRead, DekuWrite}; -use alloc::{boxed::Box, vec::Vec}; +use std::io::Read; + +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))) + } + + fn from_reader( + container: &mut crate::container::Container, + inner_ctx: Ctx, + ) -> Result { + let val = ::from_reader(container, inner_ctx)?; + Ok(Box::new(val)) } } @@ -41,13 +52,22 @@ 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())) + } + + 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()) } } @@ -67,10 +87,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 +102,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 +134,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..fe9edf86 100644 --- a/src/impls/cow.rs +++ b/src/impls/cow.rs @@ -1,6 +1,11 @@ -use crate::{DekuError, DekuRead, DekuWrite}; +use std::{ + borrow::{Borrow, Cow}, + io::Read, +}; + use bitvec::prelude::*; -use std::borrow::{Borrow, Cow}; + +use crate::{DekuError, DekuRead, DekuWrite}; impl<'a, T, Ctx> DekuRead<'a, Ctx> for Cow<'a, T> where @@ -8,15 +13,20 @@ where 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))) + } + + fn from_reader( + container: &mut crate::container::Container, + inner_ctx: Ctx, + ) -> Result { + let val = ::from_reader(container, inner_ctx)?; + Ok(Cow::Owned(val)) } } @@ -33,9 +43,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 +57,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..f0bc384d 100644 --- a/src/impls/cstring.rs +++ b/src/impls/cstring.rs @@ -1,6 +1,10 @@ -use crate::{ctx::*, DekuError, DekuRead, DekuWrite}; -use bitvec::prelude::*; use std::ffi::CString; +use std::io::Read; + +use bitvec::prelude::*; + +use crate::ctx::*; +use crate::{DekuError, DekuRead, DekuWrite}; impl DekuWrite for CString where @@ -16,14 +20,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 +37,36 @@ 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)) + } + + 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)] 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 +84,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..7a617487 100644 --- a/src/impls/ipaddr.rs +++ b/src/impls/ipaddr.rs @@ -1,20 +1,30 @@ -use crate::{DekuError, DekuRead, DekuWrite}; +use std::{ + io::Read, + net::{IpAddr, Ipv4Addr, Ipv6Addr}, +}; + use bitvec::prelude::*; -use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + +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())) + } + + fn from_reader( + container: &mut crate::container::Container, + inner_ctx: Ctx, + ) -> Result { + let ip = u32::from_reader(container, inner_ctx)?; + Ok(ip.into()) } } @@ -32,15 +42,20 @@ 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())) + } + + fn from_reader( + container: &mut crate::container::Container, + inner_ctx: Ctx, + ) -> Result { + let ip = u128::from_reader(container, inner_ctx)?; + Ok(ip.into()) } } @@ -69,9 +84,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 +101,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 +122,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 +143,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..f57ab34a 100644 --- a/src/impls/nonzero.rs +++ b/src/impls/nonzero.rs @@ -1,9 +1,12 @@ -use crate::{ctx::*, DekuError, DekuRead, DekuWrite}; -use bitvec::prelude::*; -use core::num::*; - #[cfg(feature = "alloc")] use alloc::format; +use core::num::*; +use std::io::Read; + +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 +14,29 @@ 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((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((rest, v)), + Some(v) => Ok(v), } } } @@ -62,10 +78,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 +91,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..cba6d245 100644 --- a/src/impls/option.rs +++ b/src/impls/option.rs @@ -1,5 +1,7 @@ -use crate::{DekuError, DekuRead, DekuWrite}; use bitvec::prelude::*; +use std::io::Read; + +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) @@ -10,19 +12,24 @@ 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))) + } + + fn from_reader( + container: &mut crate::container::Container, + inner_ctx: Ctx, + ) -> Result { + let val = ::from_reader(container, inner_ctx)?; + Ok(Some(val)) } } diff --git a/src/impls/primitive.rs b/src/impls/primitive.rs index f77a1ea3..42ed671a 100644 --- a/src/impls/primitive.rs +++ b/src/impls/primitive.rs @@ -1,73 +1,59 @@ -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 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, - (_, size): (Endian, ByteSize), - ) -> Result<(&BitSlice, Self), DekuError> { + (_, _): (Endian, ByteSize), + ) -> Result<(usize, 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(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(); + // 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)) + } - // 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; + // specialize not needed? + #[inline] + fn from_reader( + container: &mut crate::container::Container, + (endian, size): (Endian, ByteSize), + ) -> Result { + let mut buf = [0; core::mem::size_of::()]; + let ret = container.read_bytes(size.0, &mut buf)?; + let a = match ret { + ContainerRet::Bits(bits) => { + let a = ::read(&bits, (endian, size))?; + a.1 } - - res + ContainerRet::Bytes => ::from_be_bytes(buf), }; - - Ok((rest, value)) + Ok(a) } } macro_rules! ImplDekuReadBits { ($typ:ty, $inner:ty) => { impl DekuRead<'_, (Endian, BitSize)> for $typ { + #[inline] 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; @@ -83,7 +69,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(); @@ -98,53 +85,63 @@ 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) + // Pad up-to size of type + for _ in 0..(MAX_TYPE_BITS - bits.len()) { + if input_is_le { + bits.push(false); } else { - 0 - }; - for _ in 0..pad { - bits.insert(index, false); + 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((bit_size, 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((rest, value)) + #[inline] + fn from_reader( + container: &mut crate::container::Container, + (endian, size): (Endian, BitSize), + ) -> Result<$typ, DekuError> { + let bits = container.read_bits(size.0)?; + let a = <$typ>::read(&bits, (endian, size))?; + Ok(a.1) } } }; @@ -153,10 +150,11 @@ 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), - ) -> Result<(&BitSlice, Self), DekuError> { + ) -> Result<(usize, Self), DekuError> { const MAX_TYPE_BITS: usize = BitSize::of::<$typ>().0; let bit_size: usize = size.0 * 8; @@ -172,7 +170,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(); @@ -191,7 +189,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] @@ -215,7 +213,30 @@ macro_rules! ImplDekuReadBytes { res as $typ }; - Ok((rest, value)) + Ok((bit_size, value)) + } + + #[inline] + fn from_reader( + container: &mut crate::container::Container, + (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 a = match ret { + ContainerRet::Bits(bits) => { + let a = <$typ>::read(&bits, (endian, size))?; + a.1 + } + ContainerRet::Bytes => { + if endian.is_le() { + <$typ>::from_le_bytes(buf.try_into().unwrap()) + } else { + <$typ>::from_be_bytes(buf.try_into().unwrap()) + } + } + }; + Ok(a) } } }; @@ -224,33 +245,57 @@ 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), - ) -> 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)) + } + + #[inline] + fn from_reader( + container: &mut crate::container::Container, + (endian, size): (Endian, ByteSize), + ) -> Result<$typ, DekuError> { + // TODO: specialize for reading byte aligned + let bits = container.read_bits(size.0 * 8)?; + 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), - ) -> 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)) + } + + #[inline] + fn from_reader( + container: &mut crate::container::Container, + (endian, size): (Endian, BitSize), + ) -> Result<$typ, DekuError> { + let bits = container.read_bits(size.0 * 8)?; + let a = <$typ>::read(&bits, (endian, size))?; + Ok(a.1) } } }; @@ -260,10 +305,11 @@ 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, - ) -> 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 @@ -273,26 +319,55 @@ macro_rules! ForwardDekuRead { <$typ>::read(input, (endian, bit_size)) } } + + #[inline] + fn from_reader( + container: &mut crate::container::Container, + endian: Endian, + ) -> Result<$typ, DekuError> { + let bit_size = BitSize::of::<$typ>(); + + // 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, - ) -> Result<(&BitSlice, Self), DekuError> { + ) -> Result<(usize, Self), DekuError> { let endian = Endian::default(); <$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 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, - ) -> Result<(&BitSlice, Self), DekuError> { + ) -> Result<(usize, Self), DekuError> { let endian = Endian::default(); // check if we can use ByteSize for performance @@ -302,15 +377,32 @@ macro_rules! ForwardDekuRead { <$typ>::read(input, (endian, bit_size)) } } + + #[inline] + fn from_reader( + container: &mut crate::container::Container, + bit_size: BitSize, + ) -> Result<$typ, DekuError> { + let endian = Endian::default(); + + let a = <$typ>::from_reader(container, (endian, bit_size))?; + Ok(a) + } } impl DekuRead<'_> for $typ { - fn read( - input: &BitSlice, - _: (), - ) -> Result<(&BitSlice, Self), DekuError> { + #[inline] + fn read(input: &BitSlice, _: ()) -> Result<(usize, Self), DekuError> { <$typ>::read(input, Endian::default()) } + + #[inline] + fn from_reader( + container: &mut crate::container::Container, + _: (), + ) -> Result<$typ, DekuError> { + <$typ>::from_reader(container, Endian::default()) + } } }; } @@ -318,6 +410,7 @@ macro_rules! ForwardDekuRead { macro_rules! ImplDekuWrite { ($typ:ty) => { impl DekuWrite<(Endian, BitSize)> for $typ { + #[inline] fn write( &self, output: &mut BitVec, @@ -363,6 +456,7 @@ macro_rules! ImplDekuWrite { } impl DekuWrite<(Endian, ByteSize)> for $typ { + #[inline] fn write( &self, output: &mut BitVec, @@ -409,6 +503,7 @@ macro_rules! ImplDekuWrite { // Only have `endian`, return all input impl DekuWrite for $typ { + #[inline] fn write( &self, output: &mut BitVec, @@ -429,6 +524,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, @@ -440,6 +536,7 @@ macro_rules! ForwardDekuWrite { // Only have `bit_size`, set `endian` to `Endian::default`. impl DekuWrite for $typ { + #[inline] fn write( &self, output: &mut BitVec, @@ -450,6 +547,7 @@ macro_rules! ForwardDekuWrite { } impl DekuWrite for $typ { + #[inline] fn write(&self, output: &mut BitVec, _: ()) -> Result<(), DekuError> { <$typ>::write(self, output, Endian::default()) } @@ -518,9 +616,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(); @@ -540,87 +639,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) ); @@ -645,13 +744,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, @@ -686,12 +785,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 { @@ -710,10 +809,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..0df8791e 100644 --- a/src/impls/unit.rs +++ b/src/impls/unit.rs @@ -1,16 +1,22 @@ -use crate::{DekuError, DekuRead, DekuWrite}; use bitvec::prelude::*; +use std::io::Read; + +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, ())) + } + + fn from_reader( + container: &mut crate::container::Container, + _inner_ctx: Ctx, + ) -> Result { + Ok(()) } } @@ -23,9 +29,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 +40,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..fe5289ce 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,50 @@ 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 +/// 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 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>, + 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 +99,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 +115,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 @@ -104,6 +147,66 @@ impl<'a, 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 + /// * `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> @@ -113,7 +216,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 +246,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 +280,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 +288,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 +323,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..e4dec3bb 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) ``` @@ -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; @@ -295,13 +298,26 @@ 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; + Self: Sized, + { + todo!(); + } + + 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 @@ -310,8 +326,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..11d6f6c6 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, + container::Container, 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..213f8b04 100644 --- a/tests/test_attributes/test_ctx.rs +++ b/tests/test_attributes/test_ctx.rs @@ -1,7 +1,10 @@ +use std::convert::{TryFrom, TryInto}; +use std::io::Cursor; + use bitvec::bitvec; use deku::bitvec::{BitView, Msb0}; +use deku::container::Container; use deku::prelude::*; -use std::convert::{TryFrom, TryInto}; /// General smoke tests for ctx /// TODO: These should be divided into smaller units @@ -12,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, @@ -52,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)))})(deku::rest)", + reader = "(u8::from_reader(container,()).map(|c|(a+b+c)))", writer = "(|c|{u8::write(&(c-a-b), deku::output, ())})(field_0)" )] u8, @@ -60,8 +63,8 @@ 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 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;]; @@ -77,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)))})(deku::rest)", + reader = "(u8::from_reader(container, ()).map(|c|(a+b+c)))", writer = "(|c|{u8::write(&(c-a-b), deku::output, ())})(field_0)" )] u8, @@ -94,8 +97,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 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(); @@ -212,8 +216,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 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(); @@ -240,7 +245,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..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<(&BitSlice, usize), DekuError> { - Ok((rest, 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 } 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();