-
Notifications
You must be signed in to change notification settings - Fork 196
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add serde support to date time (#2646)
## Motivation and Context This is a child PR of #2616 The changes that this PR introduces is same as the ones that were merged to `unstable-serde-support` branch before. Initially, we tried to make commit to unstable-serde-support branch and merge changes one by one in small PRs. However, in order to make it up to date with the main branch, we would need to go through a large PR of over 700 files. Thus, I decided to create individual PRs that commits directly to `main` branch. ## Description - Implements `serde` support to `DateTime` ## Testing - Test checks whether the serialized/de-serialized data matches with the expected value ## Checklist NA ---- _By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice._
- Loading branch information
1 parent
18aad5c
commit 74a7204
Showing
4 changed files
with
239 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
/* | ||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
use super::*; | ||
use serde::de::{Error, Visitor}; | ||
use serde::Deserialize; | ||
|
||
struct DateTimeVisitor; | ||
|
||
struct NonHumanReadableDateTimeVisitor; | ||
|
||
impl<'de> Visitor<'de> for DateTimeVisitor { | ||
type Value = DateTime; | ||
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
formatter.write_str("expected RFC-3339 Date Time") | ||
} | ||
|
||
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> | ||
where | ||
E: serde::de::Error, | ||
{ | ||
match DateTime::from_str(v, Format::DateTime) { | ||
Ok(e) => Ok(e), | ||
Err(e) => Err(Error::custom(e)), | ||
} | ||
} | ||
} | ||
|
||
impl<'de> Visitor<'de> for NonHumanReadableDateTimeVisitor { | ||
type Value = DateTime; | ||
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
formatter.write_str("DateTime type expects a tuple of i64 and u32 when deserializing from non human readable format like CBOR or AVRO, i.e. (i64, u32)") | ||
} | ||
|
||
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error> | ||
where | ||
A: serde::de::SeqAccess<'de>, | ||
{ | ||
match seq.size_hint() { | ||
Some(2) | None => match (seq.next_element()?, seq.next_element()?) { | ||
(Some(seconds), Some(subsecond_nanos)) => Ok(DateTime { | ||
seconds, | ||
subsecond_nanos, | ||
}), | ||
_ => return Err(Error::custom("datatype mismatch")), | ||
}, | ||
_ => Err(Error::custom("Size mismatch")), | ||
} | ||
} | ||
} | ||
|
||
impl<'de> Deserialize<'de> for DateTime { | ||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> | ||
where | ||
D: serde::Deserializer<'de>, | ||
{ | ||
if deserializer.is_human_readable() { | ||
deserializer.deserialize_str(DateTimeVisitor) | ||
} else { | ||
deserializer.deserialize_tuple(2, NonHumanReadableDateTimeVisitor) | ||
} | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod test { | ||
use super::*; | ||
|
||
/// check for human redable format | ||
#[test] | ||
fn de_human_readable_datetime() { | ||
use serde::{Deserialize, Serialize}; | ||
|
||
let datetime = DateTime::from_secs(1576540098); | ||
#[derive(Serialize, Deserialize, PartialEq)] | ||
struct Test { | ||
datetime: DateTime, | ||
} | ||
let datetime_json = r#"{"datetime":"2019-12-16T23:48:18Z"}"#; | ||
let test = serde_json::from_str::<Test>(&datetime_json).ok(); | ||
assert!(test == Some(Test { datetime })); | ||
} | ||
|
||
/// check for non-human redable format | ||
#[test] | ||
fn de_not_human_readable_datetime() { | ||
{ | ||
let cbor = ciborium::value::Value::Array(vec![ | ||
ciborium::value::Value::Integer(1576540098i64.into()), | ||
ciborium::value::Value::Integer(0u32.into()), | ||
]); | ||
let mut buf = vec![]; | ||
let _ = ciborium::ser::into_writer(&cbor, &mut buf); | ||
let cbor_dt: DateTime = ciborium::de::from_reader(std::io::Cursor::new(buf)).unwrap(); | ||
assert_eq!( | ||
cbor_dt, | ||
DateTime { | ||
seconds: 1576540098i64, | ||
subsecond_nanos: 0 | ||
} | ||
); | ||
}; | ||
|
||
{ | ||
let cbor = ciborium::value::Value::Array(vec![ | ||
ciborium::value::Value::Integer(0i64.into()), | ||
ciborium::value::Value::Integer(0u32.into()), | ||
]); | ||
let mut buf = vec![]; | ||
let _ = ciborium::ser::into_writer(&cbor, &mut buf); | ||
let cbor_dt: DateTime = ciborium::de::from_reader(std::io::Cursor::new(buf)).unwrap(); | ||
assert_eq!( | ||
cbor_dt, | ||
DateTime { | ||
seconds: 0, | ||
subsecond_nanos: 0 | ||
} | ||
); | ||
}; | ||
|
||
{ | ||
let cbor = ciborium::value::Value::Array(vec![ | ||
ciborium::value::Value::Integer(i64::MAX.into()), | ||
ciborium::value::Value::Integer(u32::MAX.into()), | ||
]); | ||
let mut buf = vec![]; | ||
let _ = ciborium::ser::into_writer(&cbor, &mut buf); | ||
let cbor_dt: DateTime = ciborium::de::from_reader(std::io::Cursor::new(buf)).unwrap(); | ||
assert_eq!( | ||
cbor_dt, | ||
DateTime { | ||
seconds: i64::MAX, | ||
subsecond_nanos: u32::MAX | ||
} | ||
); | ||
}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
/* | ||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
use super::*; | ||
use serde::ser::SerializeTuple; | ||
|
||
impl serde::Serialize for DateTime { | ||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> | ||
where | ||
S: serde::Serializer, | ||
{ | ||
if serializer.is_human_readable() { | ||
match self.fmt(Format::DateTime) { | ||
Ok(val) => serializer.serialize_str(&val), | ||
Err(e) => Err(serde::ser::Error::custom(e)), | ||
} | ||
} else { | ||
let mut tup_ser = serializer.serialize_tuple(2)?; | ||
tup_ser.serialize_element(&self.seconds)?; | ||
tup_ser.serialize_element(&self.subsecond_nanos)?; | ||
tup_ser.end() | ||
} | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod test { | ||
use super::*; | ||
|
||
/// check for human redable format | ||
#[test] | ||
fn ser_human_readable_datetime() { | ||
use serde::{Deserialize, Serialize}; | ||
|
||
let datetime = DateTime::from_secs(1576540098); | ||
#[derive(Serialize, Deserialize, PartialEq)] | ||
struct Test { | ||
datetime: DateTime, | ||
} | ||
let datetime_json = r#"{"datetime":"2019-12-16T23:48:18Z"}"#; | ||
assert!(serde_json::to_string(&Test { datetime }).ok() == Some(datetime_json.to_string())); | ||
} | ||
|
||
/// check for non-human redable format | ||
#[test] | ||
fn ser_not_human_readable_datetime() { | ||
{ | ||
let cbor = ciborium::value::Value::Array(vec![ | ||
ciborium::value::Value::Integer(1576540098i64.into()), | ||
ciborium::value::Value::Integer(0u32.into()), | ||
]); | ||
let mut buf = vec![]; | ||
let mut buf2 = vec![]; | ||
let _ = ciborium::ser::into_writer(&cbor, &mut buf); | ||
let _ = ciborium::ser::into_writer(&cbor, &mut buf2); | ||
assert_eq!(buf, buf2); | ||
}; | ||
|
||
{ | ||
let cbor = ciborium::value::Value::Array(vec![ | ||
ciborium::value::Value::Integer(0i64.into()), | ||
ciborium::value::Value::Integer(0u32.into()), | ||
]); | ||
let mut buf = vec![]; | ||
let mut buf2 = vec![]; | ||
let _ = ciborium::ser::into_writer(&cbor, &mut buf); | ||
let _ = ciborium::ser::into_writer(&cbor, &mut buf2); | ||
assert_eq!(buf, buf2); | ||
}; | ||
|
||
{ | ||
let cbor = ciborium::value::Value::Array(vec![ | ||
ciborium::value::Value::Integer(i64::MAX.into()), | ||
ciborium::value::Value::Integer(u32::MAX.into()), | ||
]); | ||
let mut buf = vec![]; | ||
let mut buf2 = vec![]; | ||
let _ = ciborium::ser::into_writer(&cbor, &mut buf); | ||
let _ = ciborium::ser::into_writer(&cbor, &mut buf2); | ||
assert_eq!(buf, buf2); | ||
}; | ||
} | ||
} |