From e7eba31734a906f50877d776c57664613ece4d4b Mon Sep 17 00:00:00 2001 From: Cameron Garnham Date: Tue, 13 Sep 2022 00:56:05 +0200 Subject: [PATCH] clock: add clock period modules --- src/protocol/clock/clockperiod.rs | 86 ++++++++++++++++++++++++ src/protocol/clock/mod.rs | 2 + src/protocol/clock/period.rs | 108 ++++++++++++++++++++++++++++++ 3 files changed, 196 insertions(+) create mode 100644 src/protocol/clock/clockperiod.rs create mode 100644 src/protocol/clock/period.rs diff --git a/src/protocol/clock/clockperiod.rs b/src/protocol/clock/clockperiod.rs new file mode 100644 index 000000000..5aef8a445 --- /dev/null +++ b/src/protocol/clock/clockperiod.rs @@ -0,0 +1,86 @@ +use std::num::TryFromIntError; +use std::time::Duration; + +use super::clock::{ClockType, StoppedClock, TimeNow, WorkingClock}; +use super::period::{PeriodCount, PeriodLength, Periods, SinceUnixEpochPeriods}; + +pub trait ClockPeriods: Sized +where + T: TimeNow, +{ + fn now(length: &PeriodLength) -> Option> { + match T::now().as_nanos().checked_div((*length).as_nanos()) { + None => None, + Some(count) => Some(match PeriodCount::try_from(count) { + Err(error) => Err(error), + Ok(count) => Ok(SinceUnixEpochPeriods::new(&length, &count)), + }), + } + } + + fn now_add(length: &PeriodLength, add_time: &Duration) -> Option> { + match T::add(add_time) { + None => None, + Some(time) => match time.as_nanos().checked_div(length.as_nanos()) { + None => None, + Some(count) => Some(match PeriodCount::try_from(count) { + Err(error) => Err(error), + Ok(count) => Ok(SinceUnixEpochPeriods::new(&length, &count)), + }), + }, + } + } + fn now_sub(length: &PeriodLength, sub_time: &Duration) -> Option> { + match T::sub(sub_time) { + None => None, + Some(time) => match time.as_nanos().checked_div(length.as_nanos()) { + None => None, + Some(count) => Some(match PeriodCount::try_from(count) { + Err(error) => Err(error), + Ok(count) => Ok(SinceUnixEpochPeriods::new(&length, &count)), + }), + }, + } + } +} + +#[derive(Debug)] +pub struct PeriodClock {} + +pub type ClockPeriodWorking = PeriodClock<{ ClockType::WorkingClock as usize }>; + +pub type StoppedPeriodClock = PeriodClock<{ ClockType::StoppedClock as usize }>; + +impl ClockPeriods for ClockPeriodWorking {} + +impl ClockPeriods for StoppedPeriodClock {} + +#[cfg(not(test))] +pub type DefaultPeriodClock = ClockPeriodWorking; + +#[cfg(test)] +pub type DefaultPeriodClock = StoppedPeriodClock; + +#[cfg(test)] +mod tests { + use std::time::Duration; + + use crate::protocol::clock::clock::{DefaultClock, DurationSinceUnixEpoch, StoppedTime}; + use crate::protocol::clock::clockperiod::{ClockPeriods, DefaultPeriodClock}; + use crate::protocol::clock::period::Period; + + #[test] + fn it_should_get_the_current_period() { + assert_eq!( + DefaultPeriodClock::now(&Duration::from_secs(2)).unwrap().unwrap(), + Period::from_sec(2, 0) + ); + + DefaultClock::local_set(&DurationSinceUnixEpoch::from_secs(12387687123)); + + assert_eq!( + DefaultPeriodClock::now(&Duration::from_secs(2)).unwrap().unwrap(), + Period::from_sec(2, 6193843561) + ); + } +} diff --git a/src/protocol/clock/mod.rs b/src/protocol/clock/mod.rs index 159730d2b..e60fb403b 100644 --- a/src/protocol/clock/mod.rs +++ b/src/protocol/clock/mod.rs @@ -1 +1,3 @@ pub mod clock; +pub mod clockperiod; +pub mod period; diff --git a/src/protocol/clock/period.rs b/src/protocol/clock/period.rs new file mode 100644 index 000000000..4077aeb4a --- /dev/null +++ b/src/protocol/clock/period.rs @@ -0,0 +1,108 @@ +use std::num::{IntErrorKind, TryFromIntError}; +use std::time::Duration; + +pub type PeriodLength = Duration; +pub type PeriodCount = u64; +pub type PeriodTotalTime = Duration; + +pub trait Periods: Sized + Default { + fn new(length: &PeriodLength, count: &PeriodCount) -> Self; + + fn add_count(&self, add: PeriodCount) -> Result; + fn sub_count(&self, sub: PeriodCount) -> Result; +} + +pub trait PeriodsTotals: Periods { + fn total_time(&self) -> Result, TryFromIntError>; + fn total_time_end(&self) -> Result, TryFromIntError>; +} + +#[derive(Debug, Default, Hash, PartialEq)] +pub struct Period { + pub length: PeriodLength, + pub count: PeriodCount, +} + +pub type SinceUnixEpochPeriods = Period; + +impl Period { + pub const fn from_sec(length: u64, count: u64) -> Self { + Self { + length: Duration::from_secs(length), + count: count, + } + } +} + +impl Periods for Period { + fn new(length: &PeriodLength, count: &PeriodCount) -> Self { + Self { + length: *length, + count: *count, + } + } + + fn add_count(&self, add: PeriodCount) -> Result { + match self.count.checked_add(add) { + None => Err(IntErrorKind::PosOverflow), + Some(count) => Ok(Self { + length: self.length, + count: count, + }), + } + } + + fn sub_count(&self, sub: PeriodCount) -> Result { + match self.count.checked_sub(sub) { + None => Err(IntErrorKind::NegOverflow), + Some(count) => Ok(Self { + length: self.length, + count: count, + }), + } + } +} + +impl PeriodsTotals for Period { + fn total_time(&self) -> Result, TryFromIntError> { + match u32::try_from(self.count) { + Err(error) => Err(error), + Ok(count) => Ok(self.length.checked_mul(count)), + } + } + + fn total_time_end(&self) -> Result, TryFromIntError> { + match u32::try_from(self.count) { + Err(e) => Err(e), + Ok(count) => match count.checked_add(1) { + None => Ok(None), + Some(count) => match self.length.checked_mul(count) { + None => Ok(None), + Some(time) => Ok(Some(time)), + }, + }, + } + } +} + +#[cfg(test)] +mod test { + + use std::time::Duration; + + use crate::protocol::clock::period::{Period, PeriodsTotals}; + + #[test] + fn it_should_get_the_total_time_of_a_period() { + assert_eq!(Period::default().total_time().unwrap().unwrap(), Duration::ZERO); + + assert_eq!( + Period::from_sec(12, 12).total_time().unwrap().unwrap(), + Duration::from_secs(144) + ); + assert_eq!( + Period::from_sec(12, 12).total_time_end().unwrap().unwrap(), + Duration::from_secs(156) + ); + } +}