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
2054686
            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
54778
    pub(crate) fn new(instant: Instant, wallclock: SystemTime) -> Self {
50
54778
        MockTimeCore {
51
54778
            instant,
52
54778
            coarse: MockCoarseTimeProvider::new(),
53
54778
            wallclock,
54
54778
        }
55
54778
    }
56

            
57
    /// Advance by a duration
58
    ///
59
    /// All three time values are advanced in step.
60
328848
    pub(crate) fn advance(&mut self, d: Duration) {
61
328848
        self.instant += d;
62
328848
        self.wallclock += d;
63
328848
        self.coarse.advance(d);
64
328848
    }
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
1568
    pub(crate) fn jump_wallclock(&mut self, new_wallclock: SystemTime) {
71
1568
        self.wallclock = new_wallclock;
72
1568
    }
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
54778
    pub(crate) fn new() -> Self {
93
54778
        MockCoarseTimeProvider {
94
54778
            started: RealCoarseTimeProvider::new().now_coarse(),
95
54778
            elapsed: Duration::ZERO,
96
54778
        }
97
54778
    }
98

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

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