messagepack_core/decode/
timestamp.rs

1use super::{DecodeBorrowed, Error, NbyteReader};
2use crate::{
3    Format,
4    io::IoRead,
5    timestamp::{TIMESTAMP_EXTENSION_TYPE, Timestamp32, Timestamp64, Timestamp96},
6};
7
8impl<'de> DecodeBorrowed<'de> for Timestamp32 {
9    type Value = Timestamp32;
10
11    fn decode_borrowed_with_format<R>(
12        format: crate::Format,
13        reader: &mut R,
14    ) -> core::result::Result<Self::Value, Error<R::Error>>
15    where
16        R: IoRead<'de>,
17    {
18        match format {
19            Format::FixExt4 => {}
20            _ => return Err(Error::UnexpectedFormat),
21        };
22        let ext_type: [u8; 1] = reader
23            .read_slice(1)
24            .map_err(Error::Io)?
25            .as_bytes()
26            .try_into()
27            .map_err(|_| Error::UnexpectedEof)?;
28        let ext_type = ext_type[0] as i8;
29        if ext_type != TIMESTAMP_EXTENSION_TYPE {
30            return Err(Error::InvalidData);
31        }
32
33        let data = reader.read_slice(4).map_err(Error::Io)?;
34        let buf: [u8; 4] = data
35            .as_bytes()
36            .try_into()
37            .map_err(|_| Error::UnexpectedEof)?;
38        let timestamp = Self::from_buf(buf);
39
40        Ok(timestamp)
41    }
42}
43
44impl<'de> DecodeBorrowed<'de> for Timestamp64 {
45    type Value = Timestamp64;
46
47    fn decode_borrowed_with_format<R>(
48        format: crate::Format,
49        reader: &mut R,
50    ) -> core::result::Result<Self::Value, Error<R::Error>>
51    where
52        R: IoRead<'de>,
53    {
54        match format {
55            Format::FixExt8 => {}
56            _ => return Err(Error::UnexpectedFormat),
57        };
58
59        let ext_type: [u8; 1] = reader
60            .read_slice(1)
61            .map_err(Error::Io)?
62            .as_bytes()
63            .try_into()
64            .map_err(|_| Error::UnexpectedEof)?;
65        let ext_type = ext_type[0] as i8;
66        if ext_type != TIMESTAMP_EXTENSION_TYPE {
67            return Err(Error::InvalidData);
68        }
69
70        let data = reader.read_slice(8).map_err(Error::Io)?;
71        let buf: [u8; 8] = data
72            .as_bytes()
73            .try_into()
74            .map_err(|_| Error::UnexpectedEof)?;
75        let timestamp = Self::from_buf(buf);
76        Ok(timestamp)
77    }
78}
79
80impl<'de> DecodeBorrowed<'de> for Timestamp96 {
81    type Value = Timestamp96;
82
83    fn decode_borrowed_with_format<R>(
84        format: crate::Format,
85        reader: &mut R,
86    ) -> core::result::Result<Self::Value, Error<R::Error>>
87    where
88        R: IoRead<'de>,
89    {
90        let len = match format {
91            Format::Ext8 => NbyteReader::<1>::read(reader)?,
92            _ => return Err(Error::UnexpectedFormat),
93        };
94        const TIMESTAMP96_DATA_LENGTH: usize = 12;
95        if len != TIMESTAMP96_DATA_LENGTH {
96            return Err(Error::InvalidData);
97        }
98
99        let ext_type: [u8; 1] = reader
100            .read_slice(1)
101            .map_err(Error::Io)?
102            .as_bytes()
103            .try_into()
104            .map_err(|_| Error::UnexpectedEof)?;
105        let ext_type = ext_type[0] as i8;
106        if ext_type != TIMESTAMP_EXTENSION_TYPE {
107            return Err(Error::InvalidData);
108        }
109
110        let data = reader.read_slice(12).map_err(Error::Io)?;
111        let buf: [u8; 12] = data
112            .as_bytes()
113            .try_into()
114            .map_err(|_| Error::UnexpectedEof)?;
115        let timestamp = Self::from_buf(buf);
116        Ok(timestamp)
117    }
118}
119
120#[cfg(test)]
121mod tests {
122    use super::*;
123    use crate::decode::Decode;
124    const TIMESTAMP_EXT_TYPE: u8 = 255; // -1
125
126    #[test]
127    fn decode_success_timestamp32() {
128        let secs: u32 = 1234567890;
129        let mut buf = vec![0xd6, TIMESTAMP_EXT_TYPE];
130        buf.extend_from_slice(&secs.to_be_bytes());
131
132        let mut r = crate::io::SliceReader::new(&buf);
133        let ts = Timestamp32::decode(&mut r).unwrap();
134        assert_eq!(ts.seconds(), secs);
135        assert!(r.rest().is_empty());
136    }
137
138    #[test]
139    fn decode_failed_timestamp32_invalid_ext_type() {
140        let secs: u32 = 1;
141        let mut buf = vec![0xd6, 0]; // ext type != -1
142        buf.extend_from_slice(&secs.to_be_bytes());
143
144        let mut r = crate::io::SliceReader::new(&buf);
145        let err = Timestamp32::decode(&mut r).unwrap_err();
146        assert_eq!(err, Error::InvalidData);
147    }
148
149    #[test]
150    fn decode_failed_timestamp32_eof_data() {
151        let secs: u32 = 123;
152        let mut buf = vec![0xd6, TIMESTAMP_EXT_TYPE];
153        buf.extend_from_slice(&secs.to_be_bytes()[..3]); // 1 byte short
154
155        let mut r = crate::io::SliceReader::new(&buf);
156        let err = Timestamp32::decode(&mut r).unwrap_err();
157        assert!(matches!(err, Error::Io(_)));
158    }
159
160    #[test]
161    fn decode_success_timestamp64() {
162        let secs: u64 = 1234567890;
163        let nanos: u32 = 789;
164
165        let data = ((nanos as u64) << 34) | secs;
166        let mut buf = vec![0xd7, TIMESTAMP_EXT_TYPE];
167        buf.extend_from_slice(&data.to_be_bytes());
168
169        let mut r = crate::io::SliceReader::new(&buf);
170        let ts = Timestamp64::decode(&mut r).unwrap();
171        assert_eq!(ts.seconds(), secs);
172        assert_eq!(ts.nanos(), nanos);
173        assert!(r.rest().is_empty());
174    }
175
176    #[test]
177    fn decode_failed_timestamp64_unexpected_format() {
178        let mut buf = vec![0xd6, TIMESTAMP_EXT_TYPE]; // FixExt4, not FixExt8
179        buf.extend_from_slice(&0u64.to_be_bytes());
180
181        let mut r = crate::io::SliceReader::new(&buf);
182        let err = Timestamp64::decode(&mut r).unwrap_err();
183        assert_eq!(err, Error::UnexpectedFormat);
184    }
185
186    #[test]
187    fn decode_failed_timestamp64_invalid_ext_type() {
188        let mut buf = vec![0xd7, 0]; // ext type != -1
189        buf.extend_from_slice(&0u64.to_be_bytes());
190
191        let mut r = crate::io::SliceReader::new(&buf);
192        let err = Timestamp64::decode(&mut r).unwrap_err();
193        assert_eq!(err, Error::InvalidData);
194    }
195
196    #[test]
197    fn decode_failed_timestamp64_eof_data() {
198        let mut buf = vec![0xd7, TIMESTAMP_EXT_TYPE];
199        buf.extend_from_slice(&[0u8; 7]); // 1 byte short
200
201        let mut r = crate::io::SliceReader::new(&buf);
202        let err = Timestamp64::decode(&mut r).unwrap_err();
203        assert!(matches!(err, Error::Io(_)));
204    }
205
206    #[test]
207    fn decode_success_timestamp96_positive() {
208        let secs: i64 = 123456;
209        let nanos: u32 = 789;
210
211        let mut buf = vec![0xc7, 12, TIMESTAMP_EXT_TYPE];
212        buf.extend_from_slice(&nanos.to_be_bytes());
213        buf.extend_from_slice(&secs.to_be_bytes());
214
215        let mut r = crate::io::SliceReader::new(&buf);
216        let ts = Timestamp96::decode(&mut r).unwrap();
217        assert_eq!(ts.seconds(), secs);
218        assert_eq!(ts.nanos(), nanos);
219        assert!(r.rest().is_empty());
220    }
221
222    #[test]
223    fn decode_success_timestamp96_negative() {
224        let secs: i64 = -123;
225        let nanos: u32 = 42;
226
227        let mut buf = vec![0xc7, 12, TIMESTAMP_EXT_TYPE];
228        buf.extend_from_slice(&nanos.to_be_bytes());
229        buf.extend_from_slice(&secs.to_be_bytes());
230
231        let mut r = crate::io::SliceReader::new(&buf);
232        let ts = Timestamp96::decode(&mut r).unwrap();
233        assert_eq!(ts.seconds(), secs);
234        assert_eq!(ts.nanos(), nanos);
235        assert!(r.rest().is_empty());
236    }
237
238    #[test]
239    fn decode_failed_timestamp96_unexpected_format() {
240        // FixExt8 header instead of Ext8
241        let mut buf = vec![0xd7, TIMESTAMP_EXT_TYPE];
242        buf.extend_from_slice(&[0u8; 8]);
243
244        let mut r = crate::io::SliceReader::new(&buf);
245        let err = Timestamp96::decode(&mut r).unwrap_err();
246        assert_eq!(err, Error::UnexpectedFormat);
247    }
248
249    #[test]
250    fn decode_failed_timestamp96_invalid_length() {
251        // Ext8 length != 12
252        let mut buf = vec![0xc7, 11, TIMESTAMP_EXT_TYPE];
253        buf.extend_from_slice(&[0u8; 11]);
254
255        let mut r = crate::io::SliceReader::new(&buf);
256        let err = Timestamp96::decode(&mut r).unwrap_err();
257        assert_eq!(err, Error::InvalidData);
258    }
259
260    #[test]
261    fn decode_failed_timestamp96_invalid_ext_type() {
262        let secs: i64 = 1;
263        let nanos: u32 = 2;
264
265        let mut buf = vec![0xc7, 12, 0]; // ext type != -1
266        buf.extend_from_slice(&nanos.to_be_bytes());
267        buf.extend_from_slice(&secs.to_be_bytes());
268
269        let mut r = crate::io::SliceReader::new(&buf);
270        let err = Timestamp96::decode(&mut r).unwrap_err();
271        assert_eq!(err, Error::InvalidData);
272    }
273
274    #[test]
275    fn decode_failed_timestamp96_eof_data() {
276        // length says 12 but provide 11
277        let mut buf = vec![0xc7, 12, TIMESTAMP_EXT_TYPE];
278        buf.extend_from_slice(&[0u8; 11]);
279
280        let mut r = crate::io::SliceReader::new(&buf);
281        let err = Timestamp96::decode(&mut r).unwrap_err();
282        assert!(matches!(err, Error::Io(_)));
283    }
284}