1
//! [`MockTimeCore`] and [`MockCoarseTimeProvider`]
2

            
3
use derive_deftly::{define_derive_deftly, Deftly};
4
use std::time::{Duration, Instant, SystemTime};
5
use tor_rtcompat::{CoarseDuration, CoarseInstant};
6
use tor_rtcompat::{CoarseTimeProvider, RealCoarseTimeProvider};
7

            
8
define_derive_deftly! {
9
    /// Derive getters for struct fields.
10
    ///
11
    /// Like `amplify::Getters` but `pub(crate)`.
12
    ///
13
    /// TODO add this feature to `amplify`.
14
    CrateGetters:
15
    ${define REF ${if not(fmeta(getter_copy)) { & }}}
16
    $(
17
        impl $ttype {
18
            ${fattrs doc}
19
2279083
            pub(crate) fn $fname(&self) -> $REF $ftype {
20
                $REF self.$fname
21
            }
22
        }
23
    )
24
}
25

            
26
/// Mock time, as a value
27
///
28
/// Contains an `Instant`, `SystemTime` and `CoarseInstant`.
29
///
30
/// Arranges that they are all moved in step,
31
/// unless explicitly requested otherwise.
32
#[derive(Clone, Debug, Deftly)]
33
#[derive_deftly(CrateGetters)]
34
pub(crate) struct MockTimeCore {
35
    /// Current time (monotonic clock)
36
    #[deftly(getter_copy)]
37
    instant: Instant,
38

            
39
    /// Current wallclock time
40
    #[deftly(getter_copy)]
41
    wallclock: SystemTime,
42

            
43
    /// Coarse time tracking
44
    coarse: MockCoarseTimeProvider,
45
}
46

            
47
impl MockTimeCore {
48
    /// Create a new `MockTimeCore`
49
60932
    pub(crate) fn new(instant: Instant, wallclock: SystemTime) -> Self {
50
60932
        MockTimeCore {
51
60932
            instant,
52
60932
            coarse: MockCoarseTimeProvider::new(),
53
60932
            wallclock,
54
60932
        }
55
60932
    }
56

            
57
    /// Advance by a duration
58
    ///
59
    /// All three time values are advanced in step.
60
364787
    pub(crate) fn advance(&mut self, d: Duration) {
61
364787
        self.instant += d;
62
364787
        self.wallclock += d;
63
364787
        self.coarse.advance(d);
64
364787
    }
65

            
66
    /// Warp the wallclock (only)
67
    //
68
    // We *could* just expose the field for mutable access,
69
    // but this way seems more regular.
70
1738
    pub(crate) fn jump_wallclock(&mut self, new_wallclock: SystemTime) {
71
1738
        self.wallclock = new_wallclock;
72
1738
    }
73
}
74

            
75
/// A mockable [`CoarseTimeProvider`]
76
#[derive(Clone, Debug)]
77
pub(crate) struct MockCoarseTimeProvider {
78
    /// Starting point
79
    started: CoarseInstant,
80

            
81
    /// How much we have advanced
82
    ///
83
    /// We track this as a `Duration`, not a [`CoarseDuration`] (or [`CoarseInstant`])
84
    /// to avoid accumulating rounding errors,
85
    /// which might otherwise cause the mocked `Instant` and `CoarseInstant`
86
    /// clocks to run at noticeably different *rates*.
87
    elapsed: Duration,
88
}
89

            
90
impl MockCoarseTimeProvider {
91
    /// Start a new [`MockCoarseTimeProvider`]
92
60932
    pub(crate) fn new() -> Self {
93
60932
        MockCoarseTimeProvider {
94
60932
            started: RealCoarseTimeProvider::new().now_coarse(),
95
60932
            elapsed: Duration::ZERO,
96
60932
        }
97
60932
    }
98

            
99
    /// Advance the mocked coarse time by `dur`
100
364787
    pub(crate) fn advance(&mut self, dur: Duration) {
101
364787
        self.elapsed += dur;
102
364787
    }
103
}
104

            
105
impl CoarseTimeProvider for MockCoarseTimeProvider {
106
168555
    fn now_coarse(&self) -> CoarseInstant {
107
168555
        self.started + CoarseDuration::from(self.elapsed)
108
168555
    }
109
}