1 // SPDX-License-Identifier: GPL-2.0 2 3 //! Numerical helpers functions and traits. 4 //! 5 //! This is essentially a staging module for code to mature until it can be moved to the `kernel` 6 //! crate. 7 8 use kernel::{ 9 macros::paste, 10 prelude::*, // 11 }; 12 13 /// Implements safe `as` conversion functions from a given type into a series of target types. 14 /// 15 /// These functions can be used in place of `as`, with the guarantee that they will be lossless. 16 macro_rules! impl_safe_as { 17 ($from:ty as { $($into:ty),* }) => { 18 $( 19 paste! { 20 #[doc = ::core::concat!( 21 "Losslessly converts a [`", 22 ::core::stringify!($from), 23 "`] into a [`", 24 ::core::stringify!($into), 25 "`].")] 26 /// 27 /// This conversion is allowed as it is always lossless. Prefer this over the `as` 28 /// keyword to ensure no lossy casts are performed. 29 /// 30 /// This is for use from a `const` context. For non `const` use, prefer the 31 /// [`FromSafeCast`] and [`IntoSafeCast`] traits. 32 /// 33 /// # Examples 34 /// 35 /// ``` 36 /// use crate::num; 37 /// 38 #[doc = ::core::concat!( 39 "assert_eq!(num::", 40 ::core::stringify!($from), 41 "_as_", 42 ::core::stringify!($into), 43 "(1", 44 ::core::stringify!($from), 45 "), 1", 46 ::core::stringify!($into), 47 ");")] 48 /// ``` 49 #[allow(unused)] 50 #[inline(always)] 51 pub(crate) const fn [<$from _as_ $into>](value: $from) -> $into { 52 kernel::static_assert!(size_of::<$into>() >= size_of::<$from>()); 53 54 value as $into 55 } 56 } 57 )* 58 }; 59 } 60 61 impl_safe_as!(u8 as { u16, u32, u64, usize }); 62 impl_safe_as!(u16 as { u32, u64, usize }); 63 impl_safe_as!(u32 as { u64, usize } ); 64 // `u64` and `usize` have the same size on 64-bit platforms. 65 #[cfg(CONFIG_64BIT)] 66 impl_safe_as!(u64 as { usize } ); 67 68 // A `usize` fits into a `u64` on 32 and 64-bit platforms. 69 #[cfg(any(CONFIG_32BIT, CONFIG_64BIT))] 70 impl_safe_as!(usize as { u64 }); 71 72 // A `usize` fits into a `u32` on 32-bit platforms. 73 #[cfg(CONFIG_32BIT)] 74 impl_safe_as!(usize as { u32 }); 75 76 /// Extension trait providing guaranteed lossless cast to `Self` from `T`. 77 /// 78 /// The standard library's `From` implementations do not cover conversions that are not portable or 79 /// future-proof. For instance, even though it is safe today, `From<usize>` is not implemented for 80 /// [`u64`] because of the possibility to support larger-than-64bit architectures in the future. 81 /// 82 /// The workaround is to either deal with the error handling of [`TryFrom`] for an operation that 83 /// technically cannot fail, or to use the `as` keyword, which can silently strip data if the 84 /// destination type is smaller than the source. 85 /// 86 /// Both options are hardly acceptable for the kernel. It is also a much more architecture 87 /// dependent environment, supporting only 32 and 64 bit architectures, with some modules 88 /// explicitly depending on a specific bus width that could greatly benefit from infallible 89 /// conversion operations. 90 /// 91 /// Thus this extension trait that provides, for the architecture the kernel is built for, safe 92 /// conversion between types for which such cast is lossless. 93 /// 94 /// In other words, this trait is implemented if, for the current build target and with `t: T`, the 95 /// `t as Self` operation is completely lossless. 96 /// 97 /// Prefer this over the `as` keyword to ensure no lossy casts are performed. 98 /// 99 /// If you need to perform a conversion in `const` context, use [`u64_as_usize`], [`u32_as_usize`], 100 /// [`usize_as_u64`], etc. 101 /// 102 /// # Examples 103 /// 104 /// ``` 105 /// use crate::num::FromSafeCast; 106 /// 107 /// assert_eq!(usize::from_safe_cast(0xf00u32), 0xf00u32 as usize); 108 /// ``` 109 pub(crate) trait FromSafeCast<T> { 110 /// Create a `Self` from `value`. This operation is guaranteed to be lossless. 111 fn from_safe_cast(value: T) -> Self; 112 } 113 114 impl FromSafeCast<usize> for u64 { 115 fn from_safe_cast(value: usize) -> Self { 116 usize_as_u64(value) 117 } 118 } 119 120 #[cfg(CONFIG_32BIT)] 121 impl FromSafeCast<usize> for u32 { 122 fn from_safe_cast(value: usize) -> Self { 123 usize_as_u32(value) 124 } 125 } 126 127 impl FromSafeCast<u32> for usize { 128 fn from_safe_cast(value: u32) -> Self { 129 u32_as_usize(value) 130 } 131 } 132 133 #[cfg(CONFIG_64BIT)] 134 impl FromSafeCast<u64> for usize { 135 fn from_safe_cast(value: u64) -> Self { 136 u64_as_usize(value) 137 } 138 } 139 140 /// Counterpart to the [`FromSafeCast`] trait, i.e. this trait is to [`FromSafeCast`] what [`Into`] 141 /// is to [`From`]. 142 /// 143 /// See the documentation of [`FromSafeCast`] for the motivation. 144 /// 145 /// # Examples 146 /// 147 /// ``` 148 /// use crate::num::IntoSafeCast; 149 /// 150 /// assert_eq!(0xf00u32.into_safe_cast(), 0xf00u32 as usize); 151 /// ``` 152 pub(crate) trait IntoSafeCast<T> { 153 /// Convert `self` into a `T`. This operation is guaranteed to be lossless. 154 fn into_safe_cast(self) -> T; 155 } 156 157 /// Reverse operation for types implementing [`FromSafeCast`]. 158 impl<S, T> IntoSafeCast<T> for S 159 where 160 T: FromSafeCast<S>, 161 { 162 fn into_safe_cast(self) -> T { 163 T::from_safe_cast(self) 164 } 165 } 166 167 /// Implements lossless conversion of a constant from a larger type into a smaller one. 168 macro_rules! impl_const_into { 169 ($from:ty => { $($into:ty),* }) => { 170 $( 171 paste! { 172 #[doc = ::core::concat!( 173 "Performs a build-time safe conversion of a [`", 174 ::core::stringify!($from), 175 "`] constant value into a [`", 176 ::core::stringify!($into), 177 "`].")] 178 /// 179 /// This checks at compile-time that the conversion is lossless, and triggers a build 180 /// error if it isn't. 181 /// 182 /// # Examples 183 /// 184 /// ``` 185 /// use crate::num; 186 /// 187 /// // Succeeds because the value of the source fits into the destination's type. 188 #[doc = ::core::concat!( 189 "assert_eq!(num::", 190 ::core::stringify!($from), 191 "_into_", 192 ::core::stringify!($into), 193 "::<1", 194 ::core::stringify!($from), 195 ">(), 1", 196 ::core::stringify!($into), 197 ");")] 198 /// ``` 199 #[allow(unused)] 200 pub(crate) const fn [<$from _into_ $into>]<const N: $from>() -> $into { 201 // Make sure that the target type is smaller than the source one. 202 static_assert!($from::BITS >= $into::BITS); 203 // CAST: we statically enforced above that `$from` is larger than `$into`, so the 204 // `as` conversion will be lossless. 205 build_assert!(N >= $into::MIN as $from && N <= $into::MAX as $from); 206 207 N as $into 208 } 209 } 210 )* 211 }; 212 } 213 214 impl_const_into!(usize => { u8, u16, u32 }); 215 impl_const_into!(u64 => { u8, u16, u32 }); 216 impl_const_into!(u32 => { u8, u16 }); 217 impl_const_into!(u16 => { u8 }); 218 219 /// Creates an enum type associated to a [`Bounded`](kernel::num::Bounded), with a [`From`] 220 /// conversion to the associated `Bounded` and either a [`TryFrom`] or `From` conversion from the 221 /// associated `Bounded`. 222 // TODO[FPRI]: This is a temporary solution to be replaced with the corresponding derive macros 223 // once they land. 224 #[macro_export] 225 macro_rules! bounded_enum { 226 ( 227 $(#[$enum_meta:meta])* 228 $vis:vis enum $enum_type:ident with $from_impl:ident<Bounded<$width:ty, $length:literal>> { 229 $( $(#[doc = $variant_doc:expr])* $variant:ident = $value:expr),* $(,)* 230 } 231 ) => { 232 $(#[$enum_meta])* 233 $vis enum $enum_type { 234 $( 235 $(#[doc = $variant_doc])* 236 $variant = $value 237 ),* 238 } 239 240 impl core::convert::From<$enum_type> for kernel::num::Bounded<$width, $length> { 241 fn from(value: $enum_type) -> Self { 242 match value { 243 $($enum_type::$variant => 244 kernel::num::Bounded::<$width, _>::new::<{ $value }>()),* 245 } 246 } 247 } 248 249 bounded_enum!(@impl_from $enum_type with $from_impl<Bounded<$width, $length>> { 250 $($variant = $value),* 251 }); 252 }; 253 254 // `TryFrom` implementation from associated `Bounded` to enum type. 255 (@impl_from $enum_type:ident with TryFrom<Bounded<$width:ty, $length:literal>> { 256 $($variant:ident = $value:expr),* $(,)* 257 }) => { 258 impl core::convert::TryFrom<kernel::num::Bounded<$width, $length>> for $enum_type { 259 type Error = kernel::error::Error; 260 261 fn try_from( 262 value: kernel::num::Bounded<$width, $length> 263 ) -> kernel::error::Result<Self> { 264 match value.get() { 265 $( 266 $value => Ok($enum_type::$variant), 267 )* 268 _ => Err(kernel::error::code::EINVAL), 269 } 270 } 271 } 272 }; 273 274 // `From` implementation from associated `Bounded` to enum type. Triggers a build-time error if 275 // all possible values of the `Bounded` are not covered by the enum type. 276 (@impl_from $enum_type:ident with From<Bounded<$width:ty, $length:literal>> { 277 $($variant:ident = $value:expr),* $(,)* 278 }) => { 279 impl core::convert::From<kernel::num::Bounded<$width, $length>> for $enum_type { 280 fn from(value: kernel::num::Bounded<$width, $length>) -> Self { 281 const MAX: $width = 1 << $length; 282 283 // Makes the compiler optimizer aware of the possible range of values. 284 let value = value.get() & ((1 << $length) - 1); 285 match value { 286 $( 287 $value => $enum_type::$variant, 288 )* 289 // PANIC: we cannot reach this arm as all possible variants are handled by the 290 // match arms above. It is here to make the compiler complain if `$enum_type` 291 // does not cover all values of the `0..MAX` range. 292 MAX.. => unreachable!(), 293 } 294 } 295 } 296 } 297 } 298