diff --git a/deku-derive/src/lib.rs b/deku-derive/src/lib.rs index b6a10e9d..1a6f7d4e 100644 --- a/deku-derive/src/lib.rs +++ b/deku-derive/src/lib.rs @@ -136,6 +136,9 @@ struct DekuData { /// enum only: byte size of the enum `id` bytes: Option, + + /// struct only: seek from current position + seek_from_current: Option, } impl DekuData { @@ -184,6 +187,7 @@ impl DekuData { id_type: receiver.id_type?, bits: receiver.bits, bytes: receiver.bytes, + seek_from_current: receiver.seek_from_current, }; DekuData::validate(&data)?; @@ -434,6 +438,12 @@ struct FieldData { // assert value of field assert_eq: Option, + + //seek_rewind: Option, + seek_from_current: Option, + //seek_from_end: Option, + //seek_from_start: Option, + //seek_position: Option, } impl FieldData { @@ -470,6 +480,11 @@ impl FieldData { cond: receiver.cond?, assert: receiver.assert?, assert_eq: receiver.assert_eq?, + //seek_rewind: receiver.seek_rewind?, + seek_from_current: receiver.seek_from_current?, + //seek_from_end: receiver.seek_from_end?, + //seek_from_start: receiver.seek_from_start?, + //seek_position: receiver.seek_position?, }; FieldData::validate(&data)?; @@ -649,6 +664,9 @@ struct DekuReceiver { /// enum only: byte size of the enum `id` #[darling(default)] bytes: Option, + + #[darling(default)] + seek_from_current: Option, } type ReplacementError = TokenStream; @@ -825,6 +843,10 @@ struct DekuFieldReceiver { // assert value of field #[darling(default = "default_res_opt", map = "map_litstr_as_tokenstream")] assert_eq: Result, ReplacementError>, + + /// seek from current position + #[darling(default = "default_res_opt", map = "map_litstr_as_tokenstream")] + seek_from_current: Result, ReplacementError>, } /// Receiver for the variant-level attributes inside a enum diff --git a/deku-derive/src/macros/deku_read.rs b/deku-derive/src/macros/deku_read.rs index 30fe0e06..caf5825c 100644 --- a/deku-derive/src/macros/deku_read.rs +++ b/deku-derive/src/macros/deku_read.rs @@ -554,6 +554,17 @@ fn emit_field_read( &f.assert_eq, ]; + let seek = if let Some(num) = &f.seek_from_current { + quote! { + use ::#crate_::no_std_io::Seek; + use ::#crate_::no_std_io::SeekFrom; + // TODO: use ? + __deku_reader.seek(SeekFrom::Current(i64::try_from(#num).unwrap())).unwrap(); + } + } else { + quote! {} + }; + let (bit_offset, byte_offset) = emit_bit_byte_offsets(&field_check_vars); let field_map = f @@ -748,6 +759,7 @@ fn emit_field_read( }; let field_read = quote! { + #seek #pad_bits_before #bit_offset diff --git a/examples/custom_reader_and_writer.rs b/examples/custom_reader_and_writer.rs index ecff5b5f..0bded4b3 100644 --- a/examples/custom_reader_and_writer.rs +++ b/examples/custom_reader_and_writer.rs @@ -62,7 +62,7 @@ fn main() { let test_data = [0x01, 0b1001_0110]; let mut cursor = std::io::Cursor::new(test_data); - let (_read_amt, ret_read) = DekuTest::from_reader((&mut test_data.as_slice(), 0)).unwrap(); + let (_read_amt, ret_read) = DekuTest::from_reader((&mut cursor, 0)).unwrap(); assert_eq!( ret_read, diff --git a/examples/deku_input.rs b/examples/deku_input.rs index 8d450fbe..ebfaa3ab 100644 --- a/examples/deku_input.rs +++ b/examples/deku_input.rs @@ -9,7 +9,7 @@ struct ReaderCrc { pub cache: Vec, } -impl ReaderCrc { +impl ReaderCrc { pub fn new(reader: R) -> Self { Self { reader, @@ -18,7 +18,7 @@ impl ReaderCrc { } } -impl Read for ReaderCrc { +impl Read for ReaderCrc { fn read(&mut self, buf: &mut [u8]) -> io::Result { let n = self.reader.read(buf); self.cache.extend_from_slice(buf); @@ -26,6 +26,12 @@ impl Read for ReaderCrc { } } +impl Seek for ReaderCrc { + fn seek(&mut self, seek: SeekFrom) -> io::Result { + self.reader.seek(seek) + } +} + #[derive(Debug, DekuRead)] pub struct DekuStruct { pub a: u8, diff --git a/src/impls/slice.rs b/src/impls/slice.rs index 059c43f5..20c7a0c1 100644 --- a/src/impls/slice.rs +++ b/src/impls/slice.rs @@ -108,40 +108,4 @@ mod tests { input.to_writer(&mut writer, endian).unwrap(); assert_eq!(expected, out_buf.to_vec()); } - - #[rstest(input,endian,expected, - case::normal_le( - [[0xCCDD, 0xAABB], [0x8899, 0x6677]], - Endian::Little, - vec![0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88, 0x77, 0x66], - ), - case::normal_be( - [[0xDDCC, 0xBBAA], [0x9988, 0x7766]], - Endian::Big, - vec![0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88, 0x77, 0x66], - ), - )] - fn test_nested_array_bit_write(input: [[u16; 2]; 2], endian: Endian, expected: Vec) { - let mut res_write = bitvec![u8, Msb0;]; - input.write(&mut res_write, endian).unwrap(); - assert_eq!(expected, res_write.into_vec()); - - // test &slice - let input = input.as_ref(); - let mut res_write = bitvec![u8, Msb0;]; - input.write(&mut res_write, endian).unwrap(); - assert_eq!(expected, res_write.into_vec()); - - // test writer - let mut res_write = bitvec![u8, Msb0;]; - input.write(&mut res_write, endian).unwrap(); - assert_eq!(expected, res_write.into_vec()); - - // test &slice - let input = input.as_ref(); - let mut out_buf = vec![]; - let mut writer = Writer::new(&mut out_buf); - input.to_writer(&mut writer, endian).unwrap(); - assert_eq!(expected, out_buf.to_vec()); - } } diff --git a/src/reader.rs b/src/reader.rs index 3c46fab9..1e5c347e 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -31,6 +31,14 @@ pub struct Reader<'a, R: Read + Seek> { /// Max bits requested from [`Reader::read_bits`] during one call pub const MAX_BITS_AMT: usize = 128; +impl Seek for Reader<'_, R> { + fn seek(&mut self, pos: SeekFrom) -> no_std_io::io::Result { + // clear leftover + self.leftover = BitVec::new(); + self.inner.seek(pos) + } +} + impl<'a, R: Read + Seek> Reader<'a, R> { /// Create a new `Reader` #[inline] diff --git a/tests/test_regression.rs b/tests/test_regression.rs index 81c1ee22..e92dfd94 100644 --- a/tests/test_regression.rs +++ b/tests/test_regression.rs @@ -1,4 +1,5 @@ use deku::prelude::*; +use std::io::Cursor; // Invalid alignment assumptions when converting // BitSlice to type diff --git a/tests/test_seek.rs b/tests/test_seek.rs new file mode 100644 index 00000000..d206c0e1 --- /dev/null +++ b/tests/test_seek.rs @@ -0,0 +1,27 @@ +use deku::prelude::*; +use hexlit::hex; +use rstest::*; + +use std::convert::TryFrom; + +#[derive(DekuRead, Debug, PartialEq, Eq)] +pub struct Test { + // how many following bytes to skip + skip_u8: u8, + #[deku(seek_from_current = "*skip_u8")] + byte: u8, +} + +#[rstest(input, expected, + case(&hex!("010020"), Test{ skip_u8: 1, byte: 0x20 }), +)] +fn test_seek_from_current(input: &[u8], expected: Test) { + let input = input.to_vec(); + // TODO: fix, "too much data" + //let ret_read = Test::try_from(input.as_slice()).unwrap(); + + let mut cursor = std::io::Cursor::new(input); + let (_, ret_read) = Test::from_reader((&mut cursor, 0)).unwrap(); + + assert_eq!(ret_read, expected); +}