modular_bitfield/lib.rs
1//! Provides macros to support bitfield structs allowing for modular use of bit-enums.
2//!
3//! The mainly provided macros are `#[bitfield]` for structs and
4//! `#[derive(BitfieldSpecifier)]` for enums that shall be usable
5//! within bitfield structs.
6//!
7//! There are preset bitfield specifiers such as `B1`, `B2`,..,`B64`
8//! that allow for easy bitfield usage in structs very similar to how
9//! they work in C or C++.
10//!
11//! - Performance of the macro generated code is as fast as its hand-written
12//! alternative.
13//! - Compile-time checks allow for safe usage of bitfield structs and enums.
14//!
15//!
16//! ### Usage
17//!
18//! Annotate a Rust struct with the `#[bitfield]` attribute in order to convert it into a bitfield.
19//! The `B1`, `B2`, ... `B128` prelude types can be used as primitives to declare the number of bits per field.
20//!
21//! ```
22//! # use modular_bitfield::prelude::*;
23//! #
24//! #[bitfield]
25//! pub struct PackedData {
26//! header: B4,
27//! body: B9,
28//! is_alive: B1,
29//! status: B2,
30//! }
31//! ```
32//!
33//! This produces a `new` constructor as well as a variety of getters and setters that
34//! allows to interact with the bitfield in a safe fashion:
35//!
36//! #### Example: Constructors
37//!
38//! ```
39//! # use modular_bitfield::prelude::*;
40//! #
41//! # #[bitfield]
42//! # pub struct PackedData {
43//! # header: B4,
44//! # body: B9,
45//! # is_alive: B1,
46//! # status: B2,
47//! # }
48//! let data = PackedData::new()
49//! .with_header(1)
50//! .with_body(2)
51//! .with_is_alive(0)
52//! .with_status(3);
53//! assert_eq!(data.header(), 1);
54//! assert_eq!(data.body(), 2);
55//! assert_eq!(data.is_alive(), 0);
56//! assert_eq!(data.status(), 3);
57//! ```
58//!
59//! #### Example: Primitive Types
60//!
61//! Any type that implements the `Specifier` trait can be used as a bitfield field.
62//! Besides the already mentioned `B1`, .. `B128` also the `bool`, `u8, `u16, `u32,
63//! `u64` or `u128` primitive types can be used from prelude.
64//!
65//! We can use this knowledge to encode our `is_alive` as `bool` type instead of `B1`:
66//!
67//! ```
68//! # use modular_bitfield::prelude::*;
69//! #
70//! #[bitfield]
71//! pub struct PackedData {
72//! header: B4,
73//! body: B9,
74//! is_alive: bool,
75//! status: B2,
76//! }
77//!
78//! let mut data = PackedData::new()
79//! .with_is_alive(true);
80//! assert!(data.is_alive());
81//! data.set_is_alive(false);
82//! assert!(!data.is_alive());
83//! ```
84//!
85//! #### Example: Enum Specifiers
86//!
87//! It is possible to derive the `Specifier` trait for `enum` types very easily to make
88//! them also usable as a field within a bitfield type:
89//!
90//! ```
91//! # use modular_bitfield::prelude::*;
92//! #
93//! #[derive(BitfieldSpecifier)]
94//! pub enum Status {
95//! Red, Green, Yellow, None,
96//! }
97//!
98//! #[bitfield]
99//! pub struct PackedData {
100//! header: B4,
101//! body: B9,
102//! is_alive: bool,
103//! status: Status,
104//! }
105//! ```
106//!
107//! #### Example: Extra Safety Guard
108//!
109//! In order to make sure that our `Status` enum still requires exatly 2 bit we can add
110//! `#[bits = 2]` to its field:
111//!
112//! ```
113//! # use modular_bitfield::prelude::*;
114//! #
115//! # #[derive(BitfieldSpecifier)]
116//! # pub enum Status {
117//! # Red, Green, Yellow, None,
118//! # }
119//! #
120//! #[bitfield]
121//! pub struct PackedData {
122//! header: B4,
123//! body: B9,
124//! is_alive: bool,
125//! #[bits = 2]
126//! status: Status,
127//! }
128//! ```
129//!
130//! Setting and getting our new `status` field is naturally as follows:
131//!
132//! ```
133//! # use modular_bitfield::prelude::*;
134//! #
135//! # #[derive(BitfieldSpecifier)]
136//! # #[derive(Debug, PartialEq, Eq)]
137//! # pub enum Status {
138//! # Red, Green, Yellow, None,
139//! # }
140//! #
141//! # #[bitfield]
142//! # pub struct PackedData {
143//! # header: B4,
144//! # body: B9,
145//! # is_alive: bool,
146//! # #[bits = 2]
147//! # status: Status,
148//! # }
149//! #
150//! let mut data = PackedData::new()
151//! .with_status(Status::Green);
152//! assert_eq!(data.status(), Status::Green);
153//! data.set_status(Status::Red);
154//! assert_eq!(data.status(), Status::Red);
155//! ```
156//!
157//! #### Example: Skipping Fields
158//!
159//! It might make sense to only allow users to set or get information from a field or
160//! even to entirely disallow interaction with a bitfield. For this the `#[skip]` attribute
161//! can be used on a bitfield of a `#[bitfield]` annotated struct.
162//!
163//! ```
164//! # use modular_bitfield::prelude::*;
165//! #
166//! #[bitfield]
167//! pub struct SomeBitsUndefined {
168//! #[skip(setters)]
169//! read_only: bool,
170//! #[skip(getters)]
171//! write_only: bool,
172//! #[skip]
173//! unused: B6,
174//! }
175//! ```
176//!
177//! It is possible to use `#[skip(getters, setters)]` or `#[skip(getters)]` followed by a `#[skip(setters)]`
178//! attribute applied on the same bitfield. The effects are the same. When skipping both, getters and setters,
179//! it is possible to completely avoid having to specify a name:
180//!
181//! ```
182//! # use modular_bitfield::prelude::*;
183//! #
184//! #[bitfield]
185//! pub struct SomeBitsUndefined {
186//! #[skip] __: B2,
187//! is_activ: bool,
188//! #[skip] __: B2,
189//! is_received: bool,
190//! #[skip] __: B2,
191//! }
192//! ```
193//!
194//! #### Example: Unfilled Bitfields
195//!
196//! Sometimes it might be useful to not be required to construct a bitfield that defines
197//! all bits and therefore is required to have a bit width divisible by 8. In this case
198//! you can use the `filled: bool` parameter of the `#[bitfield]` macro in order to toggle
199//! this for your respective bitfield:
200//!
201//! ```
202//! # use modular_bitfield::prelude::*;
203//! #
204//! #[bitfield(filled = false)]
205//! pub struct SomeBitsUndefined {
206//! is_compact: bool,
207//! is_secure: bool,
208//! pre_status: B3,
209//! }
210//! ```
211//!
212//! In the above example `SomeBitsUndefined` only defines the first 5 bits and leaves the rest
213//! 3 bits of its entire 8 bits undefined. The consequences are that its generated `from_bytes`
214//! method is fallible since it must guard against those undefined bits.
215//!
216//! #### Example: Recursive Bitfields
217//!
218//! It is possible to use `#[bitfield]` structs as fields of `#[bitfield]` structs.
219//! This is generally useful if there are some common fields for multiple bitfields
220//! and is achieved by adding the `#[derive(BitfieldSpecifier)]` attribute to the struct
221//! annotated with `#[bitfield]`:
222//!
223//! ```
224//! # use modular_bitfield::prelude::*;
225//! #
226//! # #[derive(BitfieldSpecifier)]
227//! # pub enum Status {
228//! # Red, Green, Yellow, None,
229//! # }
230//! #
231//! #[bitfield(filled = false)]
232//! #[derive(BitfieldSpecifier)]
233//! pub struct Header {
234//! is_compact: bool,
235//! is_secure: bool,
236//! pre_status: Status,
237//! }
238//!
239//! #[bitfield]
240//! pub struct PackedData {
241//! header: Header,
242//! body: B9,
243//! is_alive: bool,
244//! status: Status,
245//! }
246//! ```
247//!
248//! With the `bits: int` parameter of the `#[bitfield]` macro on the `Header` struct and the
249//! `#[bits: int]` attribute of the `#[derive(BitfieldSpecifier)]` on the `Status` enum we
250//! can have additional compile-time guarantees about the bit widths of the resulting entities:
251//!
252//! ```
253//! # use modular_bitfield::prelude::*;
254//! #
255//! #[derive(BitfieldSpecifier)]
256//! #[bits = 2]
257//! pub enum Status {
258//! Red, Green, Yellow, None,
259//! }
260//!
261//! #[bitfield(bits = 4)]
262//! #[derive(BitfieldSpecifier)]
263//! pub struct Header {
264//! is_compact: bool,
265//! is_secure: bool,
266//! #[bits = 2]
267//! pre_status: Status,
268//! }
269//!
270//! #[bitfield(bits = 16)]
271//! pub struct PackedData {
272//! #[bits = 4]
273//! header: Header,
274//! body: B9,
275//! is_alive: bool,
276//! #[bits = 2]
277//! status: Status,
278//! }
279//! ```
280//!
281//! #### Example: Advanced Enum Specifiers
282//!
283//! For our `Status` enum we actually just need 3 status variants: `Green`, `Yellow` and `Red`.
284//! We introduced the `None` status variants because `Specifier` enums by default are required
285//! to have a number of variants that is a power of two. We can ship around this by specifying
286//! `#[bits = 2]` on the top and get rid of our placeholder `None` variant while maintaining
287//! the invariant of it requiring 2 bits:
288//!
289//! ```
290//! # use modular_bitfield::prelude::*;
291//!
292//! #[derive(BitfieldSpecifier)]
293//! #[bits = 2]
294//! pub enum Status {
295//! Red, Green, Yellow,
296//! }
297//! ```
298//!
299//! However, having such enums now yields the possibility that a bitfield might contain invalid bit
300//! patterns for such fields. We can safely access those fields with protected getters. For the sake
301//! of demonstration we will use the generated `from_bytes` constructor with which we can easily
302//! construct bitfields that may contain invalid bit patterns:
303//!
304//! ```
305//! # use modular_bitfield::prelude::*;
306//! # use modular_bitfield::error::InvalidBitPattern;
307//! #
308//! # #[derive(BitfieldSpecifier)]
309//! # #[derive(Debug, PartialEq, Eq)]
310//! # #[bits = 2]
311//! # pub enum Status {
312//! # Red, Green, Yellow,
313//! # }
314//! #
315//! # #[bitfield(filled = false)]
316//! # #[derive(BitfieldSpecifier)]
317//! # pub struct Header {
318//! # is_compact: bool,
319//! # is_secure: bool,
320//! # pre_status: Status,
321//! # }
322//! #
323//! # #[bitfield]
324//! # pub struct PackedData {
325//! # header: Header,
326//! # body: B9,
327//! # is_alive: bool,
328//! # status: Status,
329//! # }
330//! #
331//! let mut data = PackedData::from_bytes([0b0000_0000, 0b1100_0000]);
332//! // The 2 status field bits are invalid -----^^
333//! // as Red = 0x00, Green = 0x01 and Yellow = 0x10
334//! assert_eq!(data.status_or_err(), Err(InvalidBitPattern { invalid_bytes: 0b11 }));
335//! data.set_status(Status::Green);
336//! assert_eq!(data.status_or_err(), Ok(Status::Green));
337//! ```
338//!
339//! ## Generated Implementations
340//!
341//! For the example `#[bitfield]` struct the following implementations are going to be generated:
342//!
343//! ```
344//! # use modular_bitfield::prelude::*;
345//! #
346//! #[bitfield]
347//! pub struct Example {
348//! a: bool,
349//! b: B7,
350//! }
351//! ```
352//!
353//! | Signature | Description |
354//! |:--|:--|
355//! | `fn new() -> Self` | Creates a new instance of the bitfield with all bits initialized to 0. |
356//! | `fn from_bytes([u8; 1]) -> Self` | Creates a new instance of the bitfield from the given raw bytes. |
357//! | `fn into_bytes(self) -> [u8; 1]` | Returns the underlying bytes of the bitfield. |
358//!
359//! And below the generated signatures for field `a`:
360//!
361//! | Signature | Description |
362//! |:--|:--|
363//! | `fn a() -> bool` | Returns the value of `a` or panics if invalid. |
364//! | `fn a_or_err() -> Result<bool, InvalidBitPattern<u8>>` | Returns the value of `a` of an error providing information about the invalid bits. |
365//! | `fn set_a(&mut self, new_value: bool)` | Sets `a` to the new value or panics if `new_value` contains invalid bits. |
366//! | `fn set_a_checked(&mut self, new_value: bool) -> Result<(), OutOfBounds>` | Sets `a` to the new value of returns an out of bounds error. |
367//! | `fn with_a(self, new_value: bool) -> Self` | Similar to `set_a` but useful for method chaining. |
368//! | `fn with_a_checked(self, new_value: bool) -> Result<Self, OutOfBounds>` | Similar to `set_a_checked` but useful for method chaining. |
369//!
370//! ## Generated Structure
371//!
372//! From David Tolnay's procedural macro workshop:
373//!
374//! The macro conceptualizes given structs as a sequence of bits 0..N.
375//! The bits are grouped into fields in the order specified by the struct written by the user.
376//!
377//! The `#[bitfield]` attribute rewrites the caller's struct into a private byte array representation
378//! with public getter and setter methods for each field.
379//! The total number of bits N is required to be a multiple of 8: This is checked at compile time.
380//!
381//! ### Example
382//!
383//! The following invocation builds a struct with a total size of 32 bits or 4 bytes.
384//! It places field `a` in the least significant bit of the first byte,
385//! field `b` in the next three least significant bits,
386//! field `c` in the remaining four most significant bits of the first byte,
387//! and field `d` spanning the next three bytes.
388//!
389//! ```rust
390//! use modular_bitfield::prelude::*;
391//!
392//! #[bitfield]
393//! pub struct MyFourBytes {
394//! a: B1,
395//! b: B3,
396//! c: B4,
397//! d: B24,
398//! }
399//! ```
400//! ```no_compile
401//! least significant bit of third byte
402//! ┊ most significant
403//! ┊ ┊
404//! ┊ ┊
405//! ║ first byte ║ second byte ║ third byte ║ fourth byte ║
406//! ╟───────────────╫───────────────╫───────────────╫───────────────╢
407//! ║▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒║
408//! ╟─╫─────╫───────╫───────────────────────────────────────────────╢
409//! ║a║ b ║ c ║ d ║
410//! ┊ ┊
411//! ┊ ┊
412//! least significant bit of d most significant
413//! ```
414
415#![no_std]
416#![forbid(unsafe_code)]
417
418extern crate static_assertions;
419
420pub mod error;
421#[doc(hidden)]
422pub mod private;
423
424use self::error::{
425 InvalidBitPattern,
426 OutOfBounds,
427};
428pub use modular_bitfield_impl::{
429 bitfield,
430 BitfieldSpecifier,
431};
432
433/// The prelude: `use modular_bitfield::prelude::*;`
434pub mod prelude {
435 pub use super::{
436 bitfield,
437 specifiers::*,
438 BitfieldSpecifier,
439 Specifier,
440 };
441}
442
443/// Trait implemented by all bitfield specifiers.
444///
445/// Should generally not be implemented directly by users
446/// but through the macros provided by the crate.
447///
448/// # Note
449///
450/// These can be all unsigned fixed-size primitives,
451/// represented by `B1, B2, ... B64` and enums that
452/// derive from `BitfieldSpecifier`.
453pub trait Specifier {
454 /// The amount of bits used by the specifier.
455 const BITS: usize;
456
457 /// The base type of the specifier.
458 ///
459 /// # Note
460 ///
461 /// This is the type that is used internally for computations.
462 type Bytes;
463
464 /// The interface type of the specifier.
465 ///
466 /// # Note
467 ///
468 /// This is the type that is used for the getters and setters.
469 type InOut;
470
471 /// Converts some bytes into the in-out type.
472 ///
473 /// # Errors
474 ///
475 /// If the in-out type is out of bounds. This can for example happen if your
476 /// in-out type is `u8` (for `B7`) but you specified a value that is bigger
477 /// or equal to 128 which exceeds the 7 bits.
478 fn into_bytes(input: Self::InOut) -> Result<Self::Bytes, OutOfBounds>;
479
480 /// Converts the given bytes into the in-out type.
481 ///
482 /// # Errors
483 ///
484 /// If the given byte pattern is invalid for the in-out type.
485 /// This can happen for example for enums that have a number of variants which
486 /// is not equal to the power of two and therefore yields some invalid bit
487 /// patterns.
488 fn from_bytes(
489 bytes: Self::Bytes,
490 ) -> Result<Self::InOut, InvalidBitPattern<Self::Bytes>>;
491}
492
493/// The default set of predefined specifiers.
494pub mod specifiers {
495 ::modular_bitfield_impl::define_specifiers!();
496}