Skip to content

Commit

Permalink
clock: extent and extent maker (from clock)
Browse files Browse the repository at this point in the history
Create a new trait called `IncrementCounter` that uses three abstract types: `Increment` (size), `Count` (quantity), and `Product` (total).

Implement this new trait in a structure called `Extent`, that uses Time Duration, Integer, and Time Duration as its types. It stores a fixed length of time with a multiplayer.

Finally, define a new trait that builds extents based upon a supplied clock and the length increment. Implement this trait in two new structures, one for the working clock, and another for the stopped clock. A default is provided, selecting the working or stopped based upon the testing predicate.
  • Loading branch information
da2ce7 committed Sep 20, 2022
1 parent 028e40b commit f5400b1
Show file tree
Hide file tree
Showing 3 changed files with 205 additions and 2 deletions.
7 changes: 5 additions & 2 deletions src/protocol/clock.rs → src/protocol/clock/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use std::num::IntErrorKind;
pub use std::time::Duration;
use std::time::Duration;

pub type DurationSinceUnixEpoch = Duration;

Expand Down Expand Up @@ -240,9 +240,12 @@ mod stopped_clock {

#[test]
fn it_should_get_app_start_time() {
const TIME_AT_WRITING_THIS_TEST: Duration = Duration::new(1662983731, 000022312);
const TIME_AT_WRITING_THIS_TEST: Duration = Duration::new(1662983731, 22312);
assert!(get_app_start_time() > TIME_AT_WRITING_THIS_TEST);
}
}
}
}

pub mod timeextent;
pub mod timeextentmaker;
112 changes: 112 additions & 0 deletions src/protocol/clock/timeextent.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
use std::num::{IntErrorKind, TryFromIntError};
use std::time::Duration;

/// Count fixed sized increments. Provides the product of the increment and its count.
pub trait Extent: Sized + Default {
type Increment;
type Count;
type Product;

fn new(size: &Self::Increment, quantity: &Self::Count) -> Self;

fn add(&self, add: Self::Count) -> Result<Self, IntErrorKind>;
fn sub(&self, sub: Self::Count) -> Result<Self, IntErrorKind>;

fn get(&self) -> Result<Option<Self::Product>, TryFromIntError>;
fn get_next(&self) -> Result<Option<Self::Product>, TryFromIntError>;
}

pub type TimeExtentIncrement = Duration;
pub type TimeExtentIncrementSeconds = u64;
pub type TimeExtentCount = u64;
pub type TimeExtentExtent = TimeExtentIncrement;

#[derive(Debug, Default, Hash, PartialEq, Eq)]
pub struct TimeExtent {
pub size: TimeExtentIncrement,
pub quantity: TimeExtentCount,
}

impl TimeExtent {
pub const fn from_sec(size: TimeExtentIncrementSeconds, quantity: &TimeExtentCount) -> Self {
Self {
size: TimeExtentIncrement::from_secs(size),
quantity: *quantity,
}
}
}

impl Extent for TimeExtent {
type Increment = TimeExtentIncrement;
type Count = TimeExtentCount;
type Product = TimeExtentExtent;

fn new(size: &Self::Increment, quantity: &Self::Count) -> Self {
Self {
size: *size,
quantity: *quantity,
}
}

fn add(&self, add: Self::Count) -> Result<Self, IntErrorKind> {
match self.quantity.checked_add(add) {
None => Err(IntErrorKind::PosOverflow),
Some(quantity) => Ok(Self {
size: self.size,
quantity,
}),
}
}

fn sub(&self, sub: Self::Count) -> Result<Self, IntErrorKind> {
match self.quantity.checked_sub(sub) {
None => Err(IntErrorKind::NegOverflow),
Some(quantity) => Ok(Self {
size: self.size,
quantity,
}),
}
}

fn get(&self) -> Result<Option<Self::Product>, TryFromIntError> {
match u32::try_from(self.quantity) {
Err(error) => Err(error),
Ok(quantity) => Ok(self.size.checked_mul(quantity)),
}
}

fn get_next(&self) -> Result<Option<Self::Product>, TryFromIntError> {
match u32::try_from(self.quantity) {
Err(e) => Err(e),
Ok(quantity) => match quantity.checked_add(1) {
None => Ok(None),
Some(quantity) => match self.size.checked_mul(quantity) {
None => Ok(None),
Some(extent) => Ok(Some(extent)),
},
},
}
}
}

#[cfg(test)]
mod test {

use std::time::Duration;

use crate::protocol::clock::timeextent::{Extent, TimeExtent};

#[test]
fn it_should_get_the_total_time_of_a_period() {
assert_eq!(TimeExtent::default().get().unwrap().unwrap(), Duration::ZERO);

assert_eq!(
TimeExtent::from_sec(12, &12).get().unwrap().unwrap(),
Duration::from_secs(144)
);
assert_eq!(
TimeExtent::from_sec(12, &12).get_next().unwrap().unwrap(),
Duration::from_secs(156)
);
}
}
88 changes: 88 additions & 0 deletions src/protocol/clock/timeextentmaker.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
use std::num::TryFromIntError;
use std::time::Duration;

use super::timeextent::{Extent, TimeExtent, TimeExtentCount, TimeExtentIncrement};
use super::{ClockType, StoppedClock, TimeNow, WorkingClock};

pub trait MakeTimeExtent<Clock>: Sized
where
Clock: TimeNow,
{
fn now(size: &TimeExtentIncrement) -> Option<Result<TimeExtent, TryFromIntError>> {
Clock::now()
.as_nanos()
.checked_div((*size).as_nanos())
.map(|quantity| match TimeExtentCount::try_from(quantity) {
Err(error) => Err(error),
Ok(quantity) => Ok(TimeExtent::new(size, &quantity)),
})
}

fn now_add(size: &TimeExtentIncrement, add_time: &Duration) -> Option<Result<TimeExtent, TryFromIntError>> {
match Clock::add(add_time) {
None => None,
Some(time) => {
time.as_nanos()
.checked_div(size.as_nanos())
.map(|quantity| match TimeExtentCount::try_from(quantity) {
Err(error) => Err(error),
Ok(quantity) => Ok(TimeExtent::new(size, &quantity)),
})
}
}
}
fn now_sub(size: &TimeExtentIncrement, sub_time: &Duration) -> Option<Result<TimeExtent, TryFromIntError>> {
match Clock::sub(sub_time) {
None => None,
Some(time) => {
time.as_nanos()
.checked_div(size.as_nanos())
.map(|quantity| match TimeExtentCount::try_from(quantity) {
Err(error) => Err(error),
Ok(quantity) => Ok(TimeExtent::new(size, &quantity)),
})
}
}
}
}

#[derive(Debug)]
pub struct ExtentClock<const T: usize> {}

pub type WorkingClockExtentMaker = ExtentClock<{ ClockType::WorkingClock as usize }>;

pub type StoppedClockExtentMaker = ExtentClock<{ ClockType::StoppedClock as usize }>;

impl MakeTimeExtent<WorkingClock> for WorkingClockExtentMaker {}

impl MakeTimeExtent<StoppedClock> for StoppedClockExtentMaker {}

#[cfg(not(test))]
pub type DefaultClockExtentMaker = WorkingClockExtentMaker;

#[cfg(test)]
pub type DefaultClockExtentMaker = StoppedClockExtentMaker;

#[cfg(test)]
mod tests {
use std::time::Duration;

use crate::protocol::clock::timeextent::TimeExtent;
use crate::protocol::clock::timeextentmaker::{DefaultClockExtentMaker, MakeTimeExtent};
use crate::protocol::clock::{DefaultClock, DurationSinceUnixEpoch, StoppedTime};

#[test]
fn it_should_get_the_current_period() {
assert_eq!(
DefaultClockExtentMaker::now(&Duration::from_secs(2)).unwrap().unwrap(),
TimeExtent::from_sec(2, &0)
);

DefaultClock::local_set(&DurationSinceUnixEpoch::from_secs(12387687123));

assert_eq!(
DefaultClockExtentMaker::now(&Duration::from_secs(2)).unwrap().unwrap(),
TimeExtent::from_sec(2, &6193843561)
);
}
}

0 comments on commit f5400b1

Please sign in to comment.