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