Hi Alex, > On 17 Feb 2025, at 11:04, Alexandre Courbot <acour...@nvidia.com> wrote: > > It is common to build a u64 from its high and low parts obtained from > two 32-bit registers. Conversely, it is also common to split a u64 into > two u32s to write them into registers. Add an extension trait for u64 > that implement these methods in a new `num` module.
Thank you for working on that. I find myself doing this manually extremely often indeed. > > It is expected that this trait will be extended with other useful > operations, and similar extension traits implemented for other types. > > Signed-off-by: Alexandre Courbot <acour...@nvidia.com> > --- > rust/kernel/lib.rs | 1 + > rust/kernel/num.rs | 32 ++++++++++++++++++++++++++++++++ > 2 files changed, 33 insertions(+) > > diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs > index > 496ed32b0911a9fdbce5d26738b9cf7ef910b269..8c0c7c20a16aa96e3d3e444be3e03878650ddf77 > 100644 > --- a/rust/kernel/lib.rs > +++ b/rust/kernel/lib.rs > @@ -59,6 +59,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..5e714cbda4575b8d74f50660580dc4c5683f8c2b > --- /dev/null > +++ b/rust/kernel/num.rs > @@ -0,0 +1,32 @@ > +// SPDX-License-Identifier: GPL-2.0 > + > +//! Numerical and binary utilities for primitive types. > + > +/// Useful operations for `u64`. > +pub trait U64Ext { > + /// Build a `u64` by combining its `high` and `low` parts. > + /// > + /// ``` > + /// use kernel::num::U64Ext; > + /// assert_eq!(u64::from_u32s(0x01234567, 0x89abcdef), > 0x01234567_89abcdef); > + /// ``` > + fn from_u32s(high: u32, low: u32) -> Self; > + > + /// Returns the `(high, low)` u32s that constitute `self`. > + /// > + /// ``` > + /// use kernel::num::U64Ext; > + /// assert_eq!(u64::into_u32s(0x01234567_89abcdef), (0x1234567, > 0x89abcdef)); > + /// ``` > + fn into_u32s(self) -> (u32, u32); > +} > + > +impl U64Ext for u64 { > + fn from_u32s(high: u32, low: u32) -> Self { > + ((high as u64) << u32::BITS) | low as u64 > + } > + > + fn into_u32s(self) -> (u32, u32) { I wonder if a struct would make more sense here. Just recently I had to debug an issue where I forgot the right order for code I had just written. Something like: let (pgcount, pgsize) = foo(); where the function actually returned (pgsize, pgcount). A proper struct with `high` and `low` might be more verbose, but it rules out this issue. > + ((self >> u32::BITS) as u32, self as u32) > + } > +} > > -- > 2.48.1 > — Daniel >