@@ -31,7 +31,7 @@ use std::error;
3131
3232use num_traits:: cast:: FromPrimitive ;
3333
34- use crate :: Marker ;
34+ use crate :: { Marker , Timestamp } ;
3535
3636pub mod bytes;
3737pub use bytes:: Bytes ;
@@ -244,6 +244,79 @@ pub fn read_marker<R: RmpRead>(rd: &mut R) -> Result<Marker, MarkerReadError<R::
244244 Ok ( Marker :: from_u8 ( rd. read_u8 ( ) ?) )
245245}
246246
247+ /// Attempts to read an Extension struct from the given reader and to decode it as a Timestamp value.
248+ ///
249+ /// According to the MessagePack specification, there are 3 types of Timestamp, 32, 64, and 96.
250+ ///
251+ /// # Errors
252+ ///
253+ /// This function will return `ValueReadError` on any I/O error while reading the Timestamp,
254+ /// except the EINTR, which is handled internally.
255+ ///
256+ /// It also returns `ValueReadError::TypeMismatch` if the actual type is not equal with the
257+ /// expected one, indicating you with the actual type.
258+ ///
259+ /// # Note
260+ ///
261+ /// This function will silently retry on every EINTR received from the underlying `Read` until
262+ /// successful read.
263+ ///
264+ /// # Examples
265+ ///
266+ /// ```
267+ /// use rmp::Timestamp;
268+ ///
269+ /// // FixExt4 with a type of -1 (0xff)
270+ /// let mut buf1 = [0xd6, 0xff, 0x66, 0xc1, 0xde, 0x7c];
271+ /// // FixExt8 with a type of -1 (0xff)
272+ /// let mut buf2 = [0xd7, 0xff, 0xee, 0x6b, 0x27, 0xfc, 0x66, 0xc1, 0xde, 0x7c];
273+ /// // Ext8 with a size of 12 (0x0c) and a type of -1 (0xff)
274+ /// let mut buf3 = [0xc7, 0x0c, 0xff, 0x3b, 0x9a, 0xc9, 0xff, 0x00, 0x00, 0x00, 0x00, 0x66, 0xc1, 0xde, 0x7c];
275+ ///
276+ /// let ts1_expected = Timestamp::from_32(0x66c1de7c);
277+ /// let ts2_expected = Timestamp::from_64(0x66c1de7c, 0x3b9ac9ff).unwrap();
278+ /// let ts3_expected = Timestamp::from_96(0x66c1de7c, 0x3b9ac9ff).unwrap();
279+ ///
280+ /// let ts1_result = rmp::decode::read_timestamp(&mut buf1.as_slice()).unwrap();
281+ /// let ts2_result = rmp::decode::read_timestamp(&mut buf2.as_slice()).unwrap();
282+ /// let ts3_result = rmp::decode::read_timestamp(&mut buf3.as_slice()).unwrap();
283+ ///
284+ /// assert_eq!(ts1_expected, ts1_result);
285+ /// assert_eq!(ts2_expected, ts2_result);
286+ /// assert_eq!(ts3_expected, ts3_result);
287+ /// ```
288+ pub fn read_timestamp < R : RmpRead > ( rd : & mut R ) -> Result < Timestamp , ValueReadError < R :: Error > > {
289+ let marker = read_marker ( rd) ?;
290+ let prefix = rd. read_data_i8 ( ) ?;
291+ match ( marker, prefix) {
292+ // timestamp 32
293+ ( Marker :: FixExt4 , -1 ) => {
294+ let secs = rd. read_data_u32 ( ) ?;
295+ Ok ( Timestamp :: from_32 ( secs) )
296+ } ,
297+ // timestamp 64
298+ ( Marker :: FixExt8 , -1 ) => {
299+ let data = rd. read_data_u64 ( ) ?;
300+ Timestamp :: from_combined_64 ( data)
301+ . ok_or ( ValueReadError :: TypeMismatch ( Marker :: Reserved ) )
302+ } ,
303+ // timestamp 96
304+ ( Marker :: Ext8 , 12 ) => {
305+ let prefix = rd. read_data_i8 ( ) ?;
306+ if prefix == -1 {
307+ let nsecs = rd. read_data_u32 ( ) ?;
308+ let secs = rd. read_data_i64 ( ) ?;
309+ Timestamp :: from_96 ( secs, nsecs)
310+ . ok_or ( ValueReadError :: TypeMismatch ( Marker :: Reserved ) )
311+ } else {
312+ Err ( ValueReadError :: TypeMismatch ( Marker :: Reserved ) )
313+ }
314+ } ,
315+ ( Marker :: Ext8 | Marker :: FixExt4 | Marker :: FixExt8 , _) => Err ( ValueReadError :: TypeMismatch ( Marker :: Reserved ) ) ,
316+ ( marker, _) => Err ( ValueReadError :: TypeMismatch ( marker) ) ,
317+ }
318+ }
319+
247320/// Attempts to read a single byte from the given reader and to decode it as a nil value.
248321///
249322/// According to the MessagePack specification, a nil value is represented as a single `0xc0` byte.
0 commit comments