// 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 {
            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);
    }
}
