Skip to content

Commit

Permalink
Add basic seek attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
wcampbell0x2a committed Dec 20, 2023
1 parent 5778a0e commit ad7fa88
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 39 deletions.
22 changes: 22 additions & 0 deletions deku-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,9 @@ struct DekuData {

/// enum only: byte size of the enum `id`
bytes: Option<Num>,

/// struct only: seek from current position
seek_from_current: Option<Num>,

Check warning on line 141 in deku-derive/src/lib.rs

View workflow job for this annotation

GitHub Actions / Build

field `seek_from_current` is never read

Check failure on line 141 in deku-derive/src/lib.rs

View workflow job for this annotation

GitHub Actions / Clippy

field `seek_from_current` is never read

Check warning on line 141 in deku-derive/src/lib.rs

View workflow job for this annotation

GitHub Actions / Build

field `seek_from_current` is never read

Check failure on line 141 in deku-derive/src/lib.rs

View workflow job for this annotation

GitHub Actions / Clippy

field `seek_from_current` is never read

Check warning on line 141 in deku-derive/src/lib.rs

View workflow job for this annotation

GitHub Actions / Test Suite

field `seek_from_current` is never read

Check warning on line 141 in deku-derive/src/lib.rs

View workflow job for this annotation

GitHub Actions / Test Suite

field `seek_from_current` is never read
}

impl DekuData {
Expand Down Expand Up @@ -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)?;
Expand Down Expand Up @@ -434,6 +438,12 @@ struct FieldData {

// assert value of field
assert_eq: Option<TokenStream>,

//seek_rewind: Option<Num>,
seek_from_current: Option<TokenStream>,
//seek_from_end: Option<Num>,
//seek_from_start: Option<Num>,
//seek_position: Option<Num>,
}

impl FieldData {
Expand Down Expand Up @@ -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)?;
Expand Down Expand Up @@ -649,6 +664,9 @@ struct DekuReceiver {
/// enum only: byte size of the enum `id`
#[darling(default)]
bytes: Option<Num>,

#[darling(default)]
seek_from_current: Option<Num>,
}

type ReplacementError = TokenStream;
Expand Down Expand Up @@ -825,6 +843,10 @@ struct DekuFieldReceiver {
// assert value of field
#[darling(default = "default_res_opt", map = "map_litstr_as_tokenstream")]
assert_eq: Result<Option<TokenStream>, ReplacementError>,

/// seek from current position
#[darling(default = "default_res_opt", map = "map_litstr_as_tokenstream")]
seek_from_current: Result<Option<TokenStream>, ReplacementError>,
}

/// Receiver for the variant-level attributes inside a enum
Expand Down
12 changes: 12 additions & 0 deletions deku-derive/src/macros/deku_read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -748,6 +759,7 @@ fn emit_field_read(
};

let field_read = quote! {
#seek
#pad_bits_before

#bit_offset
Expand Down
2 changes: 1 addition & 1 deletion examples/custom_reader_and_writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
10 changes: 8 additions & 2 deletions examples/deku_input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ struct ReaderCrc<R: Read + Seek> {
pub cache: Vec<u8>,
}

impl<R: Read> ReaderCrc<R> {
impl<R: Read + Seek> ReaderCrc<R> {
pub fn new(reader: R) -> Self {
Self {
reader,
Expand All @@ -18,14 +18,20 @@ impl<R: Read> ReaderCrc<R> {
}
}

impl<R: Read> Read for ReaderCrc<R> {
impl<R: Read + Seek> Read for ReaderCrc<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let n = self.reader.read(buf);
self.cache.extend_from_slice(buf);
n
}
}

impl<R: Read + Seek> Seek for ReaderCrc<R> {
fn seek(&mut self, seek: SeekFrom) -> io::Result<u64> {
self.reader.seek(seek)
}
}

#[derive(Debug, DekuRead)]
pub struct DekuStruct {
pub a: u8,
Expand Down
36 changes: 0 additions & 36 deletions src/impls/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<u8>) {
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());
}
}
8 changes: 8 additions & 0 deletions src/reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<R: Read + Seek> Seek for Reader<'_, R> {
fn seek(&mut self, pos: SeekFrom) -> no_std_io::io::Result<u64> {
// clear leftover
self.leftover = BitVec::new();
self.inner.seek(pos)
}
}

impl<'a, R: Read + Seek> Reader<'a, R> {
/// Create a new `Reader`
#[inline]
Expand Down
1 change: 1 addition & 0 deletions tests/test_regression.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use deku::prelude::*;
use std::io::Cursor;

// Invalid alignment assumptions when converting
// BitSlice to type
Expand Down
27 changes: 27 additions & 0 deletions tests/test_seek.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use deku::prelude::*;
use hexlit::hex;
use rstest::*;

use std::convert::TryFrom;

Check warning on line 5 in tests/test_seek.rs

View workflow job for this annotation

GitHub Actions / Test Suite

unused import: `std::convert::TryFrom`

Check warning on line 5 in tests/test_seek.rs

View workflow job for this annotation

GitHub Actions / Test Suite

unused import: `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);
}

0 comments on commit ad7fa88

Please sign in to comment.