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 909f42e
Show file tree
Hide file tree
Showing 3 changed files with 203 additions and 2 deletions.
112 changes: 112 additions & 0 deletions src/protocol/clock/extent.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
use std::num::{IntErrorKind, TryFromIntError};
use std::time::Duration;

pub trait IncrementCounter: Sized + Default {
type Increment;

type IncrementCount;
type IncrementProduct;

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

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

fn product_current(&self) -> Result<Option<Self::IncrementProduct>, TryFromIntError>;
fn product_next(&self) -> Result<Option<Self::IncrementProduct>, TryFromIntError>;
}

pub type ExtentUnit = Duration;
pub type ExtentUnitSeconds = u64;
pub type ExtentCount = u64;
pub type ExtentProduct = ExtentUnit;

#[derive(Debug, Default, Hash, PartialEq, Eq)]
pub struct Extent {
pub size: ExtentUnit,
pub quantity: ExtentCount,
}

impl Extent {
pub const fn from_sec(size: ExtentUnitSeconds, quantity: &ExtentCount) -> Self {
Self {
size: ExtentUnit::from_secs(size),
quantity: *quantity,
}
}
}

impl IncrementCounter for Extent {
type Increment = ExtentUnit;
type IncrementCount = ExtentCount;
type IncrementProduct = ExtentProduct;

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

fn add(&self, add: Self::IncrementCount) -> 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::IncrementCount) -> Result<Self, IntErrorKind> {
match self.quantity.checked_sub(sub) {
None => Err(IntErrorKind::NegOverflow),
Some(quantity) => Ok(Self {
size: self.size,
quantity,
}),
}
}

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

fn product_next(&self) -> Result<Option<Self::IncrementProduct>, 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::extent::{Extent, IncrementCounter};

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

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

use super::extent::{Extent, ExtentCount, ExtentUnit, IncrementCounter};
use super::{ClockType, StoppedClock, TimeNow, WorkingClock};

pub trait ExtentFromClock<T>: Sized
where
T: TimeNow,
{
fn now(size: &ExtentUnit) -> Option<Result<Extent, TryFromIntError>> {
T::now()
.as_nanos()
.checked_div((*size).as_nanos())
.map(|quantity| match ExtentCount::try_from(quantity) {
Err(error) => Err(error),
Ok(quantity) => Ok(Extent::new(size, &quantity)),
})
}

fn now_add(size: &ExtentUnit, add_time: &Duration) -> Option<Result<Extent, TryFromIntError>> {
match T::add(add_time) {
None => None,
Some(time) => time
.as_nanos()
.checked_div(size.as_nanos())
.map(|quantity| match ExtentCount::try_from(quantity) {
Err(error) => Err(error),
Ok(quantity) => Ok(Extent::new(size, &quantity)),
}),
}
}
fn now_sub(size: &ExtentUnit, sub_time: &Duration) -> Option<Result<Extent, TryFromIntError>> {
match T::sub(sub_time) {
None => None,
Some(time) => time
.as_nanos()
.checked_div(size.as_nanos())
.map(|quantity| match ExtentCount::try_from(quantity) {
Err(error) => Err(error),
Ok(quantity) => Ok(Extent::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 ExtentFromClock<WorkingClock> for WorkingClockExtentMaker {}

impl ExtentFromClock<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::extent::Extent;
use crate::protocol::clock::extentmaker::{DefaultClockExtentMaker, ExtentFromClock};
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(),
Extent::from_sec(2, &0)
);

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

assert_eq!(
DefaultClockExtentMaker::now(&Duration::from_secs(2)).unwrap().unwrap(),
Extent::from_sec(2, &6193843561)
);
}
}
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 extent;
pub mod extentmaker;

0 comments on commit 909f42e

Please sign in to comment.