|
|
@@ -0,0 +1,137 @@ |
|
|
|
use std::net::Ipv4Addr; |
|
|
|
use chrono::{DateTime, Utc}; |
|
|
|
use uuid::Uuid; |
|
|
|
|
|
|
|
pub struct Event<T> { |
|
|
|
pub time: DateTime<Utc>, |
|
|
|
pub id: Uuid, |
|
|
|
pub event: T, |
|
|
|
} |
|
|
|
|
|
|
|
pub struct Pending{ |
|
|
|
pub recipient: Ipv4Addr, |
|
|
|
} |
|
|
|
|
|
|
|
pub struct Sending { |
|
|
|
pub payload: Vec<u8>, |
|
|
|
pub bytes_sent: usize, |
|
|
|
pub prev: Event<Ipv4Addr>, |
|
|
|
} |
|
|
|
|
|
|
|
pub struct Sent { |
|
|
|
pub ack_req: bool, |
|
|
|
pub prev: Event<Sending>, |
|
|
|
} |
|
|
|
|
|
|
|
pub struct Ack { |
|
|
|
pub data: Vec<u8>, |
|
|
|
pub prev: Event<Sent>, |
|
|
|
} |
|
|
|
|
|
|
|
pub struct Finished<T> { |
|
|
|
pub prev: Event<T>, |
|
|
|
} |
|
|
|
|
|
|
|
pub enum Active { |
|
|
|
Pending(Event<Pending>), |
|
|
|
Sending(Event<Sending>), |
|
|
|
Sent(Event<Sent>), |
|
|
|
Acked(Event<Ack>), |
|
|
|
FinishedNoAck(Event<Finished<Sent>>), |
|
|
|
FinishedAcked(Event<Finished<Ack>>), |
|
|
|
} |
|
|
|
|
|
|
|
pub trait Timestamped { |
|
|
|
fn time(&self) -> DateTime<Utc>; |
|
|
|
} |
|
|
|
|
|
|
|
pub trait Chronological { |
|
|
|
type Prev; |
|
|
|
type Next; |
|
|
|
|
|
|
|
fn prev(&self) -> Self::Prev; |
|
|
|
fn next(&self) -> Self::Next; |
|
|
|
} |
|
|
|
|
|
|
|
pub trait Elapsed<P, N>: Chronological<Prev = P, Next = N> { |
|
|
|
fn elapsed(&self) -> chrono::Duration; |
|
|
|
} |
|
|
|
|
|
|
|
impl<T> Timestamped for Event<T> { |
|
|
|
fn time(&self) -> DateTime<Utc> { self.time } |
|
|
|
} |
|
|
|
|
|
|
|
impl<P, N, T> Elapsed<P, N> for T |
|
|
|
where T: Chronological<Prev = P, Next = N>, |
|
|
|
P: Timestamped, |
|
|
|
N: Timestamped |
|
|
|
{ |
|
|
|
fn elapsed(&self) -> chrono::Duration { |
|
|
|
self.next().time().signed_duration_since(self.prev().time()) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
impl<N, T> Elapsed<(), N> for T |
|
|
|
where T: Chronological<Prev = (), Next = N> |
|
|
|
{ |
|
|
|
fn elapsed(&self) -> chrono::Duration { |
|
|
|
chrono::Duration::seconds(0) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
impl Timestamped for Active { |
|
|
|
fn time(&self) -> DateTime<Utc> { |
|
|
|
use Active::*; |
|
|
|
match self { |
|
|
|
Pending(event) => event.time, |
|
|
|
Sending(event) => event.time, |
|
|
|
Sent(event) => event.time, |
|
|
|
Acked(event) => event.time, |
|
|
|
FinishedNoAck(event) => event.time, |
|
|
|
FinishedAcked(event) => event.time, |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
macro_rules! event_attr { |
|
|
|
($method:ident, $t:ident, $attr:ident) => { |
|
|
|
fn $method(&self) -> $t { |
|
|
|
use Active::*; |
|
|
|
match self { |
|
|
|
Pending(event) => event.$attr, |
|
|
|
Sending(event) => event.$attr, |
|
|
|
Sent(event) => event.$attr, |
|
|
|
Acked(event) => event.$attr, |
|
|
|
FinishedNoAck(event) => event.$attr, |
|
|
|
FinishedAcked(event) => event.$attr, |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
impl Active { |
|
|
|
event_attr!(id, Uuid, id); |
|
|
|
} |
|
|
|
|
|
|
|
#[allow(unused)] |
|
|
|
#[cfg(test)] |
|
|
|
mod tests { |
|
|
|
use super::*; |
|
|
|
use std::str::FromStr; |
|
|
|
|
|
|
|
#[test] |
|
|
|
fn event_attr_accessors_work() { |
|
|
|
let pending = Pending { recipient: "0.0.0.0".parse().unwrap() }; |
|
|
|
let now = Utc::now(); |
|
|
|
let id = Uuid::new_v4(); |
|
|
|
let pending_event = Event { |
|
|
|
time: now, |
|
|
|
id, |
|
|
|
event: pending, |
|
|
|
}; |
|
|
|
let pending_active = Active::Pending(pending_event); |
|
|
|
assert_eq!(pending_active.time(), now); |
|
|
|
assert_eq!(pending_active.id(), id); |
|
|
|
} |
|
|
|
} |
|
|
|
|