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);