twine_codec/dataset/
timestamp.rs1use twine_rs_macros::Tlv;
9
10#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
11pub struct Authoritative(pub bool);
12
13impl Authoritative {
14 pub(crate) fn is_authoritative(&self) -> bool {
15 self.0
16 }
17}
18
19#[derive(Copy, Clone, Default, Eq, PartialEq, Tlv)]
20#[tlv(variants = [("Active", tlv_type = 0x0e), ("Pending", tlv_type = 0x33)], tlv_length = 8, derive_inner)]
21pub struct Timestamp(u64);
22
23impl Timestamp {
24 #[cfg(any(test, feature = "std"))]
25 pub fn now(auth: Authoritative) -> Self {
26 use std::time::{SystemTime, UNIX_EPOCH};
27
28 let now = SystemTime::now();
29 let seconds = now.duration_since(UNIX_EPOCH).unwrap().as_secs();
30
31 Self::from((seconds, 0, auth))
32 }
33
34 pub fn seconds(&self) -> u64 {
35 self.0 >> 16
36 }
37
38 pub fn ticks(&self) -> u16 {
39 ((self.0 >> 1) & 0x7fff) as u16
40 }
41
42 pub fn is_authoritative(&self) -> bool {
43 (self.0 & 0x1) != 0
44 }
45}
46impl core::fmt::Display for Timestamp {
47 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
48 write!(f, "{}", self.seconds(),)
49 }
50}
51
52impl core::fmt::Debug for Timestamp {
53 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
54 write!(
55 f,
56 "Timestamp {{ seconds: {}, ticks: {}, authoritative: {} }}",
57 self.seconds(),
58 self.ticks(),
59 self.is_authoritative()
60 )
61 }
62}
63
64impl From<(u64, u16, Authoritative)> for Timestamp {
65 fn from(parts: (u64, u16, Authoritative)) -> Self {
66 let (seconds, ticks, auth) = parts;
67 let seconds = seconds << 16;
68 let ticks = (ticks as u64) & 0xfffe;
69 let auth = if auth.is_authoritative() { 1u64 } else { 0u64 };
70
71 Self(seconds | ticks | auth)
72 }
73}
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78
79 use twine_tlv::TryEncodeTlv;
80
81 #[test]
82 fn success_from_parts() {
83 let timestamp = Timestamp::from((0x1234_5678, 0x9abc, Authoritative(true)));
84 assert_eq!(timestamp.0, 0x1234_5678_9abd_u64);
85
86 assert_eq!(timestamp.seconds(), 0x1234_5678);
87 assert_eq!(timestamp.ticks(), 0x9abc >> 1);
88 assert!(timestamp.is_authoritative());
89 }
90
91 #[test]
92 fn success_active_timestamp_to_tlv() {
93 let timestamp = Timestamp::from((0x1234_5678, 0x9abc, Authoritative(true)));
94 let timestamp = ActiveTimestamp::from(timestamp);
95
96 let mut buffer = [0u8; 2 + 8];
97 let written = timestamp.try_encode_tlv(&mut buffer).unwrap();
98
99 assert_eq!(written, 10);
100 assert_eq!(buffer[0], 0x0e); assert_eq!(buffer[1], 0x08); assert_eq!(&buffer[2..], &0x1234_5678_9abd_u64.to_be_bytes()[..]);
103 }
104
105 #[test]
106 fn success_pending_timestamp_to_tlv() {
107 let timestamp = Timestamp::from((0x1234_5678, 0x9abc, Authoritative(true)));
108 let timestamp = PendingTimestamp::from(timestamp);
109
110 let mut buffer = [0u8; 2 + 8];
111 let written = timestamp.try_encode_tlv(&mut buffer).unwrap();
112
113 assert_eq!(written, 10);
114 assert_eq!(buffer[0], 0x33); assert_eq!(buffer[1], 0x08); assert_eq!(&buffer[2..], &0x1234_5678_9abd_u64.to_be_bytes()[..]);
117 }
118}