// SPDX-License-Identifier: GPL-2.0 //! Support for defining bitfields as Rust structures. //! //! The [`bitfield!`](kernel::bitfield!) macro declares integer types that are split into distinct //! bit fields of arbitrary length. Each field is typed using [`Bounded`](kernel::num::Bounded) to //! ensure values are properly validated and to avoid implicit data loss. //! //! # Example //! //! ```rust //! use kernel::bitfield; //! use kernel::num::Bounded; //! //! bitfield! { //! pub struct Rgb(u16) { //! 15:11 blue; //! 10:5 green; //! 4:0 red; //! } //! } //! //! // Valid value for the `blue` field. //! let blue = Bounded::::new::<0x18>(); //! //! // Setters can be chained. Values ranges are checked at compile-time. //! let color = Rgb::zeroed() //! // Compile-time bounds check of constant value. //! .with_const_red::<0x10>() //! .with_const_green::<0x1f>() //! // A `Bounded` can also be passed. //! .with_blue(blue); //! //! assert_eq!(color.red(), 0x10); //! assert_eq!(color.green(), 0x1f); //! assert_eq!(color.blue(), 0x18); //! assert_eq!( //! color.into_raw(), //! (0x18 << Rgb::BLUE_SHIFT) + (0x1f << Rgb::GREEN_SHIFT) + 0x10, //! ); //! //! // Convert to/from the backing storage type. //! let raw: u16 = color.into(); //! assert_eq!(Rgb::from(raw), color); //! ``` //! //! # Syntax //! //! ```text //! bitfield! { //! #[attributes] //! // Documentation for `Name`. //! pub struct Name(storage_type) { //! // `field_1` documentation. //! hi:lo field_1; //! // `field_2` documentation. //! hi:lo field_2 => ConvertedType; //! // `field_3` documentation. //! hi:lo field_3 ?=> ConvertedType; //! ... //! } //! } //! ``` //! //! - `storage_type`: The underlying unsigned integer type ([`u8`], [`u16`], [`u32`], [`u64`]). //! Signed integer storage types are not supported. //! - `hi:lo`: Bit range (inclusive), where `hi >= lo`. //! - `=> Type`: Optional infallible conversion (see [below](#infallible-conversion-)). //! - `?=> Type`: Optional fallible conversion (see [below](#fallible-conversion-)). //! - Documentation strings and attributes are optional. //! //! # Generated code //! //! Each field is internally represented as a [`Bounded`] parameterized by its bit width. Field //! values can either be set/retrieved directly, or converted from/to another type. //! //! The use of [`Bounded`] for each field enforces bounds-checking (at build time or runtime) of //! every value assigned to a field. This ensures that data is never accidentally truncated. //! //! The macro generates the bitfield type, [`From`] and [`Into`] implementations for its storage //! type, as well as [`Debug`] and [`Zeroable`](pin_init::Zeroable) implementations. //! //! For each field, it also generates: //! //! - `field()`: Getter method for the field value. //! - `with_field(value)`: Infallible setter; the argument type must fit within the field's width. //! - `with_const_field::()`: `const` setter; the value is validated at compile time. //! Usually shorter to use than `with_field` for constant values as it doesn't require //! constructing a [`Bounded`]. //! - `try_with_field(value)`: Fallible setter. Returns an error if the value is out of range. //! - `FIELD_MASK`, `FIELD_SHIFT`, `FIELD_RANGE`: Constants for manual bit manipulation. //! //! # Reserved names for field identifiers //! //! Field identifiers are used to generate methods and associated constants on the bitfield type. //! For a field named `field`, the macro may generate methods named `field`, `with_field`, //! `with_const_field`, `try_with_field`, `__field` and `__with_field`, as well as constants named //! `FIELD_MASK`, `FIELD_SHIFT` and `FIELD_RANGE`. //! //! Therefore, field identifiers must not use names that would collide with generated items for //! any field in the same bitfield. The following prefixes are thus reserved for field identifiers: //! //! - `with_` //! - `const_` //! - `try_with_` //! - `__` //! //! The field identifiers `from_raw`, `into_raw`, and `into` are also reserved. //! //! In addition, field identifiers should follow Rust `snake_case` conventions, since the associated //! constants are generated by uppercasing the field name. //! //! # Implicit conversions //! //! Types that fit entirely within a field's bit width can be used directly with setters. For //! example, [`bool`] works with single-bit fields, and [`u8`] works with 8-bit fields: //! //! ```rust //! use kernel::bitfield; //! //! bitfield! { //! pub struct Flags(u32) { //! 15:8 byte_field; //! 0:0 flag; //! } //! } //! //! let flags = Flags::zeroed() //! .with_byte_field(0x42_u8) //! .with_flag(true); //! //! assert_eq!(flags.into_raw(), (0x42 << Flags::BYTE_FIELD_SHIFT) | 1); //! ``` //! //! # Runtime bounds checking //! //! When a value is not known at compile time, use `try_with_field()` to check bounds at runtime: //! //! ```rust //! use kernel::bitfield; //! //! bitfield! { //! pub struct Config(u8) { //! 3:0 nibble; //! } //! } //! //! fn set_nibble(config: Config, value: u8) -> Result { //! // Returns `EOVERFLOW` if `value > 0xf`. //! config.try_with_nibble(value) //! } //! # Ok::<(), Error>(()) //! ``` //! //! # Type conversion //! //! Fields can be automatically converted to/from a custom type using `=>` (infallible) or `?=>` //! (fallible). The custom type must implement the appropriate [`From`] or [`TryFrom`] traits with //! [`Bounded`]. //! //! ## Infallible conversion (`=>`) //! //! Use this when all possible bit patterns of a field map to valid values: //! //! ```rust //! use kernel::bitfield; //! use kernel::num::Bounded; //! //! #[derive(Debug, Clone, Copy, PartialEq)] //! enum Power { //! Off, //! On, //! } //! //! impl From> for Power { //! fn from(v: Bounded) -> Self { //! match *v { //! 0 => Power::Off, //! _ => Power::On, //! } //! } //! } //! //! impl From for Bounded { //! fn from(p: Power) -> Self { //! (p as u32 != 0).into() //! } //! } //! //! bitfield! { //! pub struct Control(u32) { //! 0:0 power => Power; //! } //! } //! //! let ctrl = Control::zeroed().with_power(Power::On); //! assert_eq!(ctrl.power(), Power::On); //! ``` //! //! ## Fallible conversion (`?=>`) //! //! Use this when some bit patterns of a field are invalid. The getter returns a [`Result`]: //! //! ```rust //! use kernel::bitfield; //! use kernel::num::Bounded; //! //! #[derive(Debug, Clone, Copy, PartialEq)] //! enum Mode { //! Low = 0, //! High = 1, //! Auto = 2, //! // 3 is invalid //! } //! //! impl TryFrom> for Mode { //! type Error = u32; //! //! fn try_from(v: Bounded) -> Result { //! match *v { //! 0 => Ok(Mode::Low), //! 1 => Ok(Mode::High), //! 2 => Ok(Mode::Auto), //! n => Err(n), //! } //! } //! } //! //! impl From for Bounded { //! fn from(m: Mode) -> Self { //! match m { //! Mode::Low => Bounded::::new::<0>(), //! Mode::High => Bounded::::new::<1>(), //! Mode::Auto => Bounded::::new::<2>(), //! } //! } //! } //! //! bitfield! { //! pub struct Config(u32) { //! 1:0 mode ?=> Mode; //! } //! } //! //! let cfg = Config::zeroed().with_mode(Mode::Auto); //! assert_eq!(cfg.mode(), Ok(Mode::Auto)); //! //! // Invalid bit pattern returns an error. //! assert_eq!(Config::from(0b11).mode(), Err(3)); //! ``` //! //! # Bits outside of declared fields //! //! Bits of the storage type that are not part of any declared field are preserved by the setter //! methods, and can only be modified through `from_raw` or the [`From`] implementation from the //! storage type. //! //! ```rust //! use kernel::bitfield; //! //! bitfield! { //! pub struct Sparse(u8) { //! 7:6 high; //! // Bits 5:1 are not covered by any field. //! 0:0 low; //! } //! } //! //! // Set the gap bits via `from_raw`, then mutate the declared fields. //! let val = Sparse::from_raw(0b0010_1010) //! .with_const_high::<0b11>() //! .with_low(true); //! //! // Bits 5:1 are unchanged. //! assert_eq!(val.into_raw(), 0b1110_1011); //! ``` //! //! # Signed field values //! //! Bitfield storage types are unsigned. Since field getter methods return a [`Bounded`] of the //! storage type, fields are also unsigned by default. //! //! If a field needs to encode a signed value, use a custom conversion type with `=>` or `?=>` to //! perform the sign interpretation explicitly. //! //! [`Bounded`]: kernel::num::Bounded /// Defines a bitfield struct with bounds-checked accessors for individual bit ranges. /// /// See the [`mod@kernel::bitfield`] module for full documentation and examples. #[macro_export] macro_rules! bitfield { // Entry point defining the bitfield struct, its implementations and its field accessors. ( $(#[$attr:meta])* $vis:vis struct $name:ident($storage:ty) { $($fields:tt)* } ) => { $crate::bitfield!(@core #[allow(non_camel_case_types)] $(#[$attr])* $vis $name $storage ); $crate::bitfield!(@fields $vis $name $storage { $($fields)* }); }; // All rules below are helpers. // Defines the wrapper `$name` type and its conversions from/to the storage type. (@core $(#[$attr:meta])* $vis:vis $name:ident $storage:ty) => { $(#[$attr])* #[repr(transparent)] #[derive(Clone, Copy, PartialEq, Eq)] $vis struct $name { inner: $storage, } #[allow(dead_code)] impl $name { /// Creates a bitfield from a raw value. #[inline(always)] $vis const fn from_raw(value: $storage) -> Self { Self{ inner: value } } /// Turns this bitfield into its raw value. /// /// This is similar to the [`From`] implementation, but is shorter to invoke in /// most cases. #[inline(always)] $vis const fn into_raw(self) -> $storage { self.inner } } // SAFETY: `$storage` is `Zeroable` and `$name` is transparent. unsafe impl ::pin_init::Zeroable for $name {} impl ::core::convert::From<$name> for $storage { #[inline(always)] fn from(val: $name) -> $storage { val.into_raw() } } impl ::core::convert::From<$storage> for $name { #[inline(always)] fn from(val: $storage) -> $name { Self::from_raw(val) } } }; // Definitions requiring knowledge of individual fields: private and public field accessors, // and `Debug` implementation. (@fields $vis:vis $name:ident $storage:ty { $($(#[doc = $doc:expr])* $hi:literal:$lo:literal $field:ident $(?=> $try_into_type:ty)? $(=> $into_type:ty)? ; )* } ) => { #[allow(dead_code)] impl $name { $( $crate::bitfield!(@private_field_accessors $vis $name $storage : $hi:$lo $field); $crate::bitfield!( @public_field_accessors $(#[doc = $doc])* $vis $name $storage : $hi:$lo $field $(?=> $try_into_type)? $(=> $into_type)? ); )* } $crate::bitfield!(@debug $name { $($field;)* }); }; // Private field accessors working with the exact `Bounded` type for the field. ( @private_field_accessors $vis:vis $name:ident $storage:ty : $hi:tt:$lo:tt $field:ident ) => { ::kernel::macros::paste!( $vis const [<$field:upper _RANGE>]: ::core::ops::RangeInclusive = $lo..=$hi; $vis const [<$field:upper _MASK>]: $storage = ((((1 << $hi) - 1) << 1) + 1) - ((1 << $lo) - 1); $vis const [<$field:upper _SHIFT>]: u32 = $lo; ); ::kernel::macros::paste!( #[inline(always)] fn [<__ $field>](self) -> ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }> { // Left shift to align the field's MSB with the storage MSB. const ALIGN_TOP: u32 = $storage::BITS - ($hi + 1); // Right shift to move the top-aligned field to bit 0 of the storage. const ALIGN_BOTTOM: u32 = ALIGN_TOP + $lo; // Extract the field using two shifts. `Bounded::shr` produces the correctly-sized // output type. let val = ::kernel::num::Bounded::<$storage, { $storage::BITS }>::from( self.inner << ALIGN_TOP ); val.shr::() } #[inline(always)] const fn [<__with_ $field>]( mut self, value: ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>, ) -> Self { const MASK: $storage = <$name>::[<$field:upper _MASK>]; const SHIFT: u32 = <$name>::[<$field:upper _SHIFT>]; let value = value.get() << SHIFT; self.inner = (self.inner & !MASK) | value; self } ); }; // Public accessors for fields infallibly (`=>`) converted to a type. ( @public_field_accessors $(#[doc = $doc:expr])* $vis:vis $name:ident $storage:ty : $hi:literal:$lo:literal $field:ident => $into_type:ty ) => { ::kernel::macros::paste!( $(#[doc = $doc])* #[doc = "Returns the value of this field."] #[inline(always)] $vis fn $field(self) -> $into_type { self.[<__ $field>]().into() } $(#[doc = $doc])* #[doc = "Sets this field to the given `value`."] #[inline(always)] $vis fn [](self, value: $into_type) -> Self { self.[<__with_ $field>](value.into()) } ); }; // Public accessors for fields fallibly (`?=>`) converted to a type. ( @public_field_accessors $(#[doc = $doc:expr])* $vis:vis $name:ident $storage:ty : $hi:tt:$lo:tt $field:ident ?=> $try_into_type:ty ) => { ::kernel::macros::paste!( $(#[doc = $doc])* #[doc = "Returns the value of this field."] #[inline(always)] $vis fn $field(self) -> ::core::result::Result< $try_into_type, <$try_into_type as ::core::convert::TryFrom< ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }> >>::Error > { self.[<__ $field>]().try_into() } $(#[doc = $doc])* #[doc = "Sets this field to the given `value`."] #[inline(always)] $vis fn [](self, value: $try_into_type) -> Self { self.[<__with_ $field>](value.into()) } ); }; // Public accessors for fields not converted to a type. ( @public_field_accessors $(#[doc = $doc:expr])* $vis:vis $name:ident $storage:ty : $hi:tt:$lo:tt $field:ident ) => { ::kernel::macros::paste!( $(#[doc = $doc])* #[doc = "Returns the value of this field."] #[inline(always)] $vis fn $field(self) -> ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }> { self.[<__ $field>]() } $(#[doc = $doc])* #[doc = "Sets this field to the compile-time constant `VALUE`."] #[inline(always)] $vis const fn [](self) -> Self { self.[<__with_ $field>]( ::kernel::num::Bounded::<$storage, { $hi + 1 - $lo }>::new::() ) } $(#[doc = $doc])* #[doc = "Sets this field to the given `value`."] #[inline(always)] $vis fn []( self, value: T, ) -> Self where T: ::core::convert::Into<::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>>, { self.[<__with_ $field>](value.into()) } $(#[doc = $doc])* #[doc = "Tries to set this field to `value`, returning an error if it is out of range."] #[inline(always)] $vis fn []( self, value: T, ) -> ::kernel::error::Result where T: ::kernel::num::TryIntoBounded<$storage, { $hi + 1 - $lo }>, { Ok( self.[<__with_ $field>]( value.try_into_bounded().ok_or(::kernel::error::code::EOVERFLOW)? ) ) } ); }; // `Debug` implementation. (@debug $name:ident { $($field:ident;)* }) => { impl ::kernel::fmt::Debug for $name { #[inline] fn fmt(&self, f: &mut ::kernel::fmt::Formatter<'_>) -> ::kernel::fmt::Result { f.debug_struct(stringify!($name)) .field("", &::kernel::prelude::fmt!("{:#x}", self.inner)) $( .field(stringify!($field), &self.$field()) )* .finish() } } }; } #[cfg(CONFIG_RUST_BITFIELD_KUNIT_TEST)] #[::kernel::macros::kunit_tests(rust_kernel_bitfield)] mod tests { use core::convert::TryFrom; use pin_init::Zeroable; use kernel::num::Bounded; // Enum types for testing `=>` and `?=>` conversions. #[derive(Debug, Clone, Copy, PartialEq)] enum MemoryType { Unmapped = 0, Normal = 1, Device = 2, Reserved = 3, } impl TryFrom> for MemoryType { type Error = u64; fn try_from(value: Bounded) -> Result { match value.get() { 0 => Ok(MemoryType::Unmapped), 1 => Ok(MemoryType::Normal), 2 => Ok(MemoryType::Device), 3 => Ok(MemoryType::Reserved), _ => Err(value.get()), } } } impl From for Bounded { fn from(mt: MemoryType) -> Bounded { Bounded::from_expr(mt as u64) } } #[derive(Debug, Clone, Copy, PartialEq)] enum Priority { Low = 0, Medium = 1, High = 2, Critical = 3, } impl From> for Priority { fn from(value: Bounded) -> Self { match value & 0x3 { 0 => Priority::Low, 1 => Priority::Medium, 2 => Priority::High, _ => Priority::Critical, } } } impl From for Bounded { fn from(p: Priority) -> Bounded { Bounded::from_expr(p as u16) } } bitfield! { struct TestU64(u64) { 63:63 field_63; 61:52 field_61_52; 51:16 field_51_16; 15:12 field_15_12 ?=> MemoryType; 11:9 field_11_9; 1:1 field_1; 0:0 field_0; } } bitfield! { struct TestU16(u16) { 15:8 field_15_8; 7:4 field_7_4; // Partial overlap with `field_5_4`. 5:4 field_5_4 => Priority; 3:1 field_3_1; 0:0 field_0; } } bitfield! { struct TestU8(u8) { 7:0 field_7_0; // Full byte overlap. 7:4 field_7_4; 3:2 field_3_2; 1:1 field_1; 0:0 field_0; } } // Single and multi-bit fields basic access. #[test] fn test_basic_access() { // `TestU64`. let mut val = TestU64::zeroed(); assert_eq!(val.into_raw(), 0x0); val = val.with_field_0(true); assert!(val.field_0().into_bool()); assert_eq!(val.into_raw(), 0x1); val = val.with_field_1(true); assert!(val.field_1().into_bool()); val = val.with_field_1(false); assert!(!val.field_1().into_bool()); assert_eq!(val.into_raw(), 0x1); val = val.with_const_field_11_9::<0x5>(); assert_eq!(val.field_11_9(), 0x5); assert_eq!(val.into_raw(), 0xA01); val = val.with_const_field_51_16::<0x123456>(); assert_eq!(val.field_51_16(), 0x123456); assert_eq!(val.into_raw(), 0x0012_3456_0A01); const MAX_FIELD_51_16: u64 = ::kernel::bits::genmask_u64(0..=35); val = val.with_const_field_51_16::<{ MAX_FIELD_51_16 }>(); assert_eq!(val.field_51_16(), MAX_FIELD_51_16); val = val.with_const_field_61_52::<0x3FF>(); assert_eq!(val.field_61_52(), 0x3FF); val = val.with_field_63(true); assert!(val.field_63().into_bool()); // `TestU16`. let mut val = TestU16::zeroed(); assert_eq!(val.into_raw(), 0x0); val = val.with_field_0(true); assert!(val.field_0().into_bool()); assert_eq!(val.into_raw(), 0x1); val = val.with_const_field_3_1::<0x5>(); assert_eq!(val.field_3_1(), 0x5); assert_eq!(val.into_raw(), 0xB); val = val.with_const_field_7_4::<0xA>(); assert_eq!(val.field_7_4(), 0xA); assert_eq!(val.into_raw(), 0xAB); val = val.with_const_field_15_8::<0x42>(); assert_eq!(val.field_15_8(), 0x42); assert_eq!(val.into_raw(), 0x42AB); // `TestU8`. let mut val = TestU8::zeroed(); assert_eq!(val.into_raw(), 0x0); val = val.with_field_0(true); assert!(val.field_0().into_bool()); assert_eq!(val.into_raw(), 0x1); val = val.with_field_1(true); assert!(val.field_1().into_bool()); assert_eq!(val.into_raw(), 0x3); val = val.with_const_field_3_2::<0x3>(); assert_eq!(val.field_3_2(), 0x3); assert_eq!(val.into_raw(), 0xF); val = val.with_const_field_7_4::<0xA>(); assert_eq!(val.field_7_4(), 0xA); assert_eq!(val.into_raw(), 0xAF); } // `=>` infallible conversion. #[test] fn test_infallible_conversion() { let mut val = TestU16::zeroed(); val = val.with_field_5_4(Priority::Low); assert_eq!(val.field_5_4(), Priority::Low); assert_eq!(val.into_raw() & 0x30, 0x00); val = val.with_field_5_4(Priority::Medium); assert_eq!(val.field_5_4(), Priority::Medium); assert_eq!(val.into_raw() & 0x30, 0x10); val = val.with_field_5_4(Priority::High); assert_eq!(val.field_5_4(), Priority::High); assert_eq!(val.into_raw() & 0x30, 0x20); val = val.with_field_5_4(Priority::Critical); assert_eq!(val.field_5_4(), Priority::Critical); assert_eq!(val.into_raw() & 0x30, 0x30); } // `?=>` fallible conversion. #[test] fn test_fallible_conversion() { let mut val = TestU64::zeroed(); val = val.with_field_15_12(MemoryType::Unmapped); assert_eq!(val.field_15_12(), Ok(MemoryType::Unmapped)); val = val.with_field_15_12(MemoryType::Normal); assert_eq!(val.field_15_12(), Ok(MemoryType::Normal)); val = val.with_field_15_12(MemoryType::Device); assert_eq!(val.field_15_12(), Ok(MemoryType::Device)); val = val.with_field_15_12(MemoryType::Reserved); assert_eq!(val.field_15_12(), Ok(MemoryType::Reserved)); // `field_15_12` is 4 bits wide (0-15); `MemoryType` only covers 0-3, so 4-15 return `Err`. let raw = (val.into_raw() & !::kernel::bits::genmask_u64(12..=15)) | (0x7 << 12); assert_eq!(TestU64::from_raw(raw).field_15_12(), Err(0x7)); } // Test that setting an overlapping field affects the overlapped one as expected. #[test] fn test_overlapping_fields() { let mut val = TestU16::zeroed(); val = val.with_field_5_4(Priority::High); // High == 2 == 0b10. assert_eq!(val.field_5_4(), Priority::High); assert_eq!(val.field_7_4(), 0x2); // Bits 7:6 == 0, bits 5:4 == 0b10. val = val.with_const_field_7_4::<0xF>(); assert_eq!(val.field_7_4(), 0xF); assert_eq!(val.field_5_4(), Priority::Critical); // Bits 5:4 == 0b11. // `field_7_0` should encompass all other fields. let mut val = TestU8::zeroed() .with_field_0(true) .with_field_1(true) .with_const_field_3_2::<0x3>() .with_const_field_7_4::<0xA>(); assert_eq!(val.into_raw(), 0xAF); val = val.with_field_7_0(0x55); assert_eq!(val.field_7_0(), 0x55); assert!(val.field_0().into_bool()); assert!(!val.field_1().into_bool()); assert_eq!(val.field_3_2(), 0x1); assert_eq!(val.field_7_4(), 0x5); } // Checks that bits not mapped to any field are left untouched. #[test] fn test_unallocated_bits() { let gap_bits = (1u64 << 62) | 0x1FC; let set_all_fields = |val: TestU64| { val.with_field_63(true) .with_const_field_61_52::<0x155>() .with_const_field_51_16::<0x123456>() .with_field_15_12(MemoryType::Device) .with_const_field_11_9::<0x5>() .with_field_1(true) .with_field_0(true) }; // Gap bits to 0. let val = set_all_fields(TestU64::from_raw(0)); assert_eq!(val.into_raw() & gap_bits, 0); // Gap bits to 1. let val = set_all_fields(TestU64::from_raw(gap_bits)); assert_eq!(val.into_raw() & gap_bits, gap_bits); } #[test] fn test_try_with() { let val = TestU64::zeroed().try_with_field_51_16(0x123456).unwrap(); assert_eq!(val.field_51_16(), 0x123456); let err = TestU64::zeroed().try_with_field_51_16(u64::MAX); assert_eq!(err, Err(::kernel::error::code::EOVERFLOW)); let val = TestU64::zeroed() .try_with_field_51_16(0xABCDEF) .and_then(|p| p.try_with_field_0(1)) .unwrap(); assert_eq!(val.field_51_16(), 0xABCDEF); assert!(val.field_0().into_bool()); } // `from_raw`/`into_raw` and `From`/`Into` round-trips. #[test] fn test_raw() { let raw: u64 = 0xBFF0_0000_3123_3E03; let val = TestU64::from_raw(raw); assert_eq!(u64::from(val), raw); assert!(val.field_0().into_bool()); assert!(val.field_1().into_bool()); assert_eq!(val.field_11_9(), 0x7); assert_eq!(val.field_51_16(), 0x3123); assert_eq!(val.field_15_12(), Ok(MemoryType::Reserved)); assert_eq!(val.field_61_52(), 0x3FF); assert!(val.field_63().into_bool()); let raw: u16 = 0x42AB; let val = TestU16::from_raw(raw); assert_eq!(u16::from(val), raw); assert!(val.field_0().into_bool()); assert_eq!(val.field_3_1(), 0x5); assert_eq!(val.field_7_4(), 0xA); assert_eq!(val.field_15_8(), 0x42); let raw: u8 = 0xAF; let val = TestU8::from_raw(raw); assert_eq!(u8::from(val), raw); assert!(val.field_0().into_bool()); assert!(val.field_1().into_bool()); assert_eq!(val.field_3_2(), 0x3); assert_eq!(val.field_7_4(), 0xA); assert_eq!(val.field_7_0(), 0xAF); } }