Skip to content

Commit 909f42e

Browse files
committed
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.
1 parent 028e40b commit 909f42e

File tree

3 files changed

+203
-2
lines changed

3 files changed

+203
-2
lines changed

src/protocol/clock/extent.rs

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
use std::num::{IntErrorKind, TryFromIntError};
2+
use std::time::Duration;
3+
4+
pub trait IncrementCounter: Sized + Default {
5+
type Increment;
6+
7+
type IncrementCount;
8+
type IncrementProduct;
9+
10+
fn new(size: &Self::Increment, quantity: &Self::IncrementCount) -> Self;
11+
12+
fn add(&self, add: Self::IncrementCount) -> Result<Self, IntErrorKind>;
13+
fn sub(&self, sub: Self::IncrementCount) -> Result<Self, IntErrorKind>;
14+
15+
fn product_current(&self) -> Result<Option<Self::IncrementProduct>, TryFromIntError>;
16+
fn product_next(&self) -> Result<Option<Self::IncrementProduct>, TryFromIntError>;
17+
}
18+
19+
pub type ExtentUnit = Duration;
20+
pub type ExtentUnitSeconds = u64;
21+
pub type ExtentCount = u64;
22+
pub type ExtentProduct = ExtentUnit;
23+
24+
#[derive(Debug, Default, Hash, PartialEq, Eq)]
25+
pub struct Extent {
26+
pub size: ExtentUnit,
27+
pub quantity: ExtentCount,
28+
}
29+
30+
impl Extent {
31+
pub const fn from_sec(size: ExtentUnitSeconds, quantity: &ExtentCount) -> Self {
32+
Self {
33+
size: ExtentUnit::from_secs(size),
34+
quantity: *quantity,
35+
}
36+
}
37+
}
38+
39+
impl IncrementCounter for Extent {
40+
type Increment = ExtentUnit;
41+
type IncrementCount = ExtentCount;
42+
type IncrementProduct = ExtentProduct;
43+
44+
fn new(size: &Self::Increment, quantity: &Self::IncrementCount) -> Self {
45+
Self {
46+
size: *size,
47+
quantity: *quantity,
48+
}
49+
}
50+
51+
fn add(&self, add: Self::IncrementCount) -> Result<Self, IntErrorKind> {
52+
match self.quantity.checked_add(add) {
53+
None => Err(IntErrorKind::PosOverflow),
54+
Some(quantity) => Ok(Self {
55+
size: self.size,
56+
quantity,
57+
}),
58+
}
59+
}
60+
61+
fn sub(&self, sub: Self::IncrementCount) -> Result<Self, IntErrorKind> {
62+
match self.quantity.checked_sub(sub) {
63+
None => Err(IntErrorKind::NegOverflow),
64+
Some(quantity) => Ok(Self {
65+
size: self.size,
66+
quantity,
67+
}),
68+
}
69+
}
70+
71+
fn product_current(&self) -> Result<Option<Self::IncrementProduct>, TryFromIntError> {
72+
match u32::try_from(self.quantity) {
73+
Err(error) => Err(error),
74+
Ok(quantity) => Ok(self.size.checked_mul(quantity)),
75+
}
76+
}
77+
78+
fn product_next(&self) -> Result<Option<Self::IncrementProduct>, TryFromIntError> {
79+
match u32::try_from(self.quantity) {
80+
Err(e) => Err(e),
81+
Ok(quantity) => match quantity.checked_add(1) {
82+
None => Ok(None),
83+
Some(quantity) => match self.size.checked_mul(quantity) {
84+
None => Ok(None),
85+
Some(extent) => Ok(Some(extent)),
86+
},
87+
},
88+
}
89+
}
90+
}
91+
92+
#[cfg(test)]
93+
mod test {
94+
95+
use std::time::Duration;
96+
97+
use crate::protocol::clock::extent::{Extent, IncrementCounter};
98+
99+
#[test]
100+
fn it_should_get_the_total_time_of_a_period() {
101+
assert_eq!(Extent::default().product_current().unwrap().unwrap(), Duration::ZERO);
102+
103+
assert_eq!(
104+
Extent::from_sec(12, &12).product_current().unwrap().unwrap(),
105+
Duration::from_secs(144)
106+
);
107+
assert_eq!(
108+
Extent::from_sec(12, &12).product_next().unwrap().unwrap(),
109+
Duration::from_secs(156)
110+
);
111+
}
112+
}

src/protocol/clock/extentmaker.rs

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
use std::num::TryFromIntError;
2+
use std::time::Duration;
3+
4+
use super::extent::{Extent, ExtentCount, ExtentUnit, IncrementCounter};
5+
use super::{ClockType, StoppedClock, TimeNow, WorkingClock};
6+
7+
pub trait ExtentFromClock<T>: Sized
8+
where
9+
T: TimeNow,
10+
{
11+
fn now(size: &ExtentUnit) -> Option<Result<Extent, TryFromIntError>> {
12+
T::now()
13+
.as_nanos()
14+
.checked_div((*size).as_nanos())
15+
.map(|quantity| match ExtentCount::try_from(quantity) {
16+
Err(error) => Err(error),
17+
Ok(quantity) => Ok(Extent::new(size, &quantity)),
18+
})
19+
}
20+
21+
fn now_add(size: &ExtentUnit, add_time: &Duration) -> Option<Result<Extent, TryFromIntError>> {
22+
match T::add(add_time) {
23+
None => None,
24+
Some(time) => time
25+
.as_nanos()
26+
.checked_div(size.as_nanos())
27+
.map(|quantity| match ExtentCount::try_from(quantity) {
28+
Err(error) => Err(error),
29+
Ok(quantity) => Ok(Extent::new(size, &quantity)),
30+
}),
31+
}
32+
}
33+
fn now_sub(size: &ExtentUnit, sub_time: &Duration) -> Option<Result<Extent, TryFromIntError>> {
34+
match T::sub(sub_time) {
35+
None => None,
36+
Some(time) => time
37+
.as_nanos()
38+
.checked_div(size.as_nanos())
39+
.map(|quantity| match ExtentCount::try_from(quantity) {
40+
Err(error) => Err(error),
41+
Ok(quantity) => Ok(Extent::new(size, &quantity)),
42+
}),
43+
}
44+
}
45+
}
46+
47+
#[derive(Debug)]
48+
pub struct ExtentClock<const T: usize> {}
49+
50+
pub type WorkingClockExtentMaker = ExtentClock<{ ClockType::WorkingClock as usize }>;
51+
52+
pub type StoppedClockExtentMaker = ExtentClock<{ ClockType::StoppedClock as usize }>;
53+
54+
impl ExtentFromClock<WorkingClock> for WorkingClockExtentMaker {}
55+
56+
impl ExtentFromClock<StoppedClock> for StoppedClockExtentMaker {}
57+
58+
#[cfg(not(test))]
59+
pub type DefaultClockExtentMaker = WorkingClockExtentMaker;
60+
61+
#[cfg(test)]
62+
pub type DefaultClockExtentMaker = StoppedClockExtentMaker;
63+
64+
#[cfg(test)]
65+
mod tests {
66+
use std::time::Duration;
67+
68+
use crate::protocol::clock::extent::Extent;
69+
use crate::protocol::clock::extentmaker::{DefaultClockExtentMaker, ExtentFromClock};
70+
use crate::protocol::clock::{DefaultClock, DurationSinceUnixEpoch, StoppedTime};
71+
72+
#[test]
73+
fn it_should_get_the_current_period() {
74+
assert_eq!(
75+
DefaultClockExtentMaker::now(&Duration::from_secs(2)).unwrap().unwrap(),
76+
Extent::from_sec(2, &0)
77+
);
78+
79+
DefaultClock::local_set(&DurationSinceUnixEpoch::from_secs(12387687123));
80+
81+
assert_eq!(
82+
DefaultClockExtentMaker::now(&Duration::from_secs(2)).unwrap().unwrap(),
83+
Extent::from_sec(2, &6193843561)
84+
);
85+
}
86+
}

src/protocol/clock.rs renamed to src/protocol/clock/mod.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use std::num::IntErrorKind;
2-
pub use std::time::Duration;
2+
use std::time::Duration;
33

44
pub type DurationSinceUnixEpoch = Duration;
55

@@ -240,9 +240,12 @@ mod stopped_clock {
240240

241241
#[test]
242242
fn it_should_get_app_start_time() {
243-
const TIME_AT_WRITING_THIS_TEST: Duration = Duration::new(1662983731, 000022312);
243+
const TIME_AT_WRITING_THIS_TEST: Duration = Duration::new(1662983731, 22312);
244244
assert!(get_app_start_time() > TIME_AT_WRITING_THIS_TEST);
245245
}
246246
}
247247
}
248248
}
249+
250+
pub mod extent;
251+
pub mod extentmaker;

0 commit comments

Comments
 (0)