wasm_msgpack/ext/
timestamp.rs

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            // This will be at most 4 times, so it can't become a performance problem
37            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                // timestamp 32
57                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                // timestamp 64
64                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            // timestamp 96
72            #[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 32 stores the number of seconds that have elapsed since 1970-01-01 00:00:00 UTC
108                    // in an 32-bit unsigned integer:
109                    // +--------+--------+--------+--------+--------+--------+
110                    // |  0xd6  |   -1   |   seconds in 32-bit unsigned int  |
111                    // +--------+--------+--------+--------+--------+--------+
112                    Timestamp::new(i64::from(BigEndian::read_u32(&ext.data)), 0)
113                }
114                #[allow(clippy::cast_possible_wrap)]
115                8 => {
116                    // timestamp 64 stores the number of seconds and nanoseconds that have elapsed since 1970-01-01 00:00:00 UTC
117                    // in 32-bit unsigned integers:
118                    // +--------+--------+--------+--------+--------+------|-+--------+--------+--------+--------+
119                    // |  0xd7  |   -1   | nanosec. in 30-bit unsigned int |   seconds in 34-bit unsigned int    |
120                    // +--------+--------+--------+--------+--------+------^-+--------+--------+--------+--------+
121                    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                    // timestamp 96 stores the number of seconds and nanoseconds that have elapsed since 1970-01-01 00:00:00 UTC
127                    // in 64-bit signed integer and 32-bit unsigned integer:
128                    // +--------+--------+--------+--------+--------+--------+--------+
129                    // |  0xc7  |   12   |   -1   |nanoseconds in 32-bit unsigned int |
130                    // +--------+--------+--------+--------+--------+--------+--------+
131                    // +--------+--------+--------+--------+--------+--------+--------+--------+
132                    // |                   seconds in 64-bit signed int                        |
133                    // +--------+--------+--------+--------+--------+--------+--------+--------+
134                    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                // This will be called from the MsgPack deserializer
179                // if it detects an ext tag or an array tag
180                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                // This will probably be called from other deserializers
193                // or if the MsgPack deserializer sees a map tag
194
195                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, // no more fields
246                        Err(_e) => {
247                            // Error, could be an unknown field name
248                            // println!("{:?}", e);
249                            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                // }
265            }
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}