You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

347 lines
8.8KB

  1. use std::net::Ipv4Addr;
  2. use chrono::{DateTime, Utc};
  3. use uuid::Uuid;
  4. pub struct Event<T> {
  5. pub time: DateTime<Utc>,
  6. pub id: Uuid,
  7. pub event: T,
  8. }
  9. pub struct Pending{
  10. pub recipient: Ipv4Addr,
  11. }
  12. #[derive(Default)]
  13. pub struct Sending {
  14. pub payload: Vec<u8>,
  15. pub bytes_sent: usize,
  16. pub prev: Event<Pending>,
  17. }
  18. #[derive(Default)]
  19. pub struct Sent {
  20. pub ack_req: bool,
  21. pub prev: Event<Sending>,
  22. }
  23. #[derive(Default)]
  24. pub struct Ack {
  25. pub data: Vec<u8>,
  26. pub prev: Event<Sent>,
  27. }
  28. #[derive(Default)]
  29. pub struct Finished<T> {
  30. pub prev: Event<T>,
  31. }
  32. pub enum Active {
  33. Pending(Event<Pending>),
  34. Sending(Event<Sending>),
  35. Sent(Event<Sent>),
  36. Acked(Event<Ack>),
  37. FinishedNoAck(Event<Finished<Sent>>),
  38. FinishedAcked(Event<Finished<Ack>>),
  39. }
  40. pub trait Timestamped {
  41. fn time(&self) -> DateTime<Utc>;
  42. }
  43. pub trait Chronological {
  44. type Prev;
  45. type Next;
  46. fn prev(&self) -> Self::Prev;
  47. fn next(&self) -> Self::Next;
  48. }
  49. pub trait Elapsed<P, N>: Chronological<Prev = P, Next = N> {
  50. fn elapsed(&self) -> chrono::Duration;
  51. }
  52. impl<T> Timestamped for Event<T> {
  53. fn time(&self) -> DateTime<Utc> { self.time }
  54. }
  55. impl<P, N, T> Elapsed<P, N> for T
  56. where T: Chronological<Prev = P, Next = N>,
  57. P: Timestamped,
  58. N: Timestamped
  59. {
  60. fn elapsed(&self) -> chrono::Duration {
  61. self.next().time().signed_duration_since(self.prev().time())
  62. }
  63. }
  64. impl<N, T> Elapsed<(), N> for T
  65. where T: Chronological<Prev = (), Next = N>
  66. {
  67. fn elapsed(&self) -> chrono::Duration {
  68. chrono::Duration::seconds(0)
  69. }
  70. }
  71. /*
  72. impl Timestamped for Active {
  73. fn time(&self) -> DateTime<Utc> {
  74. use Active::*;
  75. match self {
  76. Pending(event) => event.time,
  77. Sending(event) => event.time,
  78. Sent(event) => event.time,
  79. Acked(event) => event.time,
  80. FinishedNoAck(event) => event.time,
  81. FinishedAcked(event) => event.time,
  82. }
  83. }
  84. }
  85. */
  86. macro_rules! event_attr {
  87. ($method:ident, $t:ty, $attr:ident) => {
  88. fn $method(&self) -> $t {
  89. use Active::*;
  90. match self {
  91. Pending(event) => event.$attr,
  92. Sending(event) => event.$attr,
  93. Sent(event) => event.$attr,
  94. Acked(event) => event.$attr,
  95. FinishedNoAck(event) => event.$attr,
  96. FinishedAcked(event) => event.$attr,
  97. }
  98. }
  99. }
  100. }
  101. impl Timestamped for Active {
  102. event_attr!(time, DateTime<Utc>, time);
  103. }
  104. macro_rules! optionally_public_event_attr {
  105. // note: `vis` is automatically optional, doesn't need
  106. // this will work as-is if there is nothing there
  107. ($pub:vis $method:ident, $t:ident, $attr:ident) => {
  108. $pub fn $method(&self) -> $t {
  109. use Active::*;
  110. match self {
  111. Pending(event) => event.$attr,
  112. Sending(event) => event.$attr,
  113. Sent(event) => event.$attr,
  114. Acked(event) => event.$attr,
  115. FinishedNoAck(event) => event.$attr,
  116. FinishedAcked(event) => event.$attr,
  117. }
  118. }
  119. }
  120. }
  121. impl Active {
  122. optionally_public_event_attr!(pub id, Uuid, id);
  123. }
  124. impl From<Event<Pending>> for Active {
  125. fn from(pending: Event<Pending>) -> Active {
  126. Active::Pending(pending)
  127. }
  128. }
  129. macro_rules! from_event {
  130. ($t:ty, $variant:ident) => {
  131. impl From<Event<$t>> for Active {
  132. fn from(event: Event<$t>) -> Active {
  133. Active::$variant(event)
  134. }
  135. }
  136. }
  137. }
  138. //from_event!(Pending, Pending);
  139. from_event!(Sending, Sending);
  140. from_event!(Sent, Sent);
  141. from_event!(Ack, Acked);
  142. from_event!(Finished<Sent>, FinishedNoAck);
  143. from_event!(Finished<Ack>, FinishedAcked);
  144. macro_rules! variant_check {
  145. ($f:ident, $variant:ident) => {
  146. impl Active {
  147. pub fn $f(&self) -> bool {
  148. match self {
  149. Active::$variant(..) => true,
  150. _ => false,
  151. }
  152. }
  153. }
  154. }
  155. }
  156. variant_check!(is_pending, Pending);
  157. variant_check!(is_sending, Sending);
  158. variant_check!(is_sent, Sent);
  159. variant_check!(is_acked, Acked);
  160. variant_check!(is_finished_noack, FinishedNoAck);
  161. variant_check!(is_finished_acked, FinishedAcked);
  162. macro_rules! multiple_variant_check {
  163. ($f:ident; $($variant:ident),*) => {
  164. impl Active {
  165. pub fn $f(&self) -> bool {
  166. match self {
  167. $( Active::$variant(..) => { true } )*
  168. _ => false,
  169. }
  170. }
  171. }
  172. }
  173. }
  174. multiple_variant_check!(is_finished; FinishedNoAck, FinishedAcked);
  175. multiple_variant_check!(is_still_unfinished; Pending, Sending, Sent, Acked);
  176. multiple_variant_check!(anything_but_sent; Pending, Sending, Acked, FinishedNoAck, FinishedAcked);
  177. // needed because Ipv4Addr does not implement Default
  178. // other event type structs derive Default instead
  179. impl Default for Pending {
  180. fn default() -> Self {
  181. Self { recipient: Ipv4Addr::new(127, 0, 0, 1) }
  182. }
  183. }
  184. impl<T> Default for Event<T>
  185. where T: Default
  186. {
  187. fn default() -> Self {
  188. Self {
  189. time: Utc::now(),
  190. id: Uuid::new_v4(),
  191. event: T::default(),
  192. }
  193. }
  194. }
  195. impl Default for Active {
  196. fn default() -> Self {
  197. Active::Pending(Default::default())
  198. }
  199. }
  200. macro_rules! new_with_default {
  201. ($f:ident, $t:ty) => {
  202. impl Active {
  203. pub fn $f() -> Self {
  204. let inner: Event<$t> = Default::default();
  205. Self::from(inner)
  206. }
  207. }
  208. }
  209. }
  210. new_with_default!(new_pending, Pending);
  211. new_with_default!(new_sending, Sending);
  212. new_with_default!(new_sent, Sent);
  213. new_with_default!(new_acked, Ack);
  214. new_with_default!(new_finished_noack, Finished<Sent>);
  215. new_with_default!(new_finished_acked, Finished<Ack>);
  216. #[allow(unused)]
  217. #[cfg(test)]
  218. mod tests {
  219. use super::*;
  220. use std::str::FromStr;
  221. #[test]
  222. fn event_attr_accessors_work() {
  223. let pending = Pending { recipient: "0.0.0.0".parse().unwrap() };
  224. let now = Utc::now();
  225. let id = Uuid::new_v4();
  226. let pending_event = Event {
  227. time: now,
  228. id,
  229. event: pending,
  230. };
  231. let pending_active = Active::Pending(pending_event);
  232. assert_eq!(pending_active.time(), now);
  233. assert_eq!(pending_active.id(), id);
  234. }
  235. #[test]
  236. fn check_generated_methods_for_pending() {
  237. let active = Active::new_pending();
  238. assert!(active.is_pending());
  239. assert!(active.is_still_unfinished());
  240. }
  241. #[test]
  242. fn generated_method_check_for_variant() {
  243. macro_rules! check_for_variant {
  244. ($new:ident, $single:ident, $multiple:ident, $not:ident) => {
  245. let active = Active::$new();
  246. assert!(active.$single());
  247. assert!(active.$multiple());
  248. assert!( ! active.$not());
  249. }
  250. }
  251. check_for_variant!(new_pending, is_pending, is_still_unfinished, is_sent);
  252. check_for_variant!(new_sending, is_sending, is_still_unfinished, is_acked);
  253. check_for_variant!(new_sent, is_sent, is_still_unfinished, is_finished_noack);
  254. check_for_variant!(new_acked, is_acked, is_still_unfinished, is_pending);
  255. check_for_variant!(new_finished_noack, is_finished_noack, is_finished, is_still_unfinished);
  256. check_for_variant!(new_finished_acked, is_finished_acked, is_finished, is_still_unfinished);
  257. }
  258. #[test]
  259. fn active_impls_timestamped() {
  260. fn tm_plus_42min<T: Timestamped>(x: &T) -> DateTime<Utc> {
  261. x.time() + chrono::Duration::minutes(42)
  262. }
  263. let active = Active::new_sent();
  264. let t2 = tm_plus_42min(&active);
  265. assert_eq!(active.time() + chrono::Duration::minutes(42), t2);
  266. }
  267. #[test]
  268. fn check_that_vis_can_handle_all_three_possibilities_for_visibility() {
  269. pub struct A {
  270. x: i32,
  271. y: DateTime<Utc>,
  272. z: f32,
  273. }
  274. macro_rules! a_attr {
  275. ($pub:vis $method:ident, $t:ty, $attr:ident) => {
  276. impl A {
  277. $pub fn $method(&self) -> $t {
  278. self.$attr
  279. }
  280. }
  281. }
  282. }
  283. a_attr!(get_x, i32, x);
  284. a_attr!(pub(crate) get_y, DateTime<Utc>, y);
  285. a_attr!(pub get_z, f32, z);
  286. let a = A { x: 0i32, y: Utc::now(), z: 1.234f32 };
  287. assert_eq!(a.get_x(), a.x);
  288. assert_eq!(a.get_y(), a.y);
  289. assert_eq!(a.get_z(), a.z);
  290. }
  291. #[test]
  292. fn usage_of_variant_check_example() {
  293. let pending = Pending { recipient: Ipv4Addr::new(127, 0, 0, 1) };
  294. let event = Event { time: Utc::now(), id: Uuid::new_v4(), event: pending };
  295. let active = Active::from(event);
  296. assert_eq!(active.is_pending(), true);
  297. }
  298. }