[PATCH v4 04/20] rust: add new `num` module with useful integer operations

Alexandre Courbot acourbot at nvidia.com
Thu May 29 01:35:02 UTC 2025


Hi Alice,

On Thu May 29, 2025 at 4:56 AM JST, Alice Ryhl wrote:
> On Wed, May 21, 2025 at 8:45 AM Alexandre Courbot <acourbot at nvidia.com> wrote:
>>
>> Introduce the `num` module, featuring the `NumExt` extension trait
>> that expands unsigned integers with useful operations for the kernel.
>>
>> These are to be used by the nova-core driver, but they are so ubiquitous
>> that other drivers should be able to take advantage of them as well.
>>
>> The currently implemented operations are:
>>
>> - align_down()
>> - align_up()
>> - fls()
>>
>> But this trait is expected to be expanded further.
>>
>> `NumExt` is on unsigned types using a macro. An approach using another
>> trait constrained by the operator traits that we need (`Add`, `Sub`,
>> etc) was also considered, but had to be dropped as we need to use
>> wrapping operations, which are not provided by any trait.
>>
>> Co-developed-by: Joel Fernandes <joelagnelf at nvidia.com>
>> Signed-off-by: Joel Fernandes <joelagnelf at nvidia.com>
>> Signed-off-by: Alexandre Courbot <acourbot at nvidia.com>
>> ---
>>  rust/kernel/lib.rs |  1 +
>>  rust/kernel/num.rs | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 83 insertions(+)
>>
>> diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
>> index ab0286857061d2de1be0279cbd2cd3490e5a48c3..be75b196aa7a29cf3eed7c902ed8fb98689bbb50 100644
>> --- a/rust/kernel/lib.rs
>> +++ b/rust/kernel/lib.rs
>> @@ -67,6 +67,7 @@
>>  pub mod miscdevice;
>>  #[cfg(CONFIG_NET)]
>>  pub mod net;
>> +pub mod num;
>>  pub mod of;
>>  pub mod page;
>>  #[cfg(CONFIG_PCI)]
>> diff --git a/rust/kernel/num.rs b/rust/kernel/num.rs
>> new file mode 100644
>> index 0000000000000000000000000000000000000000..05d45b59313d830876c1a7b452827689a6dd5400
>> --- /dev/null
>> +++ b/rust/kernel/num.rs
>> @@ -0,0 +1,82 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +
>> +//! Numerical and binary utilities for primitive types.
>> +
>> +/// Extension trait providing useful methods for the kernel on integers.
>> +pub trait NumExt {
>
> I wonder if these should just be standalone methods instead of an
> extension trait?

Standalone methods would need to have different names depending on the
type (e.g. `align_down_u8`, `align_down_u16`, etc.) as I don't think
they can be all made generic (there is for instance no trait for
`wrapping_add`). I thought an extension trait would be cleaner in that
respect.

>
>> +    /// Align `self` down to `alignment`.
>> +    ///
>> +    /// `alignment` must be a power of 2 for accurate results.
>> +    ///
>> +    /// # Examples
>> +    ///
>> +    /// ```
>> +    /// use kernel::num::NumExt;
>> +    ///
>> +    /// assert_eq!(0x4fffu32.align_down(0x1000), 0x4000);
>> +    /// assert_eq!(0x4fffu32.align_down(0x0), 0x0);
>> +    /// ```
>> +    fn align_down(self, alignment: Self) -> Self;
>> +
>> +    /// Align `self` up to `alignment`.
>> +    ///
>> +    /// `alignment` must be a power of 2 for accurate results.
>> +    ///
>> +    /// Wraps around to `0` if the requested alignment pushes the result above the type's limits.
>> +    ///
>> +    /// # Examples
>> +    ///
>> +    /// ```
>> +    /// use kernel::num::NumExt;
>> +    ///
>> +    /// assert_eq!(0x4fffu32.align_up(0x1000), 0x5000);
>> +    /// assert_eq!(0x4000u32.align_up(0x1000), 0x4000);
>> +    /// assert_eq!(0x0u32.align_up(0x1000), 0x0);
>> +    /// assert_eq!(0xffffu16.align_up(0x100), 0x0);
>> +    /// assert_eq!(0x4fffu32.align_up(0x0), 0x0);
>> +    /// ```
>> +    fn align_up(self, alignment: Self) -> Self;
>
> I would probably make alignment into a const parameter.
>
> fn align_up<ALIGN: usize>(value: usize) -> usize {
>     const { assert!(ALIGN.is_power_of_two()) };
>     self.wrapping_add(ALIGN.wrapping_sub(1)).align_down(ALIGN)
> }
>
> Here the check for power-of-two happens at compile time. Unless you
> have cases where the alignment is a dynamic parameter?

It's very tempting, and I agree that in 99% of the cases the alignment
parameter is a clear constant. There might be the odd case where e.g. a
particular device supports different page sizes for its DMA mappings,
but even there the sizes would come from a limited list.

Worst case, providing two versions, or having the user fall back to
`next_multiple_of` is also an option.


More information about the Nouveau mailing list