Skip to main content

kernel/num/
casts.rs

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
44use 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.
49macro_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.
94impl_safe_as!(u8 as { u16, u32, u64, usize });
95impl_safe_as!(u16 as { u32, u64, usize });
96impl_safe_as!(u32 as { u64 });
97// A `usize` fits into a `u64` on all supported platforms.
98impl_safe_as!(usize as { u64 });
99// A `u32` fits into a `usize` on all supported platforms.
100impl_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/// ```
136pub 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.
142impl 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.
150impl 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/// ```
169pub 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`].
175impl<S, T> IntoSafeCast<T> for S
176where
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.
186macro_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
232impl_const_into!(usize => { u8, u16, u32 });
233impl_const_into!(u64 => { u8, u16, u32 });
234impl_const_into!(u32 => { u8, u16 });
235impl_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.
243pub 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}