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
/*!
A type-safe and ergonomic library for working with bitfields.
A bitfield is defined using the [`#[bitfield]`](crate::bitfield) attribute macro and must specify either
`repr(primitive)`, where `primitive` is an unsigned integer type, or `container(T)`, where `T`
implements the [`BitContainer`] trait.
The generated bitfield struct provides access to its fields through the methods of the [`BitField`] trait.
Each field type must implement [`FieldType`], which defines its default size and the type used
for storage. The default size can be overridden with the `#[bits(N)]` attribute on individual fields.
The macro also allows customizing the generated struct: any trait can be forwarded via `derives`,
while only certain common traits can be requested via `impls`.
See the [`#[bitfield]`](crate::bitfield) documentation for all available macro arguments and options.
## Example: basic usage
```
use fray::{bitfield, BitField};
#[bitfield(repr(u8), impls(debug), derives(Clone, Copy))]
pub struct DeviceFlags {
powered_on: bool,
error: bool,
tx_enabled: bool,
rx_enabled: bool,
#[bits(3)]
priority: u8,
#[bits(1)]
reserved: (),
}
fn main() {
let mut flags = DeviceFlags::new();
flags
.with::<powered_on>(true)
.with::<tx_enabled>(true)
.with::<priority>(5);
assert!(flags.get::<powered_on>());
assert!(flags.get::<tx_enabled>());
assert_eq!(flags.get::<priority>(), 5);
assert!(!flags.get::<error>());
flags.set::<error>(true);
assert!(flags.get::<error>());
let debug_fmt = format!("{:?}", flags);
let expected = "DeviceFlags { powered_on: true, error: true, tx_enabled: true, rx_enabled: false, priority: 5, reserved: () }";
assert_eq!(debug_fmt, expected);
let flags_copy = flags;
// DeviceFlags use LSB0 ordering, so the literal is written
// with the least-significant bit on the right.
assert_eq!(flags.into_inner(), 0b0_101_0_1_1_1);
// | | | | | |
// | | | | | powered_on
// | | | | error
// | | | tx_enabled
// | | rx_enabled
// | priority
// reserved
}
```
## Example: custom field type
```
use fray::{bitfield, BitField, FieldType};
#[repr(u8)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum PriorityLevel {
Low = 0,
Medium = 1,
High = 2,
Critical = 3,
}
// Requiered for try_get
impl TryFrom<u8> for PriorityLevel {
type Error = u8;
fn try_from(value: u8) -> Result<Self, Self::Error> {
Ok(match value {
0 => Self::Low,
1 => Self::Medium,
2 => Self::High,
3 => Self::Critical,
value => return Err(value)
})
}
}
// Requiered for set/with
impl From<PriorityLevel> for u8 {
fn from(value: PriorityLevel) -> Self {
value as u8
}
}
// Requiered for being accepted as field type in struct declaration
impl FieldType for PriorityLevel {
const SIZE: usize = 3;
type BitsType = u8;
}
#[bitfield(repr(u8))]
pub struct DeviceFlags {
powered_on: bool,
error: bool,
tx_enabled: bool,
rx_enabled: bool,
priority: PriorityLevel,
#[bits(1)]
reserved: (),
}
fn main() {
let mut flags = DeviceFlags::new();
flags.with::<powered_on>(true)
.with::<priority>(PriorityLevel::High)
.with::<error>(true);
assert!(flags.get::<powered_on>());
assert!(flags.get::<error>());
assert_eq!(flags.try_get::<priority>(), Ok(PriorityLevel::High));
}
```
## Example: nested
```
use fray::{BitFieldImpl, BitField, FieldType, bitfield};
// https://datatracker.ietf.org/doc/html/rfc9293#name-header-format
#[bitfield(repr(u16), bitorder(msb0))]
pub struct TcpHeader {
#[bits(4)]
DOffset: u8,
#[bits(4)]
Rsrvd: (),
flags: ControlBits,
}
#[bitfield(repr(u8), bitorder(msb0))]
pub struct ControlBits {
CWR: bool,
ECE: bool,
URG: bool,
ACK: bool,
PSH: bool,
RST: bool,
SYN: bool,
FIN: bool,
}
impl FieldType for ControlBits {
const SIZE: usize = 8;
type BitsType = u8;
}
impl From<ControlBits> for u8 {
fn from(value: ControlBits) -> Self {
value.into_inner()
}
}
impl From<u8> for ControlBits {
fn from(value: u8) -> Self {
<Self as BitFieldImpl>::Container::from(value).into()
}
}
fn main() {
let mut control_bits = ControlBits::new();
control_bits.with::<FIN>(true).with::<ACK>(true);
let mut tcp_header = TcpHeader::new();
tcp_header.set::<flags>(control_bits);
tcp_header.set::<DOffset>(8);
let flags = tcp_header.get::<flags>();
assert!(flags.get::<FIN>());
assert!(flags.get::<ACK>());
assert_eq!(tcp_header.get::<DOffset>(), 8);
assert_eq!(tcp_header.into_inner(), 0x8011)
}
```
# How It Works
A [`BitField`] is essentially a wrapper around a [`BitContainer`]. The [`BitField`] trait provides
high-level methods for interacting with the bitfield, while the underlying [`BitContainer`] defines
how values are stored and retrieved at a low level.
To interact with individual fields, each field must also be defined and implement the
[`Field<T>`](crate::Field) trait (where T is the type of the bitfield).
The [`BitField`] trait is **sealed** and is automatically implemented for all types that implement
[`BitFieldImpl`].
The [`#[bitfield]`](crate::bitfield) attribute macro generates a struct that implements [`BitField`],
as well as structs implementing [`Field`] for each of its fields.
*/
extern crate std;
pub use ;
pub use ;
/// Attribute macro for defining bitfield structures.
///
/// Applying `#[bitfield]` to a struct:
/// - Generates a new wrapper struct around the chosen [`BitContainer`],
/// - Implements [`BitField`] for this wrapper,
/// - Generates a zero-sized [`Field`] type for each field,
/// which provides metadata such as offset and size.
///
/// The macro also determines field offsets according to the selected bit order.
/// When the [`bitorder`](#-bitorderorder) argument is used, it controls how
/// bit positions are assigned (`lsb0` by default, or `msb0` if specified).
/// The chosen order is reflected in [`BitFieldImpl::BitOrder`],
/// which serves purely as a marker and has no functional impact.
///
/// This macro is the primary way end-users create bitfield types.
///
/// # Arguments
///
/// The attribute accepts a comma-separated list of options:
///
/// - **`container(<Type>)`**
/// Specifies a custom container type to hold the bitfield data.
/// - **Mandatory** unless `repr` is specified.
/// - Mutually exclusive with `repr`.
/// - The type must implement the [`BitContainer`] trait,
/// which defines how bits are accessed and modified.
/// - Example: `container(Foobar<u8>)`, where `Foobar<u8>` implement [`BitContainer`].
///
/// - **`repr(<primitive>)`**
/// Shorthand for using [`BitIterableContainer<primitive>`](crate::iterable::BitIterableContainer)
/// as the underlying bitfield container.
/// - **Mandatory** unless `container` is specified.
/// - Mutually exclusive with `container`.
/// - Allowed primitives: `u8`, `u16`, `u32`, `u64`.
///
/// - **`impls(<trait>)`**
/// Requests generation of custom `impl` blocks for specific traits.
/// Unlike `derives`, this is restricted to a predefined set of
/// implementations provided by the macro itself.
/// - Currently supported values:
/// - `debug`: generates a custom [`Debug`] implementation
/// that prints the bitfield fields and their values.
///
/// ```
/// use fray::{bitfield, BitField};
///
/// #[bitfield(repr(u8), impls(debug))]
/// pub struct MyFlags {
/// a: bool,
/// #[bits(7)]
/// b: u8,
/// }
///
/// fn main() {
/// let mut flags = MyFlags::new();
/// flags.with::<a>(true).with::<b>(53);
/// // Custom Debug output (example):
/// // MyFlags { a: true, b: 53 }
/// let fmt_debug = format!("{:?}", flags);
/// assert_eq!(fmt_debug, "MyFlags { a: true, b: 53 }");
/// }
/// ```
/// - Optional.
/// - Can be repeated (once multiple traits are available).
///
/// - **`derives(<traits...>)`**
/// Adds `#[derive(...)]` to the generated bitfield struct.
/// - Optional.
///
/// - **`bitorder(<order>)`**
/// Defines the bit numbering order within the container.
/// - Supported values:
/// - `lsb0`: Least Significant Bit first (default).
/// - `msb0`: Most Significant Bit first.
/// - Sets [`BitFieldImpl::BitOrder`] to [`LSB0`](crate::bitorder::LSB0) or [`MSB0`](crate::bitorder::MSB0).
/// - Optional.
///
/// ```
/// use fray::bitfield;
///
/// #[bitfield(repr(u8), bitorder(msb0))]
/// pub struct Flags {
/// a: bool,
/// #[bits(3)]
/// b: u8,
/// #[bits(4)]
/// c: u8,
/// }
/// // Bit index: 7 6 5 4 3 2 1 0
/// // │ │ │ │ │ │ │ │
/// // Binary: [c0][c1][c2][c3][b0][b1][b2][a] <- bitorder(lsb0)
/// // Binary: [a] [b2][b1][b0][c3][c2][c1][c0] <- bitorder(msb0)
/// ```
///
/// > **Note:**
/// > The `bitorder` option changes how field offsets are assigned within the bitfield,
/// > but it does **not** alter the internal bit layout or significance of the underlying
/// > type.
///
pub use bitfield;
;