File Index
Files and directories
Sign in
FILE

num.rs

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/nova-core/num.rs RUST
  1// SPDX-License-Identifier: GPL-2.0
  2
  3//! Numerical helpers functions and traits.
  4//!
  5//! This is essentially a staging module for code to mature until it can be moved to the `kernel`
  6//! crate.
  7
  8use kernel::{
  9    macros::paste,
 10    prelude::*, //
 11};
 12
 13/// Implements safe `as` conversion functions from a given type into a series of target types.
 14///
 15/// These functions can be used in place of `as`, with the guarantee that they will be lossless.
 16macro_rules! impl_safe_as {
 17    ($from:ty as { $($into:ty),* }) => {
 18        $(
 19        paste! {
 20            #[doc = ::core::concat!(
 21                "Losslessly converts a [`",
 22                ::core::stringify!($from),
 23                "`] into a [`",
 24                ::core::stringify!($into),
 25                "`].")]
 26            ///
 27            /// This conversion is allowed as it is always lossless. Prefer this over the `as`
 28            /// keyword to ensure no lossy casts are performed.
 29            ///
 30            /// This is for use from a `const` context. For non `const` use, prefer the
 31            /// [`FromSafeCast`] and [`IntoSafeCast`] traits.
 32            ///
 33            /// # Examples
 34            ///
 35            /// ```
 36            /// use crate::num;
 37            ///
 38            #[doc = ::core::concat!(
 39                "assert_eq!(num::",
 40                ::core::stringify!($from),
 41                "_as_",
 42                ::core::stringify!($into),
 43                "(1",
 44                ::core::stringify!($from),
 45                "), 1",
 46                ::core::stringify!($into),
 47                ");")]
 48            /// ```
 49            #[allow(unused)]
 50            #[inline(always)]
 51            pub(crate) const fn [<$from _as_ $into>](value: $from) -> $into {
 52                kernel::static_assert!(size_of::<$into>() >= size_of::<$from>());
 53
 54                value as $into
 55            }
 56        }
 57        )*
 58    };
 59}
 60
 61impl_safe_as!(u8 as { u16, u32, u64, usize });
 62impl_safe_as!(u16 as { u32, u64, usize });
 63impl_safe_as!(u32 as { u64, usize } );
 64// `u64` and `usize` have the same size on 64-bit platforms.
 65#[cfg(CONFIG_64BIT)]
 66impl_safe_as!(u64 as { usize } );
 67
 68// A `usize` fits into a `u64` on 32 and 64-bit platforms.
 69#[cfg(any(CONFIG_32BIT, CONFIG_64BIT))]
 70impl_safe_as!(usize as { u64 });
 71
 72// A `usize` fits into a `u32` on 32-bit platforms.
 73#[cfg(CONFIG_32BIT)]
 74impl_safe_as!(usize as { u32 });
 75
 76/// Extension trait providing guaranteed lossless cast to `Self` from `T`.
 77///
 78/// The standard library's `From` implementations do not cover conversions that are not portable or
 79/// future-proof. For instance, even though it is safe today, `From<usize>` is not implemented for
 80/// [`u64`] because of the possibility to support larger-than-64bit architectures in the future.
 81///
 82/// The workaround is to either deal with the error handling of [`TryFrom`] for an operation that
 83/// technically cannot fail, or to use the `as` keyword, which can silently strip data if the
 84/// destination type is smaller than the source.
 85///
 86/// Both options are hardly acceptable for the kernel. It is also a much more architecture
 87/// dependent environment, supporting only 32 and 64 bit architectures, with some modules
 88/// explicitly depending on a specific bus width that could greatly benefit from infallible
 89/// conversion operations.
 90///
 91/// Thus this extension trait that provides, for the architecture the kernel is built for, safe
 92/// conversion between types for which such cast is lossless.
 93///
 94/// In other words, this trait is implemented if, for the current build target and with `t: T`, the
 95/// `t as Self` operation is completely lossless.
 96///
 97/// Prefer this over the `as` keyword to ensure no lossy casts are performed.
 98///
 99/// If you need to perform a conversion in `const` context, use [`u64_as_usize`], [`u32_as_usize`],
100/// [`usize_as_u64`], etc.
101///
102/// # Examples
103///
104/// ```
105/// use crate::num::FromSafeCast;
106///
107/// assert_eq!(usize::from_safe_cast(0xf00u32), 0xf00u32 as usize);
108/// ```
109pub(crate) trait FromSafeCast<T> {
110    /// Create a `Self` from `value`. This operation is guaranteed to be lossless.
111    fn from_safe_cast(value: T) -> Self;
112}
113
114impl FromSafeCast<usize> for u64 {
115    fn from_safe_cast(value: usize) -> Self {
116        usize_as_u64(value)
117    }
118}
119
120#[cfg(CONFIG_32BIT)]
121impl FromSafeCast<usize> for u32 {
122    fn from_safe_cast(value: usize) -> Self {
123        usize_as_u32(value)
124    }
125}
126
127impl FromSafeCast<u32> for usize {
128    fn from_safe_cast(value: u32) -> Self {
129        u32_as_usize(value)
130    }
131}
132
133#[cfg(CONFIG_64BIT)]
134impl FromSafeCast<u64> for usize {
135    fn from_safe_cast(value: u64) -> Self {
136        u64_as_usize(value)
137    }
138}
139
140/// Counterpart to the [`FromSafeCast`] trait, i.e. this trait is to [`FromSafeCast`] what [`Into`]
141/// is to [`From`].
142///
143/// See the documentation of [`FromSafeCast`] for the motivation.
144///
145/// # Examples
146///
147/// ```
148/// use crate::num::IntoSafeCast;
149///
150/// assert_eq!(0xf00u32.into_safe_cast(), 0xf00u32 as usize);
151/// ```
152pub(crate) trait IntoSafeCast<T> {
153    /// Convert `self` into a `T`. This operation is guaranteed to be lossless.
154    fn into_safe_cast(self) -> T;
155}
156
157/// Reverse operation for types implementing [`FromSafeCast`].
158impl<S, T> IntoSafeCast<T> for S
159where
160    T: FromSafeCast<S>,
161{
162    fn into_safe_cast(self) -> T {
163        T::from_safe_cast(self)
164    }
165}
166
167/// Implements lossless conversion of a constant from a larger type into a smaller one.
168macro_rules! impl_const_into {
169    ($from:ty => { $($into:ty),* }) => {
170        $(
171        paste! {
172            #[doc = ::core::concat!(
173                "Performs a build-time safe conversion of a [`",
174                ::core::stringify!($from),
175                "`] constant value into a [`",
176                ::core::stringify!($into),
177                "`].")]
178            ///
179            /// This checks at compile-time that the conversion is lossless, and triggers a build
180            /// error if it isn't.
181            ///
182            /// # Examples
183            ///
184            /// ```
185            /// use crate::num;
186            ///
187            /// // Succeeds because the value of the source fits into the destination's type.
188            #[doc = ::core::concat!(
189                "assert_eq!(num::",
190                ::core::stringify!($from),
191                "_into_",
192                ::core::stringify!($into),
193                "::<1",
194                ::core::stringify!($from),
195                ">(), 1",
196                ::core::stringify!($into),
197                ");")]
198            /// ```
199            #[allow(unused)]
200            pub(crate) const fn [<$from _into_ $into>]<const N: $from>() -> $into {
201                // Make sure that the target type is smaller than the source one.
202                static_assert!($from::BITS >= $into::BITS);
203                // CAST: we statically enforced above that `$from` is larger than `$into`, so the
204                // `as` conversion will be lossless.
205                build_assert!(N >= $into::MIN as $from && N <= $into::MAX as $from);
206
207                N as $into
208            }
209        }
210        )*
211    };
212}
213
214impl_const_into!(usize => { u8, u16, u32 });
215impl_const_into!(u64 => { u8, u16, u32 });
216impl_const_into!(u32 => { u8, u16 });
217impl_const_into!(u16 => { u8 });
~/ Read-only file preview.