bonsaidb_core/keyvalue/
timestamp.rs

1use std::borrow::Cow;
2use std::time::{Duration, SystemTime, UNIX_EPOCH};
3
4use serde::{Deserialize, Serialize};
5
6use crate::key::{
7    ByteSource, CompositeKind, IncorrectByteLength, Key, KeyEncoding, KeyKind, KeyVisitor,
8};
9
10/// A timestamp relative to [`UNIX_EPOCH`].
11#[derive(Serialize, Deserialize, Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Default)]
12pub 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
19impl 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    pub fn now() -> Self {
34        Self::from(SystemTime::now())
35    }
36}
37
38impl From<SystemTime> for Timestamp {
39    fn from(time: SystemTime) -> Self {
40        let duration_since_epoch = time
41            .duration_since(UNIX_EPOCH)
42            .expect("unrealistic system time");
43        Self {
44            seconds: duration_since_epoch.as_secs(),
45            nanos: duration_since_epoch.subsec_nanos(),
46        }
47    }
48}
49
50impl From<Timestamp> for Duration {
51    fn from(t: Timestamp) -> Self {
52        Self::new(t.seconds, t.nanos)
53    }
54}
55
56impl std::ops::Sub for Timestamp {
57    type Output = Option<Duration>;
58
59    fn sub(self, rhs: Self) -> Self::Output {
60        Duration::from(self).checked_sub(Duration::from(rhs))
61    }
62}
63
64impl std::ops::Add<Duration> for Timestamp {
65    type Output = Self;
66
67    fn add(self, rhs: Duration) -> Self::Output {
68        let mut nanos = self.nanos + rhs.subsec_nanos();
69        let mut seconds = self.seconds.saturating_add(rhs.as_secs());
70        while nanos > 1_000_000_000 {
71            nanos -= 1_000_000_000;
72            seconds = seconds.saturating_add(1);
73        }
74        Self { seconds, nanos }
75    }
76}
77
78impl<'k> Key<'k> for Timestamp {
79    const CAN_OWN_BYTES: bool = false;
80
81    fn from_ord_bytes<'e>(bytes: ByteSource<'k, 'e>) -> Result<Self, Self::Error> {
82        if bytes.as_ref().len() != 12 {
83            return Err(IncorrectByteLength);
84        }
85
86        Ok(Self {
87            seconds: u64::from_ord_bytes(ByteSource::Borrowed(&bytes.as_ref()[0..8]))?,
88            nanos: u32::from_ord_bytes(ByteSource::Borrowed(&bytes.as_ref()[8..12]))?,
89        })
90    }
91}
92
93impl 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    fn as_ord_bytes(&self) -> Result<std::borrow::Cow<'_, [u8]>, Self::Error> {
111        let seconds_bytes: &[u8] = &self.seconds.to_be_bytes();
112        let nanos_bytes = &self.nanos.to_be_bytes();
113        Ok(Cow::Owned([seconds_bytes, nanos_bytes].concat()))
114    }
115}
116
117#[test]
118fn key_test() {
119    let original = Timestamp::now();
120    assert_eq!(
121        Timestamp::from_ord_bytes(ByteSource::Borrowed(&original.as_ord_bytes().unwrap())).unwrap(),
122        original
123    );
124}