Something went wrong. Try again.
Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864// 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::<u16, 5>::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::<VALUE>()`: `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<Config, Error> {//! // 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<Bounded<u32, 1>> for Power {//! fn from(v: Bounded<u32, 1>) -> Self {//! match *v {//! 0 => Power::Off,//! _ => Power::On,//! }//! }//! }//!//! impl From<Power> for Bounded<u32, 1> {//! 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<Bounded<u32, 2>> for Mode {//! type Error = u32;//!//! fn try_from(v: Bounded<u32, 2>) -> Result<Self, u32> {//! match *v {//! 0 => Ok(Mode::Low),//! 1 => Ok(Mode::High),//! 2 => Ok(Mode::Auto),//! n => Err(n),//! }//! }//! }//!//! impl From<Mode> for Bounded<u32, 2> {//! fn from(m: Mode) -> Self {//! match m {//! Mode::Low => Bounded::<u32, _>::new::<0>(),//! Mode::High => Bounded::<u32, _>::new::<1>(),//! Mode::Auto => Bounded::<u32, _>::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<u8> = $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::<ALIGN_BOTTOM, { $hi + 1 - $lo } >() }
#[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 [<with_ $field>](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 [<with_ $field>](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 [<with_const_ $field>]<const VALUE: $storage>(self) -> Self { self.[<__with_ $field>]( ::kernel::num::Bounded::<$storage, { $hi + 1 - $lo }>::new::<VALUE>() ) }
$(#[doc = $doc])* #[doc = "Sets this field to the given `value`."] #[inline(always)] $vis fn [<with_ $field>]<T>( 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 [<try_with_ $field>]<T>( self, value: T, ) -> ::kernel::error::Result<Self> 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("<raw>", &::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<Bounded<u64, 4>> for MemoryType { type Error = u64; fn try_from(value: Bounded<u64, 4>) -> Result<Self, Self::Error> { match value.get() { 0 => Ok(MemoryType::Unmapped), 1 => Ok(MemoryType::Normal), 2 => Ok(MemoryType::Device), 3 => Ok(MemoryType::Reserved), _ => Err(value.get()), } } }
impl From<MemoryType> for Bounded<u64, 4> { fn from(mt: MemoryType) -> Bounded<u64, 4> { Bounded::from_expr(mt as u64) } }
#[derive(Debug, Clone, Copy, PartialEq)] enum Priority { Low = 0, Medium = 1, High = 2, Critical = 3, }
impl From<Bounded<u16, 2>> for Priority { fn from(value: Bounded<u16, 2>) -> Self { match value & 0x3 { 0 => Priority::Low, 1 => Priority::Medium, 2 => Priority::High, _ => Priority::Critical, } } }
impl From<Priority> for Bounded<u16, 2> { fn from(p: Priority) -> Bounded<u16, 2> { 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); }}