1
use std::borrow::Cow;
2
use std::time::{Duration, SystemTime, UNIX_EPOCH};
3

            
4
use serde::{Deserialize, Serialize};
5

            
6
use crate::key::{
7
    ByteSource, CompositeKind, IncorrectByteLength, Key, KeyEncoding, KeyKind, KeyVisitor,
8
};
9

            
10
/// A timestamp relative to [`UNIX_EPOCH`].
11
1455978
#[derive(Serialize, Deserialize, Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Default)]
12
pub struct Timestamp {
13
    /// The number of whole seconds since [`UNIX_EPOCH`].
14
    pub seconds: u64,
15
    /// The number of nanoseconds in the timestamp.
16
    pub nanos: u32,
17
}
18

            
19
impl Timestamp {
20
    /// The maximum valid value of Timestamp.
21
    pub const MAX: Self = Self {
22
        seconds: u64::MAX,
23
        nanos: 999_999_999,
24
    };
25
    /// The minimum representable Timestamp. This is equivalent to [`UNIX_EPOCH`].
26
    pub const MIN: Self = Self {
27
        seconds: 0,
28
        nanos: 0,
29
    };
30

            
31
    /// Returns the current timestamp according to the OS. Uses [`SystemTime::now()`].
32
    #[must_use]
33
7511241
    pub fn now() -> Self {
34
7511241
        Self::from(SystemTime::now())
35
7511241
    }
36
}
37

            
38
impl From<SystemTime> for Timestamp {
39
7513401
    fn from(time: SystemTime) -> Self {
40
7513401
        let duration_since_epoch = time
41
7513401
            .duration_since(UNIX_EPOCH)
42
7513401
            .expect("unrealistic system time");
43
7513401
        Self {
44
7513401
            seconds: duration_since_epoch.as_secs(),
45
7513401
            nanos: duration_since_epoch.subsec_nanos(),
46
7513401
        }
47
7513401
    }
48
}
49

            
50
impl From<Timestamp> for Duration {
51
876880
    fn from(t: Timestamp) -> Self {
52
876880
        Self::new(t.seconds, t.nanos)
53
876880
    }
54
}
55

            
56
impl std::ops::Sub for Timestamp {
57
    type Output = Option<Duration>;
58

            
59
438440
    fn sub(self, rhs: Self) -> Self::Output {
60
438440
        Duration::from(self).checked_sub(Duration::from(rhs))
61
438440
    }
62
}
63

            
64
impl std::ops::Add<Duration> for Timestamp {
65
    type Output = Self;
66

            
67
170000
    fn add(self, rhs: Duration) -> Self::Output {
68
170000
        let mut nanos = self.nanos + rhs.subsec_nanos();
69
170000
        let mut seconds = self.seconds.saturating_add(rhs.as_secs());
70
170080
        while nanos > 1_000_000_000 {
71
80
            nanos -= 1_000_000_000;
72
80
            seconds = seconds.saturating_add(1);
73
80
        }
74
170000
        Self { seconds, nanos }
75
170000
    }
76
}
77

            
78
impl<'k> Key<'k> for Timestamp {
79
    const CAN_OWN_BYTES: bool = false;
80

            
81
1
    fn from_ord_bytes<'e>(bytes: ByteSource<'k, 'e>) -> Result<Self, Self::Error> {
82
1
        if bytes.as_ref().len() != 12 {
83
            return Err(IncorrectByteLength);
84
1
        }
85
1

            
86
1
        Ok(Self {
87
1
            seconds: u64::from_ord_bytes(ByteSource::Borrowed(&bytes.as_ref()[0..8]))?,
88
1
            nanos: u32::from_ord_bytes(ByteSource::Borrowed(&bytes.as_ref()[8..12]))?,
89
        })
90
1
    }
91
}
92

            
93
impl KeyEncoding<Self> for Timestamp {
94
    type Error = IncorrectByteLength;
95

            
96
    const LENGTH: Option<usize> = Some(12);
97

            
98
    fn describe<Visitor>(visitor: &mut Visitor)
99
    where
100
        Visitor: KeyVisitor,
101
    {
102
        visitor.visit_composite(
103
            CompositeKind::Struct(Cow::Borrowed("std::time::Timestamp")),
104
            2,
105
        );
106
        visitor.visit_type(KeyKind::U64);
107
        visitor.visit_type(KeyKind::U32);
108
    }
109

            
110
1
    fn as_ord_bytes(&self) -> Result<std::borrow::Cow<'_, [u8]>, Self::Error> {
111
1
        let seconds_bytes: &[u8] = &self.seconds.to_be_bytes();
112
1
        let nanos_bytes = &self.nanos.to_be_bytes();
113
1
        Ok(Cow::Owned([seconds_bytes, nanos_bytes].concat()))
114
1
    }
115
}
116

            
117
1
#[test]
118
1
fn key_test() {
119
1
    let original = Timestamp::now();
120
1
    assert_eq!(
121
1
        Timestamp::from_ord_bytes(ByteSource::Borrowed(&original.as_ord_bytes().unwrap())).unwrap(),
122
1
        original
123
1
    );
124
1
}