Skip to content

Commit

Permalink
Merge 2913a9f into 7ce4d86
Browse files Browse the repository at this point in the history
  • Loading branch information
wcampbell0x2a authored May 31, 2024
2 parents 7ce4d86 + 2913a9f commit 755ed48
Show file tree
Hide file tree
Showing 10 changed files with 306 additions and 54 deletions.
9 changes: 5 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,16 @@ members = [
]

[features]
default = ["std"]
std = ["deku_derive/std", "bitvec/std", "alloc", "no_std_io/std"]
alloc = ["bitvec/alloc"]
default = ["std", "bits"]
std = ["deku_derive/std", "bitvec?/std", "alloc", "no_std_io/std"]
alloc = ["bitvec?/alloc"]
logging = ["deku_derive/logging", "log"]
no-assert-string = ["deku_derive/no-assert-string"]
bits = ["dep:bitvec", "deku_derive/bits"]

[dependencies]
deku_derive = { version = "^0.17.0", path = "deku-derive", default-features = false}
bitvec = { version = "1.0.1", default-features = false }
bitvec = { version = "1.0.1", default-features = false, optional = true }
log = { version = "0.4.21", optional = true }
no_std_io = { version = "0.6.0", default-features = false, features = ["alloc"] }
rustversion = "1.0.16"
Expand Down
40 changes: 39 additions & 1 deletion benches/deku.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::io::{Cursor, Read};
use criterion::{black_box, criterion_group, criterion_main, BatchSize, Criterion};
use deku::prelude::*;

#[cfg(feature = "bits")]
#[derive(Debug, PartialEq, DekuRead, DekuWrite)]
struct DekuBits {
#[deku(bits = 1)]
Expand Down Expand Up @@ -61,6 +62,7 @@ fn criterion_benchmark(c: &mut Criterion) {
}))
})
});
#[cfg(feature = "bits")]
c.bench_function("deku_read_bits", |b| {
let reader = Cursor::new(&[0x01; 1]);
b.iter_batched(
Expand All @@ -69,6 +71,7 @@ fn criterion_benchmark(c: &mut Criterion) {
BatchSize::SmallInput,
)
});
#[cfg(feature = "bits")]
c.bench_function("deku_write_bits", |b| {
b.iter(|| {
deku_write(black_box(&DekuBits {
Expand Down Expand Up @@ -108,5 +111,40 @@ fn criterion_benchmark(c: &mut Criterion) {
});
}

criterion_group!(benches, criterion_benchmark);
pub fn read_all_vs_count(c: &mut Criterion) {
#[derive(DekuRead, DekuWrite)]
pub struct AllWrapper {
#[deku(read_all)]
pub data: Vec<u8>,
}

#[derive(DekuRead, DekuWrite)]
#[deku(ctx = "len: usize")]
pub struct CountWrapper {
#[deku(count = "len")]
pub data: Vec<u8>,
}

c.bench_function("read_all_bytes", |b| {
b.iter(|| AllWrapper::from_bytes(black_box((&[1; 1500], 0))))
});

c.bench_function("read_all", |b| {
b.iter(|| {
let mut cursor = [1u8; 1500].as_ref();
let mut reader = Reader::new(&mut cursor);
AllWrapper::from_reader_with_ctx(black_box(&mut reader), ())
})
});

c.bench_function("count", |b| {
b.iter(|| {
let mut cursor = [1u8; 1500].as_ref();
let mut reader = Reader::new(&mut cursor);
CountWrapper::from_reader_with_ctx(black_box(&mut reader), 1500)
})
});
}

criterion_group!(benches, criterion_benchmark, read_all_vs_count);
criterion_main!(benches);
1 change: 1 addition & 0 deletions deku-derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ proc-macro = true
std = ["proc-macro-crate"]
logging = []
no-assert-string = []
bits = []

[dependencies]
quote = "1.0"
Expand Down
8 changes: 7 additions & 1 deletion deku-derive/src/macros/deku_write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ fn emit_struct(input: &DekuData) -> Result<TokenStream, syn::Error> {

// Implement `DekuContainerWrite` for types that don't need a context
if input.ctx.is_none() || (input.ctx.is_some() && input.ctx_default.is_some()) {
#[cfg(feature = "bits")]
tokens.extend(quote! {
impl #imp core::convert::TryFrom<#ident> for ::#crate_::bitvec::BitVec<u8, ::#crate_::bitvec::Msb0> #wher {
type Error = ::#crate_::DekuError;
Expand All @@ -56,7 +57,9 @@ fn emit_struct(input: &DekuData) -> Result<TokenStream, syn::Error> {
input.to_bits()
}
}
});

tokens.extend(quote! {
impl #imp core::convert::TryFrom<#ident> for Vec<u8> #wher {
type Error = ::#crate_::DekuError;

Expand Down Expand Up @@ -243,6 +246,7 @@ fn emit_enum(input: &DekuData) -> Result<TokenStream, syn::Error> {

// Implement `DekuContainerWrite` for types that don't need a context
if input.ctx.is_none() || (input.ctx.is_some() && input.ctx_default.is_some()) {
#[cfg(feature = "bits")]
tokens.extend(quote! {
impl #imp core::convert::TryFrom<#ident> for ::#crate_::bitvec::BitVec<u8, ::#crate_::bitvec::Msb0> #wher {
type Error = ::#crate_::DekuError;
Expand All @@ -252,7 +256,9 @@ fn emit_enum(input: &DekuData) -> Result<TokenStream, syn::Error> {
input.to_bits()
}
}
});

tokens.extend(quote! {
impl #imp core::convert::TryFrom<#ident> for Vec<u8> #wher {
type Error = ::#crate_::DekuError;

Expand All @@ -263,7 +269,7 @@ fn emit_enum(input: &DekuData) -> Result<TokenStream, syn::Error> {
}

impl #imp DekuContainerWrite for #ident #wher {}
})
});
}

let (ctx_types, ctx_arg) = gen_ctx_types_and_arg(input.ctx.as_ref())?;
Expand Down
2 changes: 1 addition & 1 deletion ensure_no_std/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ alloc = []

[dependencies]
cortex-m-rt = "0.7.3"
deku = { path = "../", default-features = false, features = ["alloc"] }
deku = { path = "../", default-features = false, features = ["alloc", "bits"] }
embedded-alloc = "0.5.1"

1 change: 1 addition & 0 deletions src/impls/nonzero.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ macro_rules! ImplDekuTraitsCtx {
macro_rules! ImplDekuTraits {
($typ:ty, $readtype:ty) => {
ImplDekuTraitsCtx!($typ, $readtype, (), ());
#[cfg(feature = "bits")]
ImplDekuTraitsCtx!($typ, $readtype, (endian, bitsize), (Endian, BitSize));
ImplDekuTraitsCtx!($typ, $readtype, (endian, bytesize), (Endian, ByteSize));
ImplDekuTraitsCtx!($typ, $readtype, endian, Endian);
Expand Down
35 changes: 22 additions & 13 deletions src/impls/primitive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ use alloc::borrow::Cow;
use alloc::format;
use core::convert::TryInto;

#[cfg(feature = "bits")]
use bitvec::prelude::*;

use no_std_io::io::{Read, Write};

use crate::ctx::*;
Expand All @@ -12,6 +14,7 @@ use crate::writer::Writer;
use crate::{DekuError, DekuReader, DekuWriter};

/// "Read" trait: read bits and construct type
#[cfg(feature = "bits")]
trait DekuRead<'a, Ctx = ()> {
/// Read bits and construct type
/// * **input** - Input as bits
Expand All @@ -32,7 +35,9 @@ trait DekuRead<'a, Ctx = ()> {
}

// specialize u8 for ByteSize
#[cfg(feature = "bits")]
impl DekuRead<'_, (Endian, ByteSize)> for u8 {
#[cfg(feature = "bits")]
#[inline]
fn read(
input: &BitSlice<u8, Msb0>,
Expand All @@ -57,6 +62,7 @@ impl DekuReader<'_, (Endian, ByteSize)> for u8 {
let ret = reader.read_bytes_const::<MAX_TYPE_BYTES>(&mut buf)?;
let a = match ret {
ReaderRet::Bytes => <u8>::from_be_bytes(buf),
#[cfg(feature = "bits")]
ReaderRet::Bits(bits) => {
let Some(bits) = bits else {
return Err(DekuError::Parse(Cow::from("no bits read from reader")));
Expand All @@ -71,6 +77,7 @@ impl DekuReader<'_, (Endian, ByteSize)> for u8 {

macro_rules! ImplDekuReadBits {
($typ:ty, $inner:ty) => {
#[cfg(feature = "bits")]
impl DekuRead<'_, (Endian, BitSize)> for $typ {
#[inline(never)]
fn read(
Expand Down Expand Up @@ -147,6 +154,7 @@ macro_rules! ImplDekuReadBits {
}
}

#[cfg(feature = "bits")]
impl DekuReader<'_, (Endian, BitSize)> for $typ {
#[inline(always)]
fn from_reader_with_ctx<R: Read>(
Expand All @@ -173,26 +181,16 @@ macro_rules! ImplDekuReadBits {

macro_rules! ImplDekuReadBytes {
($typ:ty, $inner:ty) => {
#[cfg(feature = "bits")]
impl DekuRead<'_, (Endian, ByteSize)> for $typ {
#[inline(never)]
fn read(
input: &BitSlice<u8, Msb0>,
(endian, size): (Endian, ByteSize),
) -> Result<(usize, Self), DekuError> {
let bit_size: usize = size.0 * 8;

let input_is_le = endian.is_le();

let bit_slice = &input[..bit_size];

let bytes = bit_slice.domain().region().unwrap().1;
let value = if input_is_le {
<$typ>::from_le_bytes(bytes.try_into()?)
} else {
<$typ>::from_be_bytes(bytes.try_into()?)
};
let bit_size = BitSize(size.0 * 8);

Ok((bit_size, value))
<$typ>::read(input, (endian, bit_size))
}
}

Expand Down Expand Up @@ -224,10 +222,12 @@ macro_rules! ImplDekuReadBytes {
<$typ>::from_be_bytes(buf.try_into().unwrap())
}
}
#[cfg(feature = "bits")]
ReaderRet::Bits(Some(bits)) => {
let a = <$typ>::read(&bits, (endian, size))?;
a.1
}
#[cfg(feature = "bits")]
ReaderRet::Bits(None) => {
return Err(DekuError::Parse(Cow::from("no bits read from reader")));
}
Expand All @@ -240,6 +240,7 @@ macro_rules! ImplDekuReadBytes {

macro_rules! ImplDekuReadSignExtend {
($typ:ty, $inner:ty) => {
#[cfg(feature = "bits")]
impl DekuRead<'_, (Endian, ByteSize)> for $typ {
#[inline(never)]
fn read(
Expand Down Expand Up @@ -273,6 +274,7 @@ macro_rules! ImplDekuReadSignExtend {
<$typ>::from_be_bytes(buf.try_into()?)
}
}
#[cfg(feature = "bits")]
ReaderRet::Bits(bits) => {
let Some(bits) = bits else {
return Err(DekuError::Parse(Cow::from("no bits read from reader")));
Expand All @@ -290,6 +292,7 @@ macro_rules! ImplDekuReadSignExtend {
}
}

#[cfg(feature = "bits")]
impl DekuRead<'_, (Endian, BitSize)> for $typ {
#[inline(never)]
fn read(
Expand All @@ -307,6 +310,7 @@ macro_rules! ImplDekuReadSignExtend {
}
}

#[cfg(feature = "bits")]
impl DekuReader<'_, (Endian, BitSize)> for $typ {
#[inline(always)]
fn from_reader_with_ctx<R: Read>(
Expand Down Expand Up @@ -351,10 +355,12 @@ macro_rules! ForwardDekuRead {
<$typ>::from_be_bytes(buf)
}
}
#[cfg(feature = "bits")]
ReaderRet::Bits(Some(bits)) => {
let a = <$typ>::read(&bits, (endian, ByteSize(MAX_TYPE_BYTES)))?;
a.1
}
#[cfg(feature = "bits")]
ReaderRet::Bits(None) => {
return Err(DekuError::Parse(Cow::from("no bits read from reader")));
}
Expand All @@ -378,6 +384,7 @@ macro_rules! ForwardDekuRead {
}

//// Only have `bit_size`, set `endian` to `Endian::default`.
#[cfg(feature = "bits")]
impl DekuReader<'_, BitSize> for $typ {
#[inline(always)]
fn from_reader_with_ctx<R: Read>(
Expand Down Expand Up @@ -408,6 +415,7 @@ macro_rules! ForwardDekuRead {

macro_rules! ImplDekuWrite {
($typ:ty) => {
#[cfg(feature = "bits")]
impl DekuWriter<(Endian, BitSize)> for $typ {
#[inline(always)]
fn to_writer<W: Write>(
Expand Down Expand Up @@ -505,6 +513,7 @@ macro_rules! ImplDekuWrite {

macro_rules! ForwardDekuWrite {
($typ:ty) => {
#[cfg(feature = "bits")]
impl DekuWriter<BitSize> for $typ {
#[inline(always)]
fn to_writer<W: Write>(
Expand Down
8 changes: 8 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,12 @@ environment, you will see logging messages as Deku does its deserialising.
- `DekuError` whenever possible will use a `'static str`, to make the errors compile away when following a
guide such as [min-sized-rust](/~https://github.com/johnthagen/min-sized-rust).
# Performance: Compile without `bitvec`
The feature `bits` enables the `bitvec` crate to use when reading and writing, which is enabled by default.
This however slows down the reading and writing process if your code doesn't use `bits` and the `bit_offset`
in `from_bytes`. While this option is still fully tested, you can be sure to be creating the most performant
code possible for byte only reading by _not_ using this feature.
*/
#![warn(missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)]
Expand All @@ -358,6 +364,7 @@ pub mod no_std_io {
}

/// re-export of bitvec
#[cfg(feature = "bits")]
pub mod bitvec {
pub use bitvec::prelude::*;
pub use bitvec::view::BitView;
Expand Down Expand Up @@ -537,6 +544,7 @@ pub trait DekuContainerWrite: DekuWriter<()> {
/// assert_eq!(deku::bitvec::bitvec![1, 1, 1, 1, 0, 0, 0, 1, 1], bits);
/// ```
#[inline(always)]
#[cfg(feature = "bits")]
fn to_bits(&self) -> Result<bitvec::BitVec<u8, bitvec::Msb0>, DekuError> {
let mut out_buf = Vec::new();
let mut __deku_writer = Writer::new(&mut out_buf);
Expand Down
Loading

0 comments on commit 755ed48

Please sign in to comment.