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 $(#[$attr])* $vis $name $storage
299 );
300 $crate::bitfield!(@fields $vis $name $storage { $($fields)* });
301 };
302
303 // All rules below are helpers.
304
305 // Defines the wrapper `$name` type and its conversions from/to the storage type.
306 (@core $(#[$attr:meta])* $vis:vis $name:ident $storage:ty) => {
307 $(#[$attr])*
308 #[repr(transparent)]
309 #[derive(Clone, Copy, PartialEq, Eq)]
310 $vis struct $name {
311 inner: $storage,
312 }
313
314 #[allow(dead_code)]
315 impl $name {
316 /// Creates a bitfield from a raw value.
317 #[inline(always)]
318 $vis const fn from_raw(value: $storage) -> Self {
319 Self{ inner: value }
320 }
321
322 /// Turns this bitfield into its raw value.
323 ///
324 /// This is similar to the [`From`] implementation, but is shorter to invoke in
325 /// most cases.
326 #[inline(always)]
327 $vis const fn into_raw(self) -> $storage {
328 self.inner
329 }
330 }
331
332 // SAFETY: `$storage` is `Zeroable` and `$name` is transparent.
333 unsafe impl ::pin_init::Zeroable for $name {}
334
335 impl ::core::convert::From<$name> for $storage {
336 #[inline(always)]
337 fn from(val: $name) -> $storage {
338 val.into_raw()
339 }
340 }
341
342 impl ::core::convert::From<$storage> for $name {
343 #[inline(always)]
344 fn from(val: $storage) -> $name {
345 Self::from_raw(val)
346 }
347 }
348
349 // SAFETY: `$name` is transparent over `$storage` and `$storage` has no interior mutability.
350 unsafe impl $crate::mem::AsRepr for $name {
351 // Normalize `$storage` to the canonical repr type in case it is signed.
352 type Repr = <$storage as $crate::mem::AsRepr>::Repr;
353 }
354
355 // SAFETY: `$name` is transparent over `$storage`.
356 unsafe impl $crate::mem::AsReprMut for $name {}
357 };
358
359 // Definitions requiring knowledge of individual fields: private and public field accessors,
360 // and `Debug` implementation.
361 (@fields $vis:vis $name:ident $storage:ty {
362 $($(#[doc = $doc:expr])* $hi:literal:$lo:literal $field:ident
363 $(?=> $try_into_type:ty)?
364 $(=> $into_type:ty)?
365 ;
366 )*
367 }
368 ) => {
369 #[allow(dead_code)]
370 impl $name {
371 $(
372 $crate::bitfield!(@private_field_accessors $vis $name $storage : $hi:$lo $field);
373 $crate::bitfield!(
374 @public_field_accessors $(#[doc = $doc])* $vis $name $storage : $hi:$lo $field
375 $(?=> $try_into_type)?
376 $(=> $into_type)?
377 );
378 )*
379 }
380
381 $crate::bitfield!(@debug $name { $($field;)* });
382 };
383
384 // Private field accessors working with the exact `Bounded` type for the field.
385 (
386 @private_field_accessors $vis:vis $name:ident $storage:ty : $hi:tt:$lo:tt $field:ident
387 ) => {
388 ::kernel::macros::paste!(
389 $vis const [<$field:upper _RANGE>]: ::core::ops::RangeInclusive<u8> = $lo..=$hi;
390 $vis const [<$field:upper _MASK>]: $storage =
391 ((((1 << $hi) - 1) << 1) + 1) - ((1 << $lo) - 1);
392 $vis const [<$field:upper _SHIFT>]: u32 = $lo;
393 );
394
395 ::kernel::macros::paste!(
396 #[inline(always)]
397 fn [<__ $field>](self) ->
398 ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }> {
399 // Left shift to align the field's MSB with the storage MSB.
400 const ALIGN_TOP: u32 = $storage::BITS - ($hi + 1);
401 // Right shift to move the top-aligned field to bit 0 of the storage.
402 const ALIGN_BOTTOM: u32 = ALIGN_TOP + $lo;
403
404 // Extract the field using two shifts. `Bounded::shr` produces the correctly-sized
405 // output type.
406 let val = ::kernel::num::Bounded::<$storage, { $storage::BITS }>::from(
407 self.inner << ALIGN_TOP
408 );
409 val.shr::<ALIGN_BOTTOM, { $hi + 1 - $lo } >()
410 }
411
412 #[inline(always)]
413 const fn [<__with_ $field>](
414 mut self,
415 value: ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>,
416 ) -> Self
417 {
418 const MASK: $storage = <$name>::[<$field:upper _MASK>];
419 const SHIFT: u32 = <$name>::[<$field:upper _SHIFT>];
420
421 let value = value.get() << SHIFT;
422 self.inner = (self.inner & !MASK) | value;
423
424 self
425 }
426 );
427 };
428
429 // Public accessors for fields infallibly (`=>`) converted to a type.
430 (
431 @public_field_accessors $(#[doc = $doc:expr])* $vis:vis $name:ident $storage:ty :
432 $hi:literal:$lo:literal $field:ident => $into_type:ty
433 ) => {
434 ::kernel::macros::paste!(
435
436 $(#[doc = $doc])*
437 #[doc = "Returns the value of this field."]
438 #[inline(always)]
439 $vis fn $field(self) -> $into_type
440 {
441 self.[<__ $field>]().into()
442 }
443
444 $(#[doc = $doc])*
445 #[doc = "Sets this field to the given `value`."]
446 #[inline(always)]
447 $vis fn [<with_ $field>](self, value: $into_type) -> Self
448 {
449 self.[<__with_ $field>](value.into())
450 }
451
452 );
453 };
454
455 // Public accessors for fields fallibly (`?=>`) converted to a type.
456 (
457 @public_field_accessors $(#[doc = $doc:expr])* $vis:vis $name:ident $storage:ty :
458 $hi:tt:$lo:tt $field:ident ?=> $try_into_type:ty
459 ) => {
460 ::kernel::macros::paste!(
461
462 $(#[doc = $doc])*
463 #[doc = "Returns the value of this field."]
464 #[inline(always)]
465 $vis fn $field(self) ->
466 ::core::result::Result<
467 $try_into_type,
468 <$try_into_type as ::core::convert::TryFrom<
469 ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>
470 >>::Error
471 >
472 {
473 self.[<__ $field>]().try_into()
474 }
475
476 $(#[doc = $doc])*
477 #[doc = "Sets this field to the given `value`."]
478 #[inline(always)]
479 $vis fn [<with_ $field>](self, value: $try_into_type) -> Self
480 {
481 self.[<__with_ $field>](value.into())
482 }
483
484 );
485 };
486
487 // Public accessors for fields not converted to a type.
488 (
489 @public_field_accessors $(#[doc = $doc:expr])* $vis:vis $name:ident $storage:ty :
490 $hi:tt:$lo:tt $field:ident
491 ) => {
492 ::kernel::macros::paste!(
493
494 $(#[doc = $doc])*
495 #[doc = "Returns the value of this field."]
496 #[inline(always)]
497 $vis fn $field(self) ->
498 ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>
499 {
500 self.[<__ $field>]()
501 }
502
503 $(#[doc = $doc])*
504 #[doc = "Sets this field to the compile-time constant `VALUE`."]
505 #[inline(always)]
506 $vis const fn [<with_const_ $field>]<const VALUE: $storage>(self) -> Self {
507 self.[<__with_ $field>](
508 ::kernel::num::Bounded::<$storage, { $hi + 1 - $lo }>::new::<VALUE>()
509 )
510 }
511
512 $(#[doc = $doc])*
513 #[doc = "Sets this field to the given `value`."]
514 #[inline(always)]
515 $vis fn [<with_ $field>]<T>(
516 self,
517 value: T,
518 ) -> Self
519 where T: ::core::convert::Into<::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>>,
520 {
521 self.[<__with_ $field>](value.into())
522 }
523
524 $(#[doc = $doc])*
525 #[doc = "Tries to set this field to `value`, returning an error if it is out of range."]
526 #[inline(always)]
527 $vis fn [<try_with_ $field>]<T>(
528 self,
529 value: T,
530 ) -> ::kernel::error::Result<Self>
531 where T: ::kernel::num::TryIntoBounded<$storage, { $hi + 1 - $lo }>,
532 {
533 Ok(
534 self.[<__with_ $field>](
535 value.try_into_bounded().ok_or(::kernel::error::code::EOVERFLOW)?
536 )
537 )
538 }
539
540 );
541 };
542
543 // `Debug` implementation.
544 (@debug $name:ident { $($field:ident;)* }) => {
545 impl ::kernel::fmt::Debug for $name {
546 #[inline]
547 fn fmt(&self, f: &mut ::kernel::fmt::Formatter<'_>) -> ::kernel::fmt::Result {
548 f.debug_struct(stringify!($name))
549 .field("<raw>", &::kernel::prelude::fmt!("{:#x}", self.inner))
550 $(
551 .field(stringify!($field), &self.$field())
552 )*
553 .finish()
554 }
555 }
556 };
557}
558
559#[cfg(CONFIG_RUST_BITFIELD_KUNIT_TEST)]
560#[::kernel::macros::kunit_tests(rust_kernel_bitfield)]
561mod tests {
562 use core::convert::TryFrom;
563
564 use pin_init::Zeroable;
565
566 use kernel::num::Bounded;
567
568 // Enum types for testing `=>` and `?=>` conversions.
569
570 #[derive(Debug, Clone, Copy, PartialEq)]
571 enum MemoryType {
572 Unmapped = 0,
573 Normal = 1,
574 Device = 2,
575 Reserved = 3,
576 }
577
578 impl TryFrom<Bounded<u64, 4>> for MemoryType {
579 type Error = u64;
580 fn try_from(value: Bounded<u64, 4>) -> Result<Self, Self::Error> {
581 match value.get() {
582 0 => Ok(MemoryType::Unmapped),
583 1 => Ok(MemoryType::Normal),
584 2 => Ok(MemoryType::Device),
585 3 => Ok(MemoryType::Reserved),
586 _ => Err(value.get()),
587 }
588 }
589 }
590
591 impl From<MemoryType> for Bounded<u64, 4> {
592 #[inline(always)]
593 fn from(mt: MemoryType) -> Bounded<u64, 4> {
594 Bounded::from_expr(mt as u64)
595 }
596 }
597
598 #[derive(Debug, Clone, Copy, PartialEq)]
599 enum Priority {
600 Low = 0,
601 Medium = 1,
602 High = 2,
603 Critical = 3,
604 }
605
606 impl From<Bounded<u16, 2>> for Priority {
607 fn from(value: Bounded<u16, 2>) -> Self {
608 match value & 0x3 {
609 0 => Priority::Low,
610 1 => Priority::Medium,
611 2 => Priority::High,
612 _ => Priority::Critical,
613 }
614 }
615 }
616
617 impl From<Priority> for Bounded<u16, 2> {
618 #[inline(always)]
619 fn from(p: Priority) -> Bounded<u16, 2> {
620 Bounded::from_expr(p as u16)
621 }
622 }
623
624 bitfield! {
625 struct TestU64(u64) {
626 63:63 field_63;
627 61:52 field_61_52;
628 51:16 field_51_16;
629 15:12 field_15_12 ?=> MemoryType;
630 11:9 field_11_9;
631 1:1 field_1;
632 0:0 field_0;
633 }
634 }
635
636 bitfield! {
637 struct TestU16(u16) {
638 15:8 field_15_8;
639 7:4 field_7_4; // Partial overlap with `field_5_4`.
640 5:4 field_5_4 => Priority;
641 3:1 field_3_1;
642 0:0 field_0;
643 }
644 }
645
646 bitfield! {
647 struct TestU8(u8) {
648 7:0 field_7_0; // Full byte overlap.
649 7:4 field_7_4;
650 3:2 field_3_2;
651 1:1 field_1;
652 0:0 field_0;
653 }
654 }
655
656 // Single and multi-bit fields basic access.
657 #[test]
658 fn test_basic_access() {
659 // `TestU64`.
660 let mut val = TestU64::zeroed();
661 assert_eq!(val.into_raw(), 0x0);
662
663 val = val.with_field_0(true);
664 assert!(val.field_0().into_bool());
665 assert_eq!(val.into_raw(), 0x1);
666
667 val = val.with_field_1(true);
668 assert!(val.field_1().into_bool());
669 val = val.with_field_1(false);
670 assert!(!val.field_1().into_bool());
671 assert_eq!(val.into_raw(), 0x1);
672
673 val = val.with_const_field_11_9::<0x5>();
674 assert_eq!(val.field_11_9(), 0x5);
675 assert_eq!(val.into_raw(), 0xA01);
676
677 val = val.with_const_field_51_16::<0x123456>();
678 assert_eq!(val.field_51_16(), 0x123456);
679 assert_eq!(val.into_raw(), 0x0012_3456_0A01);
680
681 const MAX_FIELD_51_16: u64 = ::kernel::bits::genmask_u64(0..=35);
682 val = val.with_const_field_51_16::<{ MAX_FIELD_51_16 }>();
683 assert_eq!(val.field_51_16(), MAX_FIELD_51_16);
684
685 val = val.with_const_field_61_52::<0x3FF>();
686 assert_eq!(val.field_61_52(), 0x3FF);
687
688 val = val.with_field_63(true);
689 assert!(val.field_63().into_bool());
690
691 // `TestU16`.
692 let mut val = TestU16::zeroed();
693 assert_eq!(val.into_raw(), 0x0);
694
695 val = val.with_field_0(true);
696 assert!(val.field_0().into_bool());
697 assert_eq!(val.into_raw(), 0x1);
698
699 val = val.with_const_field_3_1::<0x5>();
700 assert_eq!(val.field_3_1(), 0x5);
701 assert_eq!(val.into_raw(), 0xB);
702
703 val = val.with_const_field_7_4::<0xA>();
704 assert_eq!(val.field_7_4(), 0xA);
705 assert_eq!(val.into_raw(), 0xAB);
706
707 val = val.with_const_field_15_8::<0x42>();
708 assert_eq!(val.field_15_8(), 0x42);
709 assert_eq!(val.into_raw(), 0x42AB);
710
711 // `TestU8`.
712 let mut val = TestU8::zeroed();
713 assert_eq!(val.into_raw(), 0x0);
714
715 val = val.with_field_0(true);
716 assert!(val.field_0().into_bool());
717 assert_eq!(val.into_raw(), 0x1);
718
719 val = val.with_field_1(true);
720 assert!(val.field_1().into_bool());
721 assert_eq!(val.into_raw(), 0x3);
722
723 val = val.with_const_field_3_2::<0x3>();
724 assert_eq!(val.field_3_2(), 0x3);
725 assert_eq!(val.into_raw(), 0xF);
726
727 val = val.with_const_field_7_4::<0xA>();
728 assert_eq!(val.field_7_4(), 0xA);
729 assert_eq!(val.into_raw(), 0xAF);
730 }
731
732 // `=>` infallible conversion.
733 #[test]
734 fn test_infallible_conversion() {
735 let mut val = TestU16::zeroed();
736
737 val = val.with_field_5_4(Priority::Low);
738 assert_eq!(val.field_5_4(), Priority::Low);
739 assert_eq!(val.into_raw() & 0x30, 0x00);
740
741 val = val.with_field_5_4(Priority::Medium);
742 assert_eq!(val.field_5_4(), Priority::Medium);
743 assert_eq!(val.into_raw() & 0x30, 0x10);
744
745 val = val.with_field_5_4(Priority::High);
746 assert_eq!(val.field_5_4(), Priority::High);
747 assert_eq!(val.into_raw() & 0x30, 0x20);
748
749 val = val.with_field_5_4(Priority::Critical);
750 assert_eq!(val.field_5_4(), Priority::Critical);
751 assert_eq!(val.into_raw() & 0x30, 0x30);
752 }
753
754 // `?=>` fallible conversion.
755 #[test]
756 fn test_fallible_conversion() {
757 let mut val = TestU64::zeroed();
758
759 val = val.with_field_15_12(MemoryType::Unmapped);
760 assert_eq!(val.field_15_12(), Ok(MemoryType::Unmapped));
761 val = val.with_field_15_12(MemoryType::Normal);
762 assert_eq!(val.field_15_12(), Ok(MemoryType::Normal));
763 val = val.with_field_15_12(MemoryType::Device);
764 assert_eq!(val.field_15_12(), Ok(MemoryType::Device));
765 val = val.with_field_15_12(MemoryType::Reserved);
766 assert_eq!(val.field_15_12(), Ok(MemoryType::Reserved));
767
768 // `field_15_12` is 4 bits wide (0-15); `MemoryType` only covers 0-3, so 4-15 return `Err`.
769 let raw = (val.into_raw() & !::kernel::bits::genmask_u64(12..=15)) | (0x7 << 12);
770 assert_eq!(TestU64::from_raw(raw).field_15_12(), Err(0x7));
771 }
772
773 // Test that setting an overlapping field affects the overlapped one as expected.
774 #[test]
775 fn test_overlapping_fields() {
776 let mut val = TestU16::zeroed();
777
778 val = val.with_field_5_4(Priority::High); // High == 2 == 0b10.
779 assert_eq!(val.field_5_4(), Priority::High);
780 assert_eq!(val.field_7_4(), 0x2); // Bits 7:6 == 0, bits 5:4 == 0b10.
781
782 val = val.with_const_field_7_4::<0xF>();
783 assert_eq!(val.field_7_4(), 0xF);
784 assert_eq!(val.field_5_4(), Priority::Critical); // Bits 5:4 == 0b11.
785
786 // `field_7_0` should encompass all other fields.
787 let mut val = TestU8::zeroed()
788 .with_field_0(true)
789 .with_field_1(true)
790 .with_const_field_3_2::<0x3>()
791 .with_const_field_7_4::<0xA>();
792 assert_eq!(val.into_raw(), 0xAF);
793
794 val = val.with_field_7_0(0x55);
795 assert_eq!(val.field_7_0(), 0x55);
796 assert!(val.field_0().into_bool());
797 assert!(!val.field_1().into_bool());
798 assert_eq!(val.field_3_2(), 0x1);
799 assert_eq!(val.field_7_4(), 0x5);
800 }
801
802 // Checks that bits not mapped to any field are left untouched.
803 #[test]
804 fn test_unallocated_bits() {
805 let gap_bits = (1u64 << 62) | 0x1FC;
806
807 let set_all_fields = |val: TestU64| {
808 val.with_field_63(true)
809 .with_const_field_61_52::<0x155>()
810 .with_const_field_51_16::<0x123456>()
811 .with_field_15_12(MemoryType::Device)
812 .with_const_field_11_9::<0x5>()
813 .with_field_1(true)
814 .with_field_0(true)
815 };
816
817 // Gap bits to 0.
818 let val = set_all_fields(TestU64::from_raw(0));
819 assert_eq!(val.into_raw() & gap_bits, 0);
820
821 // Gap bits to 1.
822 let val = set_all_fields(TestU64::from_raw(gap_bits));
823 assert_eq!(val.into_raw() & gap_bits, gap_bits);
824 }
825
826 #[test]
827 fn test_try_with() {
828 let val = TestU64::zeroed().try_with_field_51_16(0x123456).unwrap();
829 assert_eq!(val.field_51_16(), 0x123456);
830
831 let err = TestU64::zeroed().try_with_field_51_16(u64::MAX);
832 assert_eq!(err, Err(::kernel::error::code::EOVERFLOW));
833
834 let val = TestU64::zeroed()
835 .try_with_field_51_16(0xABCDEF)
836 .and_then(|p| p.try_with_field_0(1))
837 .unwrap();
838 assert_eq!(val.field_51_16(), 0xABCDEF);
839 assert!(val.field_0().into_bool());
840 }
841
842 // `from_raw`/`into_raw` and `From`/`Into` round-trips.
843 #[test]
844 fn test_raw() {
845 let raw: u64 = 0xBFF0_0000_3123_3E03;
846 let val = TestU64::from_raw(raw);
847 assert_eq!(u64::from(val), raw);
848 assert!(val.field_0().into_bool());
849 assert!(val.field_1().into_bool());
850 assert_eq!(val.field_11_9(), 0x7);
851 assert_eq!(val.field_51_16(), 0x3123);
852 assert_eq!(val.field_15_12(), Ok(MemoryType::Reserved));
853 assert_eq!(val.field_61_52(), 0x3FF);
854 assert!(val.field_63().into_bool());
855
856 let raw: u16 = 0x42AB;
857 let val = TestU16::from_raw(raw);
858 assert_eq!(u16::from(val), raw);
859 assert!(val.field_0().into_bool());
860 assert_eq!(val.field_3_1(), 0x5);
861 assert_eq!(val.field_7_4(), 0xA);
862 assert_eq!(val.field_15_8(), 0x42);
863
864 let raw: u8 = 0xAF;
865 let val = TestU8::from_raw(raw);
866 assert_eq!(u8::from(val), raw);
867 assert!(val.field_0().into_bool());
868 assert!(val.field_1().into_bool());
869 assert_eq!(val.field_3_2(), 0x3);
870 assert_eq!(val.field_7_4(), 0xA);
871 assert_eq!(val.field_7_0(), 0xAF);
872 }
873}