Skip to content

Commit 4fb3527

Browse files
authored
Lift alloc requirement for bits feature (#614)
1 parent 4d6f477 commit 4fb3527

36 files changed

+825
-538
lines changed

.github/workflows/main.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ jobs:
2626
- run: cargo test --no-default-features --features=descriptive-errors
2727
- run: cargo test --no-default-features --features=bits
2828
- run: cargo test --no-default-features --features=logging
29+
- run: cargo test --no-default-features --features=bits,alloc
2930
# run examples
3031
- run: cargo run --example 2>&1 | grep -P ' ' | awk '{print $1}' | xargs -i cargo run --example {}
3132

@@ -36,7 +37,7 @@ jobs:
3637
matrix:
3738
toolchain:
3839
# msrv
39-
- 1.81
40+
- 1.82
4041

4142
steps:
4243
- uses: actions/checkout@v4

Cargo.toml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ keywords = ["deku", "bits", "serialization", "deserialization", "struct"]
99
categories = ["encoding", "parsing", "no-std"]
1010
description = "bit level serialization/deserialization proc-macro for structs"
1111
readme = "README.md"
12-
rust-version = "1.81"
12+
rust-version = "1.82"
1313

1414
[lib]
1515
bench = false
@@ -24,7 +24,7 @@ default = ["std", "bits", "descriptive-errors"]
2424
std = ["deku_derive/std", "bitvec?/std", "alloc", "no_std_io/std"]
2525
alloc = ["bitvec?/alloc", "deku_derive/alloc", "no_std_io/alloc" ]
2626
logging = ["deku_derive/logging", "log"]
27-
bits = ["dep:bitvec", "deku_derive/bits", "alloc" ]
27+
bits = ["dep:bitvec", "deku_derive/bits" ]
2828
descriptive-errors = ["alloc"]
2929

3030
[dependencies]
@@ -60,27 +60,27 @@ manual-unwrap-or-default = "allow"
6060

6161
[[example]]
6262
name = "custom_reader_and_writer"
63-
required-features = ["bits"]
63+
required-features = ["alloc", "bits"]
6464

6565
[[example]]
6666
name = "deku_input"
6767
required-features = ["std"]
6868

6969
[[example]]
7070
name = "enums_catch_all"
71-
required-features = ["bits"]
71+
required-features = ["alloc", "bits"]
7272

7373
[[example]]
7474
name = "enums"
7575
required-features = ["std"]
7676

7777
[[example]]
7878
name = "example"
79-
required-features = ["bits"]
79+
required-features = ["alloc", "bits"]
8080

8181
[[example]]
8282
name = "ipv4"
83-
required-features = ["bits"]
83+
required-features = ["alloc", "bits"]
8484

8585
[[example]]
8686
name = "80211"

deku-derive/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
77
repository = "https://github.com/sharksforarms/deku"
88
description = "bit level serialization/deserialization proc-macro for structs"
99
readme = "../README.md"
10-
rust-version = "1.81"
10+
rust-version = "1.82"
1111

1212
[lib]
1313
proc-macro = true

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: 14 additions & 31 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, ())?;
@@ -607,43 +607,21 @@ fn emit_padding(bit_size: &TokenStream, bit_order: Option<&LitStr>) -> TokenStre
607607
let order = gen_bit_order_from_str(bit_order).unwrap();
608608
quote! {
609609
{
610-
extern crate alloc;
611-
612610
use core::convert::TryFrom;
613611
let __deku_pad = usize::try_from(#bit_size).map_err(|e|
614612
::#crate_::deku_error!(::#crate_::DekuError::InvalidParam, "Invalid padding param, cannot convert ot usize", "{}", stringify!(#bit_size))
615613
)?;
616-
617-
if (__deku_pad % 8) == 0 {
618-
let bytes_read = __deku_pad / 8;
619-
let mut buf = alloc::vec![0; bytes_read];
620-
// TODO: use skip_bytes, or Seek in the future?
621-
let _ = __deku_reader.read_bytes(bytes_read, &mut buf, #order)?;
622-
} else {
623-
// TODO: use skip_bits, or Seek in the future?
624-
let _ = __deku_reader.read_bits(__deku_pad, #order)?;
625-
}
614+
__deku_reader.skip_bits(__deku_pad, #order)?;
626615
}
627616
}
628617
} else {
629618
quote! {
630619
{
631-
extern crate alloc;
632-
633620
use core::convert::TryFrom;
634621
let __deku_pad = usize::try_from(#bit_size).map_err(|e|
635622
::#crate_::deku_error!(::#crate_::DekuError::InvalidParam, "Invalid padding param, cannot convert to usize", "{}", stringify!(#bit_size))
636623
)?;
637-
638-
if (__deku_pad % 8) == 0 {
639-
let bytes_read = __deku_pad / 8;
640-
let mut buf = alloc::vec![0; bytes_read];
641-
// TODO: use skip_bytes, or Seek in the future?
642-
let _ = __deku_reader.read_bytes(bytes_read, &mut buf, ::#crate_::ctx::Order::default())?;
643-
} else {
644-
// TODO: use skip_bits, or Seek in the future?
645-
let _ = __deku_reader.read_bits(__deku_pad, ::#crate_::ctx::Order::default())?;
646-
}
624+
__deku_reader.skip_bits(__deku_pad, ::#crate_::ctx::Order::default())?;
647625
}
648626
}
649627
}
@@ -1070,9 +1048,14 @@ pub fn emit_try_from(
10701048
fn try_from(input: &#lifetime [u8]) -> core::result::Result<Self, Self::Error> {
10711049
let total_len = input.len();
10721050
let mut cursor = ::#crate_::no_std_io::Cursor::new(input);
1073-
let (amt_read, res) = <Self as ::#crate_::DekuContainerRead>::from_reader((&mut cursor, 0))?;
1074-
if (amt_read / 8) != total_len {
1075-
return Err(::#crate_::deku_error!(::#crate_::DekuError::Parse, "Too much data"));
1051+
let (bits_read, res) = <Self as ::#crate_::DekuContainerRead>::from_reader((&mut cursor, 0))?;
1052+
let bytes_read = bits_read / 8;
1053+
if bytes_read < total_len {
1054+
return Err(::#crate_::deku_error!(::#crate_::DekuError::Parse, "Too much data", "Read {} but total length was {}", {bits_read / 8}, total_len));
1055+
}
1056+
// Possible Seek beyond end
1057+
if bytes_read > total_len {
1058+
return Err(::#crate_::DekuError::Incomplete(::#crate_::error::NeedSize::new(bits_read - { total_len * 8 })));
10761059
}
10771060
Ok(res)
10781061
}

deku-derive/src/macros/deku_write.rs

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ fn emit_struct(input: &DekuData) -> Result<TokenStream, syn::Error> {
9999

100100
// Implement `DekuContainerWrite` for types that don't need a context
101101
if input.ctx.is_none() || (input.ctx.is_some() && input.ctx_default.is_some()) {
102-
#[cfg(feature = "bits")]
102+
#[cfg(all(feature = "alloc", feature = "bits"))]
103103
tokens.extend(quote! {
104104
#[automatically_derived]
105105
impl #imp core::convert::TryFrom<#ident> for ::#crate_::bitvec::BitVec<u8, ::#crate_::bitvec::Msb0> #wher {
@@ -357,7 +357,7 @@ fn emit_enum(input: &DekuData) -> Result<TokenStream, syn::Error> {
357357

358358
// Implement `DekuContainerWrite` for types that don't need a context
359359
if input.ctx.is_none() || (input.ctx.is_some() && input.ctx_default.is_some()) {
360-
#[cfg(feature = "bits")]
360+
#[cfg(all(feature = "alloc", feature = "bits"))]
361361
tokens.extend(quote! {
362362
#[automatically_derived]
363363
impl #imp core::convert::TryFrom<#ident> for ::#crate_::bitvec::BitVec<u8, ::#crate_::bitvec::Msb0> #wher {
@@ -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/attributes.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ pub struct BigEndian {
230230
t: u8,
231231
}
232232
233-
# #[cfg(feature = "bits")]
233+
# #[cfg(all(feature = "alloc", feature = "bits"))]
234234
# fn main() {
235235
let data = vec![0x10, 0x81];
236236
let big_endian = BigEndian::try_from(data.as_ref()).unwrap();
@@ -245,7 +245,7 @@ let bytes = big_endian.to_bytes().unwrap();
245245
assert_eq!(bytes, data);
246246
# }
247247
#
248-
# #[cfg(not(feature = "bits"))]
248+
# #[cfg(not(all(feature = "alloc", feature = "bits")))]
249249
# fn main() {}
250250
````
251251
### Field Example
@@ -261,7 +261,7 @@ pub struct LsbField {
261261
t: u8,
262262
}
263263
264-
# #[cfg(feature = "bits")]
264+
# #[cfg(all(feature = "alloc", feature = "bits"))]
265265
# fn main() {
266266
let data = vec![0x40, 0x40];
267267
let more_first = LsbField::try_from(data.as_ref()).unwrap();
@@ -270,7 +270,7 @@ let bytes = more_first.to_bytes().unwrap();
270270
assert_eq!(bytes, data);
271271
# }
272272
#
273-
# #[cfg(not(feature = "bits"))]
273+
# #[cfg(not(all(feature = "alloc", feature = "bits")))]
274274
# fn main() {}
275275
```
276276
@@ -1570,7 +1570,7 @@ Specify custom reader or writer tokens for reading a field or variant
15701570
Example:
15711571
```rust
15721572
use core::convert::{TryInto, TryFrom};
1573-
# #[cfg(feature = "bits")]
1573+
# #[cfg(all(feature = "alloc", feature = "bits"))]
15741574
use deku::bitvec::{BitSlice, BitVec, Msb0};
15751575
use deku::prelude::*;
15761576

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/cstring.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ where
6767
}
6868

6969
#[cfg(test)]
70+
#[cfg(all(feature = "alloc", feature = "descriptive-errors"))]
7071
mod tests {
71-
#[cfg(feature = "alloc")]
7272
use alloc::vec;
7373
use no_std_io::io::Cursor;
7474
use rstest::rstest;
@@ -77,7 +77,6 @@ mod tests {
7777

7878
use super::*;
7979

80-
#[cfg(feature = "alloc")]
8180
#[rstest(input, len, expected, expected_rest,
8281
case(
8382
b"test\0",

0 commit comments

Comments
 (0)