1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
//! Provides macros to support bitfield structs allowing for modular use of bit-enums.
//!
//! The mainly provided macros are `#[bitfield]` for structs and
//! `#[derive(BitfieldSpecifier)]` for enums that shall be usable
//! within bitfield structs.
//!
//! There are preset bitfield specifiers such as `B1`, `B2`,..,`B64`
//! that allow for easy bitfield usage in structs very similar to how
//! they work in C or C++.
//!
//! - Performance of the macro generated code is as fast as its hand-written
//!   alternative.
//! - Compile-time checks allow for safe usage of bitfield structs and enums.
//!
//!
//! ### Usage
//!
//! Annotate a Rust struct with the `#[bitfield]` attribute in order to convert it into a bitfield.
//! The `B1`, `B2`, ... `B128` prelude types can be used as primitives to declare the number of bits per field.
//!
//! ```
//! # use modular_bitfield::prelude::*;
//! #
//! #[bitfield]
//! pub struct PackedData {
//!     header: B4,
//!     body: B9,
//!     is_alive: B1,
//!     status: B2,
//! }
//! ```
//!
//! This produces a `new` constructor as well as a variety of getters and setters that
//! allows to interact with the bitfield in a safe fashion:
//!
//! #### Example: Constructors
//!
//! ```
//! # use modular_bitfield::prelude::*;
//! #
//! # #[bitfield]
//! # pub struct PackedData {
//! #     header: B4,
//! #     body: B9,
//! #     is_alive: B1,
//! #     status: B2,
//! # }
//! let data = PackedData::new()
//!     .with_header(1)
//!     .with_body(2)
//!     .with_is_alive(0)
//!     .with_status(3);
//! assert_eq!(data.header(), 1);
//! assert_eq!(data.body(), 2);
//! assert_eq!(data.is_alive(), 0);
//! assert_eq!(data.status(), 3);
//! ```
//!
//! #### Example: Primitive Types
//!
//! Any type that implements the `Specifier` trait can be used as a bitfield field.
//! Besides the already mentioned `B1`, .. `B128` also the `bool`, `u8, `u16, `u32,
//! `u64` or `u128` primitive types can be used from prelude.
//!
//! We can use this knowledge to encode our `is_alive` as `bool` type instead of `B1`:
//!
//! ```
//! # use modular_bitfield::prelude::*;
//! #
//! #[bitfield]
//! pub struct PackedData {
//!     header: B4,
//!     body: B9,
//!     is_alive: bool,
//!     status: B2,
//! }
//!
//! let mut data = PackedData::new()
//!     .with_is_alive(true);
//! assert!(data.is_alive());
//! data.set_is_alive(false);
//! assert!(!data.is_alive());
//! ```
//!
//! #### Example: Enum Specifiers
//!
//! It is possible to derive the `Specifier` trait for `enum` types very easily to make
//! them also usable as a field within a bitfield type:
//!
//! ```
//! # use modular_bitfield::prelude::*;
//! #
//! #[derive(BitfieldSpecifier)]
//! pub enum Status {
//!     Red, Green, Yellow, None,
//! }
//!
//! #[bitfield]
//! pub struct PackedData {
//!     header: B4,
//!     body: B9,
//!     is_alive: bool,
//!     status: Status,
//! }
//! ```
//!
//! #### Example: Extra Safety Guard
//!
//! In order to make sure that our `Status` enum still requires exatly 2 bit we can add
//! `#[bits = 2]` to its field:
//!
//! ```
//! # use modular_bitfield::prelude::*;
//! #
//! # #[derive(BitfieldSpecifier)]
//! # pub enum Status {
//! #     Red, Green, Yellow, None,
//! # }
//! #
//! #[bitfield]
//! pub struct PackedData {
//!     header: B4,
//!     body: B9,
//!     is_alive: bool,
//!     #[bits = 2]
//!     status: Status,
//! }
//! ```
//!
//! Setting and getting our new `status` field is naturally as follows:
//!
//! ```
//! # use modular_bitfield::prelude::*;
//! #
//! # #[derive(BitfieldSpecifier)]
//! # #[derive(Debug, PartialEq, Eq)]
//! # pub enum Status {
//! #     Red, Green, Yellow, None,
//! # }
//! #
//! # #[bitfield]
//! # pub struct PackedData {
//! #     header: B4,
//! #     body: B9,
//! #     is_alive: bool,
//! #     #[bits = 2]
//! #     status: Status,
//! # }
//! #
//! let mut data = PackedData::new()
//!     .with_status(Status::Green);
//! assert_eq!(data.status(), Status::Green);
//! data.set_status(Status::Red);
//! assert_eq!(data.status(), Status::Red);
//! ```
//!
//! #### Example: Recursive Bitfields
//!
//! It is possible to use `#[bitfield]` structs as fields of `#[bitfield]` structs.
//! This is generally useful if there are some common fields for multiple bitfields
//! and is achieved by adding `specifier = true` to the parameters of the `#[bitfield]`
//! attribute:
//!
//! ```
//! # use modular_bitfield::prelude::*;
//! #
//! # #[derive(BitfieldSpecifier)]
//! # pub enum Status {
//! #     Red, Green, Yellow, None,
//! # }
//! #
//! #[bitfield(specifier = true)]
//! pub struct Header {
//!     is_compact: bool,
//!     is_secure: bool,
//!     pre_status: Status,
//! }
//!
//! #[bitfield]
//! pub struct PackedData {
//!     header: Header,
//!     body: B9,
//!     is_alive: bool,
//!     status: Status,
//! }
//! ```
//!
//! #### Example: Advanced Enum Specifiers
//!
//! For our `Status` enum we actually just need 3 status variants: `Green`, `Yellow` and `Red`.
//! We introduced the `None` status variants because `Specifier` enums by default are required
//! to have a number of variants that is a power of two. We can ship around this by specifying
//! `#[bits = 2]` on the top and get rid of our placeholder `None` variant while maintaining
//! the invariant of it requiring 2 bits:
//!
//! ```
//! # use modular_bitfield::prelude::*;
//!
//! #[derive(BitfieldSpecifier)]
//! #[bits = 2]
//! pub enum Status {
//!     Red, Green, Yellow,
//! }
//! ```
//!
//! However, having such enums now yields the possibility that a bitfield might contain invalid bit
//! patterns for such fields. We can safely access those fields with protected getters. For the sake
//! of demonstration we will use the generated `from_bytes` constructor with which we can easily
//! construct bitfields that may contain invalid bit patterns:
//!
//! ```
//! # use modular_bitfield::prelude::*;
//! # use modular_bitfield::error::InvalidBitPattern;
//! #
//! # #[derive(BitfieldSpecifier)]
//! # #[derive(Debug, PartialEq, Eq)]
//! # #[bits = 2]
//! # pub enum Status {
//! #     Red, Green, Yellow,
//! # }
//! #
//! # #[bitfield(specifier = true)]
//! # pub struct Header {
//! #     is_compact: bool,
//! #     is_secure: bool,
//! #     pre_status: Status,
//! # }
//! #
//! # #[bitfield]
//! # pub struct PackedData {
//! #     header: Header,
//! #     body: B9,
//! #     is_alive: bool,
//! #     status: Status,
//! # }
//! #
//! let mut data = PackedData::from_bytes([0b0000_0000, 0b1100_0000]);
//! //           The 2 status field bits are invalid -----^^
//! //           as Red = 0x00, Green = 0x01 and Yellow = 0x10
//! assert_eq!(data.status_or_err(), Err(InvalidBitPattern { invalid_bytes: 0b11 }));
//! data.set_status(Status::Green);
//! assert_eq!(data.status_or_err(), Ok(Status::Green));
//! ```
//!
//! ## Generated Implementations
//!
//! For the example `#[bitfield]` struct the following implementations are going to be generated:
//!
//! ```
//! # use modular_bitfield::prelude::*;
//! #
//! #[bitfield]
//! pub struct Example {
//!     a: bool,
//!     b: B7,
//! }
//! ```
//!
//! | Signature | Description |
//! |:--|:--|
//! | `fn new() -> Self` | Creates a new instance of the bitfield with all bits initialized to 0. |
//! | `fn from_bytes([u8; 1]) -> Self` | Creates a new instance of the bitfield from the given raw bytes. |
//! | `fn as_bytes(&self) -> &[u8; 1]` | Returns the underlying bytes of the bitfield. |
//!
//! And below the generated signatures for field `a`:
//!
//! | Signature | Description |
//! |:--|:--|
//! | `fn a() -> bool` | Returns the value of `a` or panics if invalid. |
//! | `fn a_or_err() -> Result<bool, InvalidBitPattern<u8>>` | Returns the value of `a` of an error providing information about the invalid bits. |
//! | `fn set_a(&mut self, new_value: bool)` | Sets `a` to the new value or panics if `new_value` contains invalid bits. |
//! | `fn set_a_checked(&mut self, new_value: bool) -> Result<(), OutOfBounds>` | Sets `a` to the new value of returns an out of bounds error. |
//! | `fn with_a(self, new_value: bool) -> Self` | Similar to `set_a` but useful for method chaining. |
//! | `fn with_a_checked(self, new_value: bool) -> Result<Self, OutOfBounds>` | Similar to `set_a_checked` but useful for method chaining. |
//!
//! ## Generated Structure
//!
//! From David Tolnay's procedural macro workshop:
//!
//! The macro conceptualizes given structs as a sequence of bits 0..N.
//! The bits are grouped into fields in the order specified by the struct written by the user.
//!
//! The `#[bitfield]` attribute rewrites the caller's struct into a private byte array representation
//! with public getter and setter methods for each field.
//! The total number of bits N is required to be a multiple of 8: This is checked at compile time.
//!
//! ### Example
//!
//! The following invocation builds a struct with a total size of 32 bits or 4 bytes.
//! It places field `a` in the least significant bit of the first byte,
//! field `b` in the next three least significant bits,
//! field `c` in the remaining four most significant bits of the first byte,
//! and field `d` spanning the next three bytes.
//!
//! ```rust
//! use modular_bitfield::prelude::*;
//!
//! #[bitfield]
//! pub struct MyFourBytes {
//!     a: B1,
//!     b: B3,
//!     c: B4,
//!     d: B24,
//! }
//! ```
//! ```no_compile
//!                                least significant bit of third byte
//!                                  ┊           most significant
//!                                  ┊             ┊
//!                                  ┊             ┊
//! ║  first byte   ║  second byte  ║  third byte   ║  fourth byte  ║
//! ╟───────────────╫───────────────╫───────────────╫───────────────╢
//! ║▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒║
//! ╟─╫─────╫───────╫───────────────────────────────────────────────╢
//! ║a║  b  ║   c   ║                       d                       ║
//!                  ┊                                             ┊
//!                  ┊                                             ┊
//!                least significant bit of d         most significant
//! ```

#![no_std]
#![forbid(unsafe_code)]

pub use modular_bitfield_impl::{
    bitfield,
    BitfieldSpecifier,
};

#[doc(hidden)]
pub mod private;

pub mod error;
use self::error::{
    InvalidBitPattern,
    OutOfBounds,
};

/// The prelude: `use modular_bitfield::prelude::*;`
pub mod prelude {
    pub use super::{
        bitfield,
        specifiers::*,
        BitfieldSpecifier,
        Specifier,
    };
}

/// Trait implemented by all bitfield specifiers.
///
/// Should generally not be implemented directly by users
/// but through the macros provided by the crate.
///
/// # Note
///
/// These can be all unsigned fixed-size primitives,
/// represented by `B1, B2, ... B64` and enums that
/// derive from `BitfieldSpecifier`.
pub trait Specifier {
    /// The amount of bits used by the specifier.
    const BITS: usize;

    /// The base type of the specifier.
    ///
    /// # Note
    ///
    /// This is the type that is used internally for computations.
    type Bytes;

    /// The interface type of the specifier.
    ///
    /// # Note
    ///
    /// This is the type that is used for the getters and setters.
    type InOut;

    /// Converts some bytes into the in-out type.
    ///
    /// # Errors
    ///
    /// If the in-out type is out of bounds. This can for example happen if your
    /// in-out type is `u8` (for `B7`) but you specified a value that is bigger
    /// or equal to 128 which exceeds the 7 bits.
    fn into_bytes(input: Self::InOut) -> Result<Self::Bytes, OutOfBounds>;

    /// Converts the given bytes into the in-out type.
    ///
    /// # Errors
    ///
    /// If the given byte pattern is invalid for the in-out type.
    /// This can happen for example for enums that have a number of variants which
    /// is not equal to the power of two and therefore yields some invalid bit
    /// patterns.
    fn from_bytes(
        bytes: Self::Bytes,
    ) -> Result<Self::InOut, InvalidBitPattern<Self::Bytes>>;
}

/// The default set of predefined specifiers.
pub mod specifiers {
    ::modular_bitfield_impl::define_specifiers!();
}