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}