dfir_rs/scheduled/ticks.rs
1//! This module contains types to work with ticks.
2//!
3//! Each iteration of a process loop is called a tick. Associated with the process
4//! is a clock value, which tells you how many ticks were executed by this process prior to the
5//! current tick. Each process produces totally ordered, sequentially increasing clock values,
6//! which you can think of as the "local logical time" at the process.
7
8use std::fmt::{Display, Formatter};
9use std::ops::{Add, AddAssign, Neg, Sub, SubAssign};
10
11use serde::{Deserialize, Serialize};
12
13/// A point in time during execution on process.
14///
15/// `TickInstant` instances can be subtracted to calculate the `TickDuration` between them.
16///
17/// ```
18/// # use dfir_rs::scheduled::ticks::{TickDuration, TickInstant};
19///
20/// assert_eq!(TickInstant(1) - TickInstant(0), TickDuration::SINGLE_TICK);
21/// assert_eq!(TickInstant(0) - TickInstant(1), -TickDuration::SINGLE_TICK);
22/// ```
23#[derive(
24 Eq, PartialEq, Ord, PartialOrd, Copy, Clone, Hash, Default, Debug, Serialize, Deserialize,
25)]
26pub struct TickInstant(pub u64);
27
28/// The duration between two ticks.
29///
30/// `TickDuration` instances can be negative to allow for calculation of `TickInstant` instances in the past.
31///
32/// ```
33/// # use dfir_rs::scheduled::ticks::{TickDuration, TickInstant};
34/// assert_eq!(TickInstant(1) + TickDuration::new(-1), TickInstant(0))
35/// ```
36/// `TickDuration` instances can be added/subtracted to/from other `TickDuration` instances
37///
38/// ```
39/// # use dfir_rs::scheduled::ticks::TickDuration;
40/// assert_eq!(TickDuration::ZERO + TickDuration::ZERO, TickDuration::ZERO);
41/// assert_eq!(
42/// TickDuration::ZERO + TickDuration::SINGLE_TICK,
43/// TickDuration::SINGLE_TICK
44/// );
45/// assert_eq!(
46/// TickDuration::SINGLE_TICK - TickDuration::ZERO,
47/// TickDuration::SINGLE_TICK
48/// );
49/// assert_eq!(
50/// TickDuration::SINGLE_TICK - TickDuration::SINGLE_TICK,
51/// TickDuration::ZERO
52/// );
53/// assert_eq!(
54/// TickDuration::ZERO - TickDuration::SINGLE_TICK,
55/// -TickDuration::SINGLE_TICK
56/// );
57/// ```
58#[derive(
59 Eq, PartialEq, Ord, PartialOrd, Copy, Clone, Hash, Default, Debug, Serialize, Deserialize,
60)]
61pub struct TickDuration {
62 /// The length of the duration, measured in ticks.
63 pub ticks: i64,
64}
65
66impl TickInstant {
67 /// Create a new `TickInstant`
68 ///
69 /// The specified parameter indicates the number of ticks that have elapsed on the process,
70 /// prior to this one.
71 pub fn new(ticks: u64) -> Self {
72 TickInstant(ticks)
73 }
74}
75
76impl TickDuration {
77 /// A zero duration
78 ///
79 /// It is the identity element for addition for both `TickDuration` and
80 /// `TickInstant` (i.e. adding zero duration to a `TickInstant` or `TickDuration` results in
81 /// the same `TickInstant` or `TickDuration`.
82 ///
83 /// ```
84 /// # use dfir_rs::scheduled::ticks::{TickDuration, TickInstant};
85 /// # use dfir_lang::graph::ops::DelayType::Tick;
86 /// let ticks = TickInstant::new(100);
87 /// assert_eq!(ticks + TickDuration::ZERO, ticks);
88 /// assert_eq!(ticks - TickDuration::ZERO, ticks);
89 ///
90 /// let duration = TickDuration::new(100);
91 /// assert_eq!(duration + TickDuration::ZERO, duration);
92 /// assert_eq!(duration - TickDuration::ZERO, duration);
93 /// ```
94 pub const ZERO: Self = TickDuration { ticks: 0 };
95
96 /// A single tick duration.
97 ///
98 /// It is the duration between two consecutive `TickInstant` instances.
99 ///
100 /// ```
101 /// # use dfir_rs::scheduled::ticks::{TickDuration, TickInstant};
102 /// assert_eq!(TickInstant(0) + TickDuration::SINGLE_TICK, TickInstant(1))
103 /// ```
104 pub const SINGLE_TICK: Self = TickDuration { ticks: 1 };
105
106 /// Create a new `TickDuration` for the specified tick interval.
107 ///
108 /// A negative duration allows for calculating `TickInstants` in the past and represents a
109 /// backward movement in time.
110 pub fn new(ticks: i64) -> TickDuration {
111 TickDuration { ticks }
112 }
113}
114
115impl Add<TickDuration> for TickInstant {
116 type Output = TickInstant;
117
118 fn add(self, rhs: TickDuration) -> Self::Output {
119 let mut result = self;
120 result += rhs;
121 result
122 }
123}
124
125impl AddAssign<TickDuration> for TickInstant {
126 fn add_assign(&mut self, rhs: TickDuration) {
127 self.0 = self
128 .0
129 .checked_add_signed(rhs.ticks)
130 .expect("overflow while adding tick duration to tick instant.");
131 }
132}
133
134impl Sub<TickDuration> for TickInstant {
135 type Output = TickInstant;
136
137 fn sub(self, rhs: TickDuration) -> Self::Output {
138 let mut result = self;
139 result -= rhs;
140 result
141 }
142}
143
144impl SubAssign<TickDuration> for TickInstant {
145 fn sub_assign(&mut self, rhs: TickDuration) {
146 if rhs.ticks.is_positive() {
147 self.0 = self
148 .0
149 .checked_sub(rhs.ticks.unsigned_abs())
150 .expect("overflow while subtracting duration from instant.");
151 } else if rhs.ticks.is_negative() {
152 self.0 = self
153 .0
154 .checked_add(rhs.ticks.unsigned_abs())
155 .expect("overflow while subtracting duration from instant.")
156 }
157 }
158}
159
160impl Sub for TickInstant {
161 type Output = TickDuration;
162
163 fn sub(self, rhs: TickInstant) -> Self::Output {
164 let minuend = (self.0 as i64).wrapping_add(i64::MIN);
165 let subtrahend = (rhs.0 as i64).wrapping_add(i64::MIN);
166 let (difference, overflowed) = minuend.overflowing_sub(subtrahend);
167 assert!(!overflowed, "overflow while subtracting two TickInstants.");
168 TickDuration { ticks: difference }
169 }
170}
171
172impl Add for TickDuration {
173 type Output = TickDuration;
174
175 fn add(self, rhs: Self) -> Self::Output {
176 let mut result = self;
177 result += rhs;
178 result
179 }
180}
181
182impl AddAssign for TickDuration {
183 fn add_assign(&mut self, rhs: Self) {
184 self.ticks = self
185 .ticks
186 .checked_add(rhs.ticks)
187 .expect("Overflow occurred while adding TickDuration instances.")
188 }
189}
190
191impl Sub for TickDuration {
192 type Output = TickDuration;
193
194 fn sub(self, rhs: Self) -> Self::Output {
195 let mut result = self;
196 result -= rhs;
197 result
198 }
199}
200
201impl SubAssign for TickDuration {
202 fn sub_assign(&mut self, rhs: Self) {
203 self.ticks = self
204 .ticks
205 .checked_sub(rhs.ticks)
206 .expect("Overflow occurred while subtracting TickDuration instances.");
207 }
208}
209
210impl Neg for TickDuration {
211 type Output = TickDuration;
212
213 fn neg(self) -> Self::Output {
214 TickDuration {
215 ticks: self
216 .ticks
217 .checked_neg()
218 .expect("Overflow while negating duration."),
219 }
220 }
221}
222
223impl Display for TickInstant {
224 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
225 write!(f, "[{}]", self.0)
226 }
227}
228
229impl Display for TickDuration {
230 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
231 write!(f, "<{}>", self.ticks)
232 }
233}
234
235impl From<TickInstant> for u64 {
236 fn from(value: TickInstant) -> Self {
237 value.0
238 }
239}
240
241impl From<TickDuration> for i64 {
242 fn from(value: TickDuration) -> Self {
243 value.ticks
244 }
245}