1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/*!
The [`Clock`] type.

A clock is a service that returns a [`Timestamp`] representing the current point in time. Clock readings are not guaranteed to be monotonic. They may move forwards or backwards arbitrarily, but for diagnostics to be useful, a clock should strive for accuracy.
*/

use crate::{empty::Empty, timestamp::Timestamp};

/**
A service to measure the current time.
*/
pub trait Clock {
    /**
    Read the current time.

    This method may return `None` if the clock couldn't be read for any reason. That may involve the clock not actually supporting reading now, time moving backwards, or any other reason that could result in an inaccurate reading.
    */
    fn now(&self) -> Option<Timestamp>;
}

impl<'a, T: Clock + ?Sized> Clock for &'a T {
    fn now(&self) -> Option<Timestamp> {
        (**self).now()
    }
}

impl<'a, T: Clock> Clock for Option<T> {
    fn now(&self) -> Option<Timestamp> {
        if let Some(time) = self {
            time.now()
        } else {
            Empty.now()
        }
    }
}

#[cfg(feature = "alloc")]
impl<'a, T: Clock + ?Sized + 'a> Clock for alloc::boxed::Box<T> {
    fn now(&self) -> Option<Timestamp> {
        (**self).now()
    }
}

#[cfg(feature = "alloc")]
impl<'a, T: Clock + ?Sized + 'a> Clock for alloc::sync::Arc<T> {
    fn now(&self) -> Option<Timestamp> {
        (**self).now()
    }
}

impl Clock for Empty {
    fn now(&self) -> Option<Timestamp> {
        None
    }
}

mod internal {
    use super::Timestamp;

    pub trait DispatchClock {
        fn dispatch_now(&self) -> Option<Timestamp>;
    }

    pub trait SealedClock {
        fn erase_clock(&self) -> crate::internal::Erased<&dyn DispatchClock>;
    }
}

/**
An object-safe [`Clock`].

A `dyn ErasedClock` can be treated as `impl Clock`.
*/
pub trait ErasedClock: internal::SealedClock {}

impl<T: Clock> ErasedClock for T {}

impl<T: Clock> internal::SealedClock for T {
    fn erase_clock(&self) -> crate::internal::Erased<&dyn internal::DispatchClock> {
        crate::internal::Erased(self)
    }
}

impl<T: Clock> internal::DispatchClock for T {
    fn dispatch_now(&self) -> Option<Timestamp> {
        self.now()
    }
}

impl<'a> Clock for dyn ErasedClock + 'a {
    fn now(&self) -> Option<Timestamp> {
        self.erase_clock().0.dispatch_now()
    }
}

impl<'a> Clock for dyn ErasedClock + Send + Sync + 'a {
    fn now(&self) -> Option<Timestamp> {
        (self as &(dyn ErasedClock + 'a)).now()
    }
}

#[cfg(test)]
mod tests {
    use core::{cell::Cell, time::Duration};

    use super::*;

    #[test]
    fn erased_clock() {
        struct SomeClock {
            now: Cell<usize>,
        }

        impl Clock for SomeClock {
            fn now(&self) -> Option<Timestamp> {
                self.now.set(self.now.get() + 1);

                Some(Timestamp::from_unix(Duration::from_secs(97)).unwrap())
            }
        }

        let clock = SomeClock { now: Cell::new(0) };

        let _ = (&clock as &dyn ErasedClock).now();

        assert_eq!(1, clock.now.get());
    }
}