deku/lib.rs
1/*!
2
3# Deku: Declarative binary reading and writing
4
5Deriving a struct or enum with `DekuRead` and `DekuWrite` provides bit-level,
6symmetric, serialization/deserialization implementations.
7
8This allows the developer to focus on building and maintaining how the data is
9represented and manipulated and not on redundant, error-prone, parsing/writing code.
10This approach is especially useful when dealing with binary structures such as
11TLVs or network protocols. This allows the internal rustc compiler to choose
12the in-memory representation of the struct, while reading and writing can
13understand the struct in a "packed" C way.
14
15Under the hood, many specializations are done in order to achieve performant code.
16For reading and writing bytes, the std library is used.
17When bit-level control is required, it makes use of the [bitvec](https://crates.io/crates/bitvec)
18crate as the "Reader" and “Writer”.
19
20For documentation and examples on available `#[deku]` attributes and features,
21see [attributes list](attributes)
22
23For more examples, see the
24[examples folder](https://github.com/sharksforarms/deku/tree/master/examples)!
25
26## no_std
27
28For use in `no_std` environments, `alloc` is the single feature which is required on deku.
29
30# Example
31
32Let's read big-endian data into a struct, with fields containing different sizes,
33modify a value, and write it back. In this example we use [from_bytes](DekuContainerRead::from_bytes),
34but we could also use [from_reader](DekuContainerRead::from_reader).
35```rust
36use deku::prelude::*;
37
38# #[cfg(all(feature = "alloc", feature = "bits"))]
39#[derive(Debug, PartialEq, DekuRead, DekuWrite)]
40#[deku(endian = "big")]
41struct DekuTest {
42 #[deku(bits = 4)]
43 field_a: u8,
44 #[deku(bits = 4)]
45 field_b: u8,
46 field_c: u16,
47}
48
49# #[cfg(all(feature = "alloc", feature = "bits"))]
50# fn main() {
51let data: Vec<u8> = vec![0b0110_1001, 0xBE, 0xEF];
52let (_rest, mut val) = DekuTest::from_bytes((data.as_ref(), 0)).unwrap();
53assert_eq!(DekuTest {
54 field_a: 0b0110,
55 field_b: 0b1001,
56 field_c: 0xBEEF,
57}, val);
58
59val.field_c = 0xC0FE;
60
61let data_out = val.to_bytes().unwrap();
62assert_eq!(vec![0b0110_1001, 0xC0, 0xFE], data_out);
63# }
64#
65# #[cfg(not(all(feature = "alloc", feature = "bits")))]
66# fn main() {}
67```
68
69# Composing
70
71Deku structs/enums can be composed as long as they implement [DekuReader] / [DekuWrite] traits which
72can be derived by using the `DekuRead` and `DekuWrite` Derive macros.
73
74```rust
75# #[cfg(feature = "std")]
76# use std::io::Cursor;
77use deku::prelude::*;
78
79#[derive(Debug, PartialEq, DekuRead, DekuWrite)]
80#[deku(endian = "big")]
81struct DekuTest {
82 header: DekuHeader,
83 data: DekuData,
84}
85
86#[derive(Debug, PartialEq, DekuRead, DekuWrite)]
87#[deku(ctx = "endian: deku::ctx::Endian")] // context passed from `DekuTest` top-level endian
88struct DekuHeader(u8);
89
90#[derive(Debug, PartialEq, DekuRead, DekuWrite)]
91#[deku(ctx = "endian: deku::ctx::Endian")] // context passed from `DekuTest` top-level endian
92struct DekuData(u16);
93
94# #[cfg(feature = "std")]
95# fn main() {
96let data: Vec<u8> = vec![0xAA, 0xEF, 0xBE];
97let (_rest, mut val) = DekuTest::from_bytes((data.as_ref(), 0)).unwrap();
98assert_eq!(DekuTest {
99 header: DekuHeader(0xAA),
100 data: DekuData(0xBEEF),
101}, val);
102
103let data_out = val.to_bytes().unwrap();
104assert_eq!(data, data_out);
105# }
106#
107# #[cfg(not(feature = "std"))]
108# fn main() {}
109```
110
111Note that because we explicitly specify the endian on the top-level struct, we must pass the endian to all children via the context. Several attributes trigger this requirement, such as [endian](attributes#endian), [bit_order](attributes#bit_order), and [bits](attributes#bits). If you are getting errors of the format `mismatched types, expected A, found B` on the `DekuRead` and/or `DekuWrite` `#[derive]` attribute, then you need to update the [ctx](attributes#ctx).
112
113# Vec
114
115Vec<T> can be used in combination with the [count](attributes#count)
116attribute (T must implement DekuRead/DekuWrite)
117
118[bytes_read](attributes#bytes_read) or [bits_read](attributes#bits_read)
119can also be used instead of `count` to read a specific size of each.
120
121
122If the length of Vec changes, the original field specified in `count` will not get updated.
123Calling `.update()` can be used to "update" the field!
124
125```rust
126# #[cfg(feature = "std")]
127# use std::io::Cursor;
128use deku::prelude::*;
129
130# #[cfg(feature = "alloc")]
131#[derive(Debug, PartialEq, DekuRead, DekuWrite)]
132struct DekuTest {
133 #[deku(update = "self.data.len()")]
134 count: u8,
135 #[deku(count = "count")]
136 data: Vec<u8>,
137}
138
139# #[cfg(all(feature = "alloc", feature = "std"))]
140# fn main() {
141let data: Vec<u8> = vec![0x02, 0xBE, 0xEF, 0xFF, 0xFF];
142let (_rest, mut val) = DekuTest::from_bytes((data.as_ref(), 0)).unwrap();
143assert_eq!(DekuTest {
144 count: 0x02,
145 data: vec![0xBE, 0xEF]
146}, val);
147
148let data_out = val.to_bytes().unwrap();
149assert_eq!(vec![0x02, 0xBE, 0xEF], data_out);
150
151// Pushing an element to data
152val.data.push(0xAA);
153
154assert_eq!(DekuTest {
155 count: 0x02, // Note: this value has not changed
156 data: vec![0xBE, 0xEF, 0xAA]
157}, val);
158
159let data_out = val.to_bytes().unwrap();
160// Note: `count` is still 0x02 while 3 bytes got written
161assert_eq!(vec![0x02, 0xBE, 0xEF, 0xAA], data_out);
162
163// Use `update` to update `count`
164val.update().unwrap();
165
166assert_eq!(DekuTest {
167 count: 0x03,
168 data: vec![0xBE, 0xEF, 0xAA]
169}, val);
170# }
171#
172# #[cfg(not(all(feature = "alloc", feature = "std")))]
173# fn main() {}
174```
175
176# Enums
177
178As enums can have multiple variants, each variant must have a way to match on
179the incoming data.
180
181First the "type" is read using `id_type`, then is matched against the
182variants given `id`. What happens after is the same as structs!
183
184This is implemented with the [id](attributes#id),
185[id_pat](attributes#id_pat), [default](attributes#default) and
186[id_type](attributes#id_type) attributes. See these for more examples.
187
188If no `id` is specified, the variant will default to it's discriminant value.
189
190If no variant can be matched and the `default` is not provided, a [DekuError::Parse](crate::error::DekuError)
191error will be returned.
192
193If no variant can be matched and the `default` is provided, a variant will be returned
194based on the field marked with `default`.
195
196Example:
197
198```rust
199# #[cfg(feature = "std")]
200# use std::io::Cursor;
201use deku::prelude::*;
202
203#[derive(Debug, PartialEq, DekuRead, DekuWrite)]
204#[deku(id_type = "u8")]
205enum DekuTest {
206 #[deku(id = 0x01)]
207 VariantA,
208 #[deku(id = 0x02)]
209 VariantB(u16),
210}
211
212# #[cfg(feature = "std")]
213# fn main() {
214let data: &[u8] = &[0x01, 0x02, 0xEF, 0xBE];
215let mut cursor = Cursor::new(data);
216
217let (_, val) = DekuTest::from_reader((&mut cursor, 0)).unwrap();
218assert_eq!(DekuTest::VariantA , val);
219
220// cursor now points at 0x02
221let (_, val) = DekuTest::from_reader((&mut cursor, 0)).unwrap();
222assert_eq!(DekuTest::VariantB(0xBEEF) , val);
223# }
224#
225# #[cfg(not(feature = "std"))]
226# fn main() {}
227```
228
229Of course, trivial c-style enums works just as well too:
230
231```rust
232# #[cfg(feature = "bits")]
233# use deku::prelude::*;
234# #[cfg(feature = "bits")]
235# use deku::no_std_io::Cursor;
236
237# #[cfg(feature = "bits")]
238#[derive(Debug, PartialEq, DekuRead, DekuWrite)]
239#[deku(id_type = "u8", bits = 2, bit_order = "lsb")]
240#[repr(u8)]
241pub enum DekuTest {
242 VariantA = 0,
243 VariantB = 1,
244 VariantC = 2,
245 VariantD = 3
246}
247
248# #[cfg(feature = "bits")]
249# fn main() {
250let data: &[u8] = &[0x0D]; // 00 00 11 01 => A A D B
251let mut cursor = Cursor::new(data);
252let mut reader = Reader::new(&mut cursor);
253
254let val = DekuTest::from_reader_with_ctx(&mut reader, ()).unwrap();
255assert_eq!(DekuTest::VariantB , val);
256
257let val = DekuTest::from_reader_with_ctx(&mut reader, ()).unwrap();
258assert_eq!(DekuTest::VariantD , val);
259
260let val = DekuTest::from_reader_with_ctx(&mut reader, ()).unwrap();
261assert_eq!(DekuTest::VariantA , val);
262# }
263#
264# #[cfg(not(feature = "bits"))]
265# fn main() {}
266```
267
268# Context
269
270Child parsers can get access to the parent's parsed values using the `ctx` attribute
271
272For more information see [ctx attribute](attributes#ctx)
273
274Example:
275
276```rust
277# #[cfg(feature = "std")]
278# use std::io::Cursor;
279use deku::prelude::*;
280
281#[derive(DekuRead, DekuWrite)]
282#[deku(ctx = "a: u8")]
283struct Subtype {
284 #[deku(map = "|b: u8| -> Result<_, DekuError> { Ok(b + a) }")]
285 b: u8
286}
287
288#[derive(DekuRead, DekuWrite)]
289struct Root {
290 a: u8,
291 #[deku(ctx = "*a")] // `a` is a reference
292 sub: Subtype
293}
294
295# #[cfg(feature = "std")]
296# fn main() {
297let data: &[u8] = &[0x01, 0x02];
298let mut cursor = Cursor::new(data);
299
300let (amt_read, value) = Root::from_reader((&mut cursor, 0)).unwrap();
301assert_eq!(value.a, 0x01);
302assert_eq!(value.sub.b, 0x01 + 0x02)
303# }
304#
305# #[cfg(not(feature = "std"))]
306# fn main() {}
307```
308
309# `Read` supported
310Parsers can be created that directly read from a source implementing [Read](crate::no_std_io::Read).
311
312The crate [no_std_io2](https://crates.io/crates/no-std-io2) is re-exported as [no_std_io] for use in `no_std` environments.
313This functions as an alias for [std::io](https://doc.rust-lang.org/stable/std/io/) when not
314using `no_std`.
315
316```rust, no_run
317# #[cfg(feature = "std")]
318# use std::io::{Seek, SeekFrom, Read};
319# #[cfg(feature = "std")]
320# use std::fs::File;
321# use deku::prelude::*;
322#[derive(Debug, DekuRead, DekuWrite, PartialEq, Eq, Clone)]
323#[deku(endian = "big")]
324struct EcHdr {
325 magic: [u8; 4],
326 version: u8,
327 padding1: [u8; 3],
328}
329
330# #[cfg(feature = "std")]
331# fn main() {
332let mut file = File::options().read(true).open("file").unwrap();
333let ec = EcHdr::from_reader((&mut file, 0)).unwrap();
334# }
335#
336# #[cfg(not(feature = "std"))]
337# fn main() {}
338```
339
340# `Write` supported
341Parsers can be created that directly write to a source implementing [Write](crate::no_std_io::Write).
342
343```rust, no_run
344# #[cfg(feature = "std")]
345# use std::io::{Seek, SeekFrom, Read};
346# #[cfg(feature = "std")]
347# use std::fs::File;
348# use deku::prelude::*;
349#[derive(Debug, DekuRead, DekuWrite, PartialEq, Eq, Clone)]
350#[deku(endian = "big")]
351struct Hdr {
352 version: u8,
353}
354
355# #[cfg(feature = "std")]
356# fn main() {
357let hdr = Hdr { version: 0xf0 };
358let mut file = File::options().write(true).open("file").unwrap();
359hdr.to_writer(&mut Writer::new(file), ());
360# }
361#
362# #[cfg(not(feature = "std"))]
363# fn main() {}
364```
365
366# DekuSize
367
368For types with a known, fixed size at compile-time, the `DekuSize` trait provides
369constant `SIZE_BITS` and `SIZE_BYTES` values. This is useful for creating correctly sized
370buffers in embedded or no_std,no_alloc environments where dynamic allocation is not available.
371
372```rust
373use deku::prelude::*;
374
375#[derive(DekuRead, DekuWrite, DekuSize)]
376#[deku(endian = "big")]
377struct Message {
378 msg_type: u8,
379 payload: [u8; 16],
380 checksum: u16,
381}
382
383assert_eq!(Message::SIZE_BYTES, Some(19));
384
385const BUFFER_SIZE: usize = Message::SIZE_BYTES.unwrap();
386let mut buffer = [0u8; BUFFER_SIZE];
387
388let msg = Message {
389 msg_type: 0x01,
390 payload: [0xFF; 16],
391 checksum: 0xABCD,
392};
393
394let written = msg.to_slice(&mut buffer).unwrap();
395assert_eq!(written, BUFFER_SIZE);
396```
397
398For enums, `SIZE_BITS` represents the discriminant plus the maximum variant size:
399
400```rust
401use deku::prelude::*;
402
403#[derive(DekuRead, DekuWrite, DekuSize)]
404#[deku(id_type = "u8")]
405enum Packet {
406 #[deku(id = "1")]
407 Small { data: u16 },
408 #[deku(id = "2")]
409 Large { data: u64 },
410}
411
412assert_eq!(Packet::SIZE_BYTES, Some(9));
413
414const MAX_SIZE: usize = Packet::SIZE_BYTES.unwrap();
415let mut buffer = [0u8; MAX_SIZE];
416```
417
418Note: Variable-size types like `Vec` do not implement `DekuSize` as their size
419cannot be known at compile-time.
420
421# Internal variables and previously read fields
422
423Along similar lines to [Context](#context) variables, previously read variables
424are exposed and can be referenced:
425
426Example:
427
428```rust
429# use deku::prelude::*;
430# #[cfg(feature = "alloc")]
431#[derive(DekuRead)]
432struct DekuTest {
433 num_items: u8,
434 #[deku(count = "num_items")]
435 items: Vec<u16>,
436}
437```
438
439The following variables are internals which can be used in attributes accepting
440tokens such as `reader`, `writer`, `map`, `count`, etc.
441
442These are provided as a convenience to the user.
443
444Always included:
445- `deku::reader: &mut Reader` - Current [Reader]
446- `deku::writer: &mut Writer` - Current [Writer]
447
448Conditionally included if referenced:
449- `deku::bit_offset: usize` - Current bit offset from the input
450- `deku::byte_offset: usize` - Current byte offset from the input
451
452Example:
453```rust
454# use deku::prelude::*;
455# #[cfg(feature = "alloc")]
456#[derive(DekuRead)]
457#[deku(ctx = "size: u32")]
458pub struct EncodedString {
459 encoding: u8,
460
461 #[deku(count = "size as usize - deku::byte_offset")]
462 data: Vec<u8>
463}
464```
465
466# Debugging decoders with the `logging` feature.
467
468If you are having trouble understanding what causes a Deku parse error, you may find the `logging`
469feature useful.
470
471To use it, you will need to:
472 - enable the `logging` Cargo feature for your Deku dependency
473 - import the `log` crate and a compatible logging library
474
475For example, to log with `env_logger`, the dependencies in your `Cargo.toml` might look like:
476
477```text
478deku = { version = "*", features = ["logging"] }
479log = "*"
480env_logger = "*"
481```
482
483Then you'd call `env_logger::init()` or `env_logger::try_init()` prior to doing Deku decoding.
484
485Deku uses the `trace` logging level, so if you run your application with `RUST_LOG=trace` in your
486environment, you will see logging messages as Deku does its deserialising.
487
488# Reducing parser code size
489
490- With the use of the `no-assert-string` feature, you can remove the strings Deku adds to assertion errors.
491- `DekuError` whenever possible will use a `'static str`, to make the errors compile away when following a
492 guide such as [min-sized-rust](https://github.com/johnthagen/min-sized-rust).
493
494# Performance: Compile without `bitvec`
495The feature `bits` enables the `bitvec` crate to use when reading and writing, which is enabled by default.
496This however slows down the reading and writing process if your code doesn't use `bits` and the `bit_offset`
497in `from_bytes`.
498
499# NoSeek
500Unseekable streams such as [TcpStream](https://doc.rust-lang.org/std/net/struct.TcpStream.html) are supported through the [NoSeek](noseek::NoSeek) wrapper.
501
502*/
503#![warn(missing_docs)]
504#![cfg_attr(not(feature = "std"), no_std)]
505#![allow(clippy::unusual_byte_groupings)]
506
507#[cfg(feature = "alloc")]
508extern crate alloc;
509
510#[cfg(feature = "alloc")]
511use alloc::vec::Vec;
512
513/// re-export of [no_std_io2](https://crates.io/crates/no-std-io2)
514pub mod no_std_io {
515 pub use no_std_io::io::Cursor;
516 pub use no_std_io::io::Error;
517 pub use no_std_io::io::ErrorKind;
518 pub use no_std_io::io::Read;
519 pub use no_std_io::io::Result;
520 pub use no_std_io::io::Seek;
521 pub use no_std_io::io::SeekFrom;
522 pub use no_std_io::io::Write;
523}
524
525/// re-export of bitvec
526#[cfg(feature = "bits")]
527pub mod bitvec {
528 pub use bitvec::field::BitField;
529 pub use bitvec::prelude::*;
530 pub use bitvec::view::BitView;
531}
532
533#[cfg(feature = "bits")]
534use ::bitvec::array::BitArray;
535#[cfg(feature = "bits")]
536use ::bitvec::order::BitOrder;
537#[cfg(feature = "bits")]
538use ::bitvec::slice::BitSlice;
539#[cfg(feature = "bits")]
540use ::bitvec::store::BitStore;
541#[cfg(feature = "bits")]
542use ::bitvec::view::BitViewSized;
543
544pub use deku_derive::*;
545
546pub mod attributes;
547pub mod ctx;
548pub mod error;
549
550#[macro_use]
551mod impls;
552pub mod noseek;
553pub mod prelude;
554pub mod reader;
555pub mod writer;
556
557pub use crate::error::DekuError;
558use crate::reader::Reader;
559use crate::writer::Writer;
560
561/// "Reader" trait: read bytes and bits from [`no_std_io::Read`]er
562#[rustversion::attr(
563 since(1.78),
564 diagnostic::on_unimplemented(
565 note = "implement by adding #[derive(DekuRead)] to `{Self}`",
566 note = "make sure the `ctx` sent into the function matches `{Self}`'s `ctx`",
567 )
568)]
569pub trait DekuReader<'a, Ctx = ()> {
570 /// Construct type from `reader` implementing [`no_std_io::Read`], with ctx.
571 ///
572 /// # Example
573 /// ```rust, no_run
574 /// # #[cfg(feature = "std")]
575 /// # use std::io::{Seek, SeekFrom, Read};
576 /// # #[cfg(feature = "std")]
577 /// # use std::fs::File;
578 /// # use deku::prelude::*;
579 /// # use deku::ctx::Endian;
580 /// #[derive(Debug, DekuRead, DekuWrite, PartialEq, Eq, Clone)]
581 /// #[deku(endian = "ctx_endian", ctx = "ctx_endian: Endian")]
582 /// struct EcHdr {
583 /// magic: [u8; 4],
584 /// version: u8,
585 /// }
586 ///
587 /// # #[cfg(feature = "std")]
588 /// # fn main() {
589 /// let mut file = File::options().read(true).open("file").unwrap();
590 /// file.seek(SeekFrom::Start(0)).unwrap();
591 /// let mut reader = Reader::new(&mut file);
592 /// let ec = EcHdr::from_reader_with_ctx(&mut reader, Endian::Big).unwrap();
593 /// # }
594 /// #
595 /// # #[cfg(not(feature = "std"))]
596 /// fn main() {}
597 /// ```
598 fn from_reader_with_ctx<R: no_std_io::Read + no_std_io::Seek>(
599 reader: &mut Reader<R>,
600 ctx: Ctx,
601 ) -> Result<Self, DekuError>
602 where
603 Self: Sized;
604}
605
606/// "Reader" trait: implemented on DekuRead struct and enum containers. A `container` is a type which
607/// doesn't need any context information.
608#[rustversion::attr(
609 since(1.78),
610 diagnostic::on_unimplemented(
611 note = "implement by adding #[derive(DekuRead)] to `{Self}`",
612 note = "make sure the `ctx` sent into the function matches `{Self}`'s `ctx`",
613 )
614)]
615pub trait DekuContainerRead<'a>: DekuReader<'a, ()> {
616 /// Construct type from Reader implementing [`no_std_io::Read`].
617 /// * **input** - Input given as "Reader" and bit offset
618 ///
619 /// # Returns
620 /// (amount of total bits read, Self)
621 ///
622 /// [BufRead]: std::io::BufRead
623 ///
624 /// # Example
625 /// ```rust, no_run
626 /// # #[cfg(feature = "std")]
627 /// # use std::io::{Seek, SeekFrom, Read};
628 /// # #[cfg(feature = "std")]
629 /// # use std::fs::File;
630 /// # use deku::prelude::*;
631 /// #[derive(Debug, DekuRead, DekuWrite, PartialEq, Eq, Clone)]
632 /// #[deku(endian = "big")]
633 /// struct EcHdr {
634 /// magic: [u8; 4],
635 /// version: u8,
636 /// }
637 ///
638 /// # #[cfg(feature = "std")]
639 /// # fn main() {
640 /// let mut file = File::options().read(true).open("file").unwrap();
641 /// file.seek(SeekFrom::Start(0)).unwrap();
642 /// let ec = EcHdr::from_reader((&mut file, 0)).unwrap();
643 /// # }
644 /// #
645 /// # #[cfg(not(feature = "std"))]
646 /// # fn main() {}
647 /// ```
648 fn from_reader<R: no_std_io::Read + no_std_io::Seek>(
649 input: (&'a mut R, usize),
650 ) -> Result<(usize, Self), DekuError>
651 where
652 Self: Sized;
653
654 /// Read bytes and construct type
655 /// * **input** - Input given as data and bit offset
656 ///
657 /// Returns the remaining bytes and bit offset after parsing in addition to Self.
658 fn from_bytes(input: (&'a [u8], usize)) -> Result<((&'a [u8], usize), Self), DekuError>
659 where
660 Self: Sized;
661}
662
663/// "Writer" trait: write from type to bytes
664#[rustversion::attr(
665 since(1.78),
666 diagnostic::on_unimplemented(
667 note = "implement by adding #[derive(DekuRead)] to `{Self}`",
668 note = "make sure the `ctx` sent into the function matches `{Self}`'s `ctx`",
669 )
670)]
671pub trait DekuWriter<Ctx = ()> {
672 /// Write type to bytes
673 fn to_writer<W: no_std_io::Write + no_std_io::Seek>(
674 &self,
675 writer: &mut Writer<W>,
676 ctx: Ctx,
677 ) -> Result<(), DekuError>;
678}
679
680/// "Writer" trait: implemented on DekuWrite struct and enum containers. A `container` is a type which
681/// doesn't need any context information.
682#[rustversion::attr(
683 since(1.78),
684 diagnostic::on_unimplemented(
685 note = "implement by adding #[derive(DekuWrite)] to `{Self}`",
686 note = "make sure the `ctx` sent into the function matches `{Self}`'s `ctx`",
687 )
688)]
689pub trait DekuContainerWrite: DekuWriter<()> {
690 /// Write struct/enum to Vec<u8>
691 ///
692 /// ```rust
693 /// # use deku::prelude::*;
694 /// #[derive(Debug, PartialEq, DekuRead, DekuWrite)]
695 /// #[deku(endian = "little")]
696 /// struct S {
697 /// data_00: u8,
698 /// data_01: u16,
699 /// data_02: u32,
700 /// }
701 ///
702 /// let s = S { data_00: 0x01, data_01: 0x02, data_02: 0x03 };
703 /// let bytes = s.to_bytes().unwrap();
704 /// assert_eq!(bytes, [0x01, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00]);
705 /// ````
706 #[cfg(feature = "alloc")]
707 #[inline(always)]
708 fn to_bytes(&self) -> Result<Vec<u8>, DekuError> {
709 let mut out_buf = Vec::new();
710 let mut cursor = no_std_io::Cursor::new(&mut out_buf);
711 let mut __deku_writer = Writer::new(&mut cursor);
712 DekuWriter::to_writer(self, &mut __deku_writer, ())?;
713 __deku_writer.finalize()?;
714 Ok(out_buf)
715 }
716
717 /// Write struct/enum to a given slice
718 ///
719 /// ```rust
720 /// # use deku::prelude::*;
721 /// #[derive(Debug, PartialEq, DekuRead, DekuWrite)]
722 /// #[deku(endian = "little")]
723 /// struct S {
724 /// data_00: u8,
725 /// data_01: u16,
726 /// data_02: u32,
727 /// }
728 ///
729 /// let mut buf = [0; 7];
730 /// let s = S { data_00: 0x01, data_01: 0x02, data_02: 0x03 };
731 /// let amt_written = s.to_slice(&mut buf).unwrap();
732 /// assert_eq!(buf, [0x01, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00]);
733 /// assert_eq!(amt_written, 7)
734 /// ````
735 #[inline(always)]
736 fn to_slice(&self, buf: &mut [u8]) -> Result<usize, DekuError> {
737 let mut cursor = no_std_io::Cursor::new(buf);
738 let mut writer = Writer::new(&mut cursor);
739 DekuWriter::to_writer(self, &mut writer, ())?;
740 writer.finalize()?;
741
742 Ok(writer.bits_written / 8)
743 }
744
745 /// Write struct/enum to BitVec
746 ///
747 /// ```rust
748 /// # use deku::prelude::*;
749 /// # use deku::bitvec::Lsb0;
750 /// #[derive(PartialEq, Debug, DekuRead, DekuWrite)]
751 /// #[deku(endian = "little")]
752 /// pub struct TestOver {
753 /// #[deku(bits = "4")]
754 /// pub a: u8,
755 /// #[deku(bits = "4")]
756 /// pub b: u8,
757 /// #[deku(bits = "1")]
758 /// pub c: u8,
759 /// }
760 ///
761 /// let test_data: &[u8] = &[0xf1, 0x80];
762 /// let test = TestOver::from_bytes((test_data, 0)).unwrap().1;
763 /// let bits = test.to_bits().unwrap();
764 /// assert_eq!(deku::bitvec::bitvec![1, 1, 1, 1, 0, 0, 0, 1, 1], bits);
765 /// ```
766 #[inline(always)]
767 #[cfg(all(feature = "bits", feature = "alloc"))]
768 fn to_bits(&self) -> Result<bitvec::BitVec<u8, bitvec::Msb0>, DekuError> {
769 let mut out_buf = Vec::new();
770 let mut cursor = no_std_io::Cursor::new(&mut out_buf);
771 let mut __deku_writer = Writer::new(&mut cursor);
772 DekuWriter::to_writer(self, &mut __deku_writer, ())?;
773 let leftover = __deku_writer.leftover;
774 let mut bv = bitvec::BitVec::from_slice(&out_buf);
775 bv.extend_from_bitslice(leftover.0.as_bitslice());
776 Ok(bv)
777 }
778}
779
780/// "Updater" trait: apply mutations to a type
781pub trait DekuUpdate {
782 /// Apply updates
783 fn update(&mut self) -> Result<(), DekuError>;
784}
785
786/// "Extended Enum" trait: obtain additional enum information
787pub trait DekuEnumExt<'__deku, T> {
788 /// Obtain `id` of a given enum variant
789 fn deku_id(&self) -> Result<T, DekuError>;
790}
791
792/// Trait for types with a known, fixed binary size at compile-time
793///
794/// Only implemented for fixed-size types (primitives, arrays, structs/enums composed
795/// entirely of fixed-size fields). Variable-size types like `Vec` do not implement this.
796///
797/// ```rust
798/// use deku::prelude::*;
799///
800/// #[derive(DekuRead, DekuWrite, DekuSize)]
801/// struct Packet {
802/// header: u8,
803/// value: u32,
804/// }
805///
806/// const SIZE: usize = Packet::SIZE_BYTES.unwrap();
807/// let mut buffer = [0u8; SIZE];
808/// ```
809pub trait DekuSize {
810 /// Size in bits when serialized
811 const SIZE_BITS: usize;
812
813 /// Size in bytes if byte-aligned, `None` otherwise
814 const SIZE_BYTES: Option<usize> = if Self::SIZE_BITS % 8 == 0 {
815 Some(Self::SIZE_BITS / 8)
816 } else {
817 None
818 };
819}
820
821impl<T, Ctx> DekuWriter<Ctx> for &T
822where
823 T: DekuWriter<Ctx>,
824 Ctx: Copy,
825{
826 #[inline(always)]
827 fn to_writer<W: no_std_io::Write + no_std_io::Seek>(
828 &self,
829 writer: &mut Writer<W>,
830 ctx: Ctx,
831 ) -> Result<(), DekuError> {
832 <T>::to_writer(self, writer, ctx)?;
833 Ok(())
834 }
835}
836
837/// Like BitVec but with bounded, local storage
838#[cfg(feature = "bits")]
839#[derive(Clone, Debug)]
840pub struct BoundedBitVec<A, O>
841where
842 A: BitViewSized,
843 O: BitOrder,
844{
845 bits: crate::bitvec::BitArray<A, O>,
846 size: usize,
847}
848
849#[cfg(feature = "bits")]
850impl<A, O> From<BitArray<A, O>> for BoundedBitVec<A, O>
851where
852 A: BitViewSized,
853 O: BitOrder,
854{
855 fn from(value: BitArray<A, O>) -> Self {
856 Self {
857 bits: value.clone(),
858 size: value.len(),
859 }
860 }
861}
862
863#[cfg(feature = "bits")]
864impl<A, O> From<&BitSlice<A::Store, O>> for BoundedBitVec<A, O>
865where
866 A: BitViewSized,
867 O: BitOrder,
868{
869 fn from(value: &BitSlice<A::Store, O>) -> Self {
870 let mut bbv = BoundedBitVec::new();
871 bbv.extend_from_bitslice(value);
872 bbv
873 }
874}
875
876#[cfg(feature = "bits")]
877impl<A, O> From<&mut BitSlice<<A::Store as BitStore>::Alias, O>> for BoundedBitVec<A, O>
878where
879 A: BitViewSized,
880 O: BitOrder,
881{
882 fn from(value: &mut BitSlice<<A::Store as BitStore>::Alias, O>) -> Self {
883 let mut bbv = BoundedBitVec::new();
884 let end = value.len();
885 debug_assert!(end <= bbv.bits.len());
886 bbv.bits[..end]
887 .split_at_mut(end)
888 .0
889 .copy_from_bitslice(value);
890 bbv.size = value.len();
891 bbv
892 }
893}
894
895#[cfg(all(feature = "bits", feature = "alloc"))]
896impl<A, O> From<crate::bitvec::BitVec<A::Store, O>> for BoundedBitVec<A, O>
897where
898 A: BitViewSized,
899 O: BitOrder,
900{
901 fn from(value: crate::bitvec::BitVec<A::Store, O>) -> Self {
902 let mut bbv = Self::new();
903 bbv.extend_from_bitslice(value.as_bitslice());
904 bbv
905 }
906}
907
908#[cfg(feature = "bits")]
909impl<A, O> From<&[bool]> for BoundedBitVec<A, O>
910where
911 A: BitViewSized,
912 O: BitOrder,
913{
914 fn from(value: &[bool]) -> Self {
915 let mut bbv = BoundedBitVec::new();
916 for v in value {
917 bbv.push(*v);
918 }
919 bbv
920 }
921}
922
923#[cfg(feature = "bits")]
924impl<A, O> BoundedBitVec<A, O>
925where
926 A: BitViewSized,
927 O: BitOrder,
928{
929 fn new() -> Self {
930 Self {
931 bits: crate::bitvec::BitArray::ZERO,
932 size: 0,
933 }
934 }
935
936 fn as_bitslice(&self) -> &BitSlice<A::Store, O> {
937 assert!(self.size <= self.bits.len());
938 &self.bits[..self.size]
939 }
940
941 fn as_mut_bitslice(&mut self) -> &mut BitSlice<A::Store, O> {
942 assert!(self.size <= self.bits.len());
943 &mut self.bits[..self.size]
944 }
945
946 fn as_raw_slice(&self) -> &[A::Store] {
947 self.bits.as_raw_slice()
948 }
949
950 fn capacity(&self) -> usize {
951 self.bits.len()
952 }
953
954 fn clear(&mut self) {
955 self.size = 0;
956 }
957
958 fn extend_from_bitslice(&mut self, bits: &BitSlice<A::Store, O>) {
959 assert!(self.size + bits.len() <= self.bits.len());
960 self.bits
961 .get_mut(self.size..{ self.size + bits.len() })
962 .expect("Asserted already")
963 .copy_from_bitslice(bits);
964 self.size += bits.len();
965 }
966
967 fn is_empty(&self) -> bool {
968 self.size == 0
969 }
970
971 fn is_full(&self) -> bool {
972 self.size == self.bits.len()
973 }
974
975 fn len(&self) -> usize {
976 self.size
977 }
978
979 fn insert(&mut self, index: usize, value: bool) {
980 assert!(self.size < self.bits.len());
981 assert!(index < self.size);
982 let (_left, right) = self.bits.split_at_mut(index);
983 right.shift_right(1);
984 right.set(0, value);
985 self.size += 1;
986 }
987
988 fn push(&mut self, value: bool) {
989 assert!(self.len() < self.bits.len());
990 *self.bits.get_mut(self.size).expect("Bad index") = value;
991 self.size += 1;
992 }
993
994 fn split_off(&mut self, index: usize) -> Self {
995 assert!(index < self.size);
996 let (left, right) = self.bits[..self.size].split_at(index);
997 debug_assert_eq!(left.len() + right.len(), self.size);
998 self.size = left.len();
999 right.into()
1000 }
1001}
1002
1003#[cfg(test)]
1004#[path = "../tests/test_common/mod.rs"]
1005pub mod test_common;