From: Alexandre Courbot Date: Mon, 10 Nov 2025 13:34:11 +0000 (+0900) Subject: gpu: nova-core: num: add functions to safely convert a const value to a smaller type X-Git-Url: https://gentwo.org/gitweb/?a=commitdiff_plain;h=89605daa1ee0de634d7f2ee6370363cfaa8c9499;p=linux%2F.git gpu: nova-core: num: add functions to safely convert a const value to a smaller type There are times where we need to store a constant value defined as a larger type (e.g. through a binding) into a smaller type, knowing that the value will fit. Rust, unfortunately, only provides us with the `as` operator for that purpose, the use of which is discouraged as it silently strips data. Extend the `num` module with functions allowing to perform the conversion infallibly, at compile time. Example: const FOO_VALUE: u32 = 1; // `FOO_VALUE` fits into a `u8`, so the conversion is valid. let foo = num::u32_to_u8::<{ FOO_VALUE }>(); We are going to use this feature extensively in Nova. Reviewed-by: Mikko Perttunen [acourbot@nvidia.com: fix mistake in example pointed out by Mikko.] Signed-off-by: Alexandre Courbot Message-ID: <20251110-gsp_boot-v9-3-8ae4058e3c0e@nvidia.com> --- diff --git a/drivers/gpu/nova-core/num.rs b/drivers/gpu/nova-core/num.rs index 92a91b9e30de..c952a834e662 100644 --- a/drivers/gpu/nova-core/num.rs +++ b/drivers/gpu/nova-core/num.rs @@ -163,3 +163,55 @@ 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>]() -> $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 });