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