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: &'static str = "$Timestamp";
13pub(crate) const FIELD_SECONDS_NAME: &'static str = "seconds";
14pub(crate) const FIELD_NANOSECONDS_NAME: &'static str = "nanoseconds";
15
16#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
17#[cfg_attr(any(test, feature = "derive-debug"), derive(core::fmt::Debug))]
18pub struct Timestamp {
19 seconds: i64,
20 nanoseconds: u32,
21}
22
23impl Timestamp {
24 pub const fn new(seconds: i64, nanoseconds: u32) -> Result<Timestamp, DeError> {
25 let mut seconds = seconds;
26 let mut nanoseconds = nanoseconds;
27 while nanoseconds >= 1_000_000_000 {
28 seconds += 1;
30 nanoseconds -= 1_000_000_000;
31 }
32 Ok(Timestamp { seconds, nanoseconds })
33 }
34
35 pub const fn seconds(&self) -> i64 { self.seconds }
36 pub const fn nanoseconds(&self) -> u32 { self.nanoseconds }
37
38 #[allow(clippy::cast_sign_loss)]
39 #[allow(clippy::cast_possible_truncation)]
40 pub fn to_ext<'a>(&self, data: &'a mut [u8]) -> Result<Ext<'a>, SerError> {
41 if self.seconds >> 34 == 0 {
42 let x = (u64::from(self.nanoseconds) << 34) | self.seconds as u64;
43 if x & 0xffff_ffff_0000_0000_u64 == 0 {
44 if data.len() < 4 {
46 return Err(SerError::EndOfBuffer);
47 }
48 BigEndian::write_u32(data, x as u32);
49 Ok(Ext::new(-1, &data[0..4]))
50 } else {
51 if data.len() < 8 {
53 return Err(SerError::EndOfBuffer);
54 }
55 BigEndian::write_u64(data, x);
56 Ok(Ext::new(-1, &data[0..8]))
57 }
58 } else {
59 #[cfg(feature = "timestamp96")]
61 {
62 if data.len() < 12 {
63 return Err(SerError::EndOfBuffer);
64 }
65 BigEndian::write_u32(data, self.nanoseconds);
66 BigEndian::write_i64(&mut data[4..], self.seconds);
67 return Ok(Ext::new(-1, &data[0..12]));
68 }
69 #[cfg(not(feature = "timestamp96"))]
70 return Err(SerError::InvalidType);
71 }
72 }
73}
74
75impl SerializeIntoSlice for Timestamp {
76 fn write_into_slice(&self, buf: &mut [u8]) -> Result<usize, SerError> {
77 let mut tmp = [0; 12];
78 let ext = self.to_ext(&mut tmp)?;
79 crate::ext::serialize_ext(&ext, buf)
80 }
81}
82
83pub fn try_deserialize(buf: &[u8]) -> Result<Timestamp, DeError> { crate::ext::try_deserialize_ext(&buf)?.try_into() }
84
85impl<'a> TryFrom<Ext<'a>> for Timestamp {
86 type Error = DeError;
87
88 #[allow(clippy::cast_possible_truncation)]
89 fn try_from(ext: Ext<'a>) -> Result<Self, Self::Error> {
90 if ext.typ == EXT_TIMESTAMP {
91 match ext.data.len() {
92 4 => {
93 Timestamp::new(i64::from(BigEndian::read_u32(&ext.data)), 0)
99 }
100 #[allow(clippy::cast_possible_wrap)]
101 8 => {
102 let value = BigEndian::read_u64(&ext.data);
108 Timestamp::new((value & 0x0000_0003_ffff_ffff_u64) as i64, (value >> 34) as u32)
109 }
110 #[cfg(feature = "timestamp96")]
111 12 => {
112 let nanos = BigEndian::read_u32(&ext.data[0..4]);
121 let s = BigEndian::read_i64(&ext.data[4..12]);
122 Timestamp::new(s, nanos)
123 }
124 _ => Err(DeError::InvalidType),
125 }
126 } else {
127 Err(DeError::InvalidType)
128 }
129 }
130}
131
132#[cfg(feature = "serde")]
133impl ::serde::ser::Serialize for Timestamp {
134 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
135 where S: serde::Serializer {
136 use serde::ser::SerializeStruct;
137 let mut s = serializer.serialize_struct(TYPE_NAME, 2)?;
138 s.serialize_field(FIELD_SECONDS_NAME, &self.seconds)?;
139 s.serialize_field(FIELD_NANOSECONDS_NAME, &self.nanoseconds)?;
140 s.end()
141 }
142}
143
144#[cfg(feature = "serde")]
145impl<'de> ::serde::de::Deserialize<'de> for Timestamp {
146 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
147 where D: ::serde::de::Deserializer<'de> {
148 use crate::encode::Binary;
149 struct TimestampVisitor<'a>(core::marker::PhantomData<&'a ()>);
150
151 impl<'de: 'a, 'a> ::serde::de::Visitor<'de> for TimestampVisitor<'a> {
152 type Value = Timestamp;
153 fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { formatter.write_str("a MsgPack ext data") }
154 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
155 where A: serde::de::SeqAccess<'de> {
156 let typ: Option<ExtType> = seq.next_element()?;
159 let data: Option<Binary> = seq.next_element()?;
160 match (typ, data) {
161 (Some(typ), Some(data)) => Ok(Ext::new(typ.0, &data).try_into().map_err(::serde::de::Error::custom)?),
162 (Some(_), None) => Err(::serde::de::Error::custom("ext data not found")),
163 _ => Err(::serde::de::Error::custom("ext type field not found")),
164 }
165 }
166 fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
167 where V: ::serde::de::MapAccess<'de> {
168 enum Field {
172 Seconds,
173 Nanoseconds,
174 Type,
175 Data,
176 }
177
178 impl<'de> ::serde::de::Deserialize<'de> for Field {
179 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
180 where D: serde::Deserializer<'de> {
181 struct FieldVisitor;
182 impl<'de> ::serde::de::Visitor<'de> for FieldVisitor {
183 type Value = Field;
184 fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
185 formatter.write_str("`seconds`, `secs`, `s`, `nanoseconds`, `nanos`, `ns`, `type` or `data`")
186 }
187 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
188 where E: serde::de::Error {
189 match v {
190 "seconds" | "secs" | "s" => Ok(Field::Seconds),
191 "nanoseconds" | "nanos" | "ns" => Ok(Field::Nanoseconds),
192 "type" => Ok(Field::Type),
193 "data" => Ok(Field::Data),
194 _ => Err(::serde::de::Error::unknown_field(
195 v,
196 &["seconds", "secs", "s", "nanoseconds", "nanos", "ns", "type", "data"],
197 )),
198 }
199 }
200 }
201
202 deserializer.deserialize_identifier(FieldVisitor)
203 }
204 }
205
206 let mut typ = None;
207 let mut data = None;
208 let mut seconds = None;
209 let mut nanoseconds = None;
210
211 loop {
212 match map.next_key::<Field>() {
213 Ok(Some(Field::Type)) => typ = Some(map.next_value::<ExtType>()?),
214 Ok(Some(Field::Data)) => data = Some(map.next_value::<Binary>()?),
215 Ok(Some(Field::Seconds)) => seconds = Some(map.next_value::<i64>()?),
216 Ok(Some(Field::Nanoseconds)) => nanoseconds = Some(map.next_value::<u32>()?),
217 Ok(None) => break, Err(_e) => {
219 map.next_value()?;
222 }
223 }
224 }
225
226 match (typ, data, seconds, nanoseconds) {
227 (Some(typ), Some(data), None, None) => Ok(Ext::new(typ.0, &data).try_into().map_err(::serde::de::Error::custom)?),
228 (None, None, Some(seconds), Some(nanoseconds)) => {
229 Ok(Timestamp::new(seconds, nanoseconds).map_err(::serde::de::Error::custom)?)
230 }
231 (None, None, Some(seconds), None) => Ok(Timestamp::new(seconds, 0).map_err(::serde::de::Error::custom)?),
232 (None, None, None, Some(nanoseconds)) => Ok(Timestamp::new(0, nanoseconds).map_err(::serde::de::Error::custom)?),
233 (Some(_), None, _, _) => Err(::serde::de::Error::custom("ext data not found")),
234 _ => Err(::serde::de::Error::custom("ext type field not found")),
235 }
236 }
238 }
239
240 static FIELDS: [&str; 2] = [FIELD_SECONDS_NAME, FIELD_NANOSECONDS_NAME];
241 deserializer.deserialize_struct(TYPE_NAME, &FIELDS, TimestampVisitor(core::marker::PhantomData))
242 }
243}