Skip to main content

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