Skip to content

Commit e130bad

Browse files
committed
deku: Remove allocations in bits feature paths
Don't prevent the bits feature from being enabled in no-alloc environments. Signed-off-by: Andrew Jeffery <andrew@codeconstruct.com.au>
1 parent 36fc010 commit e130bad

12 files changed

Lines changed: 725 additions & 454 deletions

File tree

deku-derive/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ mod macros;
4848
//
4949
// [github-search-pad-bytes]:
5050
// https://github.com/search?q=pad_bytes_before+OR+pad_bytes_after&type=code
51-
#[cfg(not(feature = "bits"))]
5251
const PAD_ARRAY_SIZE: usize = 64;
5352

5453
#[derive(Debug)]

deku-derive/src/macros/deku_read.rs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ fn emit_struct(input: &DekuData) -> Result<TokenStream, syn::Error> {
117117
use ::#crate_::DekuReader as _;
118118
let __deku_reader = &mut deku::reader::Reader::new(__deku_input.0);
119119
if __deku_input.1 != 0 {
120-
__deku_reader.skip_bits(__deku_input.1)?;
120+
__deku_reader.skip_bits(__deku_input.1, ::#crate_::ctx::Order::default())?;
121121
}
122122

123123
let __deku_value = Self::from_reader_with_ctx(__deku_reader, ())?;
@@ -131,7 +131,7 @@ fn emit_struct(input: &DekuData) -> Result<TokenStream, syn::Error> {
131131
let mut __deku_cursor = #crate_::no_std_io::Cursor::new(__deku_input.0);
132132
let mut __deku_reader = &mut deku::reader::Reader::new(&mut __deku_cursor);
133133
if __deku_input.1 != 0 {
134-
__deku_reader.skip_bits(__deku_input.1)?;
134+
__deku_reader.skip_bits(__deku_input.1, ::#crate_::ctx::Order::default())?;
135135
}
136136

137137
let __deku_value = Self::from_reader_with_ctx(__deku_reader, ())?;
@@ -406,7 +406,7 @@ fn emit_enum(input: &DekuData) -> Result<TokenStream, syn::Error> {
406406
use ::#crate_::DekuReader as _;
407407
let __deku_reader = &mut deku::reader::Reader::new(__deku_input.0);
408408
if __deku_input.1 != 0 {
409-
__deku_reader.skip_bits(__deku_input.1)?;
409+
__deku_reader.skip_bits(__deku_input.1, ::#crate_::ctx::Order::default())?;
410410
}
411411

412412
let __deku_value = Self::from_reader_with_ctx(__deku_reader, ())?;
@@ -420,7 +420,7 @@ fn emit_enum(input: &DekuData) -> Result<TokenStream, syn::Error> {
420420
let mut __deku_cursor = #crate_::no_std_io::Cursor::new(__deku_input.0);
421421
let mut __deku_reader = &mut deku::reader::Reader::new(&mut __deku_cursor);
422422
if __deku_input.1 != 0 {
423-
__deku_reader.skip_bits(__deku_input.1)?;
423+
__deku_reader.skip_bits(__deku_input.1, ::#crate_::ctx::Order::default())?;
424424
}
425425

426426
let __deku_value = Self::from_reader_with_ctx(__deku_reader, ())?;
@@ -620,8 +620,7 @@ fn emit_padding(bit_size: &TokenStream, bit_order: Option<&LitStr>) -> TokenStre
620620
// TODO: use skip_bytes, or Seek in the future?
621621
let _ = __deku_reader.read_bytes(bytes_read, &mut buf, #order)?;
622622
} else {
623-
// TODO: use skip_bits, or Seek in the future?
624-
let _ = __deku_reader.read_bits(__deku_pad, #order)?;
623+
__deku_reader.skip_bits(__deku_pad, #order)?;
625624
}
626625
}
627626
}
@@ -641,8 +640,7 @@ fn emit_padding(bit_size: &TokenStream, bit_order: Option<&LitStr>) -> TokenStre
641640
// TODO: use skip_bytes, or Seek in the future?
642641
let _ = __deku_reader.read_bytes(bytes_read, &mut buf, ::#crate_::ctx::Order::default())?;
643642
} else {
644-
// TODO: use skip_bits, or Seek in the future?
645-
let _ = __deku_reader.read_bits(__deku_pad, ::#crate_::ctx::Order::default())?;
643+
__deku_reader.skip_bits(__deku_pad, ::#crate_::ctx::Order::default())?;
646644
}
647645
}
648646
}

deku-derive/src/macros/deku_write.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -544,25 +544,36 @@ fn emit_bit_byte_offsets(
544544
#[cfg(feature = "bits")]
545545
fn emit_padding(bit_size: &TokenStream, bit_order: Option<&LitStr>) -> TokenStream {
546546
let crate_ = super::get_crate_name();
547+
const PAD: usize = crate::PAD_ARRAY_SIZE * 8;
547548
if let Some(bit_order) = bit_order {
548549
let order = gen_bit_order_from_str(bit_order).unwrap();
549550
quote! {
550551
{
551552
use core::convert::TryFrom;
552-
let __deku_pad = usize::try_from(#bit_size).map_err(|e|
553+
let mut __deku_pad = usize::try_from(#bit_size).map_err(|e|
553554
::#crate_::deku_error!(::#crate_::DekuError::InvalidParam, "Invalid padding param, cannot convert to usize", "{}", stringify!(#bit_size))
554555
)?;
555-
__deku_writer.write_bits_order(::#crate_::bitvec::bitvec![u8, ::#crate_::bitvec::Msb0; 0; __deku_pad].as_bitslice(), #order)?;
556+
let __deku_pad_source = ::#crate_::bitvec::bitarr!(u8, ::#crate_::bitvec::Msb0; 0; #PAD);
557+
while __deku_pad > 0 {
558+
let __deku_pad_chunk = core::cmp::min(__deku_pad_source.len(), __deku_pad);
559+
__deku_writer.write_bits_order(&__deku_pad_source[..__deku_pad_chunk], #order)?;
560+
__deku_pad -= __deku_pad_chunk;
561+
}
556562
}
557563
}
558564
} else {
559565
quote! {
560566
{
561567
use core::convert::TryFrom;
562-
let __deku_pad = usize::try_from(#bit_size).map_err(|e|
568+
let mut __deku_pad = usize::try_from(#bit_size).map_err(|e|
563569
::#crate_::deku_error!(::#crate_::DekuError::InvalidParam, "Invalid padding param, cannot convert to usize", "{}", stringify!(#bit_size))
564570
)?;
565-
__deku_writer.write_bits(::#crate_::bitvec::bitvec![u8, ::#crate_::bitvec::Msb0; 0; __deku_pad].as_bitslice())?;
571+
let __deku_pad_source = ::#crate_::bitvec::bitarr!(u8, ::#crate_::bitvec::Msb0; 0; #PAD);
572+
while __deku_pad > 0 {
573+
let __deku_pad_chunk = core::cmp::min(__deku_pad_source.len(), __deku_pad);
574+
__deku_writer.write_bits(&__deku_pad_source[..__deku_pad_chunk])?;
575+
__deku_pad -= __deku_pad_chunk;
576+
}
566577
}
567578
}
568579
}

src/error.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,3 +213,9 @@ impl From<DekuError> for std::io::Error {
213213
}
214214
}
215215
}
216+
217+
impl From<no_std_io::io::Error> for DekuError {
218+
fn from(value: no_std_io::io::Error) -> Self {
219+
DekuError::Io(value.kind())
220+
}
221+
}

src/impls/bool.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,6 @@ mod tests {
5353
use no_std_io::io::Cursor;
5454
use rstest::rstest;
5555

56-
#[cfg(feature = "bits")]
57-
use crate::ctx::BitSize;
5856
use crate::reader::Reader;
5957

6058
use super::*;
@@ -87,6 +85,8 @@ mod tests {
8785
#[cfg(all(feature = "alloc", feature = "bits"))]
8886
#[test]
8987
fn test_writer_bits() {
88+
use crate::ctx::BitSize;
89+
9090
let mut writer = Writer::new(Cursor::new(alloc::vec![]));
9191
true.to_writer(&mut writer, BitSize(1)).unwrap();
9292
assert_eq!(alloc::vec![true], writer.rest());

src/impls/primitive.rs

Lines changed: 42 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -55,19 +55,8 @@ impl DekuReader<'_, (Endian, ByteSize, Order)> for u8 {
5555
) -> Result<u8, DekuError> {
5656
const MAX_TYPE_BYTES: usize = core::mem::size_of::<u8>();
5757
let mut buf = [0; MAX_TYPE_BYTES];
58-
let ret = reader.read_bytes_const::<MAX_TYPE_BYTES>(&mut buf, order)?;
59-
let a = match ret {
60-
ReaderRet::Bytes => <u8>::from_be_bytes(buf),
61-
#[cfg(feature = "bits")]
62-
ReaderRet::Bits(bits) => {
63-
let Some(bits) = bits else {
64-
return Err(deku_error!(DekuError::Parse, "no bits read from reader"));
65-
};
66-
let a = <u8>::read(&bits, (_endian, _size))?;
67-
a.1
68-
}
69-
};
70-
Ok(a)
58+
reader.read_bytes_const_into::<MAX_TYPE_BYTES>(&mut buf, order)?;
59+
Ok(<u8>::from_be_bytes(buf))
7160
}
7261
}
7362

@@ -175,6 +164,7 @@ macro_rules! ImplDekuReadBits {
175164
let bit_slice = &input;
176165

177166
let pad = 8 * bit_slice.len().div_ceil(8) - bit_slice.len();
167+
debug_assert!(MAX_TYPE_BITS >= bit_slice.len() + pad);
178168

179169
// if everything is aligned, just read the value
180170
if pad == 0 && bit_slice.len() == MAX_TYPE_BITS {
@@ -197,29 +187,20 @@ macro_rules! ImplDekuReadBits {
197187
// we want to read from right to left when lsb (without using BitVec BitFields)
198188
//
199189
// Turning this into [0x23, 0x01] (then appending till type size)
190+
debug_assert_eq!(bit_size, bit_slice.len());
191+
const MAX_TYPE_BYTES: usize = core::mem::size_of::<$typ>();
200192
if order == Order::Lsb0 && bit_slice.len() > 8 && pad != 0 {
201-
let mut bits = BitVec::<u8, Msb0>::with_capacity(bit_slice.len() + pad);
193+
let mut bits = crate::BoundedBitVec::<[u8; MAX_TYPE_BYTES], Msb0>::new();
202194

203195
bits.extend_from_bitslice(&bit_slice);
204196

205197
for _ in 0..pad {
206198
bits.insert(0, false);
207199
}
208200

209-
let mut buf = alloc::vec![];
210-
let mut n = bits.len() - 8;
211-
while let Some(slice) = bits.get(n..n + 8) {
212-
let a: u8 = slice.load_be();
213-
buf.push(a);
214-
if n < 8 {
215-
break;
216-
}
217-
n -= 8;
218-
}
219-
220-
// Pad up-to size of type
221-
for _ in 0..core::mem::size_of::<$typ>() - buf.len() {
222-
buf.push(0x00);
201+
let mut buf = [0u8; MAX_TYPE_BYTES];
202+
for (slice, slot) in bits.as_bitslice().rchunks_exact(8).zip(buf.iter_mut()) {
203+
*slot = slice.load_be();
223204
}
224205

225206
// Read value
@@ -231,18 +212,14 @@ macro_rules! ImplDekuReadBits {
231212

232213
Ok((bit_size, value))
233214
} else {
234-
// Create a new BitVec from the slice and pad un-aligned chunks
215+
// Create a new BoundedBitVec from the slice and pad un-aligned chunks
235216
// i.e. [10010110, 1110] -> [10010110, 00001110]
236-
let bits: BitVec<u8, Msb0> = {
237-
let mut bits = BitVec::with_capacity(bit_slice.len() + pad);
217+
let bits: crate::BoundedBitVec<[u8; MAX_TYPE_BYTES], Msb0> = {
218+
let mut bits = crate::BoundedBitVec::new();
238219

239-
// Copy bits to new BitVec
220+
// Copy bits to new BoundedBitVec
240221
bits.extend_from_bitslice(&bit_slice);
241222

242-
// Force align
243-
//i.e. [1110, 10010110] -> [11101001, 0110]
244-
bits.force_align();
245-
246223
// Some padding to next byte
247224
let index = if input_is_le {
248225
bits.len() - (8 - pad)
@@ -264,7 +241,7 @@ macro_rules! ImplDekuReadBits {
264241

265242
bits
266243
};
267-
let bytes: &[u8] = bits.domain().region().unwrap().1;
244+
let bytes = bits.as_raw_slice();
268245

269246
// Read value
270247
let value = if input_is_le {
@@ -309,18 +286,15 @@ macro_rules! ImplDekuReadBits {
309286
}
310287
}
311288

312-
// Create a new BitVec from the slice and pad un-aligned chunks
289+
// Create a new BoundedBitVec from the slice and pad un-aligned chunks
313290
// i.e. [10010110, 1110] -> [10010110, 00001110]
314-
let bits: BitVec<u8, Msb0> = {
315-
let mut bits = BitVec::with_capacity(bit_slice.len() + pad);
291+
const MAX_TYPE_BYTES: usize = core::mem::size_of::<$typ>();
292+
let bits: crate::BoundedBitVec<[u8; MAX_TYPE_BYTES], Msb0> = {
293+
let mut bits = crate::BoundedBitVec::new();
316294

317-
// Copy bits to new BitVec
295+
// Copy bits to new BoundedBitVec
318296
bits.extend_from_bitslice(&bit_slice);
319297

320-
// Force align
321-
//i.e. [1110, 10010110] -> [11101001, 0110]
322-
bits.force_align();
323-
324298
// Some padding to next byte
325299
let index = if input_is_le {
326300
bits.len() - (8 - pad)
@@ -343,7 +317,7 @@ macro_rules! ImplDekuReadBits {
343317
bits
344318
};
345319

346-
let bytes: &[u8] = bits.domain().region().unwrap().1;
320+
let bytes = bits.as_raw_slice();
347321

348322
// Read value
349323
let value = if input_is_le {
@@ -372,11 +346,11 @@ macro_rules! ImplDekuReadBits {
372346
size.0
373347
));
374348
}
375-
let bits = reader.read_bits(size.0, Order::default())?;
376-
let Some(bits) = bits else {
377-
return Err(deku_error!(DekuError::Parse, "no bits read from reader"));
378-
};
379-
let a = <$typ>::read(&bits, (endian, size))?;
349+
let mut bits = ::bitvec::array::BitArray::<[u8; { MAX_TYPE_BITS / 8 }], Msb0>::new(
350+
[0; { MAX_TYPE_BITS / 8 }],
351+
);
352+
reader.read_bits_into(&mut bits[..size.0], Order::default())?;
353+
let a = <$typ>::read(&bits[..size.0], (endian, size))?;
380354
Ok(a.1)
381355
}
382356
}
@@ -398,11 +372,11 @@ macro_rules! ImplDekuReadBits {
398372
size.0
399373
));
400374
}
401-
let bits = reader.read_bits(size.0, order)?;
402-
let Some(bits) = bits else {
403-
return Err(deku_error!(DekuError::Parse, "no bits read from reader"));
404-
};
405-
let a = <$typ>::read(&bits, (endian, size, order))?;
375+
let mut bits = ::bitvec::array::BitArray::<[u8; { MAX_TYPE_BITS / 8 }], Msb0>::new(
376+
[0; { MAX_TYPE_BITS / 8 }],
377+
);
378+
reader.read_bits_into(&mut bits[..size.0], order)?;
379+
let a = <$typ>::read(&bits[..size.0], (endian, size, order))?;
406380
Ok(a.1)
407381
}
408382
}
@@ -587,11 +561,12 @@ macro_rules! ImplDekuReadSignExtend {
587561
size.0
588562
));
589563
}
590-
let bits = reader.read_bits(size.0, order)?;
591-
let Some(bits) = bits else {
592-
return Err(deku_error!(DekuError::Parse, "no bits read from reader"));
593-
};
594-
let a = <$typ>::read(&bits, (endian, size, order))?;
564+
let mut bits = ::bitvec::array::BitArray::<[u8; { MAX_TYPE_BITS / 8 }], Msb0>::new(
565+
[0; { MAX_TYPE_BITS / 8 }],
566+
);
567+
568+
reader.read_bits_into(&mut bits[..size.0], order)?;
569+
let a = <$typ>::read(&bits[..size.0], (endian, size, order))?;
595570
Ok(a.1)
596571
}
597572
}
@@ -676,26 +651,12 @@ macro_rules! ForwardDekuRead {
676651
) -> Result<$typ, DekuError> {
677652
const MAX_TYPE_BYTES: usize = core::mem::size_of::<$typ>();
678653
let mut buf = [0; MAX_TYPE_BYTES];
679-
let ret = reader.read_bytes_const::<MAX_TYPE_BYTES>(&mut buf, Order::default())?;
680-
let a = match ret {
681-
ReaderRet::Bytes => {
682-
if endian.is_le() {
683-
<$typ>::from_le_bytes(buf)
684-
} else {
685-
<$typ>::from_be_bytes(buf)
686-
}
687-
}
688-
#[cfg(feature = "bits")]
689-
ReaderRet::Bits(Some(bits)) => {
690-
let a = <$typ>::read(&bits, (endian, ByteSize(MAX_TYPE_BYTES)))?;
691-
a.1
692-
}
693-
#[cfg(feature = "bits")]
694-
ReaderRet::Bits(None) => {
695-
return Err(deku_error!(DekuError::Parse, "no bits read from reader"));
696-
}
697-
};
698-
Ok(a)
654+
reader.read_bytes_const_into::<MAX_TYPE_BYTES>(&mut buf, Order::default())?;
655+
if endian.is_le() {
656+
Ok(<$typ>::from_le_bytes(buf))
657+
} else {
658+
Ok(<$typ>::from_be_bytes(buf))
659+
}
699660
}
700661
}
701662

0 commit comments

Comments
 (0)