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 if overflowed {
168 panic!("overflow while subtracting two TickInstants.")
169 }
170 TickDuration { ticks: difference }
171 }
172}
173
174impl Add for TickDuration {
175 type Output = TickDuration;
176
177 fn add(self, rhs: Self) -> Self::Output {
178 let mut result = self;
179 result += rhs;
180 result
181 }
182}
183
184impl AddAssign for TickDuration {
185 fn add_assign(&mut self, rhs: Self) {
186 self.ticks = self
187 .ticks
188 .checked_add(rhs.ticks)
189 .expect("Overflow occurred while adding TickDuration instances.")
190 }
191}
192
193impl Sub for TickDuration {
194 type Output = TickDuration;
195
196 fn sub(self, rhs: Self) -> Self::Output {
197 let mut result = self;
198 result -= rhs;
199 result
200 }
201}
202
203impl SubAssign for TickDuration {
204 fn sub_assign(&mut self, rhs: Self) {
205 self.ticks = self
206 .ticks
207 .checked_sub(rhs.ticks)
208 .expect("Overflow occurred while subtracting TickDuration instances.");
209 }
210}
211
212impl Neg for TickDuration {
213 type Output = TickDuration;
214
215 fn neg(self) -> Self::Output {
216 TickDuration {
217 ticks: self
218 .ticks
219 .checked_neg()
220 .expect("Overflow while negating duration."),
221 }
222 }
223}
224
225impl Display for TickInstant {
226 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
227 write!(f, "[{}]", self.0)
228 }
229}
230
231impl Display for TickDuration {
232 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
233 write!(f, "<{}>", self.ticks)
234 }
235}
236
237impl From<TickInstant> for u64 {
238 fn from(value: TickInstant) -> Self {
239 value.0
240 }
241}
242
243impl From<TickDuration> for i64 {
244 fn from(value: TickDuration) -> Self {
245 value.ticks
246 }
247}