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

            
3
use derive_deftly::{Deftly, define_derive_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

            
16
    ${define REF ${if not(fmeta(getter_copy)) { & }}}
17
    impl $ttype {
18
        $(
19
            ${fattrs doc}
20
8506109
            pub(crate) fn $fname(&self) -> $REF $ftype {
21
                $REF self.$fname
22
            }
23
        )
24
    }
25
}
26

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

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

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

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

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

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

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

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

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

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

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