1 // SPDX-License-Identifier: GPL-2.0 2 3 //! Additional numerical features for the kernel. 4 5 use core::ops; 6 7 pub mod bounded; 8 pub mod casts; 9 10 pub use bounded::*; 11 12 /// Designates unsigned primitive types. 13 pub enum Unsigned {} 14 15 /// Designates signed primitive types. 16 pub enum Signed {} 17 18 mod private { 19 pub trait Sealed {} 20 } 21 22 /// Describes core properties of integer types. 23 pub 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 61 macro_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 75 impl_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)] 147 macro_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)] 191 pub 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")] 198 pub 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. 207 macro_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 234 impl_from_const!( 235 u8 u16 u32 u64 usize 236 i8 i16 i32 i64 isize 237 ); 238