fray/
lib.rs

1/*!
2A type-safe and ergonomic library for working with bitfields.
3
4A bitfield is defined using the [`#[bitfield]`](crate::bitfield) attribute macro and must specify either
5`repr(primitive)`, where `primitive` is an unsigned integer type, or `container(T)`, where `T`
6implements the [`BitContainer`] trait.
7
8The generated bitfield struct provides access to its fields through the methods of the [`BitField`] trait.
9
10Each field type must implement [`FieldType`], which defines its default size and the type used
11for storage. The default size can be overridden with the `#[bits(N)]` attribute on individual fields.
12
13The macro also allows customizing the generated struct: any trait can be forwarded via `derives`,
14while only certain common traits can be requested via `impls`.
15
16See the [`#[bitfield]`](crate::bitfield) documentation for all available macro arguments and options.
17
18## Example: basic usage
19```
20use fray::{bitfield, BitField};
21
22#[bitfield(repr(u8), impls(debug), derives(Clone, Copy))]
23pub struct DeviceFlags {
24    powered_on: bool,
25    error: bool,
26    tx_enabled: bool,
27    rx_enabled: bool,
28    #[bits(3)]
29    priority: u8,
30    #[bits(1)]
31    reserved: (),
32}
33
34fn main() {
35    let mut flags = DeviceFlags::new();
36
37    flags
38        .with::<powered_on>(true)
39        .with::<tx_enabled>(true)
40        .with::<priority>(5);
41
42    assert!(flags.get::<powered_on>());
43    assert!(flags.get::<tx_enabled>());
44    assert_eq!(flags.get::<priority>(), 5);
45
46    assert!(!flags.get::<error>());
47    flags.set::<error>(true);
48    assert!(flags.get::<error>());
49
50    let debug_fmt = format!("{:?}", flags);
51    let expected = "DeviceFlags { powered_on: true, error: true, tx_enabled: true, rx_enabled: false, priority: 5, reserved: () }";
52    assert_eq!(debug_fmt, expected);
53
54    let flags_copy = flags;
55
56    // DeviceFlags use LSB0 ordering, so the literal is written
57    // with the least-significant bit on the right.
58    assert_eq!(flags.into_inner(), 0b0_101_0_1_1_1);
59    //                               | |   | | | |
60    //                               | |   | | | powered_on
61    //                               | |   | | error
62    //                               | |   | tx_enabled
63    //                               | |   rx_enabled
64    //                               | priority
65    //                               reserved
66}
67```
68## Example: custom field type
69```
70use fray::{bitfield, BitField, FieldType};
71
72#[repr(u8)]
73#[derive(Clone, Copy, Debug, PartialEq)]
74pub enum PriorityLevel {
75    Low = 0,
76    Medium = 1,
77    High = 2,
78    Critical = 3,
79}
80
81// Requiered for try_get
82impl TryFrom<u8> for PriorityLevel {
83    type Error = u8;
84
85    fn try_from(value: u8) -> Result<Self, Self::Error> {
86        Ok(match value {
87            0 => Self::Low,
88            1 => Self::Medium,
89            2 => Self::High,
90            3 => Self::Critical,
91            value => return Err(value)
92        })
93    }
94}
95
96// Requiered for set/with
97impl From<PriorityLevel> for u8 {
98    fn from(value: PriorityLevel) -> Self {
99        value as u8
100    }
101}
102
103// Requiered for being accepted as field type in struct declaration
104impl FieldType for PriorityLevel {
105    const SIZE: usize = 3;
106    type BitsType = u8;
107}
108
109#[bitfield(repr(u8))]
110pub struct DeviceFlags {
111    powered_on: bool,
112    error: bool,
113    tx_enabled: bool,
114    rx_enabled: bool,
115    priority: PriorityLevel,
116    #[bits(1)]
117    reserved: (),
118}
119
120fn main() {
121    let mut flags = DeviceFlags::new();
122
123    flags.with::<powered_on>(true)
124        .with::<priority>(PriorityLevel::High)
125        .with::<error>(true);
126
127    assert!(flags.get::<powered_on>());
128    assert!(flags.get::<error>());
129    assert_eq!(flags.try_get::<priority>(), Ok(PriorityLevel::High));
130}
131```
132
133## Example: nested
134```
135use fray::{BitFieldImpl, BitField, FieldType, bitfield};
136
137// https://datatracker.ietf.org/doc/html/rfc9293#name-header-format
138#[bitfield(repr(u16), bitorder(msb0))]
139pub struct TcpHeader {
140    #[bits(4)]
141    DOffset: u8,
142    #[bits(4)]
143    Rsrvd: (),
144    flags: ControlBits,
145}
146
147#[bitfield(repr(u8), bitorder(msb0))]
148pub struct ControlBits {
149    CWR: bool,
150    ECE: bool,
151    URG: bool,
152    ACK: bool,
153    PSH: bool,
154    RST: bool,
155    SYN: bool,
156    FIN: bool,
157}
158
159impl FieldType for ControlBits {
160    const SIZE: usize = 8;
161
162    type BitsType = u8;
163}
164
165impl From<ControlBits> for u8 {
166    fn from(value: ControlBits) -> Self {
167        value.into_inner()
168    }
169}
170
171impl From<u8> for ControlBits {
172    fn from(value: u8) -> Self {
173        <Self as BitFieldImpl>::Container::from(value).into()
174    }
175}
176
177fn main() {
178    let mut control_bits = ControlBits::new();
179    control_bits.with::<FIN>(true).with::<ACK>(true);
180    let mut tcp_header = TcpHeader::new();
181    tcp_header.set::<flags>(control_bits);
182    tcp_header.set::<DOffset>(8);
183
184    let flags = tcp_header.get::<flags>();
185    assert!(flags.get::<FIN>());
186    assert!(flags.get::<ACK>());
187
188    assert_eq!(tcp_header.get::<DOffset>(), 8);
189
190    assert_eq!(tcp_header.into_inner(), 0x8011)
191}
192```
193
194# How It Works
195
196A [`BitField`] is essentially a wrapper around a [`BitContainer`]. The [`BitField`] trait provides
197high-level methods for interacting with the bitfield, while the underlying [`BitContainer`] defines
198how values are stored and retrieved at a low level.
199
200To interact with individual fields, each field must also be defined and implement the
201[`Field<T>`](crate::Field) trait (where T is the type of the bitfield).
202
203The [`BitField`] trait is **sealed** and is automatically implemented for all types that implement
204[`BitFieldImpl`].
205
206The [`#[bitfield]`](crate::bitfield) attribute macro generates a struct that implements [`BitField`],
207as well as structs implementing [`Field`] for each of its fields.
208*/
209
210#![allow(clippy::needless_doctest_main)]
211#![no_std]
212#![warn(missing_docs)]
213#![warn(missing_debug_implementations)]
214
215#[cfg(test)]
216extern crate std;
217
218mod bitcontainers;
219pub use bitcontainers::{BitContainer, BitContainerFor, iterable};
220mod bitfields;
221pub use bitfields::{BitField, BitFieldImpl, Field, FieldType, bitorder};
222pub mod debug;
223
224/// Attribute macro for defining bitfield structures.
225///
226/// Applying `#[bitfield]` to a struct:
227/// - Generates a new wrapper struct around the chosen [`BitContainer`],
228/// - Implements [`BitField`] for this wrapper,
229/// - Generates a zero-sized [`Field`] type for each field,
230///   which provides metadata such as offset and size.
231///
232/// The macro also determines field offsets according to the selected bit order.
233/// When the [`bitorder`](#-bitorderorder) argument is used, it controls how
234/// bit positions are assigned (`lsb0` by default, or `msb0` if specified).
235/// The chosen order is reflected in [`BitFieldImpl::BitOrder`],
236/// which serves purely as a marker and has no functional impact.
237///
238/// This macro is the primary way end-users create bitfield types.
239///
240/// # Arguments
241///
242/// The attribute accepts a comma-separated list of options:
243///
244/// - **`container(<Type>)`**
245///   Specifies a custom container type to hold the bitfield data.
246///   - **Mandatory** unless `repr` is specified.
247///   - Mutually exclusive with `repr`.
248///   - The type must implement the [`BitContainer`] trait,
249///     which defines how bits are accessed and modified.
250///   - Example: `container(Foobar<u8>)`, where `Foobar<u8>` implement [`BitContainer`].
251///
252/// - **`repr(<primitive>)`**
253///   Shorthand for using [`BitIterableContainer<primitive>`](crate::iterable::BitIterableContainer)
254///   as the underlying bitfield container.
255///   - **Mandatory** unless `container` is specified.
256///   - Mutually exclusive with `container`.
257///   - Allowed primitives: `u8`, `u16`, `u32`, `u64`.
258///
259/// - **`impls(<trait>)`**
260///   Requests generation of custom `impl` blocks for specific traits.
261///   Unlike `derives`, this is restricted to a predefined set of
262///   implementations provided by the macro itself.
263///   - Currently supported values:
264///     - `debug`: generates a custom [`Debug`] implementation
265///       that prints the bitfield fields and their values.
266///
267///       ```
268///       use fray::{bitfield, BitField};
269///
270///       #[bitfield(repr(u8), impls(debug))]
271///       pub struct MyFlags {
272///           a: bool,
273///           #[bits(7)]
274///           b: u8,
275///       }
276///
277///       fn main() {
278///           let mut flags = MyFlags::new();
279///           flags.with::<a>(true).with::<b>(53);
280///           // Custom Debug output (example):
281///           // MyFlags { a: true, b: 53 }
282///           let fmt_debug = format!("{:?}", flags);
283///           assert_eq!(fmt_debug, "MyFlags { a: true, b: 53 }");
284///       }
285///       ```
286///   - Optional.
287///   - Can be repeated (once multiple traits are available).
288///
289/// - **`derives(<traits...>)`**
290///   Adds `#[derive(...)]` to the generated bitfield struct.
291///   - Optional.
292///
293/// - **`bitorder(<order>)`**
294///   Defines the bit numbering order within the container.
295///   - Supported values:
296///     - `lsb0`: Least Significant Bit first (default).
297///     - `msb0`: Most Significant Bit first.
298///   - Sets [`BitFieldImpl::BitOrder`] to [`LSB0`](crate::bitorder::LSB0) or [`MSB0`](crate::bitorder::MSB0).
299///   - Optional.
300///
301///   ```
302///   use fray::bitfield;
303///
304///   #[bitfield(repr(u8), bitorder(msb0))]
305///   pub struct Flags {
306///       a: bool,
307///       #[bits(3)]
308///       b: u8,
309///       #[bits(4)]
310///       c: u8,
311///   }
312///   // Bit index:  7   6   5   4   3   2   1   0
313///   //             │   │   │   │   │   │   │   │
314///   // Binary:    [c0][c1][c2][c3][b0][b1][b2][a]   <- bitorder(lsb0)
315///   // Binary:    [a] [b2][b1][b0][c3][c2][c1][c0]  <- bitorder(msb0)
316///   ```
317///
318///   > **Note:**
319///   > The `bitorder` option changes how field offsets are assigned within the bitfield,
320///   > but it does **not** alter the internal bit layout or significance of the underlying
321///   > type.
322///
323pub use fray_macro::bitfield;
324
325#[doc = include_str!("../../README.md")]
326#[cfg(doctest)]
327struct ReadmeDoctests;