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;