bit_field/
lib.rs

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
269use std::fmt;
270use std::fmt::Display;
271
272pub use bit_field_derive::bitfield;
273
274/// Error type for bit field get.
275#[derive(Debug)]
276pub struct Error {
277    type_name: &'static str,
278    val: u64,
279}
280
281impl 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
291impl 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
301impl std::error::Error for Error {}
302
303#[doc(hidden)]
304pub 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]
324pub 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.
333bit_field_derive::define_bit_field_specifiers!();
334
335impl 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)]
354pub struct Check<T: checks::TotalSizeIsMultipleOfEightBits> {
355    marker: std::marker::PhantomData<T>,
356}
357
358mod checks {
359    pub trait TotalSizeIsMultipleOfEightBits {}
360    impl TotalSizeIsMultipleOfEightBits for [u8; 0] {}
361}