bitfield: Documentation and simplifications

Changes in this CL:

- Crate-level documentation for bit_field crate!

- Use absolute paths within generated code so that the caller is no
  longer required to have various implementation details from the
  bit_field crate in scope.

- Check that the total number of bits is a multiple of 8. Previously, it
  would generate compilable code that panicked when invoking accessors.

- Provide B0 .. B64 as shorthand for BitField0 .. BitField64.

- Use `bool` as the bool specifier rather than BitFieldBool.

- Disallow BitFieldSpecifier impls outside the bit_field crate.

- Simplify declaration of the BitFieldN types by replacing the recursive
  macro_rules with a simpler procedural macro.

TEST=`cargo test` in bit_field and in bit_field_derive

Change-Id: Ica9347bc89901de85f74366edd038fb5d8042ee6
Reviewed-on: https://chromium-review.googlesource.com/1382578
Commit-Ready: David Tolnay <dtolnay@chromium.org>
Tested-by: David Tolnay <dtolnay@chromium.org>
Reviewed-by: Jingkui Wang <jkwang@google.com>
This commit is contained in:
David Tolnay 2018-12-18 16:26:50 -08:00 committed by chrome-bot
parent c13a68eecb
commit f71764228a
2 changed files with 319 additions and 159 deletions

View file

@ -119,19 +119,27 @@ fn get_struct_def(
field_types.push(ty.clone());
}
// It will be something like:
// "(BitField1::FIELD_WIDTH + BitField3::FIELD_WIDTH + BitField4::FIELD_WIDTH) / 8)"
let data_size_in_bytes = quote! {
( #( #field_types::FIELD_WIDTH as usize )+* ) / 8
// `(BitField1::FIELD_WIDTH + BitField3::FIELD_WIDTH + ...)`
let data_size_in_bits = quote! {
(
#(
<#field_types as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
)+*
)
};
quote! {
#[repr(C)]
#vis struct #name {
data: [u8; #data_size_in_bytes],
data: [u8; #data_size_in_bits / 8],
}
impl #name {
pub fn new() -> #name {
let _: ::bit_field::Check<[u8; #data_size_in_bits % 8]>;
#name {
data: [0; #data_size_in_bytes],
data: [0; #data_size_in_bits / 8],
}
}
}
@ -142,7 +150,7 @@ fn get_struct_def(
fn get_fields_impl(fields: &[(String, TokenStream)]) -> Vec<TokenStream> {
let mut impls = Vec::new();
// This vec keeps track of types before this field, used to generate the offset.
let mut current_types = vec![quote!(BitField0)];
let mut current_types = vec![quote!(::bit_field::BitField0)];
for &(ref name, ref ty) in fields {
// Creating two copies of current types. As they are going to be moved in quote!.
@ -151,17 +159,17 @@ fn get_fields_impl(fields: &[(String, TokenStream)]) -> Vec<TokenStream> {
let getter_ident = Ident::new(format!("get_{}", name).as_str(), Span::call_site());
let setter_ident = Ident::new(format!("set_{}", name).as_str(), Span::call_site());
impls.push(quote! {
pub fn #getter_ident(&self) -> <#ty as BitFieldSpecifier>::DefaultFieldType {
let offset = #(#ct0::FIELD_WIDTH as usize)+*;
let val = self.get(offset, #ty::FIELD_WIDTH);
<#ty as BitFieldSpecifier>::from_u64(val)
pub fn #getter_ident(&self) -> <#ty as ::bit_field::BitFieldSpecifier>::DefaultFieldType {
let offset = #(<#ct0 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize)+*;
let val = self.get(offset, <#ty as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH);
<#ty as ::bit_field::BitFieldSpecifier>::from_u64(val)
}
pub fn #setter_ident(&mut self, val: <#ty as BitFieldSpecifier>::DefaultFieldType) {
let val = <#ty as BitFieldSpecifier>::into_u64(val);
debug_assert!(val <= #ty::field_max());
let offset = #(#ct1::FIELD_WIDTH as usize)+*;
self.set(offset, #ty::FIELD_WIDTH, val)
pub fn #setter_ident(&mut self, val: <#ty as ::bit_field::BitFieldSpecifier>::DefaultFieldType) {
let val = <#ty as ::bit_field::BitFieldSpecifier>::into_u64(val);
debug_assert!(val <= ::bit_field::max::<#ty>());
let offset = #(<#ct1 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize)+*;
self.set(offset, <#ty as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH, val)
}
});
current_types.push(ty.clone());
@ -203,14 +211,14 @@ fn get_tests_impl(struct_name: &Ident, fields: &[(String, TokenStream)]) -> Vec<
impls.push(quote! {
#[test]
fn test_total_size() {
let total_size = #(#field_types::FIELD_WIDTH as usize)+*;
let total_size = #(<#field_types as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize)+*;
assert_eq!(total_size % 8, 0);
}
});
impls.push(quote! {
#[test]
fn test_bits_boundary() {
let fields_sizes = vec![#(#field_types2::FIELD_WIDTH as usize),*];
let fields_sizes = vec![#(<#field_types2 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize),*];
let mut sum = 0usize;
for s in fields_sizes {
if sum % 64 == 0 {
@ -236,14 +244,14 @@ fn get_tests_impl(struct_name: &Ident, fields: &[(String, TokenStream)]) -> Vec<
#[test]
fn #testname() {
let mut a = #struct_name::new();
let val = <#ty as BitFieldSpecifier>::into_u64(a.#getter_ident());
let val = <#ty as ::bit_field::BitFieldSpecifier>::into_u64(a.#getter_ident());
assert_eq!(val, 0);
let val = <#ty as BitFieldSpecifier>::from_u64(#ty::field_max());
let val = <#ty as ::bit_field::BitFieldSpecifier>::from_u64(::bit_field::max::<#ty>());
a.#setter_ident(val);
let val = <#ty as BitFieldSpecifier>::into_u64(a.#getter_ident());
assert_eq!(val, #ty::field_max());
let val = <#ty as ::bit_field::BitFieldSpecifier>::into_u64(a.#getter_ident());
assert_eq!(val, ::bit_field::max::<#ty>());
}
});
}
@ -318,6 +326,54 @@ fn get_bits_impl(name: &Ident) -> TokenStream {
}
}
// Only intended to be used from the bit_field crate. This macro emits the
// marker types bit_field::BitField0 through bit_field::BitField64.
#[proc_macro]
#[doc(hidden)]
pub fn define_bit_field_specifiers(_input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let mut code = TokenStream::new();
for width in 0u8..=64 {
let span = Span::call_site();
let long_name = Ident::new(&format!("BitField{}", width), span);
let short_name = Ident::new(&format!("B{}", width), span);
let default_field_type = if width <= 8 {
quote!(u8)
} else if width <= 16 {
quote!(u16)
} else if width <= 32 {
quote!(u32)
} else {
quote!(u64)
};
code.extend(quote! {
pub struct #long_name;
pub use self::#long_name as #short_name;
impl BitFieldSpecifier for #long_name {
const FIELD_WIDTH: u8 = #width;
type DefaultFieldType = #default_field_type;
#[inline]
fn from_u64(val: u64) -> Self::DefaultFieldType {
val as Self::DefaultFieldType
}
#[inline]
fn into_u64(val: Self::DefaultFieldType) -> u64 {
val as u64
}
}
impl private::Sealed for #long_name {}
});
}
code.into()
}
#[cfg(test)]
mod tests {
use super::*;
@ -335,18 +391,27 @@ mod tests {
let expected = quote! {
#[derive(Clone)]
#[repr(C)]
struct MyBitField {
data: [u8; (BitField1::FIELD_WIDTH as usize
+ BitField2::FIELD_WIDTH as usize
+ BitField5::FIELD_WIDTH as usize)
data: [u8; (<BitField1 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
+ <BitField2 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
+ <BitField5 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize)
/ 8],
}
impl MyBitField {
pub fn new() -> MyBitField {
let _: ::bit_field::Check<[
u8;
(<BitField1 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
+ <BitField2 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
+ <BitField5 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize)
% 8
]>;
MyBitField {
data: [0; (BitField1::FIELD_WIDTH as usize
+ BitField2::FIELD_WIDTH as usize
+ BitField5::FIELD_WIDTH as usize)
data: [0; (<BitField1 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
+ <BitField2 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
+ <BitField5 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize)
/ 8],
}
}
@ -402,42 +467,44 @@ mod tests {
}
}
impl MyBitField {
pub fn get_a(&self) -> <BitField1 as BitFieldSpecifier>::DefaultFieldType {
let offset = BitField0::FIELD_WIDTH as usize;
let val = self.get(offset, BitField1::FIELD_WIDTH);
<BitField1 as BitFieldSpecifier>::from_u64(val)
pub fn get_a(&self) -> <BitField1 as ::bit_field::BitFieldSpecifier>::DefaultFieldType {
let offset = <::bit_field::BitField0 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize;
let val = self.get(offset, <BitField1 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH);
<BitField1 as ::bit_field::BitFieldSpecifier>::from_u64(val)
}
pub fn set_a(&mut self, val: <BitField1 as BitFieldSpecifier>::DefaultFieldType) {
let val = <BitField1 as BitFieldSpecifier>::into_u64(val);
debug_assert!(val <= BitField1::field_max());
let offset = BitField0::FIELD_WIDTH as usize;
self.set(offset, BitField1::FIELD_WIDTH, val)
pub fn set_a(&mut self, val: <BitField1 as ::bit_field::BitFieldSpecifier>::DefaultFieldType) {
let val = <BitField1 as ::bit_field::BitFieldSpecifier>::into_u64(val);
debug_assert!(val <= ::bit_field::max::<BitField1>());
let offset = <::bit_field::BitField0 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize;
self.set(offset, <BitField1 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH, val)
}
pub fn get_b(&self) -> <BitField2 as BitFieldSpecifier>::DefaultFieldType {
let offset = BitField0::FIELD_WIDTH as usize + BitField1::FIELD_WIDTH as usize;
let val = self.get(offset, BitField2::FIELD_WIDTH);
<BitField2 as BitFieldSpecifier>::from_u64(val)
pub fn get_b(&self) -> <BitField2 as ::bit_field::BitFieldSpecifier>::DefaultFieldType {
let offset = <::bit_field::BitField0 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
+ <BitField1 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize;
let val = self.get(offset, <BitField2 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH);
<BitField2 as ::bit_field::BitFieldSpecifier>::from_u64(val)
}
pub fn set_b(&mut self, val: <BitField2 as BitFieldSpecifier>::DefaultFieldType) {
let val = <BitField2 as BitFieldSpecifier>::into_u64(val);
debug_assert!(val <= BitField2::field_max());
let offset = BitField0::FIELD_WIDTH as usize + BitField1::FIELD_WIDTH as usize;
self.set(offset, BitField2::FIELD_WIDTH, val)
pub fn set_b(&mut self, val: <BitField2 as ::bit_field::BitFieldSpecifier>::DefaultFieldType) {
let val = <BitField2 as ::bit_field::BitFieldSpecifier>::into_u64(val);
debug_assert!(val <= ::bit_field::max::<BitField2>());
let offset = <::bit_field::BitField0 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
+ <BitField1 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize;
self.set(offset, <BitField2 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH, val)
}
pub fn get_c(&self) -> <BitField5 as BitFieldSpecifier>::DefaultFieldType {
let offset = BitField0::FIELD_WIDTH as usize
+ BitField1::FIELD_WIDTH as usize
+ BitField2::FIELD_WIDTH as usize;
let val = self.get(offset, BitField5::FIELD_WIDTH);
<BitField5 as BitFieldSpecifier>::from_u64(val)
pub fn get_c(&self) -> <BitField5 as ::bit_field::BitFieldSpecifier>::DefaultFieldType {
let offset = <::bit_field::BitField0 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
+ <BitField1 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
+ <BitField2 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize;
let val = self.get(offset, <BitField5 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH);
<BitField5 as ::bit_field::BitFieldSpecifier>::from_u64(val)
}
pub fn set_c(&mut self, val: <BitField5 as BitFieldSpecifier>::DefaultFieldType) {
let val = <BitField5 as BitFieldSpecifier>::into_u64(val);
debug_assert!(val <= BitField5::field_max());
let offset = BitField0::FIELD_WIDTH as usize
+ BitField1::FIELD_WIDTH as usize
+ BitField2::FIELD_WIDTH as usize;
self.set(offset, BitField5::FIELD_WIDTH, val)
pub fn set_c(&mut self, val: <BitField5 as ::bit_field::BitFieldSpecifier>::DefaultFieldType) {
let val = <BitField5 as ::bit_field::BitFieldSpecifier>::into_u64(val);
debug_assert!(val <= ::bit_field::max::<BitField5>());
let offset = <::bit_field::BitField0 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
+ <BitField1 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
+ <BitField2 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize;
self.set(offset, <BitField5 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH, val)
}
}
impl std::fmt::Debug for MyBitField {
@ -454,17 +521,17 @@ mod tests {
use super::*;
#[test]
fn test_total_size() {
let total_size = BitField1::FIELD_WIDTH as usize
+ BitField2::FIELD_WIDTH as usize
+ BitField5::FIELD_WIDTH as usize;
let total_size = <BitField1 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
+ <BitField2 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
+ <BitField5 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize;
assert_eq!(total_size % 8, 0);
}
#[test]
fn test_bits_boundary() {
let fields_sizes = vec![
BitField1::FIELD_WIDTH as usize,
BitField2::FIELD_WIDTH as usize,
BitField5::FIELD_WIDTH as usize
<BitField1 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize,
<BitField2 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize,
<BitField5 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
];
let mut sum = 0usize;
for s in fields_sizes {
@ -481,32 +548,32 @@ mod tests {
#[test]
fn test_a() {
let mut a = MyBitField::new();
let val = <BitField1 as BitFieldSpecifier>::into_u64(a.get_a());
let val = <BitField1 as ::bit_field::BitFieldSpecifier>::into_u64(a.get_a());
assert_eq!(val, 0);
let val = <BitField1 as BitFieldSpecifier>::from_u64(BitField1::field_max());
let val = <BitField1 as ::bit_field::BitFieldSpecifier>::from_u64(::bit_field::max::<BitField1>());
a.set_a(val);
let val = <BitField1 as BitFieldSpecifier>::into_u64(a.get_a());
assert_eq!(val, BitField1::field_max());
let val = <BitField1 as ::bit_field::BitFieldSpecifier>::into_u64(a.get_a());
assert_eq!(val, ::bit_field::max::<BitField1>());
}
#[test]
fn test_b() {
let mut a = MyBitField::new();
let val = <BitField2 as BitFieldSpecifier>::into_u64(a.get_b());
let val = <BitField2 as ::bit_field::BitFieldSpecifier>::into_u64(a.get_b());
assert_eq!(val, 0);
let val = <BitField2 as BitFieldSpecifier>::from_u64(BitField2::field_max());
let val = <BitField2 as ::bit_field::BitFieldSpecifier>::from_u64(::bit_field::max::<BitField2>());
a.set_b(val);
let val = <BitField2 as BitFieldSpecifier>::into_u64(a.get_b());
assert_eq!(val, BitField2::field_max());
let val = <BitField2 as ::bit_field::BitFieldSpecifier>::into_u64(a.get_b());
assert_eq!(val, ::bit_field::max::<BitField2>());
}
#[test]
fn test_c() {
let mut a = MyBitField::new();
let val = <BitField5 as BitFieldSpecifier>::into_u64(a.get_c());
let val = <BitField5 as ::bit_field::BitFieldSpecifier>::into_u64(a.get_c());
assert_eq!(val, 0);
let val = <BitField5 as BitFieldSpecifier>::from_u64(BitField5::field_max());
let val = <BitField5 as ::bit_field::BitFieldSpecifier>::from_u64(::bit_field::max::<BitField5>());
a.set_c(val);
let val = <BitField5 as BitFieldSpecifier>::into_u64(a.get_c());
assert_eq!(val, BitField5::field_max());
let val = <BitField5 as ::bit_field::BitFieldSpecifier>::into_u64(a.get_c());
assert_eq!(val, ::bit_field::max::<BitField5>());
}
}
};

View file

@ -2,110 +2,203 @@
// 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.
//!
//! ```
//! extern crate bit_field;
//!
//! 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);
//! }
//! ```
//!
//! We also accept `bool` as a field type, which is laid out equivalently to
//! `B1` but with accessors that use `bool` rather than `u8`.
//!
//! ```
//! extern crate bit_field;
//!
//! use bit_field::*;
//!
//! #[bitfield]
//! pub struct MyFourBytes {
//! a: bool,
//! b: B3,
//! c: B4,
//! d: B24,
//! }
//! ```
//!
//! Derives may be specified and are applied to the data structure post
//! rewriting by the macro.
//!
//! ```
//! extern crate bit_field;
//!
//! use bit_field::*;
//!
//! #[bitfield]
//! #[derive(Copy, Clone)]
//! pub struct ExampleWithDerives {
//! car: B4,
//! cdr: B4,
//! }
//! ```
//!
//! 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
//! extern crate bit_field;
//!
//! use bit_field::*;
//!
//! #[bitfield]
//! pub struct Broken {
//! field_a: B1,
//! field_b: B3,
//! field_c: B6,
//! }
//! ```
#[allow(unused_imports)]
#[macro_use]
extern crate bit_field_derive;
pub use bit_field_derive::*;
pub use bit_field_derive::bitfield;
// This functions calculate max possible number represented by `width` bits. If one day this can be
// done in other ways, remove this function. For now, stop worrying and trust constant
// propagation. (checked assembly code, it's a constant when opt-leve >= 2)
fn max_number_of_width(width: u8) -> u64 {
if width < 64 {
(1 << width) - 1
// This trait is sealed and not intended to be implemented outside of the
// bit_field crate.
#[doc(hidden)]
pub trait BitFieldSpecifier: private::Sealed {
// Width of this field in bits.
const FIELD_WIDTH: u8;
// Default data type 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 DefaultFieldType;
fn from_u64(val: u64) -> Self::DefaultFieldType;
fn into_u64(val: Self::DefaultFieldType) -> 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()
}
}
/// BitFieldSpecifier is a group of structs help defining bitfield. It should only
/// be used with the #[bitfield] attribute macro.
/// Example:
/// #[bitfield]
/// pub struct MyBitFieldSchema {
/// field_a : BitField1,
/// field_b : BitField3,
/// field_c : BitField5,
/// field_d : BitField32,
/// }
///
/// bit_field_derive implementation will use the static informations associated
/// with those tyes to generate a struct named MyBitField and getter/setter for
/// all fields.
/// An example getter/setter is:
/// fn get_field_a(&self) -> u8
/// fn set_field_a(&self, val: u8)
/// For larger fields:
/// fn get_field_d(&self) -> u32
/// fn set_field_d(&self, val: u32)
///
/// You can also pass attributes to the defined bitfield structs. Simply do this:
/// #[derive(Clone)]
/// For more details, refer to bit_field_derive.
pub trait BitFieldSpecifier {
/// Width of this field in bits.
const FIELD_WIDTH: u8;
/// Default data type 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 DefaultFieldType;
// Defines bit_field::BitField0 through bit_field::BitField64.
bit_field_derive::define_bit_field_specifiers!();
/// Max value of this field.
fn field_max() -> u64 {
max_number_of_width(Self::FIELD_WIDTH)
}
fn from_u64(val: u64) -> Self::DefaultFieldType;
fn into_u64(val: Self::DefaultFieldType) -> u64;
}
pub struct BitFieldBool;
impl BitFieldSpecifier for BitFieldBool {
impl BitFieldSpecifier for bool {
const FIELD_WIDTH: u8 = 1;
type DefaultFieldType = bool;
#[inline]
fn from_u64(val: u64) -> Self::DefaultFieldType {
val > 0
}
#[inline]
fn into_u64(val: Self::DefaultFieldType) -> u64 {
val as u64
}
}
macro_rules! bitfield_structs {
($t:ty, $min_width:expr, $bt:ident $($bts:ident)*)
=> {
pub struct $bt;
impl BitFieldSpecifier for $bt {
const FIELD_WIDTH: u8 = $min_width;
type DefaultFieldType = $t;
fn from_u64(val: u64) -> Self::DefaultFieldType {
val as Self::DefaultFieldType
}
fn into_u64(val: Self::DefaultFieldType) -> u64 {
val as u64
}
}
bitfield_structs!($t, $min_width + 1, $($bts)*);
};
($t:ty, $min_width:expr,) => {};
impl private::Sealed for bool {}
mod private {
// Seal for the BitFieldSpecifier trait. This seal trait is not nameable
// outside of the bit_field crate, so we are guaranteed that all impls of
// BitFieldSpecifier come from within this crate.
pub trait Sealed {}
}
bitfield_structs! {
u8, 0, BitField0 BitField1 BitField2 BitField3 BitField4 BitField5 BitField6 BitField7 BitField8
// 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>,
}
bitfield_structs! {
u16, 9, BitField9 BitField10 BitField11 BitField12 BitField13 BitField14 BitField15 BitField16
}
bitfield_structs! {
u32, 17, BitField17 BitField18 BitField19 BitField20 BitField21 BitField22 BitField23 BitField24
BitField25 BitField26 BitField27 BitField28 BitField29 BitField30 BitField31 BitField32
}
bitfield_structs! {
u64, 33, BitField33 BitField34 BitField35 BitField36 BitField37 BitField38 BitField39 BitField40 BitField41
BitField42 BitField43 BitField44 BitField45 BitField46 BitField47 BitField48 BitField49 BitField50
BitField51 BitField52 BitField53 BitField54 BitField55 BitField56 BitField57 BitField58
BitField59 BitField60 BitField61 BitField62 BitField63 BitField64
mod checks {
pub trait TotalSizeIsMultipleOfEightBits {}
impl TotalSizeIsMultipleOfEightBits for [u8; 0] {}
}