| 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*; |
| 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 | |
| 50 | => |
| 51 | $ |
| 52 | $cratepaste! |
| 53 | |
| 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 | |
| 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 | |
| 83 | pub const fn |
| 84 | $cratestatic_assert!; |
| 85 | |
| 86 | value as $into |
| 87 | |
| 88 | |
| 89 | * |
| 90 | }; |
| 91 | |
| 92 | |
| 93 | // Valid `Into` transformations. |
| 94 | impl_safe_as!; |
| 95 | impl_safe_as!; |
| 96 | impl_safe_as!; |
| 97 | // A `usize` fits into a `u64` on all supported platforms. |
| 98 | impl_safe_as!; |
| 99 | // A `u32` fits into a `usize` on all supported platforms. |
| 100 | impl_safe_as!; |
| 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 | |
| 137 | /// Create a [`Self`] from `value`. This operation is guaranteed to be lossless. |
| 138 | ; |
| 139 | |
| 140 | |
| 141 | // A `usize` fits into a `u64` on all supported platforms. |
| 142 | |
| 143 | |
| 144 | |
| 145 | usize_as_u64 |
| 146 | |
| 147 | |
| 148 | |
| 149 | // A `u32` fits into a `usize` on all supported platforms. |
| 150 | |
| 151 | |
| 152 | |
| 153 | u32_as_usize |
| 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 | |
| 170 | /// Convert `self` into a `T`. This operation is guaranteed to be lossless. |
| 171 | ; |
| 172 | |
| 173 | |
| 174 | /// Reverse operation for types implementing [`FromSafeCast`]. |
| 175 | |
| 176 | |
| 177 | T: , |
| 178 | |
| 179 | |
| 180 | |
| 181 | from_safe_cast |
| 182 | |
| 183 | |
| 184 | |
| 185 | /// Implements lossless conversion of a constant from a larger type into a smaller one. |
| 186 | |
| 187 | => |
| 188 | $ |
| 189 | $cratepaste! |
| 190 | |
| 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 | |
| 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 | |
| 218 | pub const fn <const N: $from> |
| 219 | // Make sure that the target type is smaller than the source one. |
| 220 | $cratestatic_assert!; |
| 221 | // CAST: we statically enforced above that `$from` is larger than `$into`, so the |
| 222 | // `as` conversion will be lossless. |
| 223 | $crateconst_assert!; |
| 224 | |
| 225 | N as $into |
| 226 | |
| 227 | |
| 228 | * |
| 229 | }; |
| 230 | |
| 231 | |
| 232 | impl_const_into!; |
| 233 | impl_const_into!; |
| 234 | impl_const_into!; |
| 235 | impl_const_into!; |
| 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 | |
| 244 | /// Trait identical to [`FromSafeCast`](super::FromSafeCast), but for conversions that are not |
| 245 | /// available on all architectures. |
| 246 | |
| 247 | /// Create a [`Self`] from `value`. This operation is guaranteed to be lossless. |
| 248 | ; |
| 249 | |
| 250 | |
| 251 | /// Trait identical to [`IntoSafeCast`](super::IntoSafeCast), but for conversions that are not |
| 252 | /// available on all architectures. |
| 253 | |
| 254 | /// Convert `self` into a `T`. This operation is guaranteed to be lossless. |
| 255 | ; |
| 256 | |
| 257 | |
| 258 | /// Reverse operation for types implementing [`FromSafeCastArch`]. |
| 259 | |
| 260 | |
| 261 | T: , |
| 262 | |
| 263 | |
| 264 | |
| 265 | from_safe_cast_arch |
| 266 | |
| 267 | |
| 268 | |
| 269 | /// A [`u64`] fits into a [`usize`] on 64-bit platforms. |
| 270 | |
| 271 | |
| 272 | pub const |
| 273 | value as usize |
| 274 | |
| 275 | |
| 276 | |
| 277 | |
| 278 | |
| 279 | |
| 280 | u64_as_usize |
| 281 | |
| 282 | |
| 283 | |
| 284 | /// A [`usize`] fits into a [`u32`] on 32-bit platforms. |
| 285 | |
| 286 | |
| 287 | pub const |
| 288 | value as u32 |
| 289 | |
| 290 | |
| 291 | |
| 292 | |
| 293 | |
| 294 | |
| 295 | usize_as_u32 |
| 296 | |
| 297 | |
| 298 |