| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 |
- // SPDX-License-Identifier: GPL-2.0
- //! Numerical helpers functions and traits.
- //!
- //! This is essentially a staging module for code to mature until it can be moved to the `kernel`
- //! crate.
- use kernel::{
- macros::paste,
- prelude::*, //
- };
- /// Implements safe `as` conversion functions from a given type into a series of target types.
- ///
- /// These functions can be used in place of `as`, with the guarantee that they will be lossless.
- macro_rules! impl_safe_as {
- ($from:ty as { $($into:ty),* }) => {
- $(
- paste! {
- #[doc = ::core::concat!(
- "Losslessly converts a [`",
- ::core::stringify!($from),
- "`] into a [`",
- ::core::stringify!($into),
- "`].")]
- ///
- /// This conversion is allowed as it is always lossless. Prefer this over the `as`
- /// keyword to ensure no lossy casts are performed.
- ///
- /// This is for use from a `const` context. For non `const` use, prefer the
- /// [`FromSafeCast`] and [`IntoSafeCast`] traits.
- ///
- /// # Examples
- ///
- /// ```
- /// use crate::num;
- ///
- #[doc = ::core::concat!(
- "assert_eq!(num::",
- ::core::stringify!($from),
- "_as_",
- ::core::stringify!($into),
- "(1",
- ::core::stringify!($from),
- "), 1",
- ::core::stringify!($into),
- ");")]
- /// ```
- #[allow(unused)]
- #[inline(always)]
- pub(crate) const fn [<$from _as_ $into>](value: $from) -> $into {
- kernel::static_assert!(size_of::<$into>() >= size_of::<$from>());
- value as $into
- }
- }
- )*
- };
- }
- impl_safe_as!(u8 as { u16, u32, u64, usize });
- impl_safe_as!(u16 as { u32, u64, usize });
- impl_safe_as!(u32 as { u64, usize } );
- // `u64` and `usize` have the same size on 64-bit platforms.
- #[cfg(CONFIG_64BIT)]
- impl_safe_as!(u64 as { usize } );
- // A `usize` fits into a `u64` on 32 and 64-bit platforms.
- #[cfg(any(CONFIG_32BIT, CONFIG_64BIT))]
- impl_safe_as!(usize as { u64 });
- // A `usize` fits into a `u32` on 32-bit platforms.
- #[cfg(CONFIG_32BIT)]
- impl_safe_as!(usize as { u32 });
- /// Extension trait providing guaranteed lossless cast to `Self` from `T`.
- ///
- /// The standard library's `From` implementations do not cover conversions that are not portable or
- /// future-proof. For instance, even though it is safe today, `From<usize>` is not implemented for
- /// [`u64`] because of the possibility to support larger-than-64bit architectures in the future.
- ///
- /// The workaround is to either deal with the error handling of [`TryFrom`] for an operation that
- /// technically cannot fail, or to use the `as` keyword, which can silently strip data if the
- /// destination type is smaller than the source.
- ///
- /// Both options are hardly acceptable for the kernel. It is also a much more architecture
- /// dependent environment, supporting only 32 and 64 bit architectures, with some modules
- /// explicitly depending on a specific bus width that could greatly benefit from infallible
- /// conversion operations.
- ///
- /// Thus this extension trait that provides, for the architecture the kernel is built for, safe
- /// conversion between types for which such cast is lossless.
- ///
- /// In other words, this trait is implemented if, for the current build target and with `t: T`, the
- /// `t as Self` operation is completely lossless.
- ///
- /// Prefer this over the `as` keyword to ensure no lossy casts are performed.
- ///
- /// If you need to perform a conversion in `const` context, use [`u64_as_usize`], [`u32_as_usize`],
- /// [`usize_as_u64`], etc.
- ///
- /// # Examples
- ///
- /// ```
- /// use crate::num::FromSafeCast;
- ///
- /// assert_eq!(usize::from_safe_cast(0xf00u32), 0xf00u32 as usize);
- /// ```
- pub(crate) trait FromSafeCast<T> {
- /// Create a `Self` from `value`. This operation is guaranteed to be lossless.
- fn from_safe_cast(value: T) -> Self;
- }
- impl FromSafeCast<usize> for u64 {
- fn from_safe_cast(value: usize) -> Self {
- usize_as_u64(value)
- }
- }
- #[cfg(CONFIG_32BIT)]
- impl FromSafeCast<usize> for u32 {
- fn from_safe_cast(value: usize) -> Self {
- usize_as_u32(value)
- }
- }
- impl FromSafeCast<u32> for usize {
- fn from_safe_cast(value: u32) -> Self {
- u32_as_usize(value)
- }
- }
- #[cfg(CONFIG_64BIT)]
- impl FromSafeCast<u64> for usize {
- fn from_safe_cast(value: u64) -> Self {
- u64_as_usize(value)
- }
- }
- /// Counterpart to the [`FromSafeCast`] trait, i.e. this trait is to [`FromSafeCast`] what [`Into`]
- /// is to [`From`].
- ///
- /// See the documentation of [`FromSafeCast`] for the motivation.
- ///
- /// # Examples
- ///
- /// ```
- /// use crate::num::IntoSafeCast;
- ///
- /// assert_eq!(0xf00u32.into_safe_cast(), 0xf00u32 as usize);
- /// ```
- pub(crate) trait IntoSafeCast<T> {
- /// Convert `self` into a `T`. This operation is guaranteed to be lossless.
- fn into_safe_cast(self) -> T;
- }
- /// Reverse operation for types implementing [`FromSafeCast`].
- impl<S, T> IntoSafeCast<T> for S
- where
- T: FromSafeCast<S>,
- {
- fn into_safe_cast(self) -> T {
- T::from_safe_cast(self)
- }
- }
- /// Implements lossless conversion of a constant from a larger type into a smaller one.
- macro_rules! impl_const_into {
- ($from:ty => { $($into:ty),* }) => {
- $(
- paste! {
- #[doc = ::core::concat!(
- "Performs a build-time safe conversion of a [`",
- ::core::stringify!($from),
- "`] constant value into a [`",
- ::core::stringify!($into),
- "`].")]
- ///
- /// This checks at compile-time that the conversion is lossless, and triggers a build
- /// error if it isn't.
- ///
- /// # Examples
- ///
- /// ```
- /// use crate::num;
- ///
- /// // Succeeds because the value of the source fits into the destination's type.
- #[doc = ::core::concat!(
- "assert_eq!(num::",
- ::core::stringify!($from),
- "_into_",
- ::core::stringify!($into),
- "::<1",
- ::core::stringify!($from),
- ">(), 1",
- ::core::stringify!($into),
- ");")]
- /// ```
- #[allow(unused)]
- pub(crate) const fn [<$from _into_ $into>]<const N: $from>() -> $into {
- // Make sure that the target type is smaller than the source one.
- static_assert!($from::BITS >= $into::BITS);
- // CAST: we statically enforced above that `$from` is larger than `$into`, so the
- // `as` conversion will be lossless.
- build_assert!(N >= $into::MIN as $from && N <= $into::MAX as $from);
- N as $into
- }
- }
- )*
- };
- }
- impl_const_into!(usize => { u8, u16, u32 });
- impl_const_into!(u64 => { u8, u16, u32 });
- impl_const_into!(u32 => { u8, u16 });
- impl_const_into!(u16 => { u8 });
|