Skip to content

Commit 7bf1935

Browse files
committed
WIP: Add chrono crate as optional dependency
1 parent 783d720 commit 7bf1935

File tree

4 files changed

+58
-38
lines changed

4 files changed

+58
-38
lines changed

rmp/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ edition = "2021"
1313

1414
[dependencies]
1515
byteorder = { version = "1.4.2", default-features = false }
16+
chrono = { version = "0.4", default-features = false, optional = true }
1617
num-traits = { version = "0.2.14", default-features = false }
1718
# This is macro_only ;)
1819
paste = "1.0"

rmp/src/decode/mod.rs

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@ pub fn read_marker<R: RmpRead>(rd: &mut R) -> Result<Marker, MarkerReadError<R::
264264
/// # Examples
265265
///
266266
/// ```
267+
/// use chrono::DateTime;
267268
/// use rmp::Timestamp;
268269
///
269270
/// // FixExt4 with a type of -1 (0xff)
@@ -273,9 +274,9 @@ pub fn read_marker<R: RmpRead>(rd: &mut R) -> Result<Marker, MarkerReadError<R::
273274
/// // Ext8 with a size of 12 (0x0c) and a type of -1 (0xff)
274275
/// let mut buf3 = [0xc7, 0x0c, 0xff, 0x3b, 0x9a, 0xc9, 0xff, 0x00, 0x00, 0x00, 0x00, 0x66, 0xc1, 0xde, 0x7c];
275276
///
276-
/// let ts1_expected = Timestamp::T32 { secs: 0x66c1de7c };
277-
/// let ts2_expected = Timestamp::T64 { nsecs: 0x3b9ac9ff, secs: 0x66c1de7c };
278-
/// let ts3_expected = Timestamp::T96 { nsecs: 0x3b9ac9ff, secs: 0x66c1de7c };
277+
/// let ts1_expected = Timestamp::T32(DateTime::from_timestamp(0x66c1de7c, 0).unwrap());
278+
/// let ts2_expected = Timestamp::T64(DateTime::from_timestamp(0x66c1de7c, 0x3b9ac9ff).unwrap());
279+
/// let ts3_expected = Timestamp::T96(DateTime::from_timestamp(0x66c1de7c, 0x3b9ac9ff).unwrap());
279280
///
280281
/// let ts1_result = rmp::decode::read_timestamp(&mut buf1.as_slice()).unwrap();
281282
/// let ts2_result = rmp::decode::read_timestamp(&mut buf2.as_slice()).unwrap();
@@ -285,45 +286,47 @@ pub fn read_marker<R: RmpRead>(rd: &mut R) -> Result<Marker, MarkerReadError<R::
285286
/// assert_eq!(ts2_expected, ts2_result);
286287
/// assert_eq!(ts3_expected, ts3_result);
287288
/// ```
289+
#[cfg(feature = "chrono")]
288290
pub fn read_timestamp<R: RmpRead>(rd: &mut R) -> Result<Timestamp, ValueReadError<R::Error>> {
289291
let marker = read_marker(rd)?;
290292
let prefix = rd.read_data_i8()?;
291293
match (marker, prefix) {
292294
// timestamp 32
293295
(Marker::FixExt4, -1) => {
294296
let secs = rd.read_data_u32()? as i64;
295-
Ok(Timestamp::T32 {
296-
secs,
297-
})
297+
Ok(Timestamp::T32(
298+
chrono::DateTime::from_timestamp(secs, 0)
299+
.ok_or(ValueReadError::TypeMismatch(Marker::Reserved))?
300+
))
298301
},
299302
// timestamp 64
300303
(Marker::FixExt8, -1) => {
301304
let data = rd.read_data_u64()?;
302305
// 30 bits fits in u32
303306
let nsecs = (data >> 34) as u32;
304-
if nsecs > 999_999_999 {
307+
if nsecs > crate::MAX_NSECS {
305308
return Err(ValueReadError::TypeMismatch(Marker::Reserved))
306309
}
307310
// 34 bits fits in i64
308311
let secs = (data & 0x3_ffff_ffff) as i64;
309-
Ok(Timestamp::T64 {
310-
secs,
311-
nsecs,
312-
})
312+
Ok(Timestamp::T64(
313+
chrono::DateTime::from_timestamp(secs, nsecs)
314+
.ok_or(ValueReadError::TypeMismatch(Marker::Reserved))?
315+
))
313316
},
314317
// timestamp 96
315318
(Marker::Ext8, 12) => {
316319
let prefix = rd.read_data_i8()?;
317320
if prefix == -1 {
318321
let nsecs = rd.read_data_u32()?;
319-
if nsecs > 999_999_999 {
322+
if nsecs > crate::MAX_NSECS {
320323
return Err(ValueReadError::TypeMismatch(Marker::Reserved))
321324
}
322325
let secs = rd.read_data_i64()?;
323-
Ok(Timestamp::T96 {
324-
secs,
325-
nsecs,
326-
})
326+
Ok(Timestamp::T96(
327+
chrono::DateTime::from_timestamp(secs, nsecs)
328+
.ok_or(ValueReadError::TypeMismatch(Marker::Reserved))?
329+
))
327330
} else {
328331
Err(ValueReadError::TypeMismatch(Marker::Reserved))
329332
}

rmp/src/encode/mod.rs

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -90,26 +90,30 @@ pub fn write_nil<W: RmpWrite>(wr: &mut W) -> Result<(), W::Error> {
9090
///
9191
/// According to the MessagePack specification, a timestamp value is represented as a 32, 64, or 96 bit Extension struct.
9292
///
93+
/// This will return `Ok(false)` if the timestamp contained a value that is invalid for the msgpack spec.
94+
/// When `Ok(false)` is returned, nothing has been written to the writer.
95+
///
9396
/// # Errors
9497
///
9598
/// This function will return `Error` on any I/O error occurred while writing the timestamp.
9699
///
97100
/// # Examples
98101
///
99102
/// ```
103+
/// use chrono::DateTime;
100104
/// use rmp::Timestamp;
101105
///
102106
/// let mut buf1 = Vec::new();
103107
/// let mut buf2 = Vec::new();
104108
/// let mut buf3 = Vec::new();
105109
///
106-
/// let ts1 = Timestamp::T32 { secs: 0x66c1de7c };
107-
/// let ts2 = Timestamp::T64 { nsecs: 0x3b9ac9ff, secs: 0x66c1de7c };
108-
/// let ts3 = Timestamp::T96 { nsecs: 0x3b9ac9ff, secs: 0x66c1de7c };
110+
/// let ts1 = Timestamp::T32(DateTime::from_timestamp(0x66c1de7c, 0).unwrap());
111+
/// let ts2 = Timestamp::T64(DateTime::from_timestamp(0x66c1de7c, 0x3b9ac9ff).unwrap());
112+
/// let ts3 = Timestamp::T96(DateTime::from_timestamp(0x66c1de7c, 0x3b9ac9ff).unwrap());
109113
///
110-
/// rmp::encode::write_timestamp(&mut buf1, ts1).ok();
111-
/// rmp::encode::write_timestamp(&mut buf2, ts2).ok();
112-
/// rmp::encode::write_timestamp(&mut buf3, ts3).ok();
114+
/// assert!(rmp::encode::write_timestamp(&mut buf1, ts1).ok().unwrap());
115+
/// assert!(rmp::encode::write_timestamp(&mut buf2, ts2).ok().unwrap());
116+
/// assert!(rmp::encode::write_timestamp(&mut buf3, ts3).ok().unwrap());
113117
///
114118
/// // FixExt4 with a type of -1 (0xff)
115119
/// assert_eq!(vec![0xd6, 0xff, 0x66, 0xc1, 0xde, 0x7c], buf1);
@@ -118,29 +122,44 @@ pub fn write_nil<W: RmpWrite>(wr: &mut W) -> Result<(), W::Error> {
118122
/// // Ext8 with a size of 12 (0x0c) and a type of -1 (0xff)
119123
/// assert_eq!(vec![0xc7, 0x0c, 0xff, 0x3b, 0x9a, 0xc9, 0xff, 0x00, 0x00, 0x00, 0x00, 0x66, 0xc1, 0xde, 0x7c], buf3);
120124
/// ```
125+
#[cfg(feature = "chrono")]
121126
#[inline]
122-
pub fn write_timestamp<W: RmpWrite>(wr: &mut W, timestamp: Timestamp) -> Result<(), DataWriteError<W::Error>> {
127+
pub fn write_timestamp<W: RmpWrite>(wr: &mut W, timestamp: Timestamp) -> Result<bool, DataWriteError<W::Error>> {
123128
match timestamp {
124-
Timestamp::T32 { secs } => {
129+
Timestamp::T32(timedate) => {
130+
let secs = timedate.timestamp();
131+
if secs < 0 || secs > u32::MAX as i64 {
132+
return Ok(false)
133+
}
125134
write_marker(wr, Marker::FixExt4).map_err(|e| e.0)?;
126135
wr.write_data_i8(-1)?;
127136
wr.write_data_u32(secs as u32)?;
128137
},
129-
Timestamp::T64 { nsecs, secs } => {
138+
Timestamp::T64(timedate) => {
139+
let secs = timedate.timestamp();
140+
let nsecs = timedate.timestamp_subsec_nanos();
141+
if secs < 0 || secs > 0x3_ffff_ffff || nsecs > crate::MAX_NSECS {
142+
return Ok(false)
143+
}
130144
write_marker(wr, Marker::FixExt8).map_err(|e| e.0)?;
131145
let data = ((nsecs as u64) << 34) | (secs as u64);
132146
wr.write_data_i8(-1)?;
133147
wr.write_data_u64(data)?;
134148
},
135-
Timestamp::T96 { nsecs, secs } => {
149+
Timestamp::T96(timedate) => {
150+
let secs = timedate.timestamp();
151+
let nsecs = timedate.timestamp_subsec_nanos();
152+
if nsecs > crate::MAX_NSECS {
153+
return Ok(false)
154+
}
136155
write_marker(wr, Marker::Ext8).map_err(|e| e.0)?;
137156
wr.write_data_u8(12)?;
138157
wr.write_data_i8(-1)?;
139158
wr.write_data_u32(nsecs)?;
140159
wr.write_data_i64(secs)?;
141160
},
142161
}
143-
Ok(())
162+
Ok(true)
144163
}
145164

146165
/// Encodes and attempts to write a bool value into the given write.

rmp/src/lib.rs

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,13 @@ pub const MSGPACK_VERSION: u32 = 5;
1515

1616
/// A type for holding Timestamp information
1717
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
18+
#[cfg(feature = "chrono")]
1819
pub enum Timestamp {
19-
T32 {
20-
secs: i64,
21-
},
22-
T64 {
23-
nsecs: u32,
24-
secs: i64,
25-
},
26-
T96 {
27-
nsecs: u32,
28-
secs: i64,
29-
},
20+
T32(chrono::DateTime<chrono::Utc>),
21+
T64(chrono::DateTime<chrono::Utc>),
22+
T96(chrono::DateTime<chrono::Utc>),
3023
}
24+
25+
/// msgpack spec says nsecs must not be 1 billion or larger
26+
/// even though leap seconds can be just below 2 billion
27+
pub(crate) const MAX_NSECS: u32 = 999_999_999;

0 commit comments

Comments
 (0)