use crate::helpers::{div_round_nearest_u64, Helpers};
use crate::NanosDurationU64;
use crate::Rate;
use crate::SecsDurationU64;
use core::cmp::Ordering;
use core::convert;
use core::ops;
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(
feature = "postcard_max_size",
derive(postcard::experimental::max_size::MaxSize)
)]
#[derive(Clone, Copy, Debug)]
pub struct Duration<T, const NOM: u64, const DENOM: u64> {
pub(crate) ticks: T,
}
macro_rules! const_checked {
($e:expr, $msg:expr) => {
match $e {
Some(v) => v,
None => panic!("{}", $msg),
}
};
}
macro_rules! shorthand {
($i:ty, $nom:literal, $denum:literal, $from_unit:ident, $as_unit:ident, $from_unital:ident, $unitstr:literal) => {
#[doc = concat!("Convert the Duration to an integer number of ", $unitstr, ".")]
#[doc = ""]
#[doc = concat!("**Compile-time error** if the conversion constants don't fit in `", stringify!($i), "`. **Panics** if the multiplication overflows `", stringify!($i), "`.")]
#[inline]
#[track_caller]
pub const fn $as_unit(&self) -> $i {
const {
assert!(
Helpers::<$nom, $denum, NOM, DENOM>::RD_TIMES_LN <= <$i>::MAX as u64,
concat!("Conversion constant RD_TIMES_LN doesn't fit in ", stringify!($i), " for this Duration type")
);
assert!(
Helpers::<$nom, $denum, NOM, DENOM>::LD_TIMES_RN <= <$i>::MAX as u64,
concat!("Conversion constant LD_TIMES_RN doesn't fit in ", stringify!($i), " for this Duration type")
);
}
let prod = const_checked!(
(Helpers::<$nom, $denum, NOM, DENOM>::LD_TIMES_RN as $i).checked_mul(self.ticks),
concat!("Duration::", stringify!($as_unit), ": multiplication overflowed storage type")
);
prod / Helpers::<$nom, $denum, NOM, DENOM>::RD_TIMES_LN as $i
}
#[doc = concat!("Create a duration from a number of ", $unitstr, ".")]
#[doc = ""]
#[doc = concat!("**Compile-time error** if the conversion constants don't fit in `", stringify!($i), "`. **Panics** if the multiplication overflows `", stringify!($i), "`.")]
#[inline]
#[track_caller]
pub const fn $from_unit(val: $i) -> Self {
const {
assert!(
Helpers::<$nom, $denum, NOM, DENOM>::RD_TIMES_LN <= <$i>::MAX as u64,
concat!("Conversion constant RD_TIMES_LN doesn't fit in ", stringify!($i), " for this Duration type")
);
assert!(
Helpers::<$nom, $denum, NOM, DENOM>::LD_TIMES_RN <= <$i>::MAX as u64,
concat!("Conversion constant LD_TIMES_RN doesn't fit in ", stringify!($i), " for this Duration type")
);
}
let prod = const_checked!(
(Helpers::<$nom, $denum, NOM, DENOM>::RD_TIMES_LN as $i).checked_mul(val),
concat!("Duration::", stringify!($from_unit), ": multiplication overflowed storage type")
);
Self::from_ticks(prod / Helpers::<$nom, $denum, NOM, DENOM>::LD_TIMES_RN as $i)
}
#[doc = concat!("Create a duration from a number of ", $unitstr, " (ceil rounded).")]
#[doc = ""]
#[doc = concat!("**Compile-time error** if the conversion constants don't fit in `", stringify!($i), "`. **Panics** if the multiplication overflows `", stringify!($i), "`.")]
#[inline]
#[track_caller]
pub const fn $from_unital(val: $i) -> Self {
const {
assert!(
Helpers::<$nom, $denum, NOM, DENOM>::RD_TIMES_LN <= <$i>::MAX as u64,
concat!("Conversion constant RD_TIMES_LN doesn't fit in ", stringify!($i), " for this Duration type")
);
assert!(
Helpers::<$nom, $denum, NOM, DENOM>::LD_TIMES_RN <= <$i>::MAX as u64,
concat!("Conversion constant LD_TIMES_RN doesn't fit in ", stringify!($i), " for this Duration type")
);
}
let mul = const_checked!(
(Helpers::<$nom, $denum, NOM, DENOM>::RD_TIMES_LN as $i).checked_mul(val),
concat!("Duration::", stringify!($from_unital), ": multiplication overflowed storage type")
);
let ld_times_rn = Helpers::<$nom, $denum, NOM, DENOM>::LD_TIMES_RN as $i;
Self::from_ticks(mul.div_ceil(ld_times_rn))
}
};
}
macro_rules! impl_duration_for_integer {
($i:ty) => {
impl<const NOM: u64, const DENOM: u64> Duration<$i, NOM, DENOM> {
#[doc = concat!("let _d = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(1);")]
#[inline]
pub const fn from_ticks(ticks: $i) -> Self {
const { assert!(NOM > 0) };
const { assert!(DENOM > 0) };
Duration { ticks }
}
#[doc = concat!("let d = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(234);")]
#[inline]
pub const fn as_ticks(&self) -> $i {
self.ticks
}
#[doc = concat!("let d = Duration::<", stringify!($i), ", 1, 1_000>::ZERO;")]
pub const ZERO: Self = Self::from_ticks(0);
#[doc = concat!("let d = Duration::<", stringify!($i), ", 1, 1_000>::MAX;")]
#[doc = concat!("assert_eq!(d.as_ticks(), ", stringify!($i), "::MAX);")]
pub const MAX: Self = Self::from_ticks(<$i>::MAX);
#[doc = concat!("let zero = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(0);")]
#[doc = concat!("let one = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(1);")]
#[inline]
pub const fn is_zero(&self) -> bool {
self.ticks == 0
}
#[doc = concat!("let d1 = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(1);")]
#[doc = concat!("let d2 = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(2);")]
#[doc = concat!("let d3 = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(", stringify!($i), "::MAX);")]
pub const fn checked_add<const O_NOM: u64, const O_DENOM: u64>(
self,
other: Duration<$i, O_NOM, O_DENOM>,
) -> Option<Self> {
if Helpers::<NOM, DENOM, O_NOM, O_DENOM>::SAME_BASE {
if let Some(ticks) = self.ticks.checked_add(other.ticks) {
Some(Self::from_ticks(ticks))
} else {
None
}
} else {
if let Some(lh) = other
.ticks
.checked_mul(Helpers::<NOM, DENOM, O_NOM, O_DENOM>::LD_TIMES_RN as $i)
{
let ticks = lh / Helpers::<NOM, DENOM, O_NOM, O_DENOM>::RD_TIMES_LN as $i;
if let Some(ticks) = self.ticks.checked_add(ticks) {
Some(Self::from_ticks(ticks))
} else {
None
}
} else {
None
}
}
}
#[doc = concat!("let d1 = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(1);")]
#[doc = concat!("let d2 = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(2);")]
#[doc = concat!("let d3 = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(", stringify!($i), "::MAX);")]
pub const fn checked_sub<const O_NOM: u64, const O_DENOM: u64>(
self,
other: Duration<$i, O_NOM, O_DENOM>,
) -> Option<Self> {
if Helpers::<NOM, DENOM, O_NOM, O_DENOM>::SAME_BASE {
if let Some(ticks) = self.ticks.checked_sub(other.ticks) {
Some(Self::from_ticks(ticks))
} else {
None
}
} else {
if let Some(lh) = other
.ticks
.checked_mul(Helpers::<NOM, DENOM, O_NOM, O_DENOM>::LD_TIMES_RN as $i)
{
let ticks = lh / Helpers::<NOM, DENOM, O_NOM, O_DENOM>::RD_TIMES_LN as $i;
if let Some(ticks) = self.ticks.checked_sub(ticks) {
Some(Self::from_ticks(ticks))
} else {
None
}
} else {
None
}
}
}
#[doc = concat!("let d = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(10);")]
#[doc = concat!("assert_eq!(Duration::<", stringify!($i), ", 1, 1_000>::MAX.checked_mul(2), None);")]
#[inline]
pub const fn checked_mul(self, rhs: $i) -> Option<Self> {
if let Some(ticks) = self.ticks.checked_mul(rhs) {
Some(Self::from_ticks(ticks))
} else {
None
}
}
#[doc = concat!("let d = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(30);")]
#[doc = concat!("assert_eq!(Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(10).checked_div(0), None);")]
#[inline]
pub const fn checked_div(self, rhs: $i) -> Option<Self> {
if rhs == 0 {
None
} else {
Some(Self::from_ticks(self.ticks / rhs))
}
}
#[doc = concat!("let d1 = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(10);")]
#[doc = concat!("let d2 = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(3);")]
pub const fn checked_rem<const O_NOM: u64, const O_DENOM: u64>(
self,
other: Duration<$i, O_NOM, O_DENOM>,
) -> Option<Self> {
if other.ticks == 0 {
None
} else if Helpers::<NOM, DENOM, O_NOM, O_DENOM>::SAME_BASE {
Some(Self::from_ticks(self.ticks % other.ticks))
} else {
if let Some(lh) = other
.ticks
.checked_mul(Helpers::<NOM, DENOM, O_NOM, O_DENOM>::LD_TIMES_RN as $i)
{
let ticks = lh / Helpers::<NOM, DENOM, O_NOM, O_DENOM>::RD_TIMES_LN as $i;
if ticks > 0 {
Some(Self::from_ticks(self.ticks % ticks))
} else {
None
}
} else {
None
}
}
}
#[doc = concat!("let d = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(31);")]
#[doc = concat!("let d = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(30);")]
#[inline]
#[track_caller]
pub const fn div_ceil(self, rhs: $i) -> Self {
Self::from_ticks(self.ticks.div_ceil(rhs))
}
#[doc = concat!("let d1 = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(1);")]
#[doc = concat!("let d2 = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(2);")]
#[doc = concat!("assert_eq!(Duration::<", stringify!($i), ", 1, 1_000>::MAX.saturating_add(d1).as_ticks(), ", stringify!($i), "::MAX);")]
pub const fn saturating_add<const O_NOM: u64, const O_DENOM: u64>(
self,
other: Duration<$i, O_NOM, O_DENOM>,
) -> Self {
if let Some(result) = self.checked_add(other) {
result
} else {
Self::MAX
}
}
#[doc = concat!("let d1 = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(10);")]
#[doc = concat!("let d2 = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(2);")]
pub const fn saturating_sub<const O_NOM: u64, const O_DENOM: u64>(
self,
other: Duration<$i, O_NOM, O_DENOM>,
) -> Self {
if let Some(result) = self.checked_sub(other) {
result
} else {
Self::ZERO
}
}
#[doc = concat!("let d = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(10);")]
#[doc = concat!("assert_eq!(Duration::<", stringify!($i), ", 1, 1_000>::MAX.saturating_mul(2).as_ticks(), ", stringify!($i), "::MAX);")]
#[inline]
pub const fn saturating_mul(self, rhs: $i) -> Self {
if let Some(result) = self.checked_mul(rhs) {
result
} else {
Self::MAX
}
}
#[doc = concat!("Const `cmp` for ", stringify!($i))]
#[inline(always)]
const fn _const_cmp(a: $i, b: $i) -> Ordering {
if a < b {
Ordering::Less
} else if a > b {
Ordering::Greater
} else {
Ordering::Equal
}
}
#[doc = concat!("let d1 = Duration::<", stringify!($i), ", 1, 100>::from_ticks(1);")]
#[doc = concat!("let d2 = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(1);")]
#[inline]
pub const fn const_partial_cmp<const R_NOM: u64, const R_DENOM: u64>(
self,
other: Duration<$i, R_NOM, R_DENOM>
) -> Option<Ordering> {
if Helpers::<NOM, DENOM, R_NOM, R_DENOM>::SAME_BASE {
Some(Self::_const_cmp(self.ticks, other.ticks))
} else {
let lh = self
.ticks
.checked_mul(Helpers::<NOM, DENOM, R_NOM, R_DENOM>::RD_TIMES_LN as $i);
let rh = other
.ticks
.checked_mul(Helpers::<NOM, DENOM, R_NOM, R_DENOM>::LD_TIMES_RN as $i);
if let (Some(lh), Some(rh)) = (lh, rh) {
Some(Self::_const_cmp(lh, rh))
} else {
None
}
}
}
#[doc = concat!("let d1 = Duration::<", stringify!($i), ", 1, 1_00>::from_ticks(1);")]
#[doc = concat!("let d2 = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(10);")]
#[inline]
pub const fn const_eq<const R_NOM: u64, const R_DENOM: u64>(
self,
other: Duration<$i, R_NOM, R_DENOM>
) -> bool {
if Helpers::<NOM, DENOM, R_NOM, R_DENOM>::SAME_BASE {
self.ticks == other.ticks
} else {
let lh = self
.ticks
.checked_mul(Helpers::<NOM, DENOM, R_NOM, R_DENOM>::RD_TIMES_LN as $i);
let rh = other
.ticks
.checked_mul(Helpers::<NOM, DENOM, R_NOM, R_DENOM>::LD_TIMES_RN as $i);
if let (Some(lh), Some(rh)) = (lh, rh) {
lh == rh
} else {
false
}
}
}
#[doc = concat!("let d1 = Duration::<", stringify!($i), ", 1, 1_00>::from_ticks(1);")]
#[doc = concat!("let d2 = Duration::<", stringify!($i), ", 1, 1_000>::const_try_from(d1);")]
pub const fn const_try_from<const I_NOM: u64, const I_DENOM: u64>(
duration: Duration<$i, I_NOM, I_DENOM>,
) -> Option<Self> {
if Helpers::<I_NOM, I_DENOM, NOM, DENOM>::SAME_BASE {
Some(Self::from_ticks(duration.ticks))
} else {
if let Some(lh) = (duration.ticks as u64)
.checked_mul(Helpers::<I_NOM, I_DENOM, NOM, DENOM>::RD_TIMES_LN)
{
let ticks = div_round_nearest_u64(
lh,
Helpers::<I_NOM, I_DENOM, NOM, DENOM>::LD_TIMES_RN,
);
if ticks <= <$i>::MAX as u64 {
Some(Self::from_ticks(ticks as $i))
} else {
None
}
} else {
None
}
}
}
#[doc = concat!("let d1 = Duration::<", stringify!($i), ", 1, 1_00>::from_ticks(1);")]
#[doc = concat!("let d2: Option<Duration::<", stringify!($i), ", 1, 1_000>> = d1.const_try_into();")]
#[inline]
pub const fn const_try_into<const O_NOM: u64, const O_DENOM: u64>(
self,
) -> Option<Duration<$i, O_NOM, O_DENOM>> {
Duration::<$i, O_NOM, O_DENOM>::const_try_from(self)
}
#[doc = concat!("let d1 = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(2);")]
#[doc = concat!("let r1: Option<Rate::<", stringify!($i), ", 1, 1>> = d1.try_to_rate();")]
#[inline]
pub const fn try_to_rate<const O_NOM: u64, const O_DENOM: u64>(
self,
) -> Option<Rate<$i, O_NOM, O_DENOM>> {
Rate::<$i, O_NOM, O_DENOM>::try_from_duration(self)
}
#[inline]
#[track_caller]
pub const fn to_rate<const O_NOM: u64, const O_DENOM: u64>(
self,
) -> Rate<$i, O_NOM, O_DENOM> {
if let Some(v) = self.try_to_rate() {
v
} else {
panic!("Into rate failed, divide-by-zero!");
}
}
#[doc = concat!("let r1 = Rate::<", stringify!($i), ", 1, 1>::from_raw(1);")]
#[doc = concat!("let d1 = Duration::<", stringify!($i), ", 1, 1_000>::try_from_rate(r1);")]
#[inline]
pub const fn try_from_rate<const I_NOM: u64, const I_DENOM: u64>(
rate: Rate<$i, I_NOM, I_DENOM>,
) -> Option<Self> {
const {
assert!(
Helpers::<I_NOM, I_DENOM, NOM, DENOM>::RATE_TO_DURATION_NUMERATOR <= <$i>::MAX as u64,
concat!("RATE_TO_DURATION_NUMERATOR doesn't fit in ", stringify!($i), " for this Rate/Duration combination")
);
}
if rate.raw > 0 {
Some(Self::from_ticks(
Helpers::<I_NOM, I_DENOM, NOM, DENOM>::RATE_TO_DURATION_NUMERATOR as $i
/ rate.raw
))
} else {
None
}
}
#[inline]
#[track_caller]
pub const fn from_rate<const I_NOM: u64, const I_DENOM: u64>(
rate: Rate<$i, I_NOM, I_DENOM>,
) -> Self {
if let Some(v) = Self::try_from_rate(rate) {
v
} else {
panic!("From rate failed, divide-by-zero!");
}
}
#[doc = concat!("let d1 = Duration::<", stringify!($i), ", 1, 100>::from_ticks(1);")]
#[doc = concat!("let d2: Duration::<", stringify!($i), ", 1, 1_000> = d1.convert();")]
#[doc = concat!("const TICKS: ", stringify!($i), "= ", stringify!($i), "::MAX - 10;")]
#[doc = concat!("const D1: Duration::<", stringify!($i), ", 1, 100> = Duration::<", stringify!($i), ", 1, 100>::from_ticks(TICKS);")]
#[doc = concat!("const D2: Duration::<", stringify!($i), ", 1, 200> = D1.convert();")]
#[inline]
#[track_caller]
pub const fn convert<const O_NOM: u64, const O_DENOM: u64>(
self,
) -> Duration<$i, O_NOM, O_DENOM> {
if let Some(v) = self.const_try_into() {
v
} else {
panic!("Convert failed!");
}
}
shorthand!($i, 1, 1_000_000_000_000, from_picos, as_picos, from_picos_at_least, "picoseconds");
shorthand!($i, 1, 1_000_000_000, from_nanos, as_nanos, from_nanos_at_least, "nanoseconds");
shorthand!($i, 1, 1_000_000, from_micros, as_micros, from_micros_at_least, "microseconds");
shorthand!($i, 1, 1_000, from_millis, as_millis, from_millis_at_least, "milliseconds");
shorthand!($i, 1, 1, from_secs, as_secs, from_secs_at_least, "seconds");
shorthand!($i, 60, 1, from_minutes, as_minutes, from_minutes_at_least, "minutes");
shorthand!($i, 3600, 1, from_hours, as_hours, from_hours_at_least, "hours");
#[inline]
pub const fn as_secs_f32(&self) -> f32 {
let factor = const { NOM as f32 / DENOM as f32 };
factor * self.ticks as f32
}
#[inline]
pub const fn as_secs_f64(&self) -> f64 {
let factor = const { NOM as f64 / DENOM as f64 };
factor * self.ticks as f64
}
#[doc = concat!("let d = Duration::<", stringify!($i), ", 1, 1_000>::from_secs_f32(1.5);")]
#[doc = concat!("let d = Duration::<", stringify!($i), ", 1, 1_000>::from_secs_f32(1.5005);")]
#[inline]
pub const fn from_secs_f32(secs: f32) -> Self {
let factor = const { DENOM as f32 / NOM as f32 };
Self::from_ticks((secs * factor + 0.5) as $i)
}
#[doc = concat!("let d = Duration::<", stringify!($i), ", 1, 1_000>::from_secs_f64(1.5);")]
#[doc = concat!("let d = Duration::<", stringify!($i), ", 1, 1_000>::from_secs_f64(1.5005);")]
#[inline]
pub const fn from_secs_f64(secs: f64) -> Self {
let factor = const { DENOM as f64 / NOM as f64 };
Self::from_ticks((secs * factor + 0.5) as $i)
}
#[inline]
#[track_caller]
#[allow(non_snake_case)]
pub const fn Hz(val: $i) -> Self {
Self::from_rate(crate::Hertz::<$i>::from_raw(val))
}
#[inline]
#[track_caller]
#[allow(non_snake_case)]
pub const fn kHz(val: $i) -> Self {
Self::from_rate(crate::Kilohertz::<$i>::from_raw(val))
}
#[inline]
#[track_caller]
#[allow(non_snake_case)]
pub const fn MHz(val: $i) -> Self {
Self::from_rate(crate::Megahertz::<$i>::from_raw(val))
}
}
impl<const L_NOM: u64, const L_DENOM: u64, const R_NOM: u64, const R_DENOM: u64>
PartialOrd<Duration<$i, R_NOM, R_DENOM>> for Duration<$i, L_NOM, L_DENOM>
{
#[inline]
fn partial_cmp(&self, other: &Duration<$i, R_NOM, R_DENOM>) -> Option<Ordering> {
self.const_partial_cmp(*other)
}
}
impl<const NOM: u64, const DENOM: u64> Ord for Duration<$i, NOM, DENOM> {
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
Self::_const_cmp(self.ticks, other.ticks)
}
}
impl<const L_NOM: u64, const L_DENOM: u64, const R_NOM: u64, const R_DENOM: u64>
PartialEq<Duration<$i, R_NOM, R_DENOM>> for Duration<$i, L_NOM, L_DENOM>
{
#[inline]
fn eq(&self, other: &Duration<$i, R_NOM, R_DENOM>) -> bool {
self.const_eq(*other)
}
}
impl<const NOM: u64, const DENOM: u64> Eq for Duration<$i, NOM, DENOM> {}
impl<const NOM: u64, const DENOM: u64> ops::Sub for Duration<$i, NOM, DENOM>
{
type Output = Self;
#[inline]
#[track_caller]
fn sub(self, other: Self) -> Self::Output {
if let Some(v) = self.checked_sub(other) {
v
} else {
panic!("Sub failed!");
}
}
}
impl<const NOM: u64, const DENOM: u64> ops::SubAssign for Duration<$i, NOM, DENOM>
{
#[inline]
#[track_caller]
fn sub_assign(&mut self, other: Self) {
*self = *self - other;
}
}
impl<const NOM: u64, const DENOM: u64> ops::Add for Duration<$i, NOM, DENOM>
{
type Output = Self;
#[inline]
#[track_caller]
fn add(self, other: Self) -> Self::Output {
if let Some(v) = self.checked_add(other) {
v
} else {
panic!("Add failed!");
}
}
}
impl<const NOM: u64, const DENOM: u64> ops::AddAssign for Duration<$i, NOM, DENOM>
{
#[inline]
#[track_caller]
fn add_assign(&mut self, other: Self) {
*self = *self + other;
}
}
impl<const NOM: u64, const DENOM: u64> ops::Mul<Duration<$i, NOM, DENOM>> for u32 {
type Output = Duration<$i, NOM, DENOM>;
#[inline]
#[track_caller]
fn mul(self, mut other: Duration<$i, NOM, DENOM>) -> Self::Output {
other.ticks *= self as $i;
other
}
}
impl<const NOM: u64, const DENOM: u64> ops::Mul<u32> for Duration<$i, NOM, DENOM> {
type Output = Self;
#[inline]
#[track_caller]
fn mul(mut self, other: u32) -> Self::Output {
self.ticks *= other as $i;
self
}
}
impl<const NOM: u64, const DENOM: u64> ops::MulAssign<u32>
for Duration<$i, NOM, DENOM>
{
#[inline]
#[track_caller]
fn mul_assign(&mut self, other: u32) {
*self = *self * other;
}
}
impl<const NOM: u64, const DENOM: u64> ops::Div<u32> for Duration<$i, NOM, DENOM> {
type Output = Self;
#[inline]
#[track_caller]
fn div(mut self, other: u32) -> Self::Output {
self.ticks /= other as $i;
self
}
}
impl<const NOM: u64, const DENOM: u64> ops::DivAssign<u32>
for Duration<$i, NOM, DENOM>
{
#[inline]
#[track_caller]
fn div_assign(&mut self, other: u32) {
*self = *self / other;
}
}
impl<const NOM: u64, const DENOM: u64> ops::Rem for Duration<$i, NOM, DENOM>
{
type Output = Self;
#[inline]
#[track_caller]
fn rem(self, other: Self) -> Self::Output {
if let Some(v) = self.checked_rem(other) {
v
} else {
panic!("Rem failed!");
}
}
}
impl<const NOM: u64, const DENOM: u64> ops::RemAssign for Duration<$i, NOM, DENOM>
{
#[inline]
#[track_caller]
fn rem_assign(&mut self, other: Self) {
*self = *self % other;
}
}
impl<const L_NOM: u64, const L_DENOM: u64, const R_NOM: u64, const R_DENOM: u64> ops::Div<Duration<$i, R_NOM, R_DENOM>>
for Duration<$i, L_NOM, L_DENOM>
{
type Output = $i;
#[inline]
#[track_caller]
fn div(self, other: Duration<$i, R_NOM, R_DENOM>) -> Self::Output {
let conv: Duration<$i, R_NOM, R_DENOM> = self.convert();
conv.ticks / other.ticks
}
}
#[cfg(feature = "defmt")]
impl<const NOM: u64, const DENOM: u64> defmt::Format for Duration<$i, NOM, DENOM>
{
fn format(&self, f: defmt::Formatter) {
if NOM == 3_600 && DENOM == 1 {
defmt::write!(f, "{} h", self.ticks)
} else if NOM == 60 && DENOM == 1 {
defmt::write!(f, "{} min", self.ticks)
} else if NOM == 1 && DENOM == 1 {
defmt::write!(f, "{} s", self.ticks)
} else if NOM == 1 && DENOM == 1_000 {
defmt::write!(f, "{} ms", self.ticks)
} else if NOM == 1 && DENOM == 1_000_000 {
defmt::write!(f, "{} us", self.ticks)
} else if NOM == 1 && DENOM == 1_000_000_000 {
defmt::write!(f, "{} ns", self.ticks)
} else {
defmt::write!(f, "{} ticks @ ({}/{})", self.ticks, NOM, DENOM)
}
}
}
impl<const NOM: u64, const DENOM: u64> core::fmt::Display for Duration<$i, NOM, DENOM> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
if NOM == 3_600 && DENOM == 1 {
write!(f, "{} h", self.ticks)
} else if NOM == 60 && DENOM == 1 {
write!(f, "{} min", self.ticks)
} else if NOM == 1 && DENOM == 1 {
write!(f, "{} s", self.ticks)
} else if NOM == 1 && DENOM == 1_000 {
write!(f, "{} ms", self.ticks)
} else if NOM == 1 && DENOM == 1_000_000 {
write!(f, "{} us", self.ticks)
} else if NOM == 1 && DENOM == 1_000_000_000 {
write!(f, "{} ns", self.ticks)
} else {
write!(f, "{} ticks @ ({}/{})", self.ticks, NOM, DENOM)
}
}
}
};
}
impl_duration_for_integer!(u32);
impl_duration_for_integer!(u64);
impl<const NOM: u64, const DENOM: u64> convert::TryFrom<core::time::Duration>
for Duration<u32, NOM, DENOM>
{
type Error = ();
#[inline]
fn try_from(val: core::time::Duration) -> Result<Self, Self::Error> {
Duration::<u64, NOM, DENOM>::try_from(val)?.try_into()
}
}
impl<const NOM: u64, const DENOM: u64> convert::TryFrom<core::time::Duration>
for Duration<u64, NOM, DENOM>
{
type Error = ();
#[inline]
fn try_from(val: core::time::Duration) -> Result<Self, Self::Error> {
let secs_duration = SecsDurationU64::from_ticks(val.as_secs());
let nanos_duration = NanosDurationU64::from_ticks(val.subsec_nanos() as u64);
let secs_converted: Self = secs_duration.const_try_into().ok_or(())?;
let nanos_converted: Self = nanos_duration.const_try_into().ok_or(())?;
secs_converted.checked_add(nanos_converted).ok_or(())
}
}
impl<const NOM: u64, const DENOM: u64> From<Duration<u32, NOM, DENOM>> for core::time::Duration {
#[inline]
fn from(val: Duration<u32, NOM, DENOM>) -> Self {
let val_u64: Duration<u64, NOM, DENOM> = val.into();
core::time::Duration::from(val_u64)
}
}
impl<const NOM: u64, const DENOM: u64> From<Duration<u64, NOM, DENOM>> for core::time::Duration {
#[inline]
fn from(val: Duration<u64, NOM, DENOM>) -> Self {
let secs = val.as_secs();
let secs_duration = Duration::<u64, NOM, DENOM>::from_secs(secs);
let remainder = val.saturating_sub(secs_duration);
let nanos = remainder.as_nanos() as u32;
core::time::Duration::new(secs, nanos)
}
}
impl<const NOM: u64, const DENOM: u64> From<Duration<u32, NOM, DENOM>>
for Duration<u64, NOM, DENOM>
{
#[inline]
fn from(val: Duration<u32, NOM, DENOM>) -> Self {
Duration::<u64, NOM, DENOM>::from_ticks(val.as_ticks() as u64)
}
}
impl<const NOM: u64, const DENOM: u64> convert::TryFrom<Duration<u64, NOM, DENOM>>
for Duration<u32, NOM, DENOM>
{
type Error = ();
#[inline]
fn try_from(val: Duration<u64, NOM, DENOM>) -> Result<Self, ()> {
Ok(Duration::<u32, NOM, DENOM>::from_ticks(
val.as_ticks().try_into().map_err(|_| ())?,
))
}
}
impl<const NOM: u64, const DENOM: u64> ops::Sub<Duration<u32, NOM, DENOM>>
for Duration<u64, NOM, DENOM>
{
type Output = Self;
#[inline]
#[track_caller]
fn sub(self, other: Duration<u32, NOM, DENOM>) -> Self::Output {
if let Some(v) = self.checked_sub(Self::from_ticks(other.as_ticks() as u64)) {
v
} else {
panic!("Sub failed!");
}
}
}
impl<const NOM: u64, const DENOM: u64> ops::SubAssign<Duration<u32, NOM, DENOM>>
for Duration<u64, NOM, DENOM>
{
#[inline]
#[track_caller]
fn sub_assign(&mut self, other: Duration<u32, NOM, DENOM>) {
*self = *self - other;
}
}
impl<const NOM: u64, const DENOM: u64> ops::Add<Duration<u32, NOM, DENOM>>
for Duration<u64, NOM, DENOM>
{
type Output = Self;
#[inline]
#[track_caller]
fn add(self, other: Duration<u32, NOM, DENOM>) -> Self::Output {
if let Some(v) = self.checked_add(Self::from_ticks(other.as_ticks() as u64)) {
v
} else {
panic!("Add failed!");
}
}
}
impl<const NOM: u64, const DENOM: u64> ops::AddAssign<Duration<u32, NOM, DENOM>>
for Duration<u64, NOM, DENOM>
{
#[inline]
#[track_caller]
fn add_assign(&mut self, other: Duration<u32, NOM, DENOM>) {
*self = *self + other;
}
}
impl<const L_NOM: u64, const L_DENOM: u64, const R_NOM: u64, const R_DENOM: u64>
PartialOrd<Duration<u32, R_NOM, R_DENOM>> for Duration<u64, L_NOM, L_DENOM>
{
#[inline]
fn partial_cmp(&self, other: &Duration<u32, R_NOM, R_DENOM>) -> Option<Ordering> {
self.partial_cmp(&Duration::<u64, R_NOM, R_DENOM>::from_ticks(
other.as_ticks() as u64,
))
}
}
impl<const L_NOM: u64, const L_DENOM: u64, const R_NOM: u64, const R_DENOM: u64>
PartialEq<Duration<u32, R_NOM, R_DENOM>> for Duration<u64, L_NOM, L_DENOM>
{
#[inline]
fn eq(&self, other: &Duration<u32, R_NOM, R_DENOM>) -> bool {
self.eq(&Duration::<u64, R_NOM, R_DENOM>::from_ticks(
other.as_ticks() as u64,
))
}
}
impl<const L_NOM: u64, const L_DENOM: u64, const R_NOM: u64, const R_DENOM: u64>
PartialOrd<Duration<u64, R_NOM, R_DENOM>> for Duration<u32, L_NOM, L_DENOM>
{
#[inline]
fn partial_cmp(&self, other: &Duration<u64, R_NOM, R_DENOM>) -> Option<Ordering> {
Duration::<u64, L_NOM, L_DENOM>::from_ticks(self.ticks as u64).partial_cmp(other)
}
}
impl<const L_NOM: u64, const L_DENOM: u64, const R_NOM: u64, const R_DENOM: u64>
PartialEq<Duration<u64, R_NOM, R_DENOM>> for Duration<u32, L_NOM, L_DENOM>
{
#[inline]
fn eq(&self, other: &Duration<u64, R_NOM, R_DENOM>) -> bool {
Duration::<u64, L_NOM, L_DENOM>::from_ticks(self.ticks as u64).eq(other)
}
}
pub trait ExtU32 {
fn picos<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM>;
fn nanos<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM>;
fn micros<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM>;
fn millis<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM>;
fn secs<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM>;
fn minutes<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM>;
fn hours<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM>;
}
impl ExtU32 for u32 {
#[inline]
fn picos<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM> {
Duration::<u32, NOM, DENOM>::from_picos(self)
}
#[inline]
fn nanos<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM> {
Duration::<u32, NOM, DENOM>::from_nanos(self)
}
#[inline]
fn micros<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM> {
Duration::<u32, NOM, DENOM>::from_micros(self)
}
#[inline]
fn millis<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM> {
Duration::<u32, NOM, DENOM>::from_millis(self)
}
#[inline]
fn secs<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM> {
Duration::<u32, NOM, DENOM>::from_secs(self)
}
#[inline]
fn minutes<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM> {
Duration::<u32, NOM, DENOM>::from_minutes(self)
}
#[inline]
fn hours<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM> {
Duration::<u32, NOM, DENOM>::from_hours(self)
}
}
pub trait ExtU32Ceil {
fn picos_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM>;
fn nanos_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM>;
fn micros_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM>;
fn millis_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM>;
fn secs_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM>;
fn minutes_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM>;
fn hours_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM>;
}
impl ExtU32Ceil for u32 {
#[inline]
fn picos_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM> {
Duration::<u32, NOM, DENOM>::from_picos_at_least(self)
}
#[inline]
fn nanos_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM> {
Duration::<u32, NOM, DENOM>::from_nanos_at_least(self)
}
#[inline]
fn micros_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM> {
Duration::<u32, NOM, DENOM>::from_micros_at_least(self)
}
#[inline]
fn millis_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM> {
Duration::<u32, NOM, DENOM>::from_millis_at_least(self)
}
#[inline]
fn secs_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM> {
Duration::<u32, NOM, DENOM>::from_secs_at_least(self)
}
#[inline]
fn minutes_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM> {
Duration::<u32, NOM, DENOM>::from_minutes_at_least(self)
}
#[inline]
fn hours_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM> {
Duration::<u32, NOM, DENOM>::from_hours_at_least(self)
}
}
pub trait ExtU64 {
fn picos<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM>;
fn nanos<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM>;
fn micros<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM>;
fn millis<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM>;
fn secs<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM>;
fn minutes<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM>;
fn hours<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM>;
}
impl ExtU64 for u64 {
#[inline]
fn picos<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM> {
Duration::<u64, NOM, DENOM>::from_picos(self)
}
#[inline]
fn nanos<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM> {
Duration::<u64, NOM, DENOM>::from_nanos(self)
}
#[inline]
fn micros<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM> {
Duration::<u64, NOM, DENOM>::from_micros(self)
}
#[inline]
fn millis<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM> {
Duration::<u64, NOM, DENOM>::from_millis(self)
}
#[inline]
fn secs<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM> {
Duration::<u64, NOM, DENOM>::from_secs(self)
}
#[inline]
fn minutes<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM> {
Duration::<u64, NOM, DENOM>::from_minutes(self)
}
#[inline]
fn hours<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM> {
Duration::<u64, NOM, DENOM>::from_hours(self)
}
}
pub trait ExtU64Ceil {
fn picos_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM>;
fn nanos_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM>;
fn micros_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM>;
fn millis_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM>;
fn secs_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM>;
fn minutes_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM>;
fn hours_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM>;
}
impl ExtU64Ceil for u64 {
#[inline]
fn picos_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM> {
Duration::<u64, NOM, DENOM>::from_picos_at_least(self)
}
#[inline]
fn nanos_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM> {
Duration::<u64, NOM, DENOM>::from_nanos_at_least(self)
}
#[inline]
fn micros_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM> {
Duration::<u64, NOM, DENOM>::from_micros_at_least(self)
}
#[inline]
fn millis_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM> {
Duration::<u64, NOM, DENOM>::from_millis_at_least(self)
}
#[inline]
fn secs_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM> {
Duration::<u64, NOM, DENOM>::from_secs_at_least(self)
}
#[inline]
fn minutes_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM> {
Duration::<u64, NOM, DENOM>::from_minutes_at_least(self)
}
#[inline]
fn hours_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM> {
Duration::<u64, NOM, DENOM>::from_hours_at_least(self)
}
}