linux/rust/kernel/num.rs
Eliot Courtney 1d09c9ee13 rust: num: add cv! macro to create values from constant expressions
Currently, using NonZero/Bounded constants is quite verbose. It's
unfortunate because it disincentivizes using it in interface boundaries.
Introduce a macro to make it nicer to use. The macro `cv!` (for constant
value) takes a const integer expression and widens it to i128 (at build
time only) before passing it as a const generic value to a new trait
`FromConst`. The value is then converted and appears in the
associated constant `FromConst::VALUE`. The trait is implemented by
NonZero, Bounded, and Alignment and lets values of each be constructed
from constants without a verbose turbofish syntax.

For example, `const { NonZero::new(1).unwrap() }` can be written as
`cv!(1)`.

Add the `cv!` macro to the prelude so it doesn't need to be imported
explicitly to use it.

Suggested-by: Gary Guo <gary@garyguo.net>
Reviewed-by: Gary Guo <gary@garyguo.net>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Acked-by: Danilo Krummrich <dakr@kernel.org>
Signed-off-by: Eliot Courtney <ecourtney@nvidia.com>
Acked-by: Alexandre Courbot <acourbot@nvidia.com>
Link: https://patch.msgid.link/20261013-cv-v5-1-113a538dfaef@nvidia.com
[ Added a few intra-doc links. - Miguel ]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2026-10-13 12:33:16 +02:00

238 lines
6.9 KiB
Rust

// SPDX-License-Identifier: GPL-2.0
//! Additional numerical features for the kernel.
use core::ops;
pub mod bounded;
pub mod casts;
pub use bounded::*;
/// Designates unsigned primitive types.
pub enum Unsigned {}
/// Designates signed primitive types.
pub enum Signed {}
mod private {
pub trait Sealed {}
}
/// Describes core properties of integer types.
pub trait Integer:
private::Sealed
+ Sized
+ Copy
+ Clone
+ PartialEq
+ Eq
+ PartialOrd
+ Ord
+ ops::Add<Output = Self>
+ ops::AddAssign
+ ops::Sub<Output = Self>
+ ops::SubAssign
+ ops::Mul<Output = Self>
+ ops::MulAssign
+ ops::Div<Output = Self>
+ ops::DivAssign
+ ops::Rem<Output = Self>
+ ops::RemAssign
+ ops::BitAnd<Output = Self>
+ ops::BitAndAssign
+ ops::BitOr<Output = Self>
+ ops::BitOrAssign
+ ops::BitXor<Output = Self>
+ ops::BitXorAssign
+ ops::Shl<u32, Output = Self>
+ ops::ShlAssign<u32>
+ ops::Shr<u32, Output = Self>
+ ops::ShrAssign<u32>
+ ops::Not
{
/// Whether this type is [`Signed`] or [`Unsigned`].
type Signedness;
/// Number of bits used for value representation.
const BITS: u32;
}
macro_rules! impl_integer {
($($type:ty: $signedness:ty), *) => {
$(
impl private::Sealed for $type {}
impl Integer for $type {
type Signedness = $signedness;
const BITS: u32 = <$type>::BITS;
}
)*
};
}
impl_integer!(
u8: Unsigned,
u16: Unsigned,
u32: Unsigned,
u64: Unsigned,
u128: Unsigned,
usize: Unsigned,
i8: Signed,
i16: Signed,
i32: Signed,
i64: Signed,
i128: Signed,
isize: Signed
);
/// Creates a constant value ("cv") from an integer constant expression, with validity checked at
/// compile time.
///
/// This works for any type that implements [`FromConst`], with the target type inferred from
/// the context, or named explicitly with `cv!(value => Type)`. It can also be used in const
/// contexts.
///
/// # Pitfalls
///
/// Only the target type is inferred from the context. The expression passed to [`cv!`] is typed by
/// itself. So, unsuffixed integer literal expressions default to [`i32`]. For example
/// `cv!(2 << 31)` does not evaluate to the same value as `cv!(2i64 << 31)`, since `2 << 31` is
/// treated as an [`i32`] before being widened to [`i128`] internally. Literals and arithmetic
/// expressions that overflow [`i32`] are a compile error, it's just left shifts that require care.
///
/// # Examples
///
/// ```
/// use core::num::NonZero;
///
/// use kernel::{
/// num::Bounded,
/// ptr::Alignment, //
/// };
///
/// let v: NonZero<usize> = cv!(8);
/// assert_eq!(v.get(), 8);
///
/// // Any integer constant expression works, not only literals.
/// let m: NonZero<usize> = cv!(usize::MAX);
/// assert_eq!(m.get(), usize::MAX);
///
/// let b: Bounded<u32, 4> = cv!(15);
/// assert_eq!(b.get(), 15);
///
/// let a: Alignment = cv!(4096);
/// assert_eq!(a.as_usize(), 4096);
///
/// // Checked narrowing of integer constants, including in `const` items.
/// const SMALL: u8 = cv!(200u32);
/// assert_eq!(SMALL, 200);
///
/// const N: NonZero<u8> = cv!(5);
/// assert_eq!(N.get(), 5);
///
/// // The target type can be given explicitly.
/// let e = cv!(200u32 => u8);
/// assert_eq!(e, 200);
///
/// // With an explicit primitive target, the expression can use generic parameters.
/// const fn as_u64<const KEY: u16>() -> u64 {
/// cv!(KEY => u64)
/// }
/// assert_eq!(as_u64::<0x40>(), 0x40);
/// ```
#[macro_export]
#[doc(hidden)]
macro_rules! cv {
(@cast $v:expr => $t:ty) => {
const {
#[allow(unused_comparisons, unused_assignments, clippy::as_underscore)]
{
let v = $v;
let r = v as $t;
// Pin `back` to `v`'s type so `as _` casts back to the source type.
let mut back = v;
back = r as _;
::core::assert!(
back == v && (v < 0) == (r < 0),
"value does not fit into the target type"
);
r
}
}
};
// Using `FromConst<V>::VALUE` means const generic expressions can't be used, since it requires
// the `generic_const_exprs` feature. Provide a special path for each primitive type that allows
// const generic expressions.
($v:expr => u8) => { $crate::cv!(@cast $v => u8) };
($v:expr => u16) => { $crate::cv!(@cast $v => u16) };
($v:expr => u32) => { $crate::cv!(@cast $v => u32) };
($v:expr => u64) => { $crate::cv!(@cast $v => u64) };
($v:expr => u128) => { $crate::cv!(@cast $v => u128) };
($v:expr => usize) => { $crate::cv!(@cast $v => usize) };
($v:expr => i8) => { $crate::cv!(@cast $v => i8) };
($v:expr => i16) => { $crate::cv!(@cast $v => i16) };
($v:expr => i32) => { $crate::cv!(@cast $v => i32) };
($v:expr => i64) => { $crate::cv!(@cast $v => i64) };
($v:expr => i128) => { $crate::cv!(@cast $v => i128) };
($v:expr => isize) => { $crate::cv!(@cast $v => isize) };
($v:expr => $t:ty) => {
<$t as $crate::num::FromConst<{ $crate::cv!(@cast $v => i128) }>>::VALUE
};
($v:expr) => {
<_ as $crate::num::FromConst<{ $crate::cv!(@cast $v => i128) }>>::VALUE
};
}
#[doc(inline)]
pub use cv;
/// Types that can be created from an integer constant expression validated at compile time.
///
/// Implement this trait to make a type usable with [`cv!`]. Use the [`cv!`] macro, not this trait
/// directly, for creating values.
#[diagnostic::on_unimplemented(message = "`{Self}` cannot be converted from a constant")]
pub trait FromConst<const V: i128>: Sized {
/// The value that corresponds to the constant `V`.
///
/// Fails the build if `V` is not a valid value for [`Self`].
const VALUE: Self;
}
/// Implements [`FromConst`] for primitive integer types and their [`NonZero`](core::num::NonZero)
/// versions.
macro_rules! impl_from_const {
($($type:ty)*) => {
$(
impl<const V: i128> FromConst<V> for $type {
const VALUE: Self = {
// CAST: The macro is only used for types up to 64 bits wide, so `MIN` and `MAX`
// widen to `i128` losslessly.
assert!(
V >= <$type>::MIN as i128 && V <= <$type>::MAX as i128,
"constant cannot be represented by the target type"
);
// CAST: The assert above confirmed that `V` fits in `$type`.
V as $type
};
}
impl<const V: i128> FromConst<V> for core::num::NonZero<$type> {
const VALUE: Self = match core::num::NonZero::new(<$type as FromConst<V>>::VALUE) {
Some(value) => value,
None => panic!("constant cannot be zero"),
};
}
)*
};
}
impl_from_const!(
u8 u16 u32 u64 usize
i8 i16 i32 i64 isize
);