mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 01:08:13 -04:00
rust: extract bitfield! macro from register!
Extract the bitfield-defining part of the `register!` macro into an independent macro used to define bitfield types with bounds-checked accessors. Each field is represented as a `Bounded` of the appropriate bit width, ensuring field values are never silently truncated. Fields can optionally be converted to/from custom types, either fallibly or infallibly. Appropriate documentation is also added, and a MAINTAINERS entry created for the new module. Two minor fixups are also applied: the private accessors are inlined, and a couple of missing fully qualified types in the macro are fixed. Acked-by: Yury Norov <ynorov@nvidia.com> Acked-by: Danilo Krummrich <dakr@kernel.org> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com> Reviewed-by: Yury Norov <ynorov@nvidia.com> Link: https://patch.msgid.link/20260606-bitfield-v5-1-b92188820914@nvidia.com [ Added some more intra-doc links. - Miguel ] Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
This commit is contained in:
committed by
Miguel Ojeda
parent
09699b2419
commit
b7b8b4ccda
@@ -23422,6 +23422,13 @@ T: git https://github.com/Rust-for-Linux/linux.git alloc-next
|
||||
F: rust/kernel/alloc.rs
|
||||
F: rust/kernel/alloc/
|
||||
|
||||
RUST [BITFIELD]
|
||||
M: Alexandre Courbot <acourbot@nvidia.com>
|
||||
R: Yury Norov <yury.norov@gmail.com>
|
||||
L: rust-for-linux@vger.kernel.org
|
||||
S: Maintained
|
||||
F: rust/kernel/bitfield.rs
|
||||
|
||||
RUST [INTEROP]
|
||||
M: Joel Fernandes <joelagnelf@nvidia.com>
|
||||
M: Alexandre Courbot <acourbot@nvidia.com>
|
||||
|
||||
548
rust/kernel/bitfield.rs
Normal file
548
rust/kernel/bitfield.rs
Normal file
@@ -0,0 +1,548 @@
|
||||
// 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()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -44,6 +44,7 @@
|
||||
pub mod alloc;
|
||||
#[cfg(CONFIG_AUXILIARY_BUS)]
|
||||
pub mod auxiliary;
|
||||
pub mod bitfield;
|
||||
pub mod bitmap;
|
||||
pub mod bits;
|
||||
#[cfg(CONFIG_BLOCK)]
|
||||
|
||||
Reference in New Issue
Block a user