num.rs 7.1 KB

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