Skip to main content

kernel/
num.rs

1// SPDX-License-Identifier: GPL-2.0
2
3//! Additional numerical features for the kernel.
4
5use core::ops;
6
7pub mod bounded;
8pub mod casts;
9
10pub use bounded::*;
11
12/// Designates unsigned primitive types.
13pub enum Unsigned {}
14
15/// Designates signed primitive types.
16pub enum Signed {}
17
18mod private {
19    pub trait Sealed {}
20}
21
22/// Describes core properties of integer types.
23pub trait Integer:
24    private::Sealed
25    + Sized
26    + Copy
27    + Clone
28    + PartialEq
29    + Eq
30    + PartialOrd
31    + Ord
32    + ops::Add<Output = Self>
33    + ops::AddAssign
34    + ops::Sub<Output = Self>
35    + ops::SubAssign
36    + ops::Mul<Output = Self>
37    + ops::MulAssign
38    + ops::Div<Output = Self>
39    + ops::DivAssign
40    + ops::Rem<Output = Self>
41    + ops::RemAssign
42    + ops::BitAnd<Output = Self>
43    + ops::BitAndAssign
44    + ops::BitOr<Output = Self>
45    + ops::BitOrAssign
46    + ops::BitXor<Output = Self>
47    + ops::BitXorAssign
48    + ops::Shl<u32, Output = Self>
49    + ops::ShlAssign<u32>
50    + ops::Shr<u32, Output = Self>
51    + ops::ShrAssign<u32>
52    + ops::Not
53{
54    /// Whether this type is [`Signed`] or [`Unsigned`].
55    type Signedness;
56
57    /// Number of bits used for value representation.
58    const BITS: u32;
59}
60
61macro_rules! impl_integer {
62    ($($type:ty: $signedness:ty), *) => {
63        $(
64        impl private::Sealed for $type {}
65
66        impl Integer for $type {
67            type Signedness = $signedness;
68
69            const BITS: u32 = <$type>::BITS;
70        }
71        )*
72    };
73}
74
75impl_integer!(
76    u8: Unsigned,
77    u16: Unsigned,
78    u32: Unsigned,
79    u64: Unsigned,
80    u128: Unsigned,
81    usize: Unsigned,
82    i8: Signed,
83    i16: Signed,
84    i32: Signed,
85    i64: Signed,
86    i128: Signed,
87    isize: Signed
88);
89
90/// Creates a constant value ("cv") from an integer constant expression, with validity checked at
91/// compile time.
92///
93/// This works for any type that implements [`FromConst`], with the target type inferred from
94/// the context, or named explicitly with `cv!(value => Type)`. It can also be used in const
95/// contexts.
96///
97/// # Pitfalls
98///
99/// Only the target type is inferred from the context. The expression passed to [`cv!`] is typed by
100/// itself. So, unsuffixed integer literal expressions default to [`i32`]. For example
101/// `cv!(2 << 31)` does not evaluate to the same value as `cv!(2i64 << 31)`, since `2 << 31` is
102/// treated as an [`i32`] before being widened to [`i128`] internally. Literals and arithmetic
103/// expressions that overflow [`i32`] are a compile error, it's just left shifts that require care.
104///
105/// # Examples
106///
107/// ```
108/// use core::num::NonZero;
109///
110/// use kernel::{
111///     num::Bounded,
112///     ptr::Alignment, //
113/// };
114///
115/// let v: NonZero<usize> = cv!(8);
116/// assert_eq!(v.get(), 8);
117///
118/// // Any integer constant expression works, not only literals.
119/// let m: NonZero<usize> = cv!(usize::MAX);
120/// assert_eq!(m.get(), usize::MAX);
121///
122/// let b: Bounded<u32, 4> = cv!(15);
123/// assert_eq!(b.get(), 15);
124///
125/// let a: Alignment = cv!(4096);
126/// assert_eq!(a.as_usize(), 4096);
127///
128/// // Checked narrowing of integer constants, including in `const` items.
129/// const SMALL: u8 = cv!(200u32);
130/// assert_eq!(SMALL, 200);
131///
132/// const N: NonZero<u8> = cv!(5);
133/// assert_eq!(N.get(), 5);
134///
135/// // The target type can be given explicitly.
136/// let e = cv!(200u32 => u8);
137/// assert_eq!(e, 200);
138///
139/// // With an explicit primitive target, the expression can use generic parameters.
140/// const fn as_u64<const KEY: u16>() -> u64 {
141///     cv!(KEY => u64)
142/// }
143/// assert_eq!(as_u64::<0x40>(), 0x40);
144/// ```
145#[macro_export]
146#[doc(hidden)]
147macro_rules! cv {
148    (@cast $v:expr => $t:ty) => {
149        const {
150            #[allow(unused_comparisons, unused_assignments, clippy::as_underscore)]
151            {
152                let v = $v;
153                let r = v as $t;
154                // Pin `back` to `v`'s type so `as _` casts back to the source type.
155                let mut back = v;
156                back = r as _;
157
158                ::core::assert!(
159                    back == v && (v < 0) == (r < 0),
160                    "value does not fit into the target type"
161                );
162
163                r
164            }
165        }
166    };
167
168    // Using `FromConst<V>::VALUE` means const generic expressions can't be used, since it requires
169    // the `generic_const_exprs` feature. Provide a special path for each primitive type that allows
170    // const generic expressions.
171    ($v:expr => u8) => { $crate::cv!(@cast $v => u8) };
172    ($v:expr => u16) => { $crate::cv!(@cast $v => u16) };
173    ($v:expr => u32) => { $crate::cv!(@cast $v => u32) };
174    ($v:expr => u64) => { $crate::cv!(@cast $v => u64) };
175    ($v:expr => u128) => { $crate::cv!(@cast $v => u128) };
176    ($v:expr => usize) => { $crate::cv!(@cast $v => usize) };
177    ($v:expr => i8) => { $crate::cv!(@cast $v => i8) };
178    ($v:expr => i16) => { $crate::cv!(@cast $v => i16) };
179    ($v:expr => i32) => { $crate::cv!(@cast $v => i32) };
180    ($v:expr => i64) => { $crate::cv!(@cast $v => i64) };
181    ($v:expr => i128) => { $crate::cv!(@cast $v => i128) };
182    ($v:expr => isize) => { $crate::cv!(@cast $v => isize) };
183    ($v:expr => $t:ty) => {
184        <$t as $crate::num::FromConst<{ $crate::cv!(@cast $v => i128) }>>::VALUE
185    };
186    ($v:expr) => {
187        <_ as $crate::num::FromConst<{ $crate::cv!(@cast $v => i128) }>>::VALUE
188    };
189}
190#[doc(inline)]
191pub use cv;
192
193/// Types that can be created from an integer constant expression validated at compile time.
194///
195/// Implement this trait to make a type usable with [`cv!`]. Use the [`cv!`] macro, not this trait
196/// directly, for creating values.
197#[diagnostic::on_unimplemented(message = "`{Self}` cannot be converted from a constant")]
198pub trait FromConst<const V: i128>: Sized {
199    /// The value that corresponds to the constant `V`.
200    ///
201    /// Fails the build if `V` is not a valid value for [`Self`].
202    const VALUE: Self;
203}
204
205/// Implements [`FromConst`] for primitive integer types and their [`NonZero`](core::num::NonZero)
206/// versions.
207macro_rules! impl_from_const {
208    ($($type:ty)*) => {
209        $(
210        impl<const V: i128> FromConst<V> for $type {
211            const VALUE: Self = {
212                // CAST: The macro is only used for types up to 64 bits wide, so `MIN` and `MAX`
213                // widen to `i128` losslessly.
214                assert!(
215                    V >= <$type>::MIN as i128 && V <= <$type>::MAX as i128,
216                    "constant cannot be represented by the target type"
217                );
218
219                // CAST: The assert above confirmed that `V` fits in `$type`.
220                V as $type
221            };
222        }
223
224        impl<const V: i128> FromConst<V> for core::num::NonZero<$type> {
225            const VALUE: Self = match core::num::NonZero::new(<$type as FromConst<V>>::VALUE) {
226                Some(value) => value,
227                None => panic!("constant cannot be zero"),
228            };
229        }
230        )*
231    };
232}
233
234impl_from_const!(
235    u8 u16 u32 u64 usize
236    i8 i16 i32 i64 isize
237);