Skip to content

Commit

Permalink
Impl Write support
Browse files Browse the repository at this point in the history
  • Loading branch information
wcampbell0x2a committed Dec 15, 2023
1 parent 7176d1b commit 8a3596b
Show file tree
Hide file tree
Showing 29 changed files with 760 additions and 469 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ alloc_counter = "0.0.4"
trybuild = "1.0.77"
rustc-hash = "1.1.0"
env_logger = "0.10.0"
assert_hex = "0.2.2"

[[bench]]
name = "deku"
Expand Down
2 changes: 1 addition & 1 deletion deku-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -668,7 +668,7 @@ fn apply_replacements(input: &syn::LitStr) -> Result<Cow<'_, syn::LitStr>, Repla

let input_str = input_value
.replace("deku::reader", "__deku_reader")
.replace("deku::output", "__deku_output") // part of the public API `write`
.replace("deku::writer", "__deku_writer")
.replace("deku::bit_offset", "__deku_bit_offset")
.replace("deku::byte_offset", "__deku_byte_offset");

Expand Down
2 changes: 1 addition & 1 deletion deku-derive/src/macros/deku_read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -603,7 +603,7 @@ fn emit_field_read(

let trace_field_log = if cfg!(feature = "logging") {
quote! {
log::trace!("Reading: {}::{}", #ident, #field_ident_str);
log::trace!("Reading: {}.{}", #ident, #field_ident_str);
}
} else {
quote! {}
Expand Down
114 changes: 53 additions & 61 deletions deku-derive/src/macros/deku_write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,26 +47,8 @@ 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()) {
let to_bits_body = wrap_default_ctx(
quote! {
match *self {
#destructured => {
let mut __deku_acc: ::#crate_::bitvec::BitVec<u8, ::#crate_::bitvec::Msb0> = ::#crate_::bitvec::BitVec::new();
let __deku_output = &mut __deku_acc;

#magic_write
#(#field_writes)*

Ok(__deku_acc)
}
}
},
&input.ctx,
&input.ctx_default,
);

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

fn try_from(input: #ident) -> core::result::Result<Self, Self::Error> {
Expand All @@ -84,13 +66,22 @@ fn emit_struct(input: &DekuData) -> Result<TokenStream, syn::Error> {

impl #imp DekuContainerWrite for #ident #wher {
fn to_bytes(&self) -> core::result::Result<Vec<u8>, ::#crate_::DekuError> {
let mut acc: ::#crate_::bitvec::BitVec<u8, ::#crate_::bitvec::Msb0> = self.to_bits()?;
Ok(acc.into_vec())
let mut out_buf = vec![];
let mut __deku_writer = ::#crate_::writer::Writer::new(&mut out_buf);
::#crate_::DekuWriter::to_writer(self, &mut __deku_writer, ())?;
__deku_writer.finalize()?;
Ok(out_buf)
}

#[allow(unused_variables)]
fn to_bits(&self) -> core::result::Result<::#crate_::bitvec::BitVec<u8, ::#crate_::bitvec::Msb0>, ::#crate_::DekuError> {
#to_bits_body
let mut out_buf = vec![];
let mut __deku_writer = ::#crate_::writer::Writer::new(&mut out_buf);
::#crate_::DekuWriter::to_writer(self, &mut __deku_writer, ())?;
let mut leftover = __deku_writer.leftover;
let mut bv = ::#crate_::bitvec::BitVec::from_slice(&out_buf);
bv.append(&mut leftover);
Ok(bv)
}
}
});
Expand Down Expand Up @@ -122,9 +113,9 @@ fn emit_struct(input: &DekuData) -> Result<TokenStream, syn::Error> {
}
}

impl #imp DekuWrite<#ctx_types> for #ident #wher {
impl #imp ::#crate_::DekuWriter<#ctx_types> for #ident #wher {
#[allow(unused_variables)]
fn write(&self, __deku_output: &mut ::#crate_::bitvec::BitVec<u8, ::#crate_::bitvec::Msb0>, #ctx_arg) -> core::result::Result<(), ::#crate_::DekuError> {
fn to_writer<W: ::#crate_::no_std_io::Write>(&self, __deku_writer: &mut ::#crate_::writer::Writer<W>, #ctx_arg) -> core::result::Result<(), ::#crate_::DekuError> {
#write_body
}
}
Expand All @@ -134,9 +125,9 @@ fn emit_struct(input: &DekuData) -> Result<TokenStream, syn::Error> {
let write_body = wrap_default_ctx(write_body, &input.ctx, &input.ctx_default);

tokens.extend(quote! {
impl #imp DekuWrite for #ident #wher {
impl #imp ::#crate_::DekuWriter for #ident #wher {
#[allow(unused_variables)]
fn write(&self, __deku_output: &mut ::#crate_::bitvec::BitVec<u8, ::#crate_::bitvec::Msb0>, _: ()) -> core::result::Result<(), ::#crate_::DekuError> {
fn to_writer<W: ::#crate_::no_std_io::Write>(&self, __deku_writer: &mut ::#crate_::writer::Writer<W>, _: ()) -> core::result::Result<(), ::#crate_::DekuError> {
#write_body
}
}
Expand Down Expand Up @@ -200,13 +191,13 @@ fn emit_enum(input: &DekuData) -> Result<TokenStream, syn::Error> {
Id::TokenStream(v) => {
quote! {
let mut __deku_variant_id: #id_type = #v;
__deku_variant_id.write(__deku_output, (#id_args))?;
__deku_variant_id.to_writer(__deku_writer, (#id_args))?;
}
}
Id::LitByteStr(v) => {
quote! {
let mut __deku_variant_id: #id_type = *#v;
__deku_variant_id.write(__deku_output, (#id_args))?;
__deku_variant_id.to_writer(__deku_writer, (#id_args))?;
}
}
}
Expand All @@ -215,7 +206,7 @@ fn emit_enum(input: &DekuData) -> Result<TokenStream, syn::Error> {
} else if has_discriminant {
quote! {
let mut __deku_variant_id: #id_type = Self::#variant_ident as #id_type;
__deku_variant_id.write(__deku_output, (#id_args))?;
__deku_variant_id.to_writer(__deku_writer, (#id_args))?;
}
} else {
return Err(syn::Error::new(
Expand Down Expand Up @@ -260,25 +251,8 @@ 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()) {
let to_bits_body = wrap_default_ctx(
quote! {
let mut __deku_acc: ::#crate_::bitvec::BitVec<u8, ::#crate_::bitvec::Msb0> = ::#crate_::bitvec::BitVec::new();
let __deku_output = &mut __deku_acc;

#magic_write

match self {
#(#variant_writes),*
}

Ok(__deku_acc)
},
&input.ctx,
&input.ctx_default,
);

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

fn try_from(input: #ident) -> core::result::Result<Self, Self::Error> {
Expand All @@ -296,13 +270,22 @@ fn emit_enum(input: &DekuData) -> Result<TokenStream, syn::Error> {

impl #imp DekuContainerWrite for #ident #wher {
fn to_bytes(&self) -> core::result::Result<Vec<u8>, ::#crate_::DekuError> {
let mut acc: ::#crate_::bitvec::BitVec<u8, ::#crate_::bitvec::Msb0> = self.to_bits()?;
Ok(acc.into_vec())
let mut out_buf = vec![];
let mut __deku_writer = ::#crate_::writer::Writer::new(&mut out_buf);
::#crate_::DekuWriter::to_writer(self, &mut __deku_writer, ())?;
__deku_writer.finalize()?;
Ok(out_buf)
}

#[allow(unused_variables)]
fn to_bits(&self) -> core::result::Result<::#crate_::bitvec::BitVec<u8, ::#crate_::bitvec::Msb0>, ::#crate_::DekuError> {
#to_bits_body
let mut out_buf = vec![];
let mut __deku_writer = ::#crate_::writer::Writer::new(&mut out_buf);
::#crate_::DekuWriter::to_writer(self, &mut __deku_writer, ())?;
let mut leftover = __deku_writer.leftover;
let mut bv = ::#crate_::bitvec::BitVec::from_slice(&out_buf);
bv.append(&mut leftover);
Ok(bv)
}
}
})
Expand Down Expand Up @@ -336,9 +319,9 @@ fn emit_enum(input: &DekuData) -> Result<TokenStream, syn::Error> {
}
}

impl #imp DekuWrite<#ctx_types> for #ident #wher {
impl #imp ::#crate_::DekuWriter<#ctx_types> for #ident #wher {
#[allow(unused_variables)]
fn write(&self, __deku_output: &mut ::#crate_::bitvec::BitVec<u8, ::#crate_::bitvec::Msb0>, #ctx_arg) -> core::result::Result<(), ::#crate_::DekuError> {
fn to_writer<W: ::#crate_::no_std_io::Write>(&self, __deku_writer: &mut ::#crate_::writer::Writer<W>, #ctx_arg) -> core::result::Result<(), ::#crate_::DekuError> {
#write_body
}
}
Expand All @@ -348,9 +331,9 @@ fn emit_enum(input: &DekuData) -> Result<TokenStream, syn::Error> {
let write_body = wrap_default_ctx(write_body, &input.ctx, &input.ctx_default);

tokens.extend(quote! {
impl #imp DekuWrite for #ident #wher {
impl #imp ::#crate_::DekuWriter for #ident #wher {
#[allow(unused_variables)]
fn write(&self, __deku_output: &mut ::#crate_::bitvec::BitVec<u8, ::#crate_::bitvec::Msb0>, _: ()) -> core::result::Result<(), ::#crate_::DekuError> {
fn to_writer<W: ::#crate_::no_std_io::Write>(&self, __deku_writer: &mut ::#crate_::writer::Writer<W>, _: ()) -> core::result::Result<(), ::#crate_::DekuError> {
#write_body
}
}
Expand All @@ -362,9 +345,10 @@ fn emit_enum(input: &DekuData) -> Result<TokenStream, syn::Error> {
}

fn emit_magic_write(input: &DekuData) -> TokenStream {
let crate_ = super::get_crate_name();
if let Some(magic) = &input.magic {
quote! {
#magic.write(__deku_output, ())?;
::#crate_::DekuWriter::to_writer(#magic, __deku_writer, ())?;
}
} else {
quote! {}
Expand Down Expand Up @@ -426,7 +410,7 @@ fn emit_bit_byte_offsets(
.any(|v| token_contains_string(v, "__deku_byte_offset"))
{
Some(quote! {
let __deku_byte_offset = __deku_bit_offset / 8;
let __deku_byte_offset = __deku_writer.bits_written / 8;
})
} else {
None
Expand All @@ -438,7 +422,7 @@ fn emit_bit_byte_offsets(
|| byte_offset.is_some()
{
Some(quote! {
let __deku_bit_offset = __deku_output.len();
let __deku_bit_offset = __deku_writer.bits_written;
})
} else {
None
Expand All @@ -458,8 +442,7 @@ fn emit_padding(bit_size: &TokenStream) -> TokenStream {
stringify!(#bit_size)
))
)?;
let new_len = __deku_output.len() + __deku_pad;
__deku_output.resize(new_len, false);
__deku_writer.write_bits(::#crate_::bitvec::bitvec![u8, ::#crate_::bitvec::Msb0; 0; __deku_pad].as_bitslice())?;
}
}
}
Expand Down Expand Up @@ -522,6 +505,14 @@ fn emit_field_write(
}
});

let trace_field_log = if cfg!(feature = "logging") {
quote! {
log::trace!("Writing: {}.{}", #ident, #field_ident_str);
}
} else {
quote! {}
};

let field_write_func = if field_writer.is_some() {
quote! { #field_writer }
} else {
Expand All @@ -537,13 +528,13 @@ fn emit_field_write(
let field_type = &f.ty;
quote! {
let #field_ident: #field_type = #temp_value;
::#crate_::DekuWrite::write(#object_prefix &#field_ident, __deku_output, (#write_args))
::#crate_::DekuWriter::to_writer(#object_prefix &#field_ident, __deku_writer, (#write_args))
}
} else {
quote! { core::result::Result::<(), ::#crate_::DekuError>::Ok(()) }
}
} else {
quote! { ::#crate_::DekuWrite::write(#object_prefix #field_ident, __deku_output, (#write_args)) }
quote! { ::#crate_::DekuWriter::to_writer(#object_prefix #field_ident, __deku_writer, (#write_args)) }
}
};

Expand Down Expand Up @@ -592,6 +583,7 @@ fn emit_field_write(
#bit_offset
#byte_offset

#trace_field_log
#field_assert
#field_assert_eq

Expand Down
12 changes: 7 additions & 5 deletions examples/custom_reader_and_writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ use std::convert::TryInto;

use deku::bitvec::{BitVec, Msb0};

Check warning on line 3 in examples/custom_reader_and_writer.rs

View workflow job for this annotation

GitHub Actions / Test Suite

unused imports: `BitVec`, `Msb0`

Check warning on line 3 in examples/custom_reader_and_writer.rs

View workflow job for this annotation

GitHub Actions / Test Suite

unused imports: `BitVec`, `Msb0`
use deku::ctx::BitSize;
use deku::prelude::*;
use deku::writer::Writer;
use deku::{prelude::*, DekuWriter};
use no_std_io::io::Write;

fn bit_flipper_read<R: std::io::Read>(
field_a: u8,
Expand All @@ -24,10 +26,10 @@ fn bit_flipper_read<R: std::io::Read>(
Ok(value)
}

fn bit_flipper_write(
fn bit_flipper_write<W: Write>(
field_a: u8,
field_b: u8,
output: &mut BitVec<u8, Msb0>,
writer: &mut Writer<W>,
bit_size: BitSize,
) -> Result<(), DekuError> {
// Access to previously written fields
Expand All @@ -42,7 +44,7 @@ fn bit_flipper_write(
// flip the bits on value if field_a is 0x01
let value = if field_a == 0x01 { !field_b } else { field_b };

value.write(output, bit_size)
value.to_writer(writer, bit_size)
}

#[derive(Debug, PartialEq, DekuRead, DekuWrite)]
Expand All @@ -51,7 +53,7 @@ struct DekuTest {

#[deku(
reader = "bit_flipper_read(*field_a, deku::reader, BitSize(8))",
writer = "bit_flipper_write(*field_a, *field_b, deku::output, BitSize(8))"
writer = "bit_flipper_write(*field_a, *field_b, deku::writer, BitSize(8))"
)]
field_b: u8,
}
Expand Down
6 changes: 3 additions & 3 deletions src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -803,7 +803,7 @@ use deku::prelude::*;
struct DekuTest {
#[deku(
reader = "DekuTest::read(deku::reader)",
writer = "DekuTest::write(deku::output, &self.field_a)"
writer = "DekuTest::write(deku::writer, &self.field_a)"
)]
field_a: String,
}
Expand All @@ -818,9 +818,9 @@ impl DekuTest {
}
/// Parse from String to u8 and write
fn write(output: &mut BitVec<u8, Msb0>, field_a: &str) -> Result<(), DekuError> {
fn write<W: std::io::Write>(writer: &mut Writer<W>, field_a: &str) -> Result<(), DekuError> {
let value = field_a.parse::<u8>().unwrap();
value.write(output, ())
value.to_writer(writer, ())
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ pub enum DekuError {
Assertion(String),
/// Could not resolve `id` for variant
IdVariantNotFound,
/// IO error while writing
Write,
}

impl From<core::num::TryFromIntError> for DekuError {
Expand Down Expand Up @@ -78,6 +80,7 @@ impl core::fmt::Display for DekuError {
DekuError::Unexpected(ref err) => write!(f, "Unexpected error: {err}"),
DekuError::Assertion(ref err) => write!(f, "Assertion error: {err}"),
DekuError::IdVariantNotFound => write!(f, "Could not resolve `id` for variant"),
DekuError::Write => write!(f, "write error"),
}
}
}
Expand All @@ -100,6 +103,7 @@ impl From<DekuError> for std::io::Error {
DekuError::Unexpected(_) => io::Error::new(io::ErrorKind::Other, error),
DekuError::Assertion(_) => io::Error::new(io::ErrorKind::InvalidData, error),
DekuError::IdVariantNotFound => io::Error::new(io::ErrorKind::NotFound, error),
DekuError::Write => io::Error::new(io::ErrorKind::BrokenPipe, error),
}
}
}
Loading

0 comments on commit 8a3596b

Please sign in to comment.