blob: 1455430b9cccc049665493f23aaeafdbb3c76f7a [file] [log] [blame]
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//! This crate provides a `#[bitfield]` attribute macro for defining structs in
//! a packed binary representation that supports access to ranges of bits.
//!
//! We conceptualize one of these structs as a sequence of bits 0..N. The bits
//! are grouped into fields in the order specified by a struct written by the
//! caller. The `#[bitfield]` attribute rewrites the caller's struct into a
//! private byte array representation with public getter and setter methods for
//! each field.
//!
//! Byte order: note that we consider the bit `i` to be the `i % 8`'th least
//! significant bit in the `i / 8`'th byte of the struct.
//!
//! The total number of bits N is required to be a multiple of 8 (this is
//! checked at compile time).
//!
//! # Examples
//!
//! The following invocation builds a struct with a total size of 32 bits or 4
//! bytes. It places field `a` in the least significant bit of the first byte,
//! field `b` in the next three least significant bits, field `c` in the
//! remaining four most significant bits of the first byte, and field `d`
//! spanning the next three bytes. The least significant byte of `d` will be
//! held in the second byte of our struct, adjacent to the byte holding the
//! first three fields.
//!
//! ```
//! use bit_field::*;
//!
//! #[bitfield]
//! pub struct MyFourBytes {
//! a: B1,
//! b: B3,
//! c: B4,
//! d: B24,
//! }
//! ```
//!
//! ```text
//! less significant
//! / more significant
//! / /
//! (first byte) (second byte) / (third) / (fourth byte)
//! 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
//! | \ / \_ _/ \_______________________ _______________________/
//! a b c less significant d more significant
//! ```
//!
//! The code emitted by the `#[bitfield]` macro for this struct is as follows.
//! Note that the field getters and setters use whichever of `u8`, `u16`, `u32`,
//! `u64` is the smallest while being at least as large as the number of bits in
//! the field.
//!
//! ```ignore
//! impl MyFourBytes {
//! // Initializes all fields to 0.
//! pub fn new() -> Self;
//!
//! // Field getters and setters:
//! pub fn get_a(&self) -> u8;
//! pub fn set_a(&mut self, val: u8);
//! pub fn get_b(&self) -> u8;
//! pub fn set_b(&mut self, val: u8);
//! pub fn get_c(&self) -> u8;
//! pub fn set_c(&mut self, val: u8);
//! pub fn get_d(&self) -> u32;
//! pub fn set_d(&mut self, val: u32);
//!
//! // Bit-level accessors:
//! pub fn get_bit(&self, offset: usize) -> bool;
//! pub fn set_bit(&mut self, offset: usize, val: bool);
//! pub fn get(&self, offset: usize, width: u8) -> u64;
//! pub fn set(&mut self, offset: usize, width: u8, val: u64);
//! }
//! ```
//!
//! # Bit field specifier types
//!
//! Field types may be specified as B1 through B64, or alternatively as
//! BitField1 through BitField64 in code that benefits from the clarification.
//!
//! Fields may also be specified as `bool`, which is laid out equivalently to
//! `B1` but with accessors that use `bool` rather than `u8`.
//!
//! ```
//! use bit_field::*;
//!
//! #[bitfield]
//! pub struct MyFourBytes {
//! a: bool,
//! b: B3,
//! c: B4,
//! d: B24,
//! }
//! ```
//!
//! Fields may be user-defined single element tuple struct with primitive types. Use must specify
//! the width with `#[bits = N]`. This should be used to improve type safety.
//!
//! ```
//! use bit_field::*;
//!
//! #[bitfield]
//! #[bits = 60]
//! struct AddressField(u64);
//!
//! impl AddressField {
//! pub fn new(addr: u64) -> AddressField {
//! AddressField(addr >> 4)
//! }
//!
//! pub fn get_addr(&self) -> u64 {
//! self.0 << 4
//! }
//! }
//!
//! ```
//!
//! Finally, fields may be of user-defined enum types. The enum must satisfy one of the following
//! requirements.
//!
//! The enum has `#[bits = N]` attributes with it. `N` will be the width of the field. The getter
//! function of this enum field will return `Result<EnumType, u64>`. Raw value that does not match
//! any variant will result in an `Err(u64)`.
//!
//! ```
//! use bit_field::*;
//!
//! #[bitfield]
//! #[bits = 2]
//! #[derive(Debug, PartialEq)]
//! enum TwoBits {
//! Zero = 0b00,
//! One = 0b01,
//! Three = 0b11,
//! }
//!
//! #[bitfield]
//! struct Struct {
//! prefix: BitField1,
//! two_bits: TwoBits,
//! suffix: BitField5,
//! }
//! ```
//!
//! The enum has a number of variants which is a power of 2 and the discriminant values
//! (explicit or implicit) are 0 through (2^n)-1. In this case the generated
//! getter and setter are defined in terms of the given enum type.
//!
//! ```
//! use bit_field::*;
//!
//! #[bitfield]
//! #[derive(Debug, PartialEq)]
//! enum TwoBits {
//! Zero = 0b00,
//! One = 0b01,
//! Two = 0b10,
//! Three = 0b11,
//! }
//!
//! #[bitfield]
//! struct Struct {
//! prefix: BitField1,
//! two_bits: TwoBits,
//! suffix: BitField5,
//! }
//! ```
//!
//! An optional `#[bits = N]` attribute may be used to document the number of
//! bits in any field. This is intended for fields of enum type whose name does
//! not clearly indicate the number of bits. The attribute is optional but helps
//! make it possible to read off the field sizes directly from the definition of
//! a bitfield struct.
//!
//! ```
//! use bit_field::*;
//!
//! #[bitfield]
//! #[derive(Debug, PartialEq)]
//! enum WhoKnows {
//! Zero = 0b00,
//! One = 0b01,
//! Two = 0b10,
//! Three = 0b11,
//! }
//!
//! #[bitfield]
//! struct Struct {
//! prefix: BitField1,
//! #[bits = 2]
//! two_bits: WhoKnows,
//! suffix: BitField5,
//! }
//! ```
//!
//! # Derives
//!
//! Derives may be specified and are applied to the data structure post
//! rewriting by the macro.
//!
//! ```
//! use bit_field::*;
//!
//! #[bitfield]
//! #[derive(Copy, Clone)]
//! pub struct ExampleWithDerives {
//! car: B4,
//! cdr: B4,
//! }
//! ```
//!
//! # Compile time checks
//!
//! If the total size is not a multiple of 8 bits, you will receive an error
//! message at compile time mentioning:
//!
//! > the trait `bit_field::checks::TotalSizeIsMultipleOfEightBits` is not implemented
//!
//! ```compile_fail
//! use bit_field::*;
//!
//! #[bitfield]
//! pub struct Broken {
//! field_a: B1,
//! field_b: B3,
//! field_c: B6,
//! }
//! ```
//!
//! If a bitfield enum has discriminants that are outside the range 0 through
//! (2^n)-1, it will be caught at compile time.
//!
//! ```compile_fail
//! use bit_field::*;
//!
//! #[bitfield]
//! enum Broken {
//! Zero = 0b00,
//! One = 0b01,
//! Two = 0b10,
//! Nine = 0b1001, // error
//! }
//! ```
//!
//! If the value provided in a #[bits = N] attribute does not match the real
//! number of bits in that field, it will be caught.
//!
//! ```compile_fail
//! use bit_field::*;
//!
//! #[bitfield]
//! #[derive(Debug, PartialEq)]
//! enum OneBit {
//! No = 0,
//! Yes = 1,
//! }
//!
//! #[bitfield]
//! struct Struct {
//! #[bits = 4] // error
//! two_bits: OneBit,
//! padding: BitField7,
//! }
//! ```
use std::fmt::{self, Display};
pub use bit_field_derive::bitfield;
/// Error type for bit field get.
#[derive(Debug)]
pub struct Error {
type_name: &'static str,
val: u64,
}
impl Error {
pub fn new(type_name: &'static str, val: u64) -> Error {
Error { type_name, val }
}
pub fn raw_val(&self) -> u64 {
self.val
}
}
impl Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"enum field type {} has a bad value {}",
self.type_name, self.val
)
}
}
impl std::error::Error for Error {}
#[doc(hidden)]
pub trait BitFieldSpecifier {
// Width of this field in bits.
const FIELD_WIDTH: u8;
// Date type for setter of this field.
// For any field, we use the closest u* type. e.g. FIELD_WIDTH <= 8 will
// have defulat type of u8.
// It's possible to write a custom specifier and use i8.
type SetterType;
// Data type for getter of this field. For enums, it will be Result<EnumType, SetterType>.
// For others, it will be the same as SetterType.
type GetterType;
fn from_u64(val: u64) -> Self::GetterType;
fn into_u64(val: Self::SetterType) -> u64;
}
// Largest u64 representable by this bit field specifier. Used by generated code
// in bit_field_derive.
#[doc(hidden)]
#[inline]
pub fn max<T: BitFieldSpecifier>() -> u64 {
if T::FIELD_WIDTH < 64 {
(1 << T::FIELD_WIDTH) - 1
} else {
u64::max_value()
}
}
// Defines bit_field::BitField0 through bit_field::BitField64.
bit_field_derive::define_bit_field_specifiers!();
impl BitFieldSpecifier for bool {
const FIELD_WIDTH: u8 = 1;
type SetterType = bool;
type GetterType = bool;
#[inline]
fn from_u64(val: u64) -> Self::GetterType {
val > 0
}
#[inline]
fn into_u64(val: Self::SetterType) -> u64 {
val as u64
}
}
// Instantiated by the generated code to prove that the total size of fields is
// a multiple of 8 bits.
#[doc(hidden)]
pub struct Check<T: checks::TotalSizeIsMultipleOfEightBits> {
marker: std::marker::PhantomData<T>,
}
mod checks {
pub trait TotalSizeIsMultipleOfEightBits {}
impl TotalSizeIsMultipleOfEightBits for [u8; 0] {}
}