Skip to content

Commit 862d0ab

Browse files
committed
feat(time): implement addition/subtraction of Duration and other ops
1 parent 27de459 commit 862d0ab

File tree

2 files changed

+131
-4
lines changed

2 files changed

+131
-4
lines changed

src/constance/src/time/duration.rs

Lines changed: 129 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use core::{convert::TryInto, fmt};
1+
use core::{convert::TryInto, fmt, ops};
22

33
use crate::utils::{Init, ZeroInit};
44

@@ -168,6 +168,30 @@ impl Duration {
168168
None
169169
}
170170
}
171+
172+
/// Add the specified value to `self`, returning `None` if the result
173+
/// overflows.
174+
#[inline]
175+
pub const fn checked_add(self, other: Self) -> Option<Self> {
176+
// FIXME: `Option::map` is not `const fn` yet
177+
if let Some(x) = self.micros.checked_add(other.micros) {
178+
Some(Self::from_micros(x))
179+
} else {
180+
None
181+
}
182+
}
183+
184+
/// Subtract the specified value from `self`, returning `None` if the result
185+
/// overflows.
186+
#[inline]
187+
pub const fn checked_sub(self, other: Self) -> Option<Self> {
188+
// FIXME: `Option::map` is not `const fn` yet
189+
if let Some(x) = self.micros.checked_sub(other.micros) {
190+
Some(Self::from_micros(x))
191+
} else {
192+
None
193+
}
194+
}
171195
}
172196

173197
/// Error type returned when a checked duration type conversion fails.
@@ -217,6 +241,110 @@ impl fmt::Debug for Duration {
217241
}
218242
}
219243

244+
impl ops::Add for Duration {
245+
type Output = Self;
246+
247+
/// Perform a checked addition, panicking on overflow.
248+
#[inline]
249+
fn add(self, rhs: Self) -> Self::Output {
250+
self.checked_add(rhs)
251+
.expect("overflow when adding durations")
252+
}
253+
}
254+
255+
impl ops::AddAssign for Duration {
256+
/// Perform a checked addition, panicking on overflow.
257+
#[inline]
258+
fn add_assign(&mut self, rhs: Self) {
259+
*self = *self + rhs;
260+
}
261+
}
262+
263+
impl ops::Sub for Duration {
264+
type Output = Self;
265+
266+
/// Perform a checked subtraction, panicking on overflow.
267+
#[inline]
268+
fn sub(self, rhs: Self) -> Self::Output {
269+
self.checked_sub(rhs)
270+
.expect("overflow when subtracting durations")
271+
}
272+
}
273+
274+
impl ops::SubAssign for Duration {
275+
/// Perform a checked subtraction, panicking on overflow.
276+
#[inline]
277+
fn sub_assign(&mut self, rhs: Self) {
278+
*self = *self - rhs;
279+
}
280+
}
281+
282+
impl ops::Mul<i32> for Duration {
283+
type Output = Duration;
284+
285+
/// Perform a checked multiplication, panicking on overflow.
286+
#[inline]
287+
fn mul(self, rhs: i32) -> Self::Output {
288+
self.checked_mul(rhs)
289+
.expect("overflow when multiplying duration by scalar")
290+
}
291+
}
292+
293+
impl ops::Mul<Duration> for i32 {
294+
type Output = Duration;
295+
296+
/// Perform a checked multiplication, panicking on overflow.
297+
#[inline]
298+
fn mul(self, rhs: Duration) -> Self::Output {
299+
rhs.checked_mul(self)
300+
.expect("overflow when multiplying duration by scalar")
301+
}
302+
}
303+
304+
impl ops::MulAssign<i32> for Duration {
305+
/// Perform a checked multiplication, panicking on overflow.
306+
#[inline]
307+
fn mul_assign(&mut self, rhs: i32) {
308+
*self = *self * rhs;
309+
}
310+
}
311+
312+
impl ops::Div<i32> for Duration {
313+
type Output = Duration;
314+
315+
/// Perform a checked division, panicking on overflow or when `rhs` is zero.
316+
#[inline]
317+
fn div(self, rhs: i32) -> Self::Output {
318+
self.checked_div(rhs)
319+
.expect("divide by zero or overflow when dividing duration by scalar")
320+
}
321+
}
322+
323+
impl ops::DivAssign<i32> for Duration {
324+
/// Perform a checked division, panicking on overflow or when `rhs` is zero.
325+
#[inline]
326+
fn div_assign(&mut self, rhs: i32) {
327+
*self = *self / rhs;
328+
}
329+
}
330+
331+
impl core::iter::Sum for Duration {
332+
/// Perform a checked summation, panicking on overflow.
333+
fn sum<I: Iterator<Item = Duration>>(iter: I) -> Self {
334+
iter.fold(Duration::ZERO, |x, y| {
335+
x.checked_add(y)
336+
.expect("overflow in iter::sum over durations")
337+
})
338+
}
339+
}
340+
341+
impl<'a> core::iter::Sum<&'a Duration> for Duration {
342+
/// Perform a checked summation, panicking on overflow.
343+
fn sum<I: Iterator<Item = &'a Duration>>(iter: I) -> Self {
344+
iter.cloned().sum()
345+
}
346+
}
347+
220348
// TODO: Add more tests
221349
// TODO: Maybe add macros to construct a `Duration` with compile-time overflow
222350
// check

src/constance_test_suite/src/kernel_tests/time_adjust_limits.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,8 @@ fn task1_body<System: Kernel, D: Driver<App<System>>>(_: usize) {
3737
// `system_time += TIME_USER_HEADROOM + 1300ms`, which should fail because
3838
// `task2`'s timeout would be late by `300ms`
3939
log::debug!("system_time += TIME_USER_HEADROOM + 1300ms (should fail)");
40-
// TODO: `impl Add for Duration`
4140
assert_eq!(
42-
System::adjust_time(Duration::from_millis(1300 + TIME_USER_HEADROOM.as_millis())),
41+
System::adjust_time(TIME_USER_HEADROOM + Duration::from_millis(1300)),
4342
Err(AdjustTimeError::BadObjectState),
4443
);
4544

@@ -69,7 +68,7 @@ fn task1_body<System: Kernel, D: Driver<App<System>>>(_: usize) {
6968
// `system_time -= TIME_USER_HEADROOM - 900ms`, which should succeed because the frontier will be
7069
// only away by `TIME_USER_HEADROOM - 200ms`
7170
log::debug!("system_time -= TIME_USER_HEADROOM - 900ms");
72-
System::adjust_time(Duration::from_millis(TIME_USER_HEADROOM.as_millis() - 900)).unwrap();
71+
System::adjust_time(TIME_USER_HEADROOM - Duration::from_millis(900)).unwrap();
7372

7473
D::app().seq.expect_and_replace(3, 4);
7574

0 commit comments

Comments
 (0)