messagepack_core/
timestamp.rs1use crate::extension::{ExtensionRef, FixedExtension};
4
5pub(crate) const TIMESTAMP_EXTENSION_TYPE: i8 = -1;
6
7pub enum TryFromTimeStampError {
9 InvalidType,
11 InvalidDataLength,
13}
14
15#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
18pub struct Timestamp32 {
19 secs: u32,
20}
21
22impl Timestamp32 {
23 pub fn new(seconds: u32) -> Self {
25 Self { secs: seconds }
26 }
27
28 pub fn seconds(&self) -> u32 {
30 self.secs
31 }
32
33 pub(crate) fn to_buf(self) -> [u8; 4] {
34 self.secs.to_be_bytes()
35 }
36
37 pub(crate) fn from_buf(buf: [u8; 4]) -> Self {
38 Self {
39 secs: u32::from_be_bytes(buf),
40 }
41 }
42}
43
44impl TryFrom<ExtensionRef<'_>> for Timestamp32 {
45 type Error = TryFromTimeStampError;
46
47 fn try_from(value: ExtensionRef<'_>) -> Result<Self, Self::Error> {
48 if value.r#type != TIMESTAMP_EXTENSION_TYPE {
49 return Err(TryFromTimeStampError::InvalidType);
50 }
51
52 let data = value.data;
53 let mut buf = [0u8; 4];
54 if data.len() != buf.len() {
55 return Err(TryFromTimeStampError::InvalidDataLength);
56 }
57
58 buf.copy_from_slice(data);
59 Ok(Self::from_buf(buf))
60 }
61}
62
63impl TryFrom<FixedExtension<4>> for Timestamp32 {
64 type Error = TryFromTimeStampError;
65
66 fn try_from(value: FixedExtension<4>) -> Result<Self, Self::Error> {
67 value.as_ref().try_into()
68 }
69}
70
71impl From<Timestamp32> for FixedExtension<4> {
72 fn from(value: Timestamp32) -> Self {
73 FixedExtension::new_fixed(TIMESTAMP_EXTENSION_TYPE, value.to_buf())
74 }
75}
76
77#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
80pub struct Timestamp64 {
81 data: [u8; 8],
82}
83
84#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
86pub struct Timestamp64Error {
87 pub seconds: u64,
89 pub nanos: u32,
91}
92
93impl Timestamp64 {
94 pub fn new(seconds: u64, nanos: u32) -> Result<Self, Timestamp64Error> {
96 const SECONDS_MAX_LIMIT: u64 = 1 << 34;
97
98 if seconds >= SECONDS_MAX_LIMIT {
99 return Err(Timestamp64Error { seconds, nanos });
100 }
101
102 const NANOS_MAX_LIMIT: u32 = 1 << 30;
103 if nanos >= NANOS_MAX_LIMIT {
104 return Err(Timestamp64Error { seconds, nanos });
105 }
106
107 let mut buf = [0u8; 8];
108 buf[..].copy_from_slice(&seconds.to_be_bytes());
109
110 let nano = (nanos << 2).to_be_bytes();
111 buf[..3].copy_from_slice(&nano[..3]);
112 buf[3] |= nano[3];
113
114 Ok(Self::from_buf(buf))
115 }
116
117 pub fn nanos(&self) -> u32 {
119 let mut buf = [0u8; 4];
120 buf.copy_from_slice(&self.data[..4]);
121 let nanosec = u32::from_be_bytes(buf);
122 nanosec >> 2
123 }
124
125 pub fn seconds(&self) -> u64 {
127 const MASK: u64 = (1 << 34) - 1;
129 let mut buf = [0u8; 8];
130 buf.copy_from_slice(&self.data[..]);
131 let seconds = u64::from_be_bytes(buf);
132
133 seconds & MASK
134 }
135
136 pub(crate) fn to_buf(self) -> [u8; 8] {
137 self.data
138 }
139
140 pub(crate) fn from_buf(buf: [u8; 8]) -> Self {
141 Self { data: buf }
142 }
143}
144
145impl TryFrom<ExtensionRef<'_>> for Timestamp64 {
146 type Error = TryFromTimeStampError;
147
148 fn try_from(value: ExtensionRef<'_>) -> Result<Self, Self::Error> {
149 if value.r#type != TIMESTAMP_EXTENSION_TYPE {
150 return Err(TryFromTimeStampError::InvalidType);
151 }
152
153 let data = value.data;
154 let mut buf = [0u8; 8];
155 if data.len() != buf.len() {
156 return Err(TryFromTimeStampError::InvalidDataLength);
157 }
158
159 buf.copy_from_slice(data);
160 Ok(Self::from_buf(buf))
161 }
162}
163
164impl TryFrom<FixedExtension<8>> for Timestamp64 {
165 type Error = TryFromTimeStampError;
166
167 fn try_from(value: FixedExtension<8>) -> Result<Self, Self::Error> {
168 value.as_ref().try_into()
169 }
170}
171
172impl From<Timestamp64> for FixedExtension<8> {
173 fn from(value: Timestamp64) -> Self {
174 FixedExtension::new_fixed(TIMESTAMP_EXTENSION_TYPE, value.to_buf())
175 }
176}
177
178#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
181pub struct Timestamp96 {
182 nanos: u32,
183 secs: i64,
184}
185
186impl Timestamp96 {
187 pub fn new(seconds: i64, nanoseconds: u32) -> Self {
189 Self {
190 nanos: nanoseconds,
191 secs: seconds,
192 }
193 }
194
195 pub fn nanos(&self) -> u32 {
197 self.nanos
198 }
199
200 pub fn seconds(&self) -> i64 {
202 self.secs
203 }
204
205 pub(crate) fn to_buf(self) -> [u8; 12] {
206 let mut buf = [0u8; 12];
207 buf[..4].copy_from_slice(&self.nanos.to_be_bytes());
208 buf[4..].copy_from_slice(&self.secs.to_be_bytes());
209
210 buf
211 }
212
213 pub(crate) fn from_buf(buf: [u8; 12]) -> Self {
214 let mut nano = [0u8; 4];
215 nano.copy_from_slice(&buf[..4]);
216
217 let mut second = [0u8; 8];
218 second.copy_from_slice(&buf[4..]);
219
220 Self {
221 nanos: u32::from_be_bytes(nano),
222 secs: i64::from_be_bytes(second),
223 }
224 }
225}
226
227impl TryFrom<ExtensionRef<'_>> for Timestamp96 {
228 type Error = TryFromTimeStampError;
229
230 fn try_from(value: ExtensionRef<'_>) -> Result<Self, Self::Error> {
231 if value.r#type != TIMESTAMP_EXTENSION_TYPE {
232 return Err(TryFromTimeStampError::InvalidType);
233 }
234
235 let data = value.data;
236 let mut buf = [0u8; 12];
237 if data.len() != buf.len() {
238 return Err(TryFromTimeStampError::InvalidDataLength);
239 }
240
241 buf.copy_from_slice(data);
242 Ok(Self::from_buf(buf))
243 }
244}
245
246impl TryFrom<FixedExtension<12>> for Timestamp96 {
247 type Error = TryFromTimeStampError;
248
249 fn try_from(value: FixedExtension<12>) -> Result<Self, Self::Error> {
250 value.as_ref().try_into()
251 }
252}
253
254impl From<Timestamp96> for FixedExtension<12> {
255 fn from(value: Timestamp96) -> Self {
256 FixedExtension::new_fixed(TIMESTAMP_EXTENSION_TYPE, value.to_buf())
257 }
258}