Skip to content

Commit 91bb702

Browse files
committed
Impl Write support
1 parent c0f9fd4 commit 91bb702

28 files changed

+648
-495
lines changed

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ alloc_counter = "0.0.4"
3939
trybuild = "1.0.77"
4040
rustc-hash = "1.1.0"
4141
env_logger = "0.10.0"
42+
assert_hex = "0.2.2"
4243

4344
[[bench]]
4445
name = "deku"

deku-derive/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -668,7 +668,7 @@ fn apply_replacements(input: &syn::LitStr) -> Result<Cow<'_, syn::LitStr>, Repla
668668

669669
let input_str = input_value
670670
.replace("deku::reader", "__deku_reader")
671-
.replace("deku::output", "__deku_output") // part of the public API `write`
671+
.replace("deku::writer", "__deku_writer")
672672
.replace("deku::bit_offset", "__deku_bit_offset")
673673
.replace("deku::byte_offset", "__deku_byte_offset");
674674

deku-derive/src/macros/deku_read.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -603,7 +603,7 @@ fn emit_field_read(
603603

604604
let trace_field_log = if cfg!(feature = "logging") {
605605
quote! {
606-
log::trace!("Reading: {}::{}", #ident, #field_ident_str);
606+
log::trace!("Reading: {}.{}", #ident, #field_ident_str);
607607
}
608608
} else {
609609
quote! {}

deku-derive/src/macros/deku_write.rs

+37-83
Original file line numberDiff line numberDiff line change
@@ -47,33 +47,7 @@ fn emit_struct(input: &DekuData) -> Result<TokenStream, syn::Error> {
4747

4848
// Implement `DekuContainerWrite` for types that don't need a context
4949
if input.ctx.is_none() || (input.ctx.is_some() && input.ctx_default.is_some()) {
50-
let to_bits_body = wrap_default_ctx(
51-
quote! {
52-
match *self {
53-
#destructured => {
54-
let mut __deku_acc: ::#crate_::bitvec::BitVec<u8, ::#crate_::bitvec::Msb0> = ::#crate_::bitvec::BitVec::new();
55-
let __deku_output = &mut __deku_acc;
56-
57-
#magic_write
58-
#(#field_writes)*
59-
60-
Ok(__deku_acc)
61-
}
62-
}
63-
},
64-
&input.ctx,
65-
&input.ctx_default,
66-
);
67-
6850
tokens.extend(quote! {
69-
impl #imp core::convert::TryFrom<#ident> for ::#crate_::bitvec::BitVec<u8, ::#crate_::bitvec::Msb0> #wher {
70-
type Error = ::#crate_::DekuError;
71-
72-
fn try_from(input: #ident) -> core::result::Result<Self, Self::Error> {
73-
input.to_bits()
74-
}
75-
}
76-
7751
impl #imp core::convert::TryFrom<#ident> for Vec<u8> #wher {
7852
type Error = ::#crate_::DekuError;
7953

@@ -84,13 +58,11 @@ fn emit_struct(input: &DekuData) -> Result<TokenStream, syn::Error> {
8458

8559
impl #imp DekuContainerWrite for #ident #wher {
8660
fn to_bytes(&self) -> core::result::Result<Vec<u8>, ::#crate_::DekuError> {
87-
let mut acc: ::#crate_::bitvec::BitVec<u8, ::#crate_::bitvec::Msb0> = self.to_bits()?;
88-
Ok(acc.into_vec())
89-
}
90-
91-
#[allow(unused_variables)]
92-
fn to_bits(&self) -> core::result::Result<::#crate_::bitvec::BitVec<u8, ::#crate_::bitvec::Msb0>, ::#crate_::DekuError> {
93-
#to_bits_body
61+
let mut out_buf = vec![];
62+
let mut __deku_writer = ::#crate_::writer::Writer::new(&mut out_buf);
63+
::#crate_::DekuWriter::to_writer(self, &mut __deku_writer, ())?;
64+
__deku_writer.finalize()?;
65+
Ok(out_buf)
9466
}
9567
}
9668
});
@@ -122,9 +94,9 @@ fn emit_struct(input: &DekuData) -> Result<TokenStream, syn::Error> {
12294
}
12395
}
12496

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

136108
tokens.extend(quote! {
137-
impl #imp DekuWrite for #ident #wher {
109+
impl #imp ::#crate_::DekuWriter for #ident #wher {
138110
#[allow(unused_variables)]
139-
fn write(&self, __deku_output: &mut ::#crate_::bitvec::BitVec<u8, ::#crate_::bitvec::Msb0>, _: ()) -> core::result::Result<(), ::#crate_::DekuError> {
111+
fn to_writer<W: ::#crate_::no_std_io::Write>(&self, __deku_writer: &mut ::#crate_::writer::Writer<W>, _: ()) -> core::result::Result<(), ::#crate_::DekuError> {
140112
#write_body
141113
}
142114
}
@@ -200,13 +172,13 @@ fn emit_enum(input: &DekuData) -> Result<TokenStream, syn::Error> {
200172
Id::TokenStream(v) => {
201173
quote! {
202174
let mut __deku_variant_id: #id_type = #v;
203-
__deku_variant_id.write(__deku_output, (#id_args))?;
175+
__deku_variant_id.to_writer(__deku_writer, (#id_args))?;
204176
}
205177
}
206178
Id::LitByteStr(v) => {
207179
quote! {
208180
let mut __deku_variant_id: #id_type = *#v;
209-
__deku_variant_id.write(__deku_output, (#id_args))?;
181+
__deku_variant_id.to_writer(__deku_writer, (#id_args))?;
210182
}
211183
}
212184
}
@@ -215,7 +187,7 @@ fn emit_enum(input: &DekuData) -> Result<TokenStream, syn::Error> {
215187
} else if has_discriminant {
216188
quote! {
217189
let mut __deku_variant_id: #id_type = Self::#variant_ident as #id_type;
218-
__deku_variant_id.write(__deku_output, (#id_args))?;
190+
__deku_variant_id.to_writer(__deku_writer, (#id_args))?;
219191
}
220192
} else {
221193
return Err(syn::Error::new(
@@ -260,32 +232,7 @@ fn emit_enum(input: &DekuData) -> Result<TokenStream, syn::Error> {
260232

261233
// Implement `DekuContainerWrite` for types that don't need a context
262234
if input.ctx.is_none() || (input.ctx.is_some() && input.ctx_default.is_some()) {
263-
let to_bits_body = wrap_default_ctx(
264-
quote! {
265-
let mut __deku_acc: ::#crate_::bitvec::BitVec<u8, ::#crate_::bitvec::Msb0> = ::#crate_::bitvec::BitVec::new();
266-
let __deku_output = &mut __deku_acc;
267-
268-
#magic_write
269-
270-
match self {
271-
#(#variant_writes),*
272-
}
273-
274-
Ok(__deku_acc)
275-
},
276-
&input.ctx,
277-
&input.ctx_default,
278-
);
279-
280235
tokens.extend(quote! {
281-
impl #imp core::convert::TryFrom<#ident> for ::#crate_::bitvec::BitVec<u8, ::#crate_::bitvec::Msb0> #wher {
282-
type Error = ::#crate_::DekuError;
283-
284-
fn try_from(input: #ident) -> core::result::Result<Self, Self::Error> {
285-
input.to_bits()
286-
}
287-
}
288-
289236
impl #imp core::convert::TryFrom<#ident> for Vec<u8> #wher {
290237
type Error = ::#crate_::DekuError;
291238

@@ -296,13 +243,11 @@ fn emit_enum(input: &DekuData) -> Result<TokenStream, syn::Error> {
296243

297244
impl #imp DekuContainerWrite for #ident #wher {
298245
fn to_bytes(&self) -> core::result::Result<Vec<u8>, ::#crate_::DekuError> {
299-
let mut acc: ::#crate_::bitvec::BitVec<u8, ::#crate_::bitvec::Msb0> = self.to_bits()?;
300-
Ok(acc.into_vec())
301-
}
302-
303-
#[allow(unused_variables)]
304-
fn to_bits(&self) -> core::result::Result<::#crate_::bitvec::BitVec<u8, ::#crate_::bitvec::Msb0>, ::#crate_::DekuError> {
305-
#to_bits_body
246+
let mut out_buf = vec![];
247+
let mut __deku_writer = ::#crate_::writer::Writer::new(&mut out_buf);
248+
::#crate_::DekuWriter::to_writer(self, &mut __deku_writer, ())?;
249+
__deku_writer.finalize()?;
250+
Ok(out_buf)
306251
}
307252
}
308253
})
@@ -336,9 +281,9 @@ fn emit_enum(input: &DekuData) -> Result<TokenStream, syn::Error> {
336281
}
337282
}
338283

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

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

364309
fn emit_magic_write(input: &DekuData) -> TokenStream {
310+
let crate_ = super::get_crate_name();
365311
if let Some(magic) = &input.magic {
366312
quote! {
367-
#magic.write(__deku_output, ())?;
313+
::#crate_::DekuWriter::to_writer(#magic, __deku_writer, ())?;
368314
}
369315
} else {
370316
quote! {}
@@ -426,7 +372,7 @@ fn emit_bit_byte_offsets(
426372
.any(|v| token_contains_string(v, "__deku_byte_offset"))
427373
{
428374
Some(quote! {
429-
let __deku_byte_offset = __deku_bit_offset / 8;
375+
let __deku_byte_offset = __deku_writer.bits_written / 8;
430376
})
431377
} else {
432378
None
@@ -438,7 +384,7 @@ fn emit_bit_byte_offsets(
438384
|| byte_offset.is_some()
439385
{
440386
Some(quote! {
441-
let __deku_bit_offset = __deku_output.len();
387+
let __deku_bit_offset = __deku_writer.bits_written;
442388
})
443389
} else {
444390
None
@@ -458,8 +404,7 @@ fn emit_padding(bit_size: &TokenStream) -> TokenStream {
458404
stringify!(#bit_size)
459405
))
460406
)?;
461-
let new_len = __deku_output.len() + __deku_pad;
462-
__deku_output.resize(new_len, false);
407+
__deku_writer.write_bits(::#crate_::bitvec::bitvec![u8, ::#crate_::bitvec::Msb0; 0; __deku_pad].as_bitslice())?;
463408
}
464409
}
465410
}
@@ -522,6 +467,14 @@ fn emit_field_write(
522467
}
523468
});
524469

470+
let trace_field_log = if cfg!(feature = "logging") {
471+
quote! {
472+
log::trace!("Writing: {}.{}", #ident, #field_ident_str);
473+
}
474+
} else {
475+
quote! {}
476+
};
477+
525478
let field_write_func = if field_writer.is_some() {
526479
quote! { #field_writer }
527480
} else {
@@ -537,13 +490,13 @@ fn emit_field_write(
537490
let field_type = &f.ty;
538491
quote! {
539492
let #field_ident: #field_type = #temp_value;
540-
::#crate_::DekuWrite::write(#object_prefix &#field_ident, __deku_output, (#write_args))
493+
::#crate_::DekuWriter::to_writer(#object_prefix &#field_ident, __deku_writer, (#write_args))
541494
}
542495
} else {
543496
quote! { core::result::Result::<(), ::#crate_::DekuError>::Ok(()) }
544497
}
545498
} else {
546-
quote! { ::#crate_::DekuWrite::write(#object_prefix #field_ident, __deku_output, (#write_args)) }
499+
quote! { ::#crate_::DekuWriter::to_writer(#object_prefix #field_ident, __deku_writer, (#write_args)) }
547500
}
548501
};
549502

@@ -592,6 +545,7 @@ fn emit_field_write(
592545
#bit_offset
593546
#byte_offset
594547

548+
#trace_field_log
595549
#field_assert
596550
#field_assert_eq
597551

examples/custom_reader_and_writer.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ use std::convert::TryInto;
22

33
use deku::bitvec::{BitVec, Msb0};
44
use deku::ctx::BitSize;
5-
use deku::prelude::*;
5+
use deku::writer::Writer;
6+
use deku::{prelude::*, DekuWriter};
7+
use no_std_io::io::Write;
68

79
fn bit_flipper_read<R: std::io::Read>(
810
field_a: u8,
@@ -24,10 +26,10 @@ fn bit_flipper_read<R: std::io::Read>(
2426
Ok(value)
2527
}
2628

27-
fn bit_flipper_write(
29+
fn bit_flipper_write<W: Write>(
2830
field_a: u8,
2931
field_b: u8,
30-
output: &mut BitVec<u8, Msb0>,
32+
writer: &mut Writer<W>,
3133
bit_size: BitSize,
3234
) -> Result<(), DekuError> {
3335
// Access to previously written fields
@@ -42,7 +44,7 @@ fn bit_flipper_write(
4244
// flip the bits on value if field_a is 0x01
4345
let value = if field_a == 0x01 { !field_b } else { field_b };
4446

45-
value.write(output, bit_size)
47+
value.to_writer(writer, bit_size)
4648
}
4749

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

5254
#[deku(
5355
reader = "bit_flipper_read(*field_a, deku::reader, BitSize(8))",
54-
writer = "bit_flipper_write(*field_a, *field_b, deku::output, BitSize(8))"
56+
writer = "bit_flipper_write(*field_a, *field_b, deku::writer, BitSize(8))"
5557
)]
5658
field_b: u8,
5759
}

src/attributes.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -803,7 +803,7 @@ use deku::prelude::*;
803803
struct DekuTest {
804804
#[deku(
805805
reader = "DekuTest::read(deku::reader)",
806-
writer = "DekuTest::write(deku::output, &self.field_a)"
806+
writer = "DekuTest::write(deku::writer, &self.field_a)"
807807
)]
808808
field_a: String,
809809
}
@@ -818,9 +818,9 @@ impl DekuTest {
818818
}
819819
820820
/// Parse from String to u8 and write
821-
fn write(output: &mut BitVec<u8, Msb0>, field_a: &str) -> Result<(), DekuError> {
821+
fn write<W: std::io::Write>(writer: &mut Writer<W>, field_a: &str) -> Result<(), DekuError> {
822822
let value = field_a.parse::<u8>().unwrap();
823-
value.write(output, ())
823+
value.to_writer(writer, ())
824824
}
825825
}
826826

src/error.rs

+4
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ pub enum DekuError {
4444
Assertion(String),
4545
/// Could not resolve `id` for variant
4646
IdVariantNotFound,
47+
/// IO error while writing
48+
WriteError,
4749
}
4850

4951
impl From<core::num::TryFromIntError> for DekuError {
@@ -78,6 +80,7 @@ impl core::fmt::Display for DekuError {
7880
DekuError::Unexpected(ref err) => write!(f, "Unexpected error: {err}"),
7981
DekuError::Assertion(ref err) => write!(f, "Assertion error: {err}"),
8082
DekuError::IdVariantNotFound => write!(f, "Could not resolve `id` for variant"),
83+
DekuError::WriteError => write!(f, "write error"),
8184
}
8285
}
8386
}
@@ -100,6 +103,7 @@ impl From<DekuError> for std::io::Error {
100103
DekuError::Unexpected(_) => io::Error::new(io::ErrorKind::Other, error),
101104
DekuError::Assertion(_) => io::Error::new(io::ErrorKind::InvalidData, error),
102105
DekuError::IdVariantNotFound => io::Error::new(io::ErrorKind::NotFound, error),
106+
DekuError::WriteError => io::Error::new(io::ErrorKind::BrokenPipe, error),
103107
}
104108
}
105109
}

0 commit comments

Comments
 (0)