Skip to content

Commit 295c164

Browse files
committed
Add reader::read_bytes_const
* Reduce codegen for known sizes at compile time - DekuReader<_, Endian> for all types - DekuReader<_, (Endian, Endian)> for u8
1 parent 5799ff4 commit 295c164

File tree

3 files changed

+63
-13
lines changed

3 files changed

+63
-13
lines changed

src/impls/primitive.rs

+24-8
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,9 @@ impl DekuReader<'_, (Endian, ByteSize)> for u8 {
7979
reader: &mut Reader<R>,
8080
(endian, size): (Endian, ByteSize),
8181
) -> Result<u8, DekuError> {
82-
let mut buf = [0; core::mem::size_of::<u8>()];
83-
let ret = reader.read_bytes(size.0, &mut buf)?;
82+
const MAX_TYPE_BYTES: usize = core::mem::size_of::<u8>();
83+
let mut buf = [0; MAX_TYPE_BYTES];
84+
let ret = reader.read_bytes_const::<MAX_TYPE_BYTES>(&mut buf)?;
8485
let a = match ret {
8586
ReaderRet::Bytes => <u8>::from_be_bytes(buf),
8687
ReaderRet::Bits(bits) => {
@@ -357,20 +358,35 @@ macro_rules! ImplDekuReadSignExtend {
357358
};
358359
}
359360

360-
// TODO: these forward types should forward on a ContainerCanHoldSize or something if ByteSize or
361-
// BitSize wasn't defined
362361
macro_rules! ForwardDekuRead {
363362
($typ:ty) => {
364-
// Only have `endian`, set `bit_size` to `Size::of::<Type>()`
363+
// Only have `endian`, specialize and use read_bytes_const
365364
impl DekuReader<'_, Endian> for $typ {
366365
#[inline(always)]
367366
fn from_reader_with_ctx<R: Read>(
368367
reader: &mut Reader<R>,
369368
endian: Endian,
370369
) -> Result<$typ, DekuError> {
371-
const BYTE_SIZE: usize = core::mem::size_of::<$typ>();
372-
373-
<$typ>::from_reader_with_ctx(reader, (endian, ByteSize(BYTE_SIZE)))
370+
const MAX_TYPE_BYTES: usize = core::mem::size_of::<$typ>();
371+
let mut buf = [0; MAX_TYPE_BYTES];
372+
let ret = reader.read_bytes_const::<MAX_TYPE_BYTES>(&mut buf)?;
373+
let a = match ret {
374+
ReaderRet::Bytes => {
375+
if endian.is_le() {
376+
<$typ>::from_le_bytes(buf)
377+
} else {
378+
<$typ>::from_be_bytes(buf)
379+
}
380+
}
381+
ReaderRet::Bits(Some(bits)) => {
382+
let a = <$typ>::read(&bits, (endian, ByteSize(MAX_TYPE_BYTES)))?;
383+
a.1
384+
}
385+
ReaderRet::Bits(None) => {
386+
return Err(DekuError::Parse(format!("no bits read from reader")));
387+
}
388+
};
389+
Ok(a)
374390
}
375391
}
376392

src/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ assert_eq!(value.a, 0x01);
227227
assert_eq!(value.sub.b, 0x01 + 0x02)
228228
```
229229
230-
# `Read` enabled
230+
# `Read` supported
231231
Parsers can be created that directly read from a source implementing [Read](crate::no_std_io::Read).
232232
233233
The crate [no_std_io] is re-exported for use in `no_std` environments.
@@ -250,7 +250,7 @@ let mut file = File::options().read(true).open("file").unwrap();
250250
let ec = EcHdr::from_reader((&mut file, 0)).unwrap();
251251
```
252252
253-
# `Write` enabled
253+
# `Write` supported
254254
Parsers can be created that directly write to a source implementing [Write](crate::no_std_io::Write).
255255
256256
```rust, no_run

src/reader.rs

+37-3
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ impl<'a, R: Read> Reader<'a, R> {
206206
///
207207
/// # Params
208208
/// `amt` - Amount of bytes that will be read
209+
/// `buf` - result bytes
209210
#[inline(always)]
210211
pub fn read_bytes(&mut self, amt: usize, buf: &mut [u8]) -> Result<ReaderRet, DekuError> {
211212
#[cfg(feature = "logging")]
@@ -232,6 +233,39 @@ impl<'a, R: Read> Reader<'a, R> {
232233
Ok(ReaderRet::Bits(self.read_bits(amt * 8)?))
233234
}
234235
}
236+
237+
/// Attempt to read bytes from `Reader`. This will return `ReaderRet::Bytes` with a valid
238+
/// `buf` of bytes if we have no "leftover" bytes and thus are byte aligned. If we are not byte
239+
/// aligned, this will call `read_bits` and return `ReaderRet::Bits(_)` of size `N` * 8.
240+
///
241+
/// # Params
242+
/// `buf` - result bytes
243+
#[inline(always)]
244+
pub fn read_bytes_const<const N: usize>(
245+
&mut self,
246+
buf: &mut [u8; N],
247+
) -> Result<ReaderRet, DekuError> {
248+
#[cfg(feature = "logging")]
249+
log::trace!("read_bytes: requesting {N} bytes");
250+
if self.leftover.is_empty() {
251+
if let Err(e) = self.inner.read_exact(buf) {
252+
if e.kind() == ErrorKind::UnexpectedEof {
253+
return Err(DekuError::Incomplete(NeedSize::new(N * 8)));
254+
}
255+
256+
// TODO: other errors?
257+
}
258+
259+
self.bits_read += N * 8;
260+
261+
#[cfg(feature = "logging")]
262+
log::trace!("read_bytes: returning {:02x?}", &buf);
263+
264+
Ok(ReaderRet::Bytes)
265+
} else {
266+
Ok(ReaderRet::Bits(self.read_bits(N * 8)?))
267+
}
268+
}
235269
}
236270

237271
#[cfg(test)]
@@ -242,12 +276,12 @@ mod tests {
242276

243277
#[test]
244278
fn test_end() {
245-
let input = hex!("aa");
279+
let input = hex!("aabb");
246280
let mut cursor = Cursor::new(input);
247281
let mut reader = Reader::new(&mut cursor);
248282
assert!(!reader.end());
249-
let mut buf = [0; 1];
250-
let _ = reader.read_bytes(1, &mut buf);
283+
let mut buf = [0; 2];
284+
let _ = reader.read_bytes_const::<2>(&mut buf).unwrap();
251285
assert!(reader.end());
252286

253287
let input = hex!("aa");

0 commit comments

Comments
 (0)