1use super::ExtType;
2use crate::{
3 decode::Error as DeError,
4 encode::{Error as SerError, SerializeIntoSlice},
5 Ext,
6};
7use byteorder::{BigEndian, ByteOrder};
8use core::convert::{TryFrom, TryInto};
9
10const EXT_TIMESTAMP: ExtType = ExtType(-1);
11
12pub(crate) const TYPE_NAME: &str = "$Timestamp";
13pub(crate) const FIELD_SECONDS_NAME: &str = "seconds";
14pub(crate) const FIELD_NANOSECONDS_NAME: &str = "nanoseconds";
15
16#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
17pub struct Timestamp {
18 seconds: i64,
19 nanoseconds: u32,
20}
21
22impl core::fmt::Debug for Timestamp {
23 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
24 f.debug_struct("Timestamp")
25 .field("seconds", &self.seconds)
26 .field("nanoseconds", &self.nanoseconds)
27 .finish()
28 }
29}
30
31impl Timestamp {
32 pub const fn new(seconds: i64, nanoseconds: u32) -> Result<Timestamp, DeError> {
33 let mut seconds = seconds;
34 let mut nanoseconds = nanoseconds;
35 while nanoseconds >= 1_000_000_000 {
36 seconds += 1;
38 nanoseconds -= 1_000_000_000;
39 }
40 Ok(Timestamp { seconds, nanoseconds })
41 }
42
43 pub const fn seconds(&self) -> i64 {
44 self.seconds
45 }
46 pub const fn nanoseconds(&self) -> u32 {
47 self.nanoseconds
48 }
49
50 #[allow(clippy::cast_sign_loss)]
51 #[allow(clippy::cast_possible_truncation)]
52 pub fn to_ext<'a>(&self, data: &'a mut [u8]) -> Result<Ext<'a>, SerError> {
53 if self.seconds >> 34 == 0 {
54 let x = (u64::from(self.nanoseconds) << 34) | self.seconds as u64;
55 if x & 0xffff_ffff_0000_0000_u64 == 0 {
56 if data.len() < 4 {
58 return Err(SerError::EndOfBuffer);
59 }
60 BigEndian::write_u32(data, x as u32);
61 Ok(Ext::new(-1, &data[0..4]))
62 } else {
63 if data.len() < 8 {
65 return Err(SerError::EndOfBuffer);
66 }
67 BigEndian::write_u64(data, x);
68 Ok(Ext::new(-1, &data[0..8]))
69 }
70 } else {
71 #[cfg(feature = "timestamp96")]
73 {
74 if data.len() < 12 {
75 return Err(SerError::EndOfBuffer);
76 }
77 BigEndian::write_u32(data, self.nanoseconds);
78 BigEndian::write_i64(&mut data[4..], self.seconds);
79 return Ok(Ext::new(-1, &data[0..12]));
80 }
81 #[cfg(not(feature = "timestamp96"))]
82 return Err(SerError::InvalidType);
83 }
84 }
85}
86
87impl SerializeIntoSlice for Timestamp {
88 fn write_into_slice(&self, buf: &mut [u8]) -> Result<usize, SerError> {
89 let mut tmp = [0; 12];
90 let ext = self.to_ext(&mut tmp)?;
91 crate::ext::serialize_ext(&ext, buf)
92 }
93}
94
95pub fn try_deserialize(buf: &[u8]) -> Result<Timestamp, DeError> {
96 crate::ext::try_deserialize_ext(buf)?.try_into()
97}
98
99impl<'a> TryFrom<Ext<'a>> for Timestamp {
100 type Error = DeError;
101
102 #[allow(clippy::cast_possible_truncation)]
103 fn try_from(ext: Ext<'a>) -> Result<Self, Self::Error> {
104 if ext.typ == EXT_TIMESTAMP {
105 match ext.data.len() {
106 4 => {
107 Timestamp::new(i64::from(BigEndian::read_u32(&ext.data)), 0)
113 }
114 #[allow(clippy::cast_possible_wrap)]
115 8 => {
116 let value = BigEndian::read_u64(&ext.data);
122 Timestamp::new((value & 0x0000_0003_ffff_ffff_u64) as i64, (value >> 34) as u32)
123 }
124 #[cfg(feature = "timestamp96")]
125 12 => {
126 let nanos = BigEndian::read_u32(&ext.data[0..4]);
135 let s = BigEndian::read_i64(&ext.data[4..12]);
136 Timestamp::new(s, nanos)
137 }
138 _ => Err(DeError::InvalidType),
139 }
140 } else {
141 Err(DeError::InvalidType)
142 }
143 }
144}
145
146#[cfg(feature = "serde")]
147impl ::serde::ser::Serialize for Timestamp {
148 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
149 where
150 S: serde::Serializer,
151 {
152 use serde::ser::SerializeStruct;
153 let mut s = serializer.serialize_struct(TYPE_NAME, 2)?;
154 s.serialize_field(FIELD_SECONDS_NAME, &self.seconds)?;
155 s.serialize_field(FIELD_NANOSECONDS_NAME, &self.nanoseconds)?;
156 s.end()
157 }
158}
159
160#[cfg(feature = "serde")]
161impl<'de> ::serde::de::Deserialize<'de> for Timestamp {
162 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
163 where
164 D: ::serde::de::Deserializer<'de>,
165 {
166 use crate::encode::Binary;
167 struct TimestampVisitor<'a>(core::marker::PhantomData<&'a ()>);
168
169 impl<'de: 'a, 'a> ::serde::de::Visitor<'de> for TimestampVisitor<'a> {
170 type Value = Timestamp;
171 fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
172 formatter.write_str("a MsgPack ext data")
173 }
174 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
175 where
176 A: serde::de::SeqAccess<'de>,
177 {
178 let typ: Option<ExtType> = seq.next_element()?;
181 let data: Option<Binary> = seq.next_element()?;
182 match (typ, data) {
183 (Some(typ), Some(data)) => Ok(Ext::new(typ.0, &data).try_into().map_err(::serde::de::Error::custom)?),
184 (Some(_), None) => Err(::serde::de::Error::custom("ext data not found")),
185 _ => Err(::serde::de::Error::custom("ext type field not found")),
186 }
187 }
188 fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
189 where
190 V: ::serde::de::MapAccess<'de>,
191 {
192 enum Field {
196 Seconds,
197 Nanoseconds,
198 Type,
199 Data,
200 }
201
202 impl<'de> ::serde::de::Deserialize<'de> for Field {
203 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
204 where
205 D: serde::Deserializer<'de>,
206 {
207 struct FieldVisitor;
208 impl<'de> ::serde::de::Visitor<'de> for FieldVisitor {
209 type Value = Field;
210 fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
211 formatter.write_str("`seconds`, `secs`, `s`, `nanoseconds`, `nanos`, `ns`, `type` or `data`")
212 }
213 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
214 where
215 E: serde::de::Error,
216 {
217 match v {
218 "seconds" | "secs" | "s" => Ok(Field::Seconds),
219 "nanoseconds" | "nanos" | "ns" => Ok(Field::Nanoseconds),
220 "type" => Ok(Field::Type),
221 "data" => Ok(Field::Data),
222 _ => Err(::serde::de::Error::unknown_field(
223 v,
224 &["seconds", "secs", "s", "nanoseconds", "nanos", "ns", "type", "data"],
225 )),
226 }
227 }
228 }
229
230 deserializer.deserialize_identifier(FieldVisitor)
231 }
232 }
233
234 let mut typ = None;
235 let mut data = None;
236 let mut seconds = None;
237 let mut nanoseconds = None;
238
239 loop {
240 match map.next_key::<Field>() {
241 Ok(Some(Field::Type)) => typ = Some(map.next_value::<ExtType>()?),
242 Ok(Some(Field::Data)) => data = Some(map.next_value::<Binary>()?),
243 Ok(Some(Field::Seconds)) => seconds = Some(map.next_value::<i64>()?),
244 Ok(Some(Field::Nanoseconds)) => nanoseconds = Some(map.next_value::<u32>()?),
245 Ok(None) => break, Err(_e) => {
247 map.next_value()?;
250 }
251 }
252 }
253
254 match (typ, data, seconds, nanoseconds) {
255 (Some(typ), Some(data), None, None) => Ok(Ext::new(typ.0, &data).try_into().map_err(::serde::de::Error::custom)?),
256 (None, None, Some(seconds), Some(nanoseconds)) => {
257 Ok(Timestamp::new(seconds, nanoseconds).map_err(::serde::de::Error::custom)?)
258 }
259 (None, None, Some(seconds), None) => Ok(Timestamp::new(seconds, 0).map_err(::serde::de::Error::custom)?),
260 (None, None, None, Some(nanoseconds)) => Ok(Timestamp::new(0, nanoseconds).map_err(::serde::de::Error::custom)?),
261 (Some(_), None, _, _) => Err(::serde::de::Error::custom("ext data not found")),
262 _ => Err(::serde::de::Error::custom("ext type field not found")),
263 }
264 }
266 }
267
268 static FIELDS: [&str; 2] = [FIELD_SECONDS_NAME, FIELD_NANOSECONDS_NAME];
269 deserializer.deserialize_struct(TYPE_NAME, &FIELDS, TimestampVisitor(core::marker::PhantomData))
270 }
271}