packed_struct/
lib.rs

1//! Bit-level packing and unpacking for Rust
2//! ===========================================
3//!
4//! [![Crates.io][crates-badge]][crates-url]
5//! [![Documentation](https://docs.rs/packed_struct/badge.svg)](https://docs.rs/packed_struct)
6//! ![master](https://github.com/hashmismatch/packed_struct.rs/workflows/Rust/badge.svg)
7//!
8//! # Introduction
9//!
10//! Packing and unpacking bit-level structures is usually a programming tasks that needlessly reinvents the wheel. This library provides
11//! a meta-programming approach, using attributes to define fields and how they should be packed. The resulting trait implementations
12//! provide safe packing, unpacking and runtime debugging formatters with per-field documentation generated for each structure.
13//!
14//! # Features
15//!
16//!  * Plain Rust structures, decorated with attributes
17//!  * MSB or LSB integers of user-defined bit widths
18//!  * Primitive enum code generation helper
19//!  * MSB0 or LSB0 bit positioning
20//!  * Documents the field's packing table
21//!  * Runtime packing visualization
22//!  * Nested packed types
23//!  * Arrays of packed structures as fields
24//!  * Reserved fields, their bits are always 0 or 1
25//!
26//! # Crate-level feature flags
27//!  * `std`: use the Rust standard library. Default.
28//!  * `alloc`: use the `alloc` crate for `no_std` + `alloc` scenarios. Requires nightly Rust.
29//!  * `use_serde`: add serialization support to the built-in helper types.
30//!  * `byte_types_64`, `byte_types_256`: enlarge the size of the generated array, byte and bit width types.
31//!
32//! # Sample usage
33//!
34//! ## Cargo.toml
35//!
36//! ```toml
37//! [dependencies]
38//! packed_struct = "0.10"
39//! ```
40//! ## Importing the library with the the most common traits and the derive macros
41//!
42//! ```rust
43//! // This is only needed for pre Rust 2018
44//! #[macro_use] extern crate packed_struct;
45//! // Prelude import with the common imports
46//! use packed_struct::prelude::*;
47//! # fn main() {
48//! # }
49//! ```
50//!
51//! ## Example of a single-byte structure, with a 3 bit integer, primitive enum and a bool field.
52//!
53//! ```rust
54//! use packed_struct::prelude::*;
55//!
56//! #[derive(PackedStruct)]
57//! #[packed_struct(bit_numbering="msb0")]
58//! pub struct TestPack {
59//!     #[packed_field(bits="0..=2")]
60//!     tiny_int: Integer<u8, packed_bits::Bits::<3>>,
61//!     #[packed_field(bits="3..=4", ty="enum")]
62//!     mode: SelfTestMode,
63//!     #[packed_field(bits="7")]
64//!     enabled: bool
65//! }
66//!
67//! #[derive(PrimitiveEnum_u8, Clone, Copy, Debug, PartialEq)]
68//! pub enum SelfTestMode {
69//!     NormalMode = 0,
70//!     PositiveSignSelfTest = 1,
71//!     NegativeSignSelfTest = 2,
72//!     DebugMode = 3,
73//! }
74//!
75//! fn main() -> Result<(), PackingError> {
76//!     let test = TestPack {
77//!         tiny_int: 5.into(),
78//!         mode: SelfTestMode::DebugMode,
79//!         enabled: true
80//!     };
81//!
82//!     // pack into a byte array
83//!     let packed: [u8; 1] = test.pack()?;
84//!     assert_eq!([0b10111001], packed);
85//!
86//!     // unpack from a byte array
87//!     let unpacked = TestPack::unpack(&packed)?;
88//!     assert_eq!(*unpacked.tiny_int, 5);
89//!     assert_eq!(unpacked.mode, SelfTestMode::DebugMode);
90//!     assert_eq!(unpacked.enabled, true);
91//!
92//!     // or unpack from a slice
93//!     let unpacked = TestPack::unpack_from_slice(&packed[..])?;
94//!
95//!     Ok(())
96//! }
97//! ```
98//!
99//! # Packing attributes
100//!
101//! ## Syntax
102//!
103//! ```rust
104//! use packed_struct::prelude::*;
105//!
106//! #[derive(PackedStruct)]
107//! #[packed_struct(attr1="val", attr2="val")]
108//! pub struct Structure {
109//!     #[packed_field(attr1="val", attr2="val")]
110//!     field: u8
111//! }
112//! # fn main() {
113//! # }
114//! ```
115//!
116//! ## Per-structure attributes
117//!
118//! Attribute | Values | Comment
119//! :--|:--|:--
120//! ```size_bytes``` | ```1``` ... n | Size of the packed byte stream
121//! ```bit_numbering``` | ```msb0``` or ```lsb0``` | Bit numbering for bit positioning of fields. Required if the bits attribute field is used.
122//! ```endian``` | ```msb``` or ```lsb``` | Default integer endianness
123//!
124//! ## Per-field attributes
125//!
126//! Attribute | Values | Comment
127//! :--|:--|:--
128//! ```bits``` | ```0```, ```0..1```, ... | Position of the field in the packed structure. Three modes are supported: a single bit, the starting bit, or a range of bits. See details below.
129//! ```bytes``` | ```0```, ```0..1```, ... | Same as above, multiplied by 8.
130//! ```size_bits``` | ```1```, ... | Specifies the size of the packed structure. Mandatory for certain types. Specifying a range of bits like ```bits="0..2"``` can substite the required usage of ```size_bits```.
131//! ```size_bytes``` | ```1```, ... | Same as above, multiplied by 8.
132//! ```element_size_bits``` | ```1```, ... | For packed arrays, specifies the size of a single element of the array. Explicitly stating the size of the entire array can substite the usage of this attribute.
133//! ```element_size_bytes``` | ```1```, ... | Same as above, multiplied by 8.
134//! ```ty``` | ```enum``` | Packing helper for primitive enums.
135//! ```endian``` | ```msb``` or ```lsb``` | Integer endianness. Applies to u16/i16 and larger types.
136//! 
137//! ## Bit and byte positioning
138//! 
139//! Used for either ```bits``` or ```bytes``` on fields. The examples are for MSB0 positioning.
140//! 
141//! Value | Comment
142//! :--|:--
143//! ```0``` | A single bit or byte
144//! ```0..```, ```0:``` | The field starts at bit zero
145//! ```0..2``` | Exclusive range, bits zero and one
146//! ```0:1```, ```0..=1``` | Inclusive range, bits zero and one
147//!
148//! # More examples
149//!
150//! ## Mixed endian integers
151//!
152//! ```rust
153//! use packed_struct::prelude::*;
154//!
155//! #[derive(PackedStruct)]
156//! pub struct EndianExample {
157//!     #[packed_field(endian="lsb")]
158//!     int1: u16,
159//!     #[packed_field(endian="msb")]
160//!     int2: i32
161//! }
162//!
163//! fn main() -> Result<(), PackingError> {
164//!     let example = EndianExample {
165//!         int1: 0xBBAA,
166//!         int2: 0x11223344
167//!     };
168//!
169//!     let packed = example.pack()?;
170//!     assert_eq!([0xAA, 0xBB, 0x11, 0x22, 0x33, 0x44], packed);
171//!     Ok(())
172//! }
173//! ```
174//!
175//! ## 24 bit LSB integers
176//!
177//! ```rust
178//! use packed_struct::prelude::*;
179//!
180//! #[derive(PackedStruct)]
181//! #[packed_struct(endian="lsb")]
182//! pub struct LsbIntExample {
183//!     int1: Integer<u32, packed_bits::Bits::<24>>,
184//! }
185//!
186//! fn main() -> Result<(), PackingError> {
187//!     let example = LsbIntExample {
188//!         int1: 0xCCBBAA.into()
189//!     };
190//!
191//!     let packed = example.pack()?;
192//!     assert_eq!([0xAA, 0xBB, 0xCC], packed);
193//!     Ok(())
194//! }
195//! ```
196//!
197//! ## Nested packed types
198//! 
199//! ```rust
200//! use packed_struct::prelude::*;
201//! #[derive(PackedStruct, Debug, PartialEq)]
202//! #[packed_struct(endian="lsb")]
203//! pub struct Duration {
204//!     minutes: u8,
205//!     seconds: u8,
206//! }
207//! #[derive(PackedStruct, Debug, PartialEq)]
208//! pub struct Record {
209//!     #[packed_field(element_size_bytes="2")]
210//!     span: Duration,
211//!     events: u8,
212//! }
213//! fn main() -> Result<(), PackingError> {
214//!     let example = Record {
215//!         span: Duration {
216//!             minutes: 10,
217//!             seconds: 34,
218//!         },
219//!         events: 3,
220//!     };
221//!     let packed = example.pack()?;
222//!     let unpacked = Record::unpack(&packed)?;
223//!     assert_eq!(example, unpacked);
224//!     Ok(())
225//! }
226//! ```
227//!
228//! ## Nested packed types within arrays
229//!
230//! ```rust
231//! use packed_struct::prelude::*;
232//!
233//! #[derive(PackedStruct, Default, Debug, PartialEq)]
234//! #[packed_struct(bit_numbering="msb0")]
235//! pub struct TinyFlags {
236//!     _reserved: ReservedZero<packed_bits::Bits::<4>>,
237//!     flag1: bool,
238//!     val1: Integer<u8, packed_bits::Bits::<2>>,
239//!     flag2: bool
240//! }
241//!
242//! #[derive(PackedStruct, Debug, PartialEq)]
243//! pub struct Settings {
244//!     #[packed_field(element_size_bits="4")]
245//!     values: [TinyFlags; 4]
246//! }
247//!
248//! fn main() -> Result<(), PackingError> {
249//!     let example = Settings {
250//!         values: [
251//!             TinyFlags { flag1: true,  val1: 1.into(), flag2: false, .. TinyFlags::default() },
252//!             TinyFlags { flag1: true,  val1: 2.into(), flag2: true,  .. TinyFlags::default() },
253//!             TinyFlags { flag1: false, val1: 3.into(), flag2: false, .. TinyFlags::default() },
254//!             TinyFlags { flag1: true,  val1: 0.into(), flag2: false, .. TinyFlags::default() },
255//!         ]
256//!     };
257//!
258//!     let packed = example.pack()?;
259//!     let unpacked = Settings::unpack(&packed)?;
260//!
261//!     assert_eq!(example, unpacked);
262//!     Ok(())
263//! }
264//! ```
265//! 
266//! # Primitive enums with simple discriminants
267//! 
268//! Supported backing integer types: ```u8```, ```u16```, ```u32```, ```u64```, ```i8```, ```i16```, ```i32```, ```i64```.
269//! 
270//! Explicit or implicit backing type:
271//! 
272//! ```rust
273//! use packed_struct::prelude::*;
274//!
275//! #[derive(PrimitiveEnum, Clone, Copy, PartialEq, Debug)]
276//! pub enum ImplicitType {
277//!     VariantMin = 0,
278//!     VariantMax = 255
279//! }
280//! 
281//! #[derive(PrimitiveEnum_i16, Clone, Copy)]
282//! pub enum ExplicitType {
283//!     VariantMin = -32768,
284//!     VariantMax = 32767
285//! }
286//! 
287//! use packed_struct::PrimitiveEnum;
288//! 
289//! let t = ImplicitType::VariantMin;
290//! let tn: u8 = t.to_primitive();
291//! assert_eq!(0, tn);
292//!
293//! let t = ImplicitType::from_primitive(255).unwrap();
294//! assert_eq!(ImplicitType::VariantMax, t);
295//! ```
296//! 
297//! # Primitive enum packing with support for catch-all unknown values
298//! 
299//! ```rust
300//! use packed_struct::prelude::*;
301//! 
302//! #[derive(PrimitiveEnum_u8, Debug, Clone, Copy)]
303//! pub enum Field {
304//!     A = 1,
305//!     B = 2,
306//!     C = 3
307//! }
308//! 
309//! #[derive(PackedStruct, Debug, PartialEq)]
310//! #[packed_struct(bit_numbering="msb0")]
311//! pub struct Register {
312//!     #[packed_field(bits="0..4", ty="enum")]
313//!     field: EnumCatchAll<Field>
314//! }
315//! ```
316//! [crates-badge]: https://img.shields.io/crates/v/packed_struct.svg
317//! [crates-url]: https://crates.io/crates/packed_struct
318
319#![cfg_attr(not(feature = "std"), no_std)]
320
321#![cfg_attr(feature="alloc", feature(alloc))]
322
323extern crate packed_struct_codegen;
324
325#[cfg(feature="alloc")]
326#[macro_use]
327extern crate alloc;
328
329#[cfg(feature = "use_serde")]
330extern crate serde;
331#[cfg(feature = "use_serde")]
332#[macro_use] extern crate serde_derive;
333
334mod internal_prelude;
335
336#[macro_use]
337mod packing;
338
339mod primitive_enum;
340
341pub use primitive_enum::*;
342
343#[cfg(any(feature="alloc", feature="std"))]
344pub mod debug_fmt;
345
346mod types_array;
347mod types_basic;
348mod types_bits;
349mod types_generic;
350mod types_num;
351mod types_reserved;
352
353pub mod types_tuples;
354
355#[cfg(any(feature="alloc", feature="std"))]
356mod types_vec;
357
358/// Implementations and wrappers for various packing types.
359pub mod types {
360    pub use super::types_basic::*;
361
362    /// Types that specify the exact number of bits a packed integer should occupy.
363    pub mod bits {
364        pub use super::super::types_bits::*;
365    }
366
367    pub use super::types_num::*;
368    pub use super::types_array::*;
369    pub use super::types_reserved::*;
370    pub use super::types_generic::*;
371    #[cfg(any(feature="alloc", feature="std"))]
372    pub use super::types_vec::*;
373}
374
375pub use self::packing::*;
376
377/// The derivation macros for packing and enums.
378pub mod derive {
379    pub use packed_struct_codegen::PackedStruct;
380    pub use packed_struct_codegen::PrimitiveEnum;
381    pub use packed_struct_codegen::{PrimitiveEnum_u8, PrimitiveEnum_u16, PrimitiveEnum_u32, PrimitiveEnum_u64};
382    pub use packed_struct_codegen::{PrimitiveEnum_i8, PrimitiveEnum_i16, PrimitiveEnum_i32, PrimitiveEnum_i64};
383}
384
385pub mod prelude {
386    //! Re-exports the most useful traits and types. Meant to be glob imported.
387
388    pub use super::derive::*;
389
390    pub use crate::{PackedStruct, PackedStructSlice, PackingError};
391
392    pub use crate::PrimitiveEnum;
393    #[cfg(any(feature="alloc", feature="std"))]
394    pub use crate::PrimitiveEnumDynamicStr;
395
396    #[cfg(not(any(feature="alloc", feature="std")))]
397    pub use crate::PrimitiveEnumStaticStr;
398
399
400    pub use crate::EnumCatchAll;
401
402    pub use crate::types::*;
403    pub use crate::types::bits as packed_bits;
404}
405
406use internal_prelude::v1::*;
407
408fn lib_get_slice<T, I: slice::SliceIndex<[T]>>(src: &[T], index: I) -> Result<&<I as slice::SliceIndex<[T]>>::Output, PackingError> {
409    let slice_len = src.len();
410    src.get(index).ok_or(PackingError::SliceIndexingError { slice_len })
411}
412
413fn lib_get_mut_slice<T, I: slice::SliceIndex<[T]>>(src: &mut [T], index: I) -> Result<&mut <I as slice::SliceIndex<[T]>>::Output, PackingError> {
414    let slice_len = src.len();
415    src.get_mut(index).ok_or(PackingError::SliceIndexingError { slice_len })
416}