Commit 4521438f authored by Lyude Paul's avatar Lyude Paul Committed by Andreas Hindborg
Browse files

rust: time: Implement basic arithmetic operations for Delta



While rvkms is only going to be using a few of these, since Deltas are
basically the same as i64 it's easy enough to just implement all of the
basic arithmetic operations for Delta types.

Keep in mind there's one quirk here - the kernel has no support for
i64 % i64 on 32 bit platforms, the closest we have is i64 % i32 through
div_s64_rem(). So, instead of implementing ops::Rem or ops::RemAssign we
simply provide Delta::rem_nanos().

Signed-off-by: default avatarLyude Paul <lyude@redhat.com>
Reviewed-by: default avatarDaniel Almeida <daniel.almeida@collabora.com>
Reviewed-by: default avatarFUJITA Tomonori <fujita.tomonori@gmail.com>
Reviewed-by: default avatarAndreas Hindborg <a.hindborg@kernel.org>
Link: https://lore.kernel.org/r/20250820203704.731588-3-lyude@redhat.com


Signed-off-by: default avatarAndreas Hindborg <a.hindborg@kernel.org>
parent 22b65a40
Loading
Loading
Loading
Loading
+98 −0
Original line number Diff line number Diff line
@@ -287,6 +287,78 @@ pub struct Delta {
    nanos: i64,
}

impl ops::Add for Delta {
    type Output = Self;

    #[inline]
    fn add(self, rhs: Self) -> Self {
        Self {
            nanos: self.nanos + rhs.nanos,
        }
    }
}

impl ops::AddAssign for Delta {
    #[inline]
    fn add_assign(&mut self, rhs: Self) {
        self.nanos += rhs.nanos;
    }
}

impl ops::Sub for Delta {
    type Output = Self;

    #[inline]
    fn sub(self, rhs: Self) -> Self::Output {
        Self {
            nanos: self.nanos - rhs.nanos,
        }
    }
}

impl ops::SubAssign for Delta {
    #[inline]
    fn sub_assign(&mut self, rhs: Self) {
        self.nanos -= rhs.nanos;
    }
}

impl ops::Mul<i64> for Delta {
    type Output = Self;

    #[inline]
    fn mul(self, rhs: i64) -> Self::Output {
        Self {
            nanos: self.nanos * rhs,
        }
    }
}

impl ops::MulAssign<i64> for Delta {
    #[inline]
    fn mul_assign(&mut self, rhs: i64) {
        self.nanos *= rhs;
    }
}

impl ops::Div for Delta {
    type Output = i64;

    #[inline]
    fn div(self, rhs: Self) -> Self::Output {
        #[cfg(CONFIG_64BIT)]
        {
            self.nanos / rhs.nanos
        }

        #[cfg(not(CONFIG_64BIT))]
        {
            // SAFETY: This function is always safe to call regardless of the input values
            unsafe { bindings::div64_s64(self.nanos, rhs.nanos) }
        }
    }
}

impl Delta {
    /// A span of time equal to zero.
    pub const ZERO: Self = Self { nanos: 0 };
@@ -375,4 +447,30 @@ pub fn as_millis(self) -> i64 {
            bindings::ktime_to_ms(self.as_nanos())
        }
    }

    /// Return `self % dividend` where `dividend` is in nanoseconds.
    ///
    /// The kernel doesn't have any emulation for `s64 % s64` on 32 bit platforms, so this is
    /// limited to 32 bit dividends.
    #[inline]
    pub fn rem_nanos(self, dividend: i32) -> Self {
        #[cfg(CONFIG_64BIT)]
        {
            Self {
                nanos: self.as_nanos() % i64::from(dividend),
            }
        }

        #[cfg(not(CONFIG_64BIT))]
        {
            let mut rem = 0;

            // SAFETY: `rem` is in the stack, so we can always provide a valid pointer to it.
            unsafe { bindings::div_s64_rem(self.as_nanos(), dividend, &mut rem) };

            Self {
                nanos: i64::from(rem),
            }
        }
    }
}