Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/bit_field/src/lib.rs
5392 views
1
// Copyright 2018 The ChromiumOS Authors
2
// Use of this source code is governed by a BSD-style license that can be
3
// found in the LICENSE file.
4
5
//! This crate provides a `#[bitfield]` attribute macro for defining structs in
6
//! a packed binary representation that supports access to ranges of bits.
7
//!
8
//! We conceptualize one of these structs as a sequence of bits 0..N. The bits
9
//! are grouped into fields in the order specified by a struct written by the
10
//! caller. The `#[bitfield]` attribute rewrites the caller's struct into a
11
//! private byte array representation with public getter and setter methods for
12
//! each field.
13
//!
14
//! Byte order: note that we consider the bit `i` to be the `i % 8`'th least
15
//! significant bit in the `i / 8`'th byte of the struct.
16
//!
17
//! The total number of bits N is required to be a multiple of 8 (this is
18
//! checked at compile time).
19
//!
20
//! # Examples
21
//!
22
//! The following invocation builds a struct with a total size of 32 bits or 4
23
//! bytes. It places field `a` in the least significant bit of the first byte,
24
//! field `b` in the next three least significant bits, field `c` in the
25
//! remaining four most significant bits of the first byte, and field `d`
26
//! spanning the next three bytes. The least significant byte of `d` will be
27
//! held in the second byte of our struct, adjacent to the byte holding the
28
//! first three fields.
29
//!
30
//! ```
31
//! use bit_field::*;
32
//!
33
//! #[bitfield]
34
//! pub struct MyFourBytes {
35
//! a: B1,
36
//! b: B3,
37
//! c: B4,
38
//! d: B24,
39
//! }
40
//! ```
41
//!
42
//! ```text
43
//! less significant
44
//! / more significant
45
//! / /
46
//! (first byte) (second byte) / (third) / (fourth byte)
47
//! 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
48
//! | \ / \_ _/ \_______________________ _______________________/
49
//! a b c less significant d more significant
50
//! ```
51
//!
52
//! The code emitted by the `#[bitfield]` macro for this struct is as follows.
53
//! Note that the field getters and setters use whichever of `u8`, `u16`, `u32`,
54
//! `u64` is the smallest while being at least as large as the number of bits in
55
//! the field.
56
//!
57
//! ```ignore
58
//! impl MyFourBytes {
59
//! // Initializes all fields to 0.
60
//! pub fn new() -> Self;
61
//!
62
//! // Field getters and setters:
63
//! pub fn get_a(&self) -> u8;
64
//! pub fn set_a(&mut self, val: u8);
65
//! pub fn get_b(&self) -> u8;
66
//! pub fn set_b(&mut self, val: u8);
67
//! pub fn get_c(&self) -> u8;
68
//! pub fn set_c(&mut self, val: u8);
69
//! pub fn get_d(&self) -> u32;
70
//! pub fn set_d(&mut self, val: u32);
71
//!
72
//! // Bit-level accessors:
73
//! pub fn get_bit(&self, offset: usize) -> bool;
74
//! pub fn set_bit(&mut self, offset: usize, val: bool);
75
//! pub fn get(&self, offset: usize, width: u8) -> u64;
76
//! pub fn set(&mut self, offset: usize, width: u8, val: u64);
77
//! }
78
//! ```
79
//!
80
//! # Bit field specifier types
81
//!
82
//! Field types may be specified as B1 through B64, or alternatively as
83
//! BitField1 through BitField64 in code that benefits from the clarification.
84
//!
85
//! Fields may also be specified as `bool`, which is laid out equivalently to
86
//! `B1` but with accessors that use `bool` rather than `u8`.
87
//!
88
//! ```
89
//! use bit_field::*;
90
//!
91
//! #[bitfield]
92
//! pub struct MyFourBytes {
93
//! a: bool,
94
//! b: B3,
95
//! c: B4,
96
//! d: B24,
97
//! }
98
//! ```
99
//!
100
//! Fields may be user-defined single element tuple struct with primitive types. Use must specify
101
//! the width with `#[bits = N]`. This should be used to improve type safety.
102
//!
103
//! ```
104
//! use bit_field::*;
105
//!
106
//! #[bitfield]
107
//! #[bits = 60]
108
//! struct AddressField(u64);
109
//!
110
//! impl AddressField {
111
//! pub fn new(addr: u64) -> AddressField {
112
//! AddressField(addr >> 4)
113
//! }
114
//!
115
//! pub fn get_addr(&self) -> u64 {
116
//! self.0 << 4
117
//! }
118
//! }
119
//! ```
120
//!
121
//! Finally, fields may be of user-defined enum types. The enum must satisfy one of the following
122
//! requirements.
123
//!
124
//! The enum has `#[bits = N]` attributes with it. `N` will be the width of the field. The getter
125
//! function of this enum field will return `Result<EnumType, u64>`. Raw value that does not match
126
//! any variant will result in an `Err(u64)`.
127
//!
128
//! ```
129
//! use bit_field::*;
130
//!
131
//! #[bitfield]
132
//! #[bits = 2]
133
//! #[derive(Debug, PartialEq)]
134
//! enum TwoBits {
135
//! Zero = 0b00,
136
//! One = 0b01,
137
//! Three = 0b11,
138
//! }
139
//!
140
//! #[bitfield]
141
//! struct Struct {
142
//! prefix: BitField1,
143
//! two_bits: TwoBits,
144
//! suffix: BitField5,
145
//! }
146
//! ```
147
//!
148
//! The enum has a number of variants which is a power of 2 and the discriminant values
149
//! (explicit or implicit) are 0 through (2^n)-1. In this case the generated
150
//! getter and setter are defined in terms of the given enum type.
151
//!
152
//! ```
153
//! use bit_field::*;
154
//!
155
//! #[bitfield]
156
//! #[derive(Debug, PartialEq)]
157
//! enum TwoBits {
158
//! Zero = 0b00,
159
//! One = 0b01,
160
//! Two = 0b10,
161
//! Three = 0b11,
162
//! }
163
//!
164
//! #[bitfield]
165
//! struct Struct {
166
//! prefix: BitField1,
167
//! two_bits: TwoBits,
168
//! suffix: BitField5,
169
//! }
170
//! ```
171
//!
172
//! An optional `#[bits = N]` attribute may be used to document the number of
173
//! bits in any field. This is intended for fields of enum type whose name does
174
//! not clearly indicate the number of bits. The attribute is optional but helps
175
//! make it possible to read off the field sizes directly from the definition of
176
//! a bitfield struct.
177
//!
178
//! ```
179
//! use bit_field::*;
180
//!
181
//! #[bitfield]
182
//! #[derive(Debug, PartialEq)]
183
//! enum WhoKnows {
184
//! Zero = 0b00,
185
//! One = 0b01,
186
//! Two = 0b10,
187
//! Three = 0b11,
188
//! }
189
//!
190
//! #[bitfield]
191
//! struct Struct {
192
//! prefix: BitField1,
193
//! #[bits = 2]
194
//! two_bits: WhoKnows,
195
//! suffix: BitField5,
196
//! }
197
//! ```
198
//!
199
//! # Derives
200
//!
201
//! Derives may be specified and are applied to the data structure post
202
//! rewriting by the macro.
203
//!
204
//! ```
205
//! use bit_field::*;
206
//!
207
//! #[bitfield]
208
//! #[derive(Copy, Clone)]
209
//! pub struct ExampleWithDerives {
210
//! car: B4,
211
//! cdr: B4,
212
//! }
213
//! ```
214
//!
215
//! # Compile time checks
216
//!
217
//! If the total size is not a multiple of 8 bits, you will receive an error
218
//! message at compile time mentioning:
219
//!
220
//! > the trait `bit_field::checks::TotalSizeIsMultipleOfEightBits` is not implemented
221
//!
222
//! ```compile_fail
223
//! use bit_field::*;
224
//!
225
//! #[bitfield]
226
//! pub struct Broken {
227
//! field_a: B1,
228
//! field_b: B3,
229
//! field_c: B6,
230
//! }
231
//! ```
232
//!
233
//! If a bitfield enum has discriminants that are outside the range 0 through
234
//! (2^n)-1, it will be caught at compile time.
235
//!
236
//! ```compile_fail
237
//! use bit_field::*;
238
//!
239
//! #[bitfield]
240
//! enum Broken {
241
//! Zero = 0b00,
242
//! One = 0b01,
243
//! Two = 0b10,
244
//! Nine = 0b1001, // error
245
//! }
246
//! ```
247
//!
248
//! If the value provided in a #[bits = N] attribute does not match the real
249
//! number of bits in that field, it will be caught.
250
//!
251
//! ```compile_fail
252
//! use bit_field::*;
253
//!
254
//! #[bitfield]
255
//! #[derive(Debug, PartialEq)]
256
//! enum OneBit {
257
//! No = 0,
258
//! Yes = 1,
259
//! }
260
//!
261
//! #[bitfield]
262
//! struct Struct {
263
//! #[bits = 4] // error
264
//! two_bits: OneBit,
265
//! padding: BitField7,
266
//! }
267
//! ```
268
269
use std::fmt;
270
use std::fmt::Display;
271
272
pub use bit_field_derive::bitfield;
273
274
/// Error type for bit field get.
275
#[derive(Debug)]
276
pub struct Error {
277
type_name: &'static str,
278
val: u64,
279
}
280
281
impl Error {
282
pub fn new(type_name: &'static str, val: u64) -> Error {
283
Error { type_name, val }
284
}
285
286
pub fn raw_val(&self) -> u64 {
287
self.val
288
}
289
}
290
291
impl Display for Error {
292
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
293
write!(
294
f,
295
"enum field type {} has a bad value {}",
296
self.type_name, self.val
297
)
298
}
299
}
300
301
impl std::error::Error for Error {}
302
303
#[doc(hidden)]
304
pub trait BitFieldSpecifier {
305
// Width of this field in bits.
306
const FIELD_WIDTH: u8;
307
// Date type for setter of this field.
308
// For any field, we use the closest u* type. e.g. FIELD_WIDTH <= 8 will
309
// have defulat type of u8.
310
// It's possible to write a custom specifier and use i8.
311
type SetterType;
312
// Data type for getter of this field. For enums, it will be Result<EnumType, SetterType>.
313
// For others, it will be the same as SetterType.
314
type GetterType;
315
316
fn from_u64(val: u64) -> Self::GetterType;
317
fn into_u64(val: Self::SetterType) -> u64;
318
}
319
320
// Largest u64 representable by this bit field specifier. Used by generated code
321
// in bit_field_derive.
322
#[doc(hidden)]
323
#[inline]
324
pub fn max<T: BitFieldSpecifier>() -> u64 {
325
if T::FIELD_WIDTH < 64 {
326
(1 << T::FIELD_WIDTH) - 1
327
} else {
328
u64::MAX
329
}
330
}
331
332
// Defines bit_field::BitField0 through bit_field::BitField64.
333
bit_field_derive::define_bit_field_specifiers!();
334
335
impl BitFieldSpecifier for bool {
336
const FIELD_WIDTH: u8 = 1;
337
type SetterType = bool;
338
type GetterType = bool;
339
340
#[inline]
341
fn from_u64(val: u64) -> Self::GetterType {
342
val > 0
343
}
344
345
#[inline]
346
fn into_u64(val: Self::SetterType) -> u64 {
347
val as u64
348
}
349
}
350
351
// Instantiated by the generated code to prove that the total size of fields is
352
// a multiple of 8 bits.
353
#[doc(hidden)]
354
pub struct Check<T: checks::TotalSizeIsMultipleOfEightBits> {
355
marker: std::marker::PhantomData<T>,
356
}
357
358
mod checks {
359
pub trait TotalSizeIsMultipleOfEightBits {}
360
impl TotalSizeIsMultipleOfEightBits for [u8; 0] {}
361
}
362
363