use core::ops::{Add, Sub};
use serde::{Deserialize, Serialize};
#[cfg(feature = "defmt")]
use defmt::Format;
pub const TIME_MAX: u64 = 0xffffffffff;
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
#[cfg_attr(feature = "defmt", derive(Format))]
#[repr(C)]
pub struct Instant(u64);
impl Instant {
pub fn new(value: u64) -> Option<Self> {
if value <= TIME_MAX {
Some(Instant(value))
} else {
None
}
}
pub fn value(&self) -> u64 {
self.0
}
pub fn duration_since(&self, earlier: Instant) -> Duration {
if self.value() >= earlier.value() {
Duration(self.value() - earlier.value())
} else {
Duration(TIME_MAX - earlier.value() + self.value() + 1)
}
}
}
impl Add<Duration> for Instant {
type Output = Instant;
fn add(self, rhs: Duration) -> Self::Output {
let value = (self.value() + rhs.value()) % (TIME_MAX + 1);
Instant::new(value).unwrap()
}
}
impl Sub<Duration> for Instant {
type Output = Instant;
fn sub(self, rhs: Duration) -> Self::Output {
let value: u64 = if (self.value() as i64 - rhs.value() as i64) < 0 {
TIME_MAX + self.value() - rhs.value()
} else {
self.value() - rhs.value()
};
Instant::new(value).unwrap()
}
}
impl Sub<Instant> for Instant {
type Output = Instant;
fn sub(self, rhs: Instant) -> Self::Output {
let value: u64 = if (self.value() as i64 - rhs.value() as i64) < 0 {
TIME_MAX + self.value() - rhs.value()
} else {
self.value() - rhs.value()
};
Instant::new(value).unwrap()
}
}
#[derive(Clone, Copy, Debug, Deserialize, Serialize, Eq, PartialEq)]
#[repr(C)]
pub struct Duration(u64);
impl Duration {
pub fn new(value: u64) -> Option<Self> {
if value <= TIME_MAX {
Some(Duration(value))
} else {
None
}
}
pub fn from_nanos(nanos: u32) -> Self {
Duration::new((nanos as u64 * 638976 + 5000) / 10000).unwrap()
}
pub fn value(&self) -> u64 {
self.0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn instant_add_duration() {
let instant = Instant::new(0).unwrap();
let duration = Duration::new(1).unwrap();
let result = instant + duration;
assert_eq!(result.value(), 1);
}
#[test]
fn instant_sub_duration() {
let instant = Instant::new(1).unwrap();
let duration = Duration::new(1).unwrap();
let result = instant - duration;
assert_eq!(result.value(), 0);
}
#[test]
fn instant_sub_instant() {
let instant_1 = Instant::new(1).unwrap();
let instant_2 = Instant::new(0).unwrap();
let result = instant_1 - instant_2;
assert_eq!(result.value(), 1);
}
#[test]
fn instant_duration_since() {
let instant_1 = Instant::new(1).unwrap();
let instant_2 = Instant::new(0).unwrap();
let result = instant_1.duration_since(instant_2);
assert_eq!(result.value(), 1);
}
#[test]
fn duration_from_nanos() {
let duration = Duration::from_nanos(1);
assert_eq!(duration.value(), 64);
let duration = Duration::from_nanos(6);
assert_eq!(duration.value(), 383);
}
}