-
Notifications
You must be signed in to change notification settings - Fork 44
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
clock: extent and extent maker (from clock)
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
Showing
3 changed files
with
203 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters