bonsaidb_core/keyvalue/
timestamp.rs1use 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#[derive(Serialize, Deserialize, Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Default)]
12pub struct Timestamp {
13 pub seconds: u64,
15 pub nanos: u32,
17}
18
19impl Timestamp {
20 pub const MAX: Self = Self {
22 seconds: u64::MAX,
23 nanos: 999_999_999,
24 };
25 pub const MIN: Self = Self {
27 seconds: 0,
28 nanos: 0,
29 };
30
31 #[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}