avr_simulator/duration.rs
1use std::fmt;
2use std::ops::{Add, AddAssign, Sub, SubAssign};
3
4/// Like [`std::time::Duration`], but in AVR cycles; somewhat approximate¹.
5///
6/// ¹ <https://github.com/buserror/simavr/blob/b3ea4f93e18fa5059f76060ff718dc544ca48009/simavr/sim/sim_core.c#L621>
7#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
8pub struct AvrDuration {
9 clock_frequency: u32,
10 cycles: u64,
11}
12
13impl AvrDuration {
14 /// Creates a new duration for given clock frequency and number of cycles:
15 ///
16 /// ```
17 /// # use avr_simulator::AvrDuration;
18 /// #
19 /// AvrDuration::new(
20 /// 16_000_000, /* 16 MHz */
21 /// 8_000_000, /* 8 million clock cycles (=500ms here) */
22 /// );
23 /// ```
24 ///
25 /// If you're using AvrTester, you might find `AvrDurationExt` more
26 /// convenient than this constructor.
27 pub const fn new(clock_frequency: u32, cycles: u64) -> Self {
28 Self {
29 clock_frequency,
30 cycles,
31 }
32 }
33
34 /// Returns a new duration with increased number of cycles.
35 ///
36 /// # Examples
37 ///
38 /// ```
39 /// # use avr_simulator::AvrDuration;
40 /// #
41 /// let tt = AvrDuration::new(16_000_000, 8_000_000);
42 ///
43 /// assert_eq!(500, tt.as_millis());
44 /// assert_eq!(750, tt.add_cycles(4_000_000).as_millis());
45 /// ```
46 pub const fn add_cycles(mut self, n: u64) -> Self {
47 self.cycles += n;
48 self
49 }
50
51 /// Returns a new duration with increased number of microseconds.
52 ///
53 /// # Examples
54 ///
55 /// ```
56 /// # use avr_simulator::AvrDuration;
57 /// #
58 /// let tt = AvrDuration::new(16_000_000, 8_000_000);
59 ///
60 /// assert_eq!(500, tt.as_millis());
61 /// assert_eq!(501, tt.add_micros(1_000).as_millis());
62 /// ```
63 pub const fn add_micros(self, n: u64) -> Self {
64 self.add_cycles(n * (self.clock_frequency as u64 / 1_000_000))
65 }
66
67 /// Returns a new duration with increased number of milliseconds.
68 ///
69 /// # Examples
70 ///
71 /// ```
72 /// # use avr_simulator::AvrDuration;
73 /// #
74 /// let tt = AvrDuration::new(16_000_000, 8_000_000);
75 ///
76 /// assert_eq!(500, tt.as_millis());
77 /// assert_eq!(515, tt.add_millis(15).as_millis());
78 /// ```
79 pub const fn add_millis(self, millis: u64) -> Self {
80 self.add_cycles(millis * (self.clock_frequency as u64) / 1_000)
81 }
82
83 /// Returns a new duration with increased number of seconds.
84 ///
85 /// # Examples
86 ///
87 /// ```
88 /// # use avr_simulator::AvrDuration;
89 /// #
90 /// let tt = AvrDuration::new(16_000_000, 8_000_000);
91 ///
92 /// assert_eq!(500, tt.as_millis());
93 /// assert_eq!(2500, tt.add_secs(2).as_millis());
94 /// ```
95 pub const fn add_secs(self, secs: u64) -> Self {
96 self.add_cycles(secs * (self.clock_frequency as u64))
97 }
98
99 /// Returns a new duration with specified number of cycles.
100 ///
101 /// # Examples
102 ///
103 /// ```
104 /// # use avr_simulator::AvrDuration;
105 /// #
106 /// let tt = AvrDuration::new(16_000_000, 8_000_000);
107 ///
108 /// assert_eq!(250, tt.with_cycles(4_000_000).as_millis());
109 /// ```
110 pub const fn with_cycles(mut self, n: u64) -> Self {
111 self.cycles = n;
112 self
113 }
114
115 /// Returns a new duration with specified number of microseconds.
116 ///
117 /// # Examples
118 ///
119 /// ```
120 /// # use avr_simulator::AvrDuration;
121 /// #
122 /// let tt = AvrDuration::new(16_000_000, 8_000_000);
123 ///
124 /// assert_eq!(1, tt.with_micros(1_000).as_millis());
125 /// ```
126 pub const fn with_micros(self, n: u64) -> Self {
127 self.with_cycles(0).add_micros(n)
128 }
129
130 /// Returns a new duration with specified number of milliseconds.
131 ///
132 /// # Examples
133 ///
134 /// ```
135 /// # use avr_simulator::AvrDuration;
136 /// #
137 /// let tt = AvrDuration::new(16_000_000, 8_000_000);
138 ///
139 /// assert_eq!(15, tt.with_millis(15).as_millis());
140 /// ```
141 pub const fn with_millis(self, n: u64) -> Self {
142 self.with_cycles(0).add_millis(n)
143 }
144
145 /// Returns a new duration with specified number of seconds.
146 ///
147 /// # Examples
148 ///
149 /// ```
150 /// # use avr_simulator::AvrDuration;
151 /// #
152 /// let tt = AvrDuration::new(16_000_000, 8_000_000);
153 ///
154 /// assert_eq!(2000, tt.with_secs(2).as_millis());
155 /// ```
156 pub const fn with_secs(self, n: u64) -> Self {
157 self.with_cycles(0).add_secs(n)
158 }
159
160 /// Returns the clock frequency associated with this duration (e.g. 16 MHz).
161 ///
162 /// # Examples
163 ///
164 /// ```
165 /// # use avr_simulator::AvrDuration;
166 /// #
167 /// let tt = AvrDuration::new(16_000_000, 8_000_000);
168 ///
169 /// assert_eq!(16_000_000, tt.clock_frequency());
170 /// ```
171 pub const fn clock_frequency(self) -> u32 {
172 self.clock_frequency
173 }
174
175 /// Returns the number of cycles contained by this duration.
176 ///
177 /// # Examples
178 ///
179 /// ```
180 /// # use avr_simulator::AvrDuration;
181 /// #
182 /// let tt = AvrDuration::new(16_000_000, 8_000_000);
183 ///
184 /// assert_eq!(8_000_000, tt.as_cycles());
185 /// ```
186 ///
187 /// ```
188 /// # use avr_simulator::AvrDuration;
189 /// #
190 /// let tt = AvrDuration::new(16_000_000, 0).add_secs(3);
191 ///
192 /// assert_eq!(48_000_000, tt.as_cycles());
193 /// ```
194 pub const fn as_cycles(self) -> u64 {
195 self.cycles
196 }
197
198 /// Returns the number of microseconds contained by this duration.
199 ///
200 /// # Examples
201 ///
202 /// ```
203 /// # use avr_simulator::AvrDuration;
204 /// #
205 /// let tt = AvrDuration::new(16_000_000, 40);
206 ///
207 /// assert_eq!(3, tt.as_micros());
208 /// ```
209 pub fn as_micros(self) -> u64 {
210 self.as_micros_f64().round() as _
211 }
212
213 /// Returns the number of microseconds contained by this duration as `f64`.
214 ///
215 /// # Examples
216 ///
217 /// ```
218 /// # use avr_simulator::AvrDuration;
219 /// #
220 /// let tt = AvrDuration::new(16_000_000, 40);
221 ///
222 /// assert_eq!(2.5, tt.as_micros_f64());
223 /// ```
224 pub fn as_micros_f64(self) -> f64 {
225 (self.cycles as f64) / (self.clock_frequency as f64 / 1_000_000.0)
226 }
227
228 /// Returns the number of milliseconds contained by this duration.
229 ///
230 /// # Examples
231 ///
232 /// ```
233 /// # use avr_simulator::AvrDuration;
234 /// #
235 /// let tt = AvrDuration::new(16_000_000, 40_000);
236 ///
237 /// assert_eq!(3, tt.as_millis());
238 /// ```
239 pub fn as_millis(self) -> u64 {
240 self.as_millis_f64().round() as _
241 }
242
243 /// Returns the number of milliseconds contained by this duration as `f64`.
244 ///
245 /// # Examples
246 ///
247 /// ```
248 /// # use avr_simulator::AvrDuration;
249 /// #
250 /// let tt = AvrDuration::new(16_000_000, 40_000);
251 ///
252 /// assert_eq!(2.5, tt.as_millis_f64());
253 /// ```
254 pub fn as_millis_f64(self) -> f64 {
255 (self.cycles as f64) / (self.clock_frequency as f64 / 1_000.0)
256 }
257
258 /// Returns the number of seconds contained by this duration.
259 ///
260 /// # Examples
261 ///
262 /// ```
263 /// # use avr_simulator::AvrDuration;
264 /// #
265 /// let tt = AvrDuration::new(16_000_000, 40_000_000);
266 ///
267 /// assert_eq!(3, tt.as_secs());
268 /// ```
269 pub fn as_secs(self) -> u64 {
270 self.as_secs_f64().round() as _
271 }
272
273 /// Returns the number of seconds contained by this duration as `f64`.
274 ///
275 /// # Examples
276 ///
277 /// ```
278 /// # use avr_simulator::AvrDuration;
279 /// #
280 /// let tt = AvrDuration::new(16_000_000, 40_000_000);
281 ///
282 /// assert_eq!(2.5, tt.as_secs_f64());
283 /// ```
284 pub fn as_secs_f64(self) -> f64 {
285 (self.cycles as f64) / (self.clock_frequency as f64)
286 }
287
288 /// Returns whether the number of cycles contained by this duration is zero.
289 ///
290 /// # Examples
291 ///
292 /// ```
293 /// # use avr_simulator::AvrDuration;
294 /// #
295 /// let tt1 = AvrDuration::new(16_000_000, 0);
296 /// let tt2 = AvrDuration::new(16_000_000, 10_000);
297 ///
298 /// assert!(tt1.is_zero());
299 /// assert!(!tt2.is_zero());
300 /// ```
301 pub fn is_zero(self) -> bool {
302 self.as_cycles() == 0
303 }
304}
305
306/// # Examples
307///
308/// ```
309/// # use avr_simulator::AvrDuration;
310/// #
311/// let a = AvrDuration::new(16_000_000, 1_000);
312/// let b = AvrDuration::new(16_000_000, 2_000);
313///
314/// assert_eq!(
315/// AvrDuration::new(16_000_000, 3_000),
316/// a + b,
317/// );
318/// ```
319impl Add for AvrDuration {
320 type Output = Self;
321
322 fn add(mut self, rhs: Self) -> Self::Output {
323 self += rhs;
324 self
325 }
326}
327
328/// # Examples
329///
330/// ```
331/// # use avr_simulator::AvrDuration;
332/// #
333/// let mut a = AvrDuration::new(16_000_000, 1_000);
334///
335/// a += AvrDuration::new(16_000_000, 2_000);
336///
337/// assert_eq!(AvrDuration::new(16_000_000, 3_000), a);
338/// ```
339impl AddAssign for AvrDuration {
340 fn add_assign(&mut self, rhs: Self) {
341 assert_eq!(
342 self.clock_frequency, rhs.clock_frequency,
343 "Cannot add durations with different clock frequencies ({} vs {})",
344 self.clock_frequency, rhs.clock_frequency
345 );
346
347 self.cycles += rhs.cycles;
348 }
349}
350
351/// # Examples
352///
353/// ```
354/// # use avr_simulator::AvrDuration;
355/// #
356/// let a = AvrDuration::new(16_000_000, 3_000);
357/// let b = AvrDuration::new(16_000_000, 2_000);
358///
359/// assert_eq!(
360/// AvrDuration::new(16_000_000, 1_000),
361/// a - b,
362/// );
363/// ```
364///
365/// ```
366/// # use avr_simulator::AvrDuration;
367/// #
368/// let a = AvrDuration::new(16_000_000, 3_000);
369/// let b = AvrDuration::new(16_000_000, 4_000);
370///
371/// assert_eq!(
372/// AvrDuration::new(16_000_000, 0),
373/// a - b,
374/// );
375/// ```
376impl Sub for AvrDuration {
377 type Output = Self;
378
379 fn sub(mut self, rhs: Self) -> Self::Output {
380 self -= rhs;
381 self
382 }
383}
384
385/// # Examples
386///
387/// ```
388/// # use avr_simulator::AvrDuration;
389/// #
390/// let mut a = AvrDuration::new(16_000_000, 3_000);
391///
392/// a -= AvrDuration::new(16_000_000, 2_000);
393///
394/// assert_eq!(AvrDuration::new(16_000_000, 1_000), a);
395/// ```
396///
397/// ```
398/// # use avr_simulator::AvrDuration;
399/// #
400/// let mut a = AvrDuration::new(16_000_000, 3_000);
401///
402/// a -= AvrDuration::new(16_000_000, 4_000);
403///
404/// assert_eq!(AvrDuration::new(16_000_000, 0), a);
405/// ```
406impl SubAssign for AvrDuration {
407 fn sub_assign(&mut self, rhs: Self) {
408 assert_eq!(
409 self.clock_frequency, rhs.clock_frequency,
410 "Cannot subtract durations with different clock frequencies ({} vs {})",
411 self.clock_frequency, rhs.clock_frequency
412 );
413
414 self.cycles = self.cycles.saturating_sub(rhs.cycles);
415 }
416}
417
418/// # Examples
419///
420/// ```rust
421/// # use avr_simulator::AvrDuration;
422/// #
423/// let tt = AvrDuration::new(16_000_000, 0).add_millis(123);
424///
425/// assert_eq!("123000 µs", tt.to_string());
426/// ```
427impl fmt::Display for AvrDuration {
428 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
429 write!(f, "{} µs", self.as_micros())
430 }
431}