kernel/bitfield.rs
1// SPDX-License-Identifier: GPL-2.0
2
3//! Support for defining bitfields as Rust structures.
4//!
5//! The [`bitfield!`](kernel::bitfield!) macro declares integer types that are split into distinct
6//! bit fields of arbitrary length. Each field is typed using [`Bounded`](kernel::num::Bounded) to
7//! ensure values are properly validated and to avoid implicit data loss.
8//!
9//! # Example
10//!
11//! ```rust
12//! use kernel::bitfield;
13//! use kernel::num::Bounded;
14//!
15//! bitfield! {
16//! pub struct Rgb(u16) {
17//! 15:11 blue;
18//! 10:5 green;
19//! 4:0 red;
20//! }
21//! }
22//!
23//! // Valid value for the `blue` field.
24//! let blue = Bounded::<u16, 5>::new::<0x18>();
25//!
26//! // Setters can be chained. Values ranges are checked at compile-time.
27//! let color = Rgb::zeroed()
28//! // Compile-time bounds check of constant value.
29//! .with_const_red::<0x10>()
30//! .with_const_green::<0x1f>()
31//! // A `Bounded` can also be passed.
32//! .with_blue(blue);
33//!
34//! assert_eq!(color.red(), 0x10);
35//! assert_eq!(color.green(), 0x1f);
36//! assert_eq!(color.blue(), 0x18);
37//! assert_eq!(
38//! color.into_raw(),
39//! (0x18 << Rgb::BLUE_SHIFT) + (0x1f << Rgb::GREEN_SHIFT) + 0x10,
40//! );
41//!
42//! // Convert to/from the backing storage type.
43//! let raw: u16 = color.into();
44//! assert_eq!(Rgb::from(raw), color);
45//! ```
46//!
47//! # Syntax
48//!
49//! ```text
50//! bitfield! {
51//! #[attributes]
52//! // Documentation for `Name`.
53//! pub struct Name(storage_type) {
54//! // `field_1` documentation.
55//! hi:lo field_1;
56//! // `field_2` documentation.
57//! hi:lo field_2 => ConvertedType;
58//! // `field_3` documentation.
59//! hi:lo field_3 ?=> ConvertedType;
60//! ...
61//! }
62//! }
63//! ```
64//!
65//! - `storage_type`: The underlying unsigned integer type ([`u8`], [`u16`], [`u32`], [`u64`]).
66//! Signed integer storage types are not supported.
67//! - `hi:lo`: Bit range (inclusive), where `hi >= lo`.
68//! - `=> Type`: Optional infallible conversion (see [below](#infallible-conversion-)).
69//! - `?=> Type`: Optional fallible conversion (see [below](#fallible-conversion-)).
70//! - Documentation strings and attributes are optional.
71//!
72//! # Generated code
73//!
74//! Each field is internally represented as a [`Bounded`] parameterized by its bit width. Field
75//! values can either be set/retrieved directly, or converted from/to another type.
76//!
77//! The use of [`Bounded`] for each field enforces bounds-checking (at build time or runtime) of
78//! every value assigned to a field. This ensures that data is never accidentally truncated.
79//!
80//! The macro generates the bitfield type, [`From`] and [`Into`] implementations for its storage
81//! type, as well as [`Debug`] and [`Zeroable`](pin_init::Zeroable) implementations.
82//!
83//! For each field, it also generates:
84//!
85//! - `field()`: Getter method for the field value.
86//! - `with_field(value)`: Infallible setter; the argument type must fit within the field's width.
87//! - `with_const_field::<VALUE>()`: `const` setter; the value is validated at compile time.
88//! Usually shorter to use than `with_field` for constant values as it doesn't require
89//! constructing a [`Bounded`].
90//! - `try_with_field(value)`: Fallible setter. Returns an error if the value is out of range.
91//! - `FIELD_MASK`, `FIELD_SHIFT`, `FIELD_RANGE`: Constants for manual bit manipulation.
92//!
93//! # Reserved names for field identifiers
94//!
95//! Field identifiers are used to generate methods and associated constants on the bitfield type.
96//! For a field named `field`, the macro may generate methods named `field`, `with_field`,
97//! `with_const_field`, `try_with_field`, `__field` and `__with_field`, as well as constants named
98//! `FIELD_MASK`, `FIELD_SHIFT` and `FIELD_RANGE`.
99//!
100//! Therefore, field identifiers must not use names that would collide with generated items for
101//! any field in the same bitfield. The following prefixes are thus reserved for field identifiers:
102//!
103//! - `with_`
104//! - `const_`
105//! - `try_with_`
106//! - `__`
107//!
108//! The field identifiers `from_raw`, `into_raw`, and `into` are also reserved.
109//!
110//! In addition, field identifiers should follow Rust `snake_case` conventions, since the associated
111//! constants are generated by uppercasing the field name.
112//!
113//! # Implicit conversions
114//!
115//! Types that fit entirely within a field's bit width can be used directly with setters. For
116//! example, [`bool`] works with single-bit fields, and [`u8`] works with 8-bit fields:
117//!
118//! ```rust
119//! use kernel::bitfield;
120//!
121//! bitfield! {
122//! pub struct Flags(u32) {
123//! 15:8 byte_field;
124//! 0:0 flag;
125//! }
126//! }
127//!
128//! let flags = Flags::zeroed()
129//! .with_byte_field(0x42_u8)
130//! .with_flag(true);
131//!
132//! assert_eq!(flags.into_raw(), (0x42 << Flags::BYTE_FIELD_SHIFT) | 1);
133//! ```
134//!
135//! # Runtime bounds checking
136//!
137//! When a value is not known at compile time, use `try_with_field()` to check bounds at runtime:
138//!
139//! ```rust
140//! use kernel::bitfield;
141//!
142//! bitfield! {
143//! pub struct Config(u8) {
144//! 3:0 nibble;
145//! }
146//! }
147//!
148//! fn set_nibble(config: Config, value: u8) -> Result<Config, Error> {
149//! // Returns `EOVERFLOW` if `value > 0xf`.
150//! config.try_with_nibble(value)
151//! }
152//! # Ok::<(), Error>(())
153//! ```
154//!
155//! # Type conversion
156//!
157//! Fields can be automatically converted to/from a custom type using `=>` (infallible) or `?=>`
158//! (fallible). The custom type must implement the appropriate [`From`] or [`TryFrom`] traits with
159//! [`Bounded`].
160//!
161//! ## Infallible conversion (`=>`)
162//!
163//! Use this when all possible bit patterns of a field map to valid values:
164//!
165//! ```rust
166//! use kernel::bitfield;
167//! use kernel::num::Bounded;
168//!
169//! #[derive(Debug, Clone, Copy, PartialEq)]
170//! enum Power {
171//! Off,
172//! On,
173//! }
174//!
175//! impl From<Bounded<u32, 1>> for Power {
176//! fn from(v: Bounded<u32, 1>) -> Self {
177//! match *v {
178//! 0 => Power::Off,
179//! _ => Power::On,
180//! }
181//! }
182//! }
183//!
184//! impl From<Power> for Bounded<u32, 1> {
185//! fn from(p: Power) -> Self {
186//! (p as u32 != 0).into()
187//! }
188//! }
189//!
190//! bitfield! {
191//! pub struct Control(u32) {
192//! 0:0 power => Power;
193//! }
194//! }
195//!
196//! let ctrl = Control::zeroed().with_power(Power::On);
197//! assert_eq!(ctrl.power(), Power::On);
198//! ```
199//!
200//! ## Fallible conversion (`?=>`)
201//!
202//! Use this when some bit patterns of a field are invalid. The getter returns a [`Result`]:
203//!
204//! ```rust
205//! use kernel::bitfield;
206//! use kernel::num::Bounded;
207//!
208//! #[derive(Debug, Clone, Copy, PartialEq)]
209//! enum Mode {
210//! Low = 0,
211//! High = 1,
212//! Auto = 2,
213//! // 3 is invalid
214//! }
215//!
216//! impl TryFrom<Bounded<u32, 2>> for Mode {
217//! type Error = u32;
218//!
219//! fn try_from(v: Bounded<u32, 2>) -> Result<Self, u32> {
220//! match *v {
221//! 0 => Ok(Mode::Low),
222//! 1 => Ok(Mode::High),
223//! 2 => Ok(Mode::Auto),
224//! n => Err(n),
225//! }
226//! }
227//! }
228//!
229//! impl From<Mode> for Bounded<u32, 2> {
230//! fn from(m: Mode) -> Self {
231//! match m {
232//! Mode::Low => Bounded::<u32, _>::new::<0>(),
233//! Mode::High => Bounded::<u32, _>::new::<1>(),
234//! Mode::Auto => Bounded::<u32, _>::new::<2>(),
235//! }
236//! }
237//! }
238//!
239//! bitfield! {
240//! pub struct Config(u32) {
241//! 1:0 mode ?=> Mode;
242//! }
243//! }
244//!
245//! let cfg = Config::zeroed().with_mode(Mode::Auto);
246//! assert_eq!(cfg.mode(), Ok(Mode::Auto));
247//!
248//! // Invalid bit pattern returns an error.
249//! assert_eq!(Config::from(0b11).mode(), Err(3));
250//! ```
251//!
252//! # Bits outside of declared fields
253//!
254//! Bits of the storage type that are not part of any declared field are preserved by the setter
255//! methods, and can only be modified through `from_raw` or the [`From`] implementation from the
256//! storage type.
257//!
258//! ```rust
259//! use kernel::bitfield;
260//!
261//! bitfield! {
262//! pub struct Sparse(u8) {
263//! 7:6 high;
264//! // Bits 5:1 are not covered by any field.
265//! 0:0 low;
266//! }
267//! }
268//!
269//! // Set the gap bits via `from_raw`, then mutate the declared fields.
270//! let val = Sparse::from_raw(0b0010_1010)
271//! .with_const_high::<0b11>()
272//! .with_low(true);
273//!
274//! // Bits 5:1 are unchanged.
275//! assert_eq!(val.into_raw(), 0b1110_1011);
276//! ```
277//!
278//! # Signed field values
279//!
280//! Bitfield storage types are unsigned. Since field getter methods return a [`Bounded`] of the
281//! storage type, fields are also unsigned by default.
282//!
283//! If a field needs to encode a signed value, use a custom conversion type with `=>` or `?=>` to
284//! perform the sign interpretation explicitly.
285//!
286//! [`Bounded`]: kernel::num::Bounded
287
288/// Defines a bitfield struct with bounds-checked accessors for individual bit ranges.
289///
290/// See the [`mod@kernel::bitfield`] module for full documentation and examples.
291#[macro_export]
292macro_rules! bitfield {
293 // Entry point defining the bitfield struct, its implementations and its field accessors.
294 (
295 $(#[$attr:meta])* $vis:vis struct $name:ident($storage:ty) { $($fields:tt)* }
296 ) => {
297 $crate::bitfield!(@core
298 #[allow(non_camel_case_types)]
299 $(#[$attr])* $vis $name $storage
300 );
301 $crate::bitfield!(@fields $vis $name $storage { $($fields)* });
302 };
303
304 // All rules below are helpers.
305
306 // Defines the wrapper `$name` type and its conversions from/to the storage type.
307 (@core $(#[$attr:meta])* $vis:vis $name:ident $storage:ty) => {
308 $(#[$attr])*
309 #[repr(transparent)]
310 #[derive(Clone, Copy, PartialEq, Eq)]
311 $vis struct $name {
312 inner: $storage,
313 }
314
315 #[allow(dead_code)]
316 impl $name {
317 /// Creates a bitfield from a raw value.
318 #[inline(always)]
319 $vis const fn from_raw(value: $storage) -> Self {
320 Self{ inner: value }
321 }
322
323 /// Turns this bitfield into its raw value.
324 ///
325 /// This is similar to the [`From`] implementation, but is shorter to invoke in
326 /// most cases.
327 #[inline(always)]
328 $vis const fn into_raw(self) -> $storage {
329 self.inner
330 }
331 }
332
333 // SAFETY: `$storage` is `Zeroable` and `$name` is transparent.
334 unsafe impl ::pin_init::Zeroable for $name {}
335
336 impl ::core::convert::From<$name> for $storage {
337 #[inline(always)]
338 fn from(val: $name) -> $storage {
339 val.into_raw()
340 }
341 }
342
343 impl ::core::convert::From<$storage> for $name {
344 #[inline(always)]
345 fn from(val: $storage) -> $name {
346 Self::from_raw(val)
347 }
348 }
349 };
350
351 // Definitions requiring knowledge of individual fields: private and public field accessors,
352 // and `Debug` implementation.
353 (@fields $vis:vis $name:ident $storage:ty {
354 $($(#[doc = $doc:expr])* $hi:literal:$lo:literal $field:ident
355 $(?=> $try_into_type:ty)?
356 $(=> $into_type:ty)?
357 ;
358 )*
359 }
360 ) => {
361 #[allow(dead_code)]
362 impl $name {
363 $(
364 $crate::bitfield!(@private_field_accessors $vis $name $storage : $hi:$lo $field);
365 $crate::bitfield!(
366 @public_field_accessors $(#[doc = $doc])* $vis $name $storage : $hi:$lo $field
367 $(?=> $try_into_type)?
368 $(=> $into_type)?
369 );
370 )*
371 }
372
373 $crate::bitfield!(@debug $name { $($field;)* });
374 };
375
376 // Private field accessors working with the exact `Bounded` type for the field.
377 (
378 @private_field_accessors $vis:vis $name:ident $storage:ty : $hi:tt:$lo:tt $field:ident
379 ) => {
380 ::kernel::macros::paste!(
381 $vis const [<$field:upper _RANGE>]: ::core::ops::RangeInclusive<u8> = $lo..=$hi;
382 $vis const [<$field:upper _MASK>]: $storage =
383 ((((1 << $hi) - 1) << 1) + 1) - ((1 << $lo) - 1);
384 $vis const [<$field:upper _SHIFT>]: u32 = $lo;
385 );
386
387 ::kernel::macros::paste!(
388 #[inline(always)]
389 fn [<__ $field>](self) ->
390 ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }> {
391 // Left shift to align the field's MSB with the storage MSB.
392 const ALIGN_TOP: u32 = $storage::BITS - ($hi + 1);
393 // Right shift to move the top-aligned field to bit 0 of the storage.
394 const ALIGN_BOTTOM: u32 = ALIGN_TOP + $lo;
395
396 // Extract the field using two shifts. `Bounded::shr` produces the correctly-sized
397 // output type.
398 let val = ::kernel::num::Bounded::<$storage, { $storage::BITS }>::from(
399 self.inner << ALIGN_TOP
400 );
401 val.shr::<ALIGN_BOTTOM, { $hi + 1 - $lo } >()
402 }
403
404 #[inline(always)]
405 const fn [<__with_ $field>](
406 mut self,
407 value: ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>,
408 ) -> Self
409 {
410 const MASK: $storage = <$name>::[<$field:upper _MASK>];
411 const SHIFT: u32 = <$name>::[<$field:upper _SHIFT>];
412
413 let value = value.get() << SHIFT;
414 self.inner = (self.inner & !MASK) | value;
415
416 self
417 }
418 );
419 };
420
421 // Public accessors for fields infallibly (`=>`) converted to a type.
422 (
423 @public_field_accessors $(#[doc = $doc:expr])* $vis:vis $name:ident $storage:ty :
424 $hi:literal:$lo:literal $field:ident => $into_type:ty
425 ) => {
426 ::kernel::macros::paste!(
427
428 $(#[doc = $doc])*
429 #[doc = "Returns the value of this field."]
430 #[inline(always)]
431 $vis fn $field(self) -> $into_type
432 {
433 self.[<__ $field>]().into()
434 }
435
436 $(#[doc = $doc])*
437 #[doc = "Sets this field to the given `value`."]
438 #[inline(always)]
439 $vis fn [<with_ $field>](self, value: $into_type) -> Self
440 {
441 self.[<__with_ $field>](value.into())
442 }
443
444 );
445 };
446
447 // Public accessors for fields fallibly (`?=>`) converted to a type.
448 (
449 @public_field_accessors $(#[doc = $doc:expr])* $vis:vis $name:ident $storage:ty :
450 $hi:tt:$lo:tt $field:ident ?=> $try_into_type:ty
451 ) => {
452 ::kernel::macros::paste!(
453
454 $(#[doc = $doc])*
455 #[doc = "Returns the value of this field."]
456 #[inline(always)]
457 $vis fn $field(self) ->
458 ::core::result::Result<
459 $try_into_type,
460 <$try_into_type as ::core::convert::TryFrom<
461 ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>
462 >>::Error
463 >
464 {
465 self.[<__ $field>]().try_into()
466 }
467
468 $(#[doc = $doc])*
469 #[doc = "Sets this field to the given `value`."]
470 #[inline(always)]
471 $vis fn [<with_ $field>](self, value: $try_into_type) -> Self
472 {
473 self.[<__with_ $field>](value.into())
474 }
475
476 );
477 };
478
479 // Public accessors for fields not converted to a type.
480 (
481 @public_field_accessors $(#[doc = $doc:expr])* $vis:vis $name:ident $storage:ty :
482 $hi:tt:$lo:tt $field:ident
483 ) => {
484 ::kernel::macros::paste!(
485
486 $(#[doc = $doc])*
487 #[doc = "Returns the value of this field."]
488 #[inline(always)]
489 $vis fn $field(self) ->
490 ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>
491 {
492 self.[<__ $field>]()
493 }
494
495 $(#[doc = $doc])*
496 #[doc = "Sets this field to the compile-time constant `VALUE`."]
497 #[inline(always)]
498 $vis const fn [<with_const_ $field>]<const VALUE: $storage>(self) -> Self {
499 self.[<__with_ $field>](
500 ::kernel::num::Bounded::<$storage, { $hi + 1 - $lo }>::new::<VALUE>()
501 )
502 }
503
504 $(#[doc = $doc])*
505 #[doc = "Sets this field to the given `value`."]
506 #[inline(always)]
507 $vis fn [<with_ $field>]<T>(
508 self,
509 value: T,
510 ) -> Self
511 where T: ::core::convert::Into<::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>>,
512 {
513 self.[<__with_ $field>](value.into())
514 }
515
516 $(#[doc = $doc])*
517 #[doc = "Tries to set this field to `value`, returning an error if it is out of range."]
518 #[inline(always)]
519 $vis fn [<try_with_ $field>]<T>(
520 self,
521 value: T,
522 ) -> ::kernel::error::Result<Self>
523 where T: ::kernel::num::TryIntoBounded<$storage, { $hi + 1 - $lo }>,
524 {
525 Ok(
526 self.[<__with_ $field>](
527 value.try_into_bounded().ok_or(::kernel::error::code::EOVERFLOW)?
528 )
529 )
530 }
531
532 );
533 };
534
535 // `Debug` implementation.
536 (@debug $name:ident { $($field:ident;)* }) => {
537 impl ::kernel::fmt::Debug for $name {
538 fn fmt(&self, f: &mut ::kernel::fmt::Formatter<'_>) -> ::kernel::fmt::Result {
539 f.debug_struct(stringify!($name))
540 .field("<raw>", &::kernel::prelude::fmt!("{:#x}", self.inner))
541 $(
542 .field(stringify!($field), &self.$field())
543 )*
544 .finish()
545 }
546 }
547 };
548}
549
550#[cfg(CONFIG_RUST_BITFIELD_KUNIT_TEST)]
551#[::kernel::macros::kunit_tests(rust_kernel_bitfield)]
552mod tests {
553 use core::convert::TryFrom;
554
555 use pin_init::Zeroable;
556
557 use kernel::num::Bounded;
558
559 // Enum types for testing `=>` and `?=>` conversions.
560
561 #[derive(Debug, Clone, Copy, PartialEq)]
562 enum MemoryType {
563 Unmapped = 0,
564 Normal = 1,
565 Device = 2,
566 Reserved = 3,
567 }
568
569 impl TryFrom<Bounded<u64, 4>> for MemoryType {
570 type Error = u64;
571 fn try_from(value: Bounded<u64, 4>) -> Result<Self, Self::Error> {
572 match value.get() {
573 0 => Ok(MemoryType::Unmapped),
574 1 => Ok(MemoryType::Normal),
575 2 => Ok(MemoryType::Device),
576 3 => Ok(MemoryType::Reserved),
577 _ => Err(value.get()),
578 }
579 }
580 }
581
582 impl From<MemoryType> for Bounded<u64, 4> {
583 fn from(mt: MemoryType) -> Bounded<u64, 4> {
584 Bounded::from_expr(mt as u64)
585 }
586 }
587
588 #[derive(Debug, Clone, Copy, PartialEq)]
589 enum Priority {
590 Low = 0,
591 Medium = 1,
592 High = 2,
593 Critical = 3,
594 }
595
596 impl From<Bounded<u16, 2>> for Priority {
597 fn from(value: Bounded<u16, 2>) -> Self {
598 match value & 0x3 {
599 0 => Priority::Low,
600 1 => Priority::Medium,
601 2 => Priority::High,
602 _ => Priority::Critical,
603 }
604 }
605 }
606
607 impl From<Priority> for Bounded<u16, 2> {
608 fn from(p: Priority) -> Bounded<u16, 2> {
609 Bounded::from_expr(p as u16)
610 }
611 }
612
613 bitfield! {
614 struct TestU64(u64) {
615 63:63 field_63;
616 61:52 field_61_52;
617 51:16 field_51_16;
618 15:12 field_15_12 ?=> MemoryType;
619 11:9 field_11_9;
620 1:1 field_1;
621 0:0 field_0;
622 }
623 }
624
625 bitfield! {
626 struct TestU16(u16) {
627 15:8 field_15_8;
628 7:4 field_7_4; // Partial overlap with `field_5_4`.
629 5:4 field_5_4 => Priority;
630 3:1 field_3_1;
631 0:0 field_0;
632 }
633 }
634
635 bitfield! {
636 struct TestU8(u8) {
637 7:0 field_7_0; // Full byte overlap.
638 7:4 field_7_4;
639 3:2 field_3_2;
640 1:1 field_1;
641 0:0 field_0;
642 }
643 }
644
645 // Single and multi-bit fields basic access.
646 #[test]
647 fn test_basic_access() {
648 // `TestU64`.
649 let mut val = TestU64::zeroed();
650 assert_eq!(val.into_raw(), 0x0);
651
652 val = val.with_field_0(true);
653 assert!(val.field_0().into_bool());
654 assert_eq!(val.into_raw(), 0x1);
655
656 val = val.with_field_1(true);
657 assert!(val.field_1().into_bool());
658 val = val.with_field_1(false);
659 assert!(!val.field_1().into_bool());
660 assert_eq!(val.into_raw(), 0x1);
661
662 val = val.with_const_field_11_9::<0x5>();
663 assert_eq!(val.field_11_9(), 0x5);
664 assert_eq!(val.into_raw(), 0xA01);
665
666 val = val.with_const_field_51_16::<0x123456>();
667 assert_eq!(val.field_51_16(), 0x123456);
668 assert_eq!(val.into_raw(), 0x0012_3456_0A01);
669
670 const MAX_FIELD_51_16: u64 = ::kernel::bits::genmask_u64(0..=35);
671 val = val.with_const_field_51_16::<{ MAX_FIELD_51_16 }>();
672 assert_eq!(val.field_51_16(), MAX_FIELD_51_16);
673
674 val = val.with_const_field_61_52::<0x3FF>();
675 assert_eq!(val.field_61_52(), 0x3FF);
676
677 val = val.with_field_63(true);
678 assert!(val.field_63().into_bool());
679
680 // `TestU16`.
681 let mut val = TestU16::zeroed();
682 assert_eq!(val.into_raw(), 0x0);
683
684 val = val.with_field_0(true);
685 assert!(val.field_0().into_bool());
686 assert_eq!(val.into_raw(), 0x1);
687
688 val = val.with_const_field_3_1::<0x5>();
689 assert_eq!(val.field_3_1(), 0x5);
690 assert_eq!(val.into_raw(), 0xB);
691
692 val = val.with_const_field_7_4::<0xA>();
693 assert_eq!(val.field_7_4(), 0xA);
694 assert_eq!(val.into_raw(), 0xAB);
695
696 val = val.with_const_field_15_8::<0x42>();
697 assert_eq!(val.field_15_8(), 0x42);
698 assert_eq!(val.into_raw(), 0x42AB);
699
700 // `TestU8`.
701 let mut val = TestU8::zeroed();
702 assert_eq!(val.into_raw(), 0x0);
703
704 val = val.with_field_0(true);
705 assert!(val.field_0().into_bool());
706 assert_eq!(val.into_raw(), 0x1);
707
708 val = val.with_field_1(true);
709 assert!(val.field_1().into_bool());
710 assert_eq!(val.into_raw(), 0x3);
711
712 val = val.with_const_field_3_2::<0x3>();
713 assert_eq!(val.field_3_2(), 0x3);
714 assert_eq!(val.into_raw(), 0xF);
715
716 val = val.with_const_field_7_4::<0xA>();
717 assert_eq!(val.field_7_4(), 0xA);
718 assert_eq!(val.into_raw(), 0xAF);
719 }
720
721 // `=>` infallible conversion.
722 #[test]
723 fn test_infallible_conversion() {
724 let mut val = TestU16::zeroed();
725
726 val = val.with_field_5_4(Priority::Low);
727 assert_eq!(val.field_5_4(), Priority::Low);
728 assert_eq!(val.into_raw() & 0x30, 0x00);
729
730 val = val.with_field_5_4(Priority::Medium);
731 assert_eq!(val.field_5_4(), Priority::Medium);
732 assert_eq!(val.into_raw() & 0x30, 0x10);
733
734 val = val.with_field_5_4(Priority::High);
735 assert_eq!(val.field_5_4(), Priority::High);
736 assert_eq!(val.into_raw() & 0x30, 0x20);
737
738 val = val.with_field_5_4(Priority::Critical);
739 assert_eq!(val.field_5_4(), Priority::Critical);
740 assert_eq!(val.into_raw() & 0x30, 0x30);
741 }
742
743 // `?=>` fallible conversion.
744 #[test]
745 fn test_fallible_conversion() {
746 let mut val = TestU64::zeroed();
747
748 val = val.with_field_15_12(MemoryType::Unmapped);
749 assert_eq!(val.field_15_12(), Ok(MemoryType::Unmapped));
750 val = val.with_field_15_12(MemoryType::Normal);
751 assert_eq!(val.field_15_12(), Ok(MemoryType::Normal));
752 val = val.with_field_15_12(MemoryType::Device);
753 assert_eq!(val.field_15_12(), Ok(MemoryType::Device));
754 val = val.with_field_15_12(MemoryType::Reserved);
755 assert_eq!(val.field_15_12(), Ok(MemoryType::Reserved));
756
757 // `field_15_12` is 4 bits wide (0-15); `MemoryType` only covers 0-3, so 4-15 return `Err`.
758 let raw = (val.into_raw() & !::kernel::bits::genmask_u64(12..=15)) | (0x7 << 12);
759 assert_eq!(TestU64::from_raw(raw).field_15_12(), Err(0x7));
760 }
761
762 // Test that setting an overlapping field affects the overlapped one as expected.
763 #[test]
764 fn test_overlapping_fields() {
765 let mut val = TestU16::zeroed();
766
767 val = val.with_field_5_4(Priority::High); // High == 2 == 0b10.
768 assert_eq!(val.field_5_4(), Priority::High);
769 assert_eq!(val.field_7_4(), 0x2); // Bits 7:6 == 0, bits 5:4 == 0b10.
770
771 val = val.with_const_field_7_4::<0xF>();
772 assert_eq!(val.field_7_4(), 0xF);
773 assert_eq!(val.field_5_4(), Priority::Critical); // Bits 5:4 == 0b11.
774
775 // `field_7_0` should encompass all other fields.
776 let mut val = TestU8::zeroed()
777 .with_field_0(true)
778 .with_field_1(true)
779 .with_const_field_3_2::<0x3>()
780 .with_const_field_7_4::<0xA>();
781 assert_eq!(val.into_raw(), 0xAF);
782
783 val = val.with_field_7_0(0x55);
784 assert_eq!(val.field_7_0(), 0x55);
785 assert!(val.field_0().into_bool());
786 assert!(!val.field_1().into_bool());
787 assert_eq!(val.field_3_2(), 0x1);
788 assert_eq!(val.field_7_4(), 0x5);
789 }
790
791 // Checks that bits not mapped to any field are left untouched.
792 #[test]
793 fn test_unallocated_bits() {
794 let gap_bits = (1u64 << 62) | 0x1FC;
795
796 let set_all_fields = |val: TestU64| {
797 val.with_field_63(true)
798 .with_const_field_61_52::<0x155>()
799 .with_const_field_51_16::<0x123456>()
800 .with_field_15_12(MemoryType::Device)
801 .with_const_field_11_9::<0x5>()
802 .with_field_1(true)
803 .with_field_0(true)
804 };
805
806 // Gap bits to 0.
807 let val = set_all_fields(TestU64::from_raw(0));
808 assert_eq!(val.into_raw() & gap_bits, 0);
809
810 // Gap bits to 1.
811 let val = set_all_fields(TestU64::from_raw(gap_bits));
812 assert_eq!(val.into_raw() & gap_bits, gap_bits);
813 }
814
815 #[test]
816 fn test_try_with() {
817 let val = TestU64::zeroed().try_with_field_51_16(0x123456).unwrap();
818 assert_eq!(val.field_51_16(), 0x123456);
819
820 let err = TestU64::zeroed().try_with_field_51_16(u64::MAX);
821 assert_eq!(err, Err(::kernel::error::code::EOVERFLOW));
822
823 let val = TestU64::zeroed()
824 .try_with_field_51_16(0xABCDEF)
825 .and_then(|p| p.try_with_field_0(1))
826 .unwrap();
827 assert_eq!(val.field_51_16(), 0xABCDEF);
828 assert!(val.field_0().into_bool());
829 }
830
831 // `from_raw`/`into_raw` and `From`/`Into` round-trips.
832 #[test]
833 fn test_raw() {
834 let raw: u64 = 0xBFF0_0000_3123_3E03;
835 let val = TestU64::from_raw(raw);
836 assert_eq!(u64::from(val), raw);
837 assert!(val.field_0().into_bool());
838 assert!(val.field_1().into_bool());
839 assert_eq!(val.field_11_9(), 0x7);
840 assert_eq!(val.field_51_16(), 0x3123);
841 assert_eq!(val.field_15_12(), Ok(MemoryType::Reserved));
842 assert_eq!(val.field_61_52(), 0x3FF);
843 assert!(val.field_63().into_bool());
844
845 let raw: u16 = 0x42AB;
846 let val = TestU16::from_raw(raw);
847 assert_eq!(u16::from(val), raw);
848 assert!(val.field_0().into_bool());
849 assert_eq!(val.field_3_1(), 0x5);
850 assert_eq!(val.field_7_4(), 0xA);
851 assert_eq!(val.field_15_8(), 0x42);
852
853 let raw: u8 = 0xAF;
854 let val = TestU8::from_raw(raw);
855 assert_eq!(u8::from(val), raw);
856 assert!(val.field_0().into_bool());
857 assert!(val.field_1().into_bool());
858 assert_eq!(val.field_3_2(), 0x3);
859 assert_eq!(val.field_7_4(), 0xA);
860 assert_eq!(val.field_7_0(), 0xAF);
861 }
862}