xref: /linux/rust/kernel/num/casts.rs (revision d24f5cdbeff8b6a063fca92d0a1f94122a799b59)
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