packed_struct/lib.rs
1//! Bit-level packing and unpacking for Rust
2//! ===========================================
3//!
4//! [![Crates.io][crates-badge]][crates-url]
5//! [](https://docs.rs/packed_struct)
6//! 
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}