Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
wcampbell0x2a committed Aug 1, 2023
1 parent 32dc0a0 commit 0c40c1a
Show file tree
Hide file tree
Showing 13 changed files with 341 additions and 55 deletions.
95 changes: 45 additions & 50 deletions deku-derive/src/macros/deku_read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,43 +57,43 @@ fn emit_struct(input: &DekuData) -> Result<TokenStream, syn::Error> {

let initialize_struct = super::gen_struct_init(is_named_struct, internal_fields);

// Implement `DekuContainerRead` for types that don't need a context
if input.ctx.is_none() || (input.ctx.is_some() && input.ctx_default.is_some()) {
let from_bytes_body = wrap_default_ctx(
quote! {
use core::convert::TryFrom;
use ::#crate_::bitvec::BitView;
let __deku_input_bits = __deku_input.0.view_bits::<::#crate_::bitvec::Msb0>();
let mut __deku_rest = &__deku_input_bits[__deku_input.1..];
let mut __deku_total_read = 0;

#magic_read

#(#field_reads)*
let __deku_value = #initialize_struct;

Ok((__deku_total_read, __deku_value))
},
&input.ctx,
&input.ctx_default,
);

tokens.extend(emit_try_from(&imp, &lifetime, &ident, wher));

tokens.extend(emit_from_bytes(
&imp,
&lifetime,
&ident,
wher,
from_bytes_body,
));
}
//// Implement `DekuContainerRead` for types that don't need a context
//if input.ctx.is_none() || (input.ctx.is_some() && input.ctx_default.is_some()) {
// let from_bytes_body = wrap_default_ctx(
// quote! {
// use core::convert::TryFrom;
// use ::#crate_::bitvec::BitView;
// let __deku_input_bits = __deku_input.0.view_bits::<::#crate_::bitvec::Msb0>();
// let mut __deku_rest = &__deku_input_bits[__deku_input.1..];
// let mut __deku_total_read = 0;

// #magic_read

// #(#field_reads)*
// let __deku_value = #initialize_struct;

// Ok((__deku_total_read, __deku_value))
// },
// &input.ctx,
// &input.ctx_default,
// );

// tokens.extend(emit_try_from(&imp, &lifetime, &ident, wher));

// tokens.extend(emit_from_bytes(
// &imp,
// &lifetime,
// &ident,
// wher,
// from_bytes_body,
// ));
//}

let (ctx_types, ctx_arg) = gen_ctx_types_and_arg(input.ctx.as_ref())?;

let read_body = quote! {
use core::convert::TryFrom;
let mut __deku_rest = __deku_input_bits;
//let mut __deku_rest = __deku_input_bits;
let mut __deku_total_read = 0;

#magic_read
Expand All @@ -106,7 +106,7 @@ fn emit_struct(input: &DekuData) -> Result<TokenStream, syn::Error> {

tokens.extend(quote! {
impl #imp ::#crate_::DekuRead<#lifetime, #ctx_types> for #ident #wher {
fn read(__deku_input_bits: &#lifetime ::#crate_::bitvec::BitSlice<u8, ::#crate_::bitvec::Msb0>, #ctx_arg) -> core::result::Result<(usize, Self), ::#crate_::DekuError> {
fn from_reader<R: std::io::Read>(container: &#lifetime mut ::#crate_::container::Container<R>, #ctx_arg) -> core::result::Result<Self, ::#crate_::DekuError> {
#read_body
}
}
Expand All @@ -117,7 +117,7 @@ fn emit_struct(input: &DekuData) -> Result<TokenStream, syn::Error> {

tokens.extend(quote! {
impl #imp ::#crate_::DekuRead<#lifetime> for #ident #wher {
fn read(__deku_input_bits: &#lifetime ::#crate_::bitvec::BitSlice<u8, ::#crate_::bitvec::Msb0>, _: ()) -> core::result::Result<(usize, Self), ::#crate_::DekuError> {
fn from_reader<R: std::io::Read>(container: &#lifetime mut ::#crate_::container::Container<R>, _: ()) -> core::result::Result<Self, ::#crate_::DekuError> {
#read_body
}
}
Expand Down Expand Up @@ -226,7 +226,7 @@ fn emit_enum(input: &DekuData) -> Result<TokenStream, syn::Error> {
// if we're consuming an id, set the rest to new_rest before reading the variant
let new_rest = if consume_id {

Check failure on line 227 in deku-derive/src/macros/deku_read.rs

View workflow job for this annotation

GitHub Actions / Clippy

this `if` has identical blocks
quote! {
__deku_total_read += __deku_amt_read;
//__deku_total_read += __deku_amt_read;
}
} else {
quote! {}
Expand Down Expand Up @@ -290,7 +290,7 @@ fn emit_enum(input: &DekuData) -> Result<TokenStream, syn::Error> {
}
} else if id_type.is_some() {
quote! {
let (__deku_amt_read, __deku_variant_id) = <#id_type>::read(&__deku_rest[__deku_total_read..], (#id_args))?;
let (__deku_amt_read, __deku_variant_id) = <#id_type>::from_reader(container, (#id_args))?;
}
} else {
// either `id` or `type` needs to be specified
Expand Down Expand Up @@ -354,7 +354,7 @@ fn emit_enum(input: &DekuData) -> Result<TokenStream, syn::Error> {
tokens.extend(quote! {
#[allow(non_snake_case)]
impl #imp ::#crate_::DekuRead<#lifetime, #ctx_types> for #ident #wher {
fn read(__deku_input_bits: &#lifetime ::#crate_::bitvec::BitSlice<u8, ::#crate_::bitvec::Msb0>, #ctx_arg) -> core::result::Result<(usize, Self), ::#crate_::DekuError> {
fn from_reader<R: std::io::Read>(container: &#lifetime mut ::#crate_::container::Container<R>, #ctx_arg) -> core::result::Result<Self, ::#crate_::DekuError> {
#read_body
}
}
Expand All @@ -366,7 +366,7 @@ fn emit_enum(input: &DekuData) -> Result<TokenStream, syn::Error> {
tokens.extend(quote! {
#[allow(non_snake_case)]
impl #imp ::#crate_::DekuRead<#lifetime> for #ident #wher {
fn read(__deku_input_bits: &#lifetime ::#crate_::bitvec::BitSlice<u8, ::#crate_::bitvec::Msb0>, _: ()) -> core::result::Result<(usize, Self), ::#crate_::DekuError> {
fn from_reader<R: std::io::Read>(container: &#lifetime mut ::#crate_::container::Container<R>, _: ()) -> core::result::Result<Self, ::#crate_::DekuError> {
#read_body
}
}
Expand Down Expand Up @@ -408,12 +408,10 @@ fn emit_magic_read(input: &DekuData) -> TokenStream {
let __deku_magic = #magic;

for __deku_byte in __deku_magic {
let (__deku_amt_read, __deku_read_byte) = u8::read(&__deku_rest[__deku_total_read..], ())?;
let __deku_read_byte = u8::from_reader(&mut container, ())?;
if *__deku_byte != __deku_read_byte {
return Err(::#crate_::DekuError::Parse(format!("Missing magic value {:?}", #magic)));
}

__deku_total_read += __deku_amt_read;
}
}
} else {
Expand Down Expand Up @@ -610,29 +608,29 @@ fn emit_field_read(
quote! {
{
use core::borrow::Borrow;
#type_as_deku_read::read(&__deku_rest[__deku_total_read..], (::#crate_::ctx::Limit::new_count(usize::try_from(*((#field_count).borrow()))?), (#read_args)))
#type_as_deku_read::from_reader<R: std::io::Read>(&mut container, (::#crate_::ctx::Limit::new_count(usize::try_from(*((#field_count).borrow()))?), (#read_args)))
}
}
} else if let Some(field_bits) = &f.bits_read {
quote! {
{
use core::borrow::Borrow;
#type_as_deku_read::read(&__deku_rest[__deku_total_read..], (::#crate_::ctx::Limit::new_bit_size(::#crate_::ctx::BitSize(usize::try_from(*((#field_bits).borrow()))?)), (#read_args)))
#type_as_deku_read::from_reader<R: std::io::Read>(container, (::#crate_::ctx::Limit::new_bit_size(::#crate_::ctx::BitSize(usize::try_from(*((#field_bits).borrow()))?)), (#read_args)))
}
}
} else if let Some(field_bytes) = &f.bytes_read {
quote! {
{
use core::borrow::Borrow;
#type_as_deku_read::read(&__deku_rest[__deku_total_read..], (::#crate_::ctx::Limit::new_byte_size(::#crate_::ctx::ByteSize(usize::try_from(*((#field_bytes).borrow()))?)), (#read_args)))
#type_as_deku_read::from_reader<R: std::io::Read>(container, (::#crate_::ctx::Limit::new_byte_size(::#crate_::ctx::ByteSize(usize::try_from(*((#field_bytes).borrow()))?)), (#read_args)))
}
}
} else if let Some(field_until) = &f.until {
// We wrap the input into another closure here to enforce that it is actually a callable
// Otherwise, an incorrectly passed-in integer could unexpectedly convert into a `Count` limit
quote! {#type_as_deku_read::read(&__deku_rest[__deku_total_read..], (::#crate_::ctx::Limit::new_until(#field_until), (#read_args)))}
quote! {#type_as_deku_read::from_reader<R: std::io::Read>(container, (::#crate_::ctx::Limit::new_until(#field_until), (#read_args)))}
} else {
quote! {#type_as_deku_read::read(&__deku_rest[__deku_total_read..], (#read_args))}
quote! {#type_as_deku_read::from_reader<R: std::io::Read>(container, (#read_args))}
}
};

Expand All @@ -648,11 +646,8 @@ fn emit_field_read(
);

let field_read_normal = quote! {
let (__deku_amt_read, __deku_value) = #field_read_func?;
let __deku_value = #field_read_func?;
let __deku_value: #field_type = #field_map(__deku_value)?;

__deku_total_read += __deku_amt_read;

__deku_value
};

Expand Down
18 changes: 16 additions & 2 deletions examples/example.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@

use std::convert::{TryFrom, TryInto};

use deku::prelude::*;
use deku::{
container::Container,
ctx::{BitSize, ByteSize, Endian},
prelude::*,
};

#[derive(Debug, PartialEq, DekuRead, DekuWrite)]
struct FieldF {
Expand Down Expand Up @@ -49,8 +53,18 @@ fn main() {
]
.as_ref();

let test_deku = DekuTest::try_from(test_data).unwrap();
let mut container = Container::new(std::io::Cursor::new(test_data.clone()));
let a = u8::from_reader(&mut container, (Endian::Little, ByteSize(1)));
let b = u8::from_reader(&mut container, (Endian::Little, BitSize(7)));
let c = u8::from_reader(&mut container, (Endian::Little, BitSize(1)));
let d = u16::from_reader(&mut container, (Endian::Big, BitSize(16)));
println!("{a:02x?}");
println!("{b:02x?}");
println!("{c:02x?}");
println!("{d:02x?}");

let test_deku = DekuTest::try_from(test_data).unwrap();
println!("{test_deku:02x?}");
assert_eq!(
DekuTest {
field_a: 0xab,
Expand Down
66 changes: 66 additions & 0 deletions src/container.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
use bitvec::prelude::*;
use std::io::Read;

pub struct Container<R: std::io::Read> {
inner: R,
leftover: BitVec<u8, Msb0>,
}

impl<R: Read> Container<R> {
pub fn new(inner: R) -> Self {
Self {
inner,
leftover: BitVec::new(), // with_capacity 8?
}
}

pub fn read_bits(&mut self, amt: usize) -> std::io::Result<BitVec<u8, Msb0>> {
let mut ret = BitVec::with_capacity(amt);

if amt < self.leftover.len() {
let used = self.leftover.split_off(amt);
ret.extend(&mut self.leftover);
self.leftover = used;
} else {
ret.extend(self.leftover.clone());

let bits_left = amt - self.leftover.len();
let mut bytes_len = (bits_left / 8);

Check warning on line 28 in src/container.rs

View workflow job for this annotation

GitHub Actions / Build

unnecessary parentheses around assigned value

Check warning on line 28 in src/container.rs

View workflow job for this annotation

GitHub Actions / Test Suite

unnecessary parentheses around assigned value
if (bits_left % 8) != 0 {
bytes_len += 1;
}
let mut buf = vec![0; bytes_len];
self.inner.read_exact(&mut buf);

let mut rest: BitVec<u8, Msb0> = BitVec::try_from_slice(&buf).unwrap();
let add = rest.split_off(bits_left);
ret.extend_from_bitslice(rest.as_bitslice());

self.leftover = add;
}

Ok(ret)
}
}

#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_container() {
use std::io::Cursor;
let buf = [0x12, 0x34];
let buf = std::io::Cursor::new(buf);

let mut container = Container::new(buf);

let bits = container.read_bits(4).unwrap();
println!("{}", bits);
let bits = container.read_bits(4).unwrap();
println!("{}", bits);
let bits = container.read_bits(4).unwrap();
println!("{}", bits);
let bits = container.read_bits(4).unwrap();
println!("{}", bits);
}
}
19 changes: 18 additions & 1 deletion src/impls/bool.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use std::io::Read;

#[cfg(feature = "alloc")]
use alloc::format;

use bitvec::prelude::*;

use crate::{DekuError, DekuRead, DekuWrite};
use crate::{DekuError, DekuRead, DekuWrite, container};

Check warning on line 8 in src/impls/bool.rs

View workflow job for this annotation

GitHub Actions / Build

unused import: `container`

Check warning on line 8 in src/impls/bool.rs

View workflow job for this annotation

GitHub Actions / Test Suite

unused import: `container`

impl<'a, Ctx> DekuRead<'a, Ctx> for bool
where
Expand All @@ -23,6 +25,21 @@ where

Ok((amt_read, ret))
}

fn from_reader<R: Read>(
container: &mut crate::container::Container<R>,
inner_ctx: Ctx,
) -> Result<bool, DekuError> {
let val = u8::from_reader(container, inner_ctx)?;

let ret = match val {
0x01 => Ok(true),
0x00 => Ok(false),
_ => Err(DekuError::Parse(format!("cannot parse bool value: {val}",))),
}?;

Ok(ret)
}
}

impl<Ctx> DekuWrite<Ctx> for bool
Expand Down
19 changes: 19 additions & 0 deletions src/impls/boxed.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::io::Read;

use alloc::boxed::Box;
use alloc::vec::Vec;

Expand All @@ -19,6 +21,14 @@ where
let (amt_read, val) = <T>::read(input, inner_ctx)?;
Ok((amt_read, Box::new(val)))
}

fn from_reader<R: Read>(
container: &mut crate::container::Container<R>,
inner_ctx: Ctx,
) -> Result<Self, DekuError> {
let val = <T>::from_reader(container, inner_ctx)?;
Ok(Box::new(val))
}
}

impl<T, Ctx> DekuWrite<Ctx> for Box<T>
Expand Down Expand Up @@ -50,6 +60,15 @@ where
let (amt_read, val) = <Vec<T>>::read(input, (limit, inner_ctx))?;
Ok((amt_read, val.into_boxed_slice()))
}

fn from_reader<R: Read>(
container: &mut crate::container::Container<R>,
(limit, inner_ctx): (Limit<T, Predicate>, Ctx),
) -> Result<Self, DekuError> {
// use Vec<T>'s implementation and convert to Box<[T]>
let val = <Vec<T>>::from_reader(container, (limit, inner_ctx))?;
Ok(val.into_boxed_slice())
}
}

impl<T, Ctx> DekuWrite<Ctx> for Box<[T]>
Expand Down
10 changes: 9 additions & 1 deletion src/impls/cow.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::borrow::{Borrow, Cow};
use std::{borrow::{Borrow, Cow}, io::Read};

use bitvec::prelude::*;

Expand All @@ -17,6 +17,14 @@ where
let (amt_read, val) = <T>::read(input, inner_ctx)?;
Ok((amt_read, Cow::Owned(val)))
}

fn from_reader<R: Read>(
container: &mut crate::container::Container<R>,
inner_ctx: Ctx,
) -> Result<Self, DekuError> {
let val = <T>::from_reader(container, inner_ctx)?;
Ok(Cow::Owned(val))
}
}

impl<T, Ctx> DekuWrite<Ctx> for Cow<'_, T>
Expand Down
Loading

0 comments on commit 0c40c1a

Please sign in to comment.