From 2c522407788d51abef87d4f8480ce52c29215665 Mon Sep 17 00:00:00 2001 From: Sam Mason Date: Wed, 22 Feb 2023 00:03:38 +1100 Subject: [PATCH 1/3] Rework serde::timestamp and add timestamp::millis - Allows serde::timestamp to be used for more common types without additional modules. - Added serde::timestamp::millis for the cases where greater time fidelity is needed in a standardised way (javascript natively expects timestamps to be in milliseconds) - Included tests for the above - Deprecated the timestamp::option module as this achieves the same effect seamlessly - Maybe expanding this concept to other well-known serde types? --- tests/serde/timestamps.rs | 613 +++++++++++++++++++++++++++++++++++- time/src/serde/timestamp.rs | 364 ++++++++++++++++++++- 2 files changed, 960 insertions(+), 17 deletions(-) diff --git a/tests/serde/timestamps.rs b/tests/serde/timestamps.rs index 9a93c559d0..3f5c008f43 100644 --- a/tests/serde/timestamps.rs +++ b/tests/serde/timestamps.rs @@ -1,25 +1,25 @@ use serde::{Deserialize, Serialize}; -use serde_test::{assert_de_tokens_error, assert_tokens, Configure, Token}; +use serde_test::{assert_de_tokens_error, assert_de_tokens, assert_tokens, Configure, Token}; use time::macros::datetime; use time::serde::timestamp; -use time::OffsetDateTime; +use time::{OffsetDateTime,PrimitiveDateTime}; #[derive(Serialize, Deserialize, Debug, PartialEq)] -struct Test { +struct TestOffset { #[serde(with = "timestamp")] dt: OffsetDateTime, } #[test] -fn serialize_timestamp() { - let value = Test { +fn serialize_timestamp_offset() { + let value = TestOffset { dt: datetime!(2000-01-01 00:00:00 UTC), }; assert_tokens( &value.compact(), &[ Token::Struct { - name: "Test", + name: "TestOffset", len: 1, }, Token::Str("dt"), @@ -27,10 +27,10 @@ fn serialize_timestamp() { Token::StructEnd, ], ); - assert_de_tokens_error::( + assert_de_tokens_error::( &[ Token::Struct { - name: "Test", + name: "TestOffset", len: 1, }, Token::Str("dt"), @@ -40,3 +40,600 @@ fn serialize_timestamp() { "invalid type: string \"bad\", expected i64", ); } + + +#[derive(Serialize, Deserialize, Debug, PartialEq)] +struct TestPrimitive{ + #[serde(with = "timestamp")] + dt: PrimitiveDateTime, +} + + +#[test] +fn serialize_timestamp_primitive() { + let value = TestPrimitive { + dt: datetime!(2015-01-01 00:00:00), + }; + assert_tokens( + &value.compact(), + &[ + Token::Struct { + name: "TestPrimitive", + len: 1, + }, + Token::Str("dt"), + Token::I64(1420070400), + Token::StructEnd, + ], + ); + assert_de_tokens_error::( + &[ + Token::Struct { + name: "TestPrimitive", + len: 1, + }, + Token::Str("dt"), + Token::Str("bad"), + Token::StructEnd, + ], + "invalid type: string \"bad\", expected i64", + ); +} + + +#[derive(Serialize, Deserialize, Debug, PartialEq)] +struct TestOffsetOption { + #[serde(with = "timestamp")] + dt: Option, +} + + +#[test] +fn serialize_timestamp_offset_option() { + let value = TestOffsetOption { + dt: Some(datetime!(1990-01-01 00:00:00 UTC)), + }; + assert_tokens( + &value.compact(), + &[ + Token::Struct { + name: "TestOffsetOption", + len: 1, + }, + Token::Str("dt"), + Token::Some, + Token::I64(631152000), + Token::StructEnd, + ], + ); + let value = TestOffsetOption { + dt: None, + }; + assert_tokens( + &value.compact(), + &[ + Token::Struct { + name: "TestOffsetOption", + len: 1, + }, + Token::Str("dt"), + Token::None, + Token::StructEnd, + ], + ); + assert_de_tokens_error::( + &[ + Token::Struct { + name: "TestOffsetOption", + len: 1, + }, + Token::Str("dt"), + Token::Some, + Token::Str("bad"), + Token::StructEnd, + ], + "invalid type: string \"bad\", expected i64", + ); + assert_de_tokens::( + &TestOffsetOption { + dt: Some(datetime!(1969-09-30 09:46:40 +0000)) + }, + &[ + Token::Struct { + name: "TestOffsetOption", + len: 1, + }, + Token::Str("dt"), + Token::Some, + Token::I64(-8_000_000), + Token::StructEnd, + ], + ); +} + +#[derive(Serialize, Deserialize, Debug, PartialEq)] +struct TestPrimitiveOption { + #[serde(with = "timestamp")] + dt: Option, +} + + +#[test] +fn serialize_timestamp_primitive_option() { + let value = TestPrimitiveOption { + dt: Some(datetime!(1980-01-01 00:00:00)), + }; + assert_tokens( + &value.compact(), + &[ + Token::Struct { + name: "TestPrimitiveOption", + len: 1, + }, + Token::Str("dt"), + Token::Some, + Token::I64(315532800), + Token::StructEnd, + ], + ); + let value = TestPrimitiveOption { + dt: None, + }; + assert_tokens( + &value.compact(), + &[ + Token::Struct { + name: "TestPrimitiveOption", + len: 1, + }, + Token::Str("dt"), + Token::None, + Token::StructEnd, + ], + ); + assert_de_tokens_error::( + &[ + Token::Struct { + name: "TestPrimitiveOption", + len: 1, + }, + Token::Str("dt"), + Token::Some, + Token::Str("bad"), + Token::StructEnd, + ], + "invalid type: string \"bad\", expected i64", + ); + assert_de_tokens::( + &TestPrimitiveOption { + dt: Some(datetime!(1930-04-11 02:35:12)) + }, + &[ + Token::Struct { + name: "TestPrimitiveOption", + len: 1, + }, + Token::Str("dt"), + Token::Some, + Token::I64(-1253654688), + Token::StructEnd, + ], + ); +} + + +#[derive(Serialize, Deserialize, Debug, PartialEq)] +struct TestOffsetMillis { + #[serde(with = "timestamp::millis")] + dt: OffsetDateTime, +} + +#[test] +fn serialize_timestamp_offset_millis() { + let value = TestOffsetMillis { + dt: datetime!(2000-01-01 00:00:00.123 UTC), + }; + assert_tokens( + &value.compact(), + &[ + Token::Struct { + name: "TestOffsetMillis", + len: 1, + }, + Token::Str("dt"), + Token::I64(946684800123), + Token::StructEnd, + ], + ); + assert_de_tokens_error::( + &[ + Token::Struct { + name: "TestOffsetMillis", + len: 1, + }, + Token::Str("dt"), + Token::Str("bad"), + Token::StructEnd, + ], + "invalid type: string \"bad\", expected i64", + ); + + assert_de_tokens::( + &TestOffsetMillis { + dt: datetime!(1930-04-11 02:35:12.123 +00) + }, + &[ + Token::Struct { + name: "TestOffsetMillis", + len: 1, + }, + Token::Str("dt"), + Token::I64(-1253654687877), + Token::StructEnd, + ], + ); +} + + +#[derive(Serialize, Deserialize, Debug, PartialEq)] +struct TestPrimitiveMillis{ + #[serde(with = "timestamp::millis")] + dt: PrimitiveDateTime, +} + + +#[test] +fn serialize_timestamp_primitive_millis() { + let value = TestPrimitiveMillis { + dt: datetime!(2015-01-01 00:00:00.123), + }; + assert_tokens( + &value.compact(), + &[ + Token::Struct { + name: "TestPrimitiveMillis", + len: 1, + }, + Token::Str("dt"), + Token::I64(1420070400123), + Token::StructEnd, + ], + ); + assert_de_tokens_error::( + &[ + Token::Struct { + name: "TestPrimitiveMillis", + len: 1, + }, + Token::Str("dt"), + Token::Str("bad"), + Token::StructEnd, + ], + "invalid type: string \"bad\", expected i64", + ); + assert_de_tokens::( + &TestPrimitiveMillis { + dt: datetime!(1969-09-30 09:46:40.123) + }, + &[ + Token::Struct { + name: "TestPrimitiveMillis", + len: 1, + }, + Token::Str("dt"), + Token::I64(-7_999_999_877), + Token::StructEnd, + ], + ); +} + + +#[derive(Serialize, Deserialize, Debug, PartialEq)] +struct TestOffsetOptionMillis { + #[serde(with = "timestamp::millis")] + dt: Option, +} + + +#[test] +fn serialize_timestamp_offset_option_millis() { + let value = TestOffsetOptionMillis { + dt: Some(datetime!(1990-01-01 00:00:00.123 UTC)), + }; + assert_tokens( + &value.compact(), + &[ + Token::Struct { + name: "TestOffsetOptionMillis", + len: 1, + }, + Token::Str("dt"), + Token::Some, + Token::I64(631152000123), + Token::StructEnd, + ], + ); + let value = TestOffsetOptionMillis { + dt: None, + }; + assert_tokens( + &value.compact(), + &[ + Token::Struct { + name: "TestOffsetOptionMillis", + len: 1, + }, + Token::Str("dt"), + Token::None, + Token::StructEnd, + ], + ); + assert_de_tokens_error::( + &[ + Token::Struct { + name: "TestOffsetOptionMillis", + len: 1, + }, + Token::Str("dt"), + Token::Some, + Token::Str("bad"), + Token::StructEnd, + ], + "invalid type: string \"bad\", expected i64", + ); + assert_de_tokens::( + &TestOffsetOptionMillis { + dt: Some(datetime!(1969-09-30 09:46:40.123 +0000)) + }, + &[ + Token::Struct { + name: "TestOffsetOptionMillis", + len: 1, + }, + Token::Str("dt"), + Token::Some, + Token::I64(-7_999_999_877), + Token::StructEnd, + ], + ); +} + +#[derive(Serialize, Deserialize, Debug, PartialEq)] +struct TestPrimitiveOptionMillis { + #[serde(with = "timestamp::millis")] + dt: Option, +} + + +#[test] +fn serialize_timestamp_primitive_option_millis() { + let value = TestPrimitiveOptionMillis { + dt: Some(datetime!(1980-01-01 00:00:00.123)), + }; + assert_tokens( + &value.compact(), + &[ + Token::Struct { + name: "TestPrimitiveOptionMillis", + len: 1, + }, + Token::Str("dt"), + Token::Some, + Token::I64(315532800123), + Token::StructEnd, + ], + ); + let value = TestPrimitiveOptionMillis { + dt: None, + }; + assert_tokens( + &value.compact(), + &[ + Token::Struct { + name: "TestPrimitiveOptionMillis", + len: 1, + }, + Token::Str("dt"), + Token::None, + Token::StructEnd, + ], + ); + assert_de_tokens_error::( + &[ + Token::Struct { + name: "TestPrimitiveOptionMillis", + len: 1, + }, + Token::Str("dt"), + Token::Some, + Token::Str("bad"), + Token::StructEnd, + ], + "invalid type: string \"bad\", expected i64", + ); + assert_de_tokens::( + &TestPrimitiveOptionMillis { + dt: Some(datetime!(1930-04-11 02:35:12.123)) + }, + &[ + Token::Struct { + name: "TestPrimitiveOptionMillis", + len: 1, + }, + Token::Str("dt"), + Token::Some, + Token::I64(-1253654687877), + Token::StructEnd, + ], + ); +} + + +#[derive(Serialize, Deserialize, Debug, PartialEq)] +struct TestOffsetVec { + #[serde(with = "timestamp")] + dt: Vec, +} + +#[test] +fn serialize_timestamp_offset_vec() { + let value = TestOffsetVec { + dt: vec![datetime!(2000-01-01 00:00:00 UTC),datetime!(2010-01-01 00:00:00 UTC)] + }; + assert_tokens( + &value.compact(), + &[ + Token::Struct { + name: "TestOffsetVec", + len: 1, + }, + Token::Str("dt"), + Token::Seq{ len: Some(2) }, + Token::I64(946684800), + Token::I64(1262304000), + Token::SeqEnd, + Token::StructEnd, + ], + ); + assert_de_tokens_error::( + &[ + Token::Struct { + name: "TestOffsetVec", + len: 1, + }, + Token::Str("dt"), + Token::Seq{ len : Some(1) }, + Token::Str("bad"), + Token::StructEnd, + ], + "invalid type: string \"bad\", expected i64", + ); +} + + +#[derive(Serialize, Deserialize, Debug, PartialEq)] +struct TestPrimitiveVec{ + #[serde(with = "timestamp")] + dt: Vec, +} + + +#[test] +fn serialize_timestamp_primitive_vec() { + let value = TestPrimitiveVec { + dt: vec![datetime!(1860-01-01 00:00:00),datetime!(1972-01-01 00:00:00)], + }; + assert_tokens( + &value.compact(), + &[ + Token::Struct { + name: "TestPrimitiveVec", + len: 1, + }, + Token::Str("dt"), + Token::Seq{ len: Some(2) }, + Token::I64(-3471292800), + Token::I64(63072000), + Token::SeqEnd, + Token::StructEnd, + ], + ); + assert_de_tokens_error::( + &[ + Token::Struct { + name: "TestPrimitiveVec", + len: 1, + }, + Token::Str("dt"), + Token::Seq{ len : Some(1) }, + Token::Str("bad"), + Token::StructEnd, + ], + "invalid type: string \"bad\", expected i64", + ); +} + + +#[derive(Serialize, Deserialize, Debug, PartialEq)] +struct TestOffsetVecMillis { + #[serde(with = "timestamp::millis")] + dt: Vec, +} + +#[test] +fn serialize_timestamp_offset_vec_millis() { + let value = TestOffsetVecMillis { + dt: vec![datetime!(2000-01-01 00:00:00.123 UTC),datetime!(2010-01-01 00:00:00.123 UTC)] + }; + assert_tokens( + &value.compact(), + &[ + Token::Struct { + name: "TestOffsetVecMillis", + len: 1, + }, + Token::Str("dt"), + Token::Seq{ len: Some(2) }, + Token::I64(946684800123), + Token::I64(1262304000123), + Token::SeqEnd, + Token::StructEnd, + ], + ); + assert_de_tokens_error::( + &[ + Token::Struct { + name: "TestOffsetVecMillis", + len: 1, + }, + Token::Str("dt"), + Token::Seq{ len : Some(1) }, + Token::Str("bad"), + Token::StructEnd, + ], + "invalid type: string \"bad\", expected i64", + ); +} + + +#[derive(Serialize, Deserialize, Debug, PartialEq)] +struct TestPrimitiveVecMillis{ + #[serde(with = "timestamp::millis")] + dt: Vec, +} + + +#[test] +fn serialize_timestamp_primitive_vec_millis() { + let value = TestPrimitiveVecMillis { + dt: vec![datetime!(1860-01-01 00:00:00.123),datetime!(1972-01-01 00:00:00.123)], + }; + assert_tokens( + &value.compact(), + &[ + Token::Struct { + name: "TestPrimitiveVecMillis", + len: 1, + }, + Token::Str("dt"), + Token::Seq{ len: Some(2) }, + Token::I64(-3471292799877), + Token::I64(63072000123), + Token::SeqEnd, + Token::StructEnd, + ], + ); + assert_de_tokens_error::( + &[ + Token::Struct { + name: "TestPrimitiveVecMillis", + len: 1, + }, + Token::Str("dt"), + Token::Seq{ len : Some(1) }, + Token::Str("bad"), + Token::StructEnd, + ], + "invalid type: string \"bad\", expected i64", + ); +} diff --git a/time/src/serde/timestamp.rs b/time/src/serde/timestamp.rs index d86e6b9336..7592e5e96e 100644 --- a/time/src/serde/timestamp.rs +++ b/time/src/serde/timestamp.rs @@ -1,8 +1,10 @@ -//! Treat an [`OffsetDateTime`] as a [Unix timestamp] for the purposes of serde. +//! Treat an [`OffsetDateTime`] and [`PrimitiveDateTime`] as a [Unix timestamp] for the purposes of serde. //! //! Use this module in combination with serde's [`#[with]`][with] attribute. //! //! When deserializing, the offset is assumed to be UTC. +//! +//! Also works with [`Option`], and [`Option`]. //! //! [Unix timestamp]: https://en.wikipedia.org/wiki/Unix_time //! [with]: https://serde.rs/field-attrs.html#with @@ -10,19 +12,360 @@ use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use crate::OffsetDateTime; +use crate::PrimitiveDateTime; -/// Serialize an `OffsetDateTime` as its Unix timestamp -pub fn serialize( - datetime: &OffsetDateTime, +/// Serialize an [`OffsetDateTime`] and [`PrimitiveDateTime`] as its Unix timestamp +/// +/// Also works with [`Option`], and [`Option`]. +pub fn serialize( + datetime: &T, serializer: S, -) -> Result { - datetime.unix_timestamp().serialize(serializer) +) -> Result + where for <'a> __private::Timestamp<&'a T> : Serialize { + Serialize::serialize(&__private::Timestamp(datetime),serializer) } /// Deserialize an `OffsetDateTime` from its Unix timestamp -pub fn deserialize<'a, D: Deserializer<'a>>(deserializer: D) -> Result { - OffsetDateTime::from_unix_timestamp(<_>::deserialize(deserializer)?) - .map_err(|err| de::Error::invalid_value(de::Unexpected::Signed(err.value), &err)) +/// +/// Also works with [`Option`], and [`Option`]. +pub fn deserialize<'a, D: Deserializer<'a>, T>(deserializer: D) -> Result + where __private::Timestamp : Deserialize<'a> { + let t = __private::Timestamp::deserialize(deserializer)?; + Ok(t.0) +} + +fn drop_offset(v : OffsetDateTime) -> PrimitiveDateTime { + v.date().with_time(v.time()) +} + +#[doc(hidden)] +mod __private { + use super::*; + + pub struct Timestamp(pub(super) T); + + impl<'de> Deserialize<'de> for Timestamp { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de> { + let d = + OffsetDateTime::from_unix_timestamp(<_>::deserialize(deserializer)?) + .map_err(|err| de::Error::invalid_value(de::Unexpected::Signed(err.value), &err))?; + Ok(Timestamp(d)) + } + } + + impl<'de> Deserialize<'de> for Timestamp> { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de> { + let d = Option::deserialize(deserializer)? + .map(OffsetDateTime::from_unix_timestamp) + .transpose() + .map_err(|err| de::Error::invalid_value(de::Unexpected::Signed(err.value), &err))?; + + Ok(Timestamp(d)) + } + } + + impl<'de> Deserialize<'de> for Timestamp> { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de> { + let d = Vec::deserialize(deserializer)? + .into_iter() + .map(OffsetDateTime::from_unix_timestamp) + .collect::>() + .map_err(|err| de::Error::invalid_value(de::Unexpected::Signed(err.value), &err))?; + + Ok(Timestamp(d)) + } + } + + impl<'a> Serialize for Timestamp<&'a OffsetDateTime> { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer { + self.0.unix_timestamp().serialize(serializer) + } + } + + impl<'a> Serialize for Timestamp<&'a Option> { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer { + self.0.map(OffsetDateTime::unix_timestamp).serialize(serializer) + } + } + + impl<'a> Serialize for Timestamp<&'a [OffsetDateTime]> { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer { + let mut seq = serializer.serialize_seq(Some(self.0.len()))?; + for t in self.0 { + serde::ser::SerializeSeq::serialize_element(&mut seq, &Timestamp(t))?; + } + serde::ser::SerializeSeq::end(seq) + } + } + + impl<'a> Serialize for Timestamp<&'a Vec> { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer { + Timestamp(&self.0[..]).serialize(serializer) + } + } + + impl<'de> Deserialize<'de> for Timestamp { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de> { + let t : Timestamp = <_>::deserialize(deserializer)?; + Ok(Timestamp(t.0.date().with_time(t.0.time()))) + } + } + + impl<'de> Deserialize<'de> for Timestamp> { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de> { + let t : Timestamp> = <_>::deserialize(deserializer)?; + + Ok(Timestamp(t.0.map(|t| t.date().with_time(t.time())))) + } + } + + impl<'de> Deserialize<'de> for Timestamp> { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de> { + let t : Timestamp> = <_>::deserialize(deserializer)?; + + Ok(Timestamp(t.0.into_iter().map(|t| t.date().with_time(t.time())).collect())) + } + } + + impl<'a> Serialize for Timestamp<&'a PrimitiveDateTime> { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer { + Timestamp(&self.0.assume_utc()).serialize(serializer) + } + } + + impl<'a> Serialize for Timestamp<&'a Option> { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer { + Timestamp(&self.0.map(|t| t.assume_utc())).serialize(serializer) + } + } + + impl<'a> Serialize for Timestamp<&'a [PrimitiveDateTime]> { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer { + let mut seq = serializer.serialize_seq(Some(self.0.len()))?; + for t in self.0 { + serde::ser::SerializeSeq::serialize_element(&mut seq, &Timestamp(t))?; + } + serde::ser::SerializeSeq::end(seq) + } + } + + impl<'a> Serialize for Timestamp<&'a Vec> { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer { + Timestamp(&self.0[..]).serialize(serializer) + } + } +} + +// Treat an [`OffsetDateTime`] as a [Unix timestamp (milliseconds)] for the purposes of serde. +// +// Use this module in combination with serde's [`#[with]`][with] attribute. +// +// When deserializing, the offset is assumed to be UTC. +// +// [Unix timestamp]: https://en.wikipedia.org/wiki/Unix_time +// [with]: https://serde.rs/field-attrs.html#with +pub mod millis { + use super::*; + + /// Serialize as a Unix timestamp in milliseconds + pub fn serialize( + datetime: &T, + serializer: S, + ) -> Result + where for <'a> private::TimestampMillis<&'a T> : Serialize { + Serialize::serialize(&private::TimestampMillis(datetime),serializer) + } + + /// Deserialize as a Unix timestamp in milliseconds + pub fn deserialize<'a, D: Deserializer<'a>, T>(deserializer: D) -> Result + where private::TimestampMillis : Deserialize<'a> { + let t = private::TimestampMillis::deserialize(deserializer)?; + Ok(t.0) + } + + #[doc(hidden)] + mod private { + use super::*; + + fn from_i64(v : i64) -> Result { + let seconds = v / 1000; + let millis = v % 1000; + + let d = + OffsetDateTime::from_unix_timestamp(seconds) + .map_err(|err| de::Error::invalid_value(de::Unexpected::Signed(err.value), &err))? + + crate::Duration::milliseconds(millis); + Ok(d) + } + + fn to_i64(v : OffsetDateTime) -> i64 { + let seconds = v.unix_timestamp() * 1000; + seconds + v.millisecond() as i64 + } + + pub struct TimestampMillis(pub(super) T); + + impl<'de> Deserialize<'de> for TimestampMillis { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de> { + let timestamp : i64 = <_>::deserialize(deserializer)?; + + Ok(TimestampMillis(from_i64(timestamp)?)) + } + } + + impl<'de> Deserialize<'de> for TimestampMillis> { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de> { + let d = Option::deserialize(deserializer)? + .map(from_i64) + .transpose()?; + + Ok(TimestampMillis(d)) + } + } + + impl<'de> Deserialize<'de> for TimestampMillis> { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de> { + let t = Vec::deserialize(deserializer)?; + + Ok(TimestampMillis(t.into_iter().map(from_i64).collect::,_>>()?)) + } + } + + impl<'a> Serialize for TimestampMillis<&'a OffsetDateTime> { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer { + to_i64(*self.0).serialize(serializer) + } + } + + impl<'a> Serialize for TimestampMillis<&'a Option> { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer { + self.0.map(to_i64).serialize(serializer) + } + } + + impl<'a> Serialize for TimestampMillis<&'a [OffsetDateTime]> { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer { + let mut seq = serializer.serialize_seq(Some(self.0.len()))?; + for t in self.0 { + serde::ser::SerializeSeq::serialize_element(&mut seq, &TimestampMillis(t))?; + } + serde::ser::SerializeSeq::end(seq) + } + } + + impl<'a> Serialize for TimestampMillis<&'a Vec> { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer { + TimestampMillis(&self.0[..]).serialize(serializer) + } + } + + impl<'de> Deserialize<'de> for TimestampMillis { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de> { + let t : TimestampMillis = <_>::deserialize(deserializer)?; + Ok(TimestampMillis(t.0.date().with_time(t.0.time()))) + } + } + + impl<'de> Deserialize<'de> for TimestampMillis> { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de> { + let t : TimestampMillis> = <_>::deserialize(deserializer)?; + + Ok(TimestampMillis(t.0.map(|t| t.date().with_time(t.time())))) + } + } + + impl<'de> Deserialize<'de> for TimestampMillis> { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de> { + let t : TimestampMillis> = <_>::deserialize(deserializer)?; + + Ok(TimestampMillis(t.0.into_iter().map(drop_offset).collect())) + } + } + + impl<'a> Serialize for TimestampMillis<&'a PrimitiveDateTime> { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer { + TimestampMillis(&self.0.assume_utc()).serialize(serializer) + } + } + + impl<'a> Serialize for TimestampMillis<&'a Option> { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer { + TimestampMillis(&self.0.map(|t| t.assume_utc())).serialize(serializer) + } + } + + impl<'a> Serialize for TimestampMillis<&'a [PrimitiveDateTime]> { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer { + let mut seq = serializer.serialize_seq(Some(self.0.len()))?; + for t in self.0 { + serde::ser::SerializeSeq::serialize_element(&mut seq, &TimestampMillis(t))?; + } + serde::ser::SerializeSeq::end(seq) + } + } + + impl<'a> Serialize for TimestampMillis<&'a Vec> { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer { + TimestampMillis(&self.0[..]).serialize(serializer) + } + } + } } /// Treat an `Option` as a [Unix timestamp] for the purposes of @@ -34,11 +377,13 @@ pub fn deserialize<'a, D: Deserializer<'a>>(deserializer: D) -> Result` as its Unix timestamp + #[deprecated] pub fn serialize( option: &Option, serializer: S, @@ -49,6 +394,7 @@ pub mod option { } /// Deserialize an `Option` from its Unix timestamp + #[deprecated] pub fn deserialize<'a, D: Deserializer<'a>>( deserializer: D, ) -> Result, D::Error> { From fdb11ea8d43d01b45f73e80482c2bca444340812 Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 18 May 2023 13:23:00 +1000 Subject: [PATCH 2/3] Use AsWellKnown and FromWellKnown trait instead - Replaces intermediate structs - Allows for generic serialising/deserialising from a single function - Currently implemented for: - Timestamp/TimestampMillis - T,Option,Vec,[T] (ser only) --- .vscode/settings.json | 3 + time-macros/src/serde_types.rs | 0 time/src/serde/mod.rs | 132 +++++++++++ time/src/serde/timestamp.rs | 410 +++++++++++++++++++++------------ 4 files changed, 395 insertions(+), 150 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 time-macros/src/serde_types.rs diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000..7b2b22c3a5 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "rust-analyzer.cargo.features": "all" +} \ No newline at end of file diff --git a/time-macros/src/serde_types.rs b/time-macros/src/serde_types.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/time/src/serde/mod.rs b/time/src/serde/mod.rs index 844d7bdefa..f042a7b3d9 100644 --- a/time/src/serde/mod.rs +++ b/time/src/serde/mod.rs @@ -489,3 +489,135 @@ impl<'a> Deserialize<'a> for Month { } } // endregion Month + +pub trait AsWellKnown { + type IntoWellKnownError: core::fmt::Display; + type WellKnownSer<'s>: Serialize where Self: 's; + + fn as_well_known<'s>(&'s self) -> Result,Self::IntoWellKnownError>; + + fn fmt_err(error : Self::IntoWellKnownError) -> E { + E::custom(error) + } + + #[inline] + fn serialize_from_wellknown(&self, serializer : S) -> Result { + let wk = self.as_well_known().map_err(Self::fmt_err)?; + wk.serialize(serializer) + } +} + +impl AsWellKnown for Option + where T : AsWellKnown { + + type IntoWellKnownError = T::IntoWellKnownError; + + type WellKnownSer<'s> = Option> where Self: 's, T : 's; + + #[inline] + fn as_well_known<'s>(&'s self) -> Result,Self::IntoWellKnownError> { + self.as_ref().map(T::as_well_known).transpose() + } +} + +impl AsWellKnown for [T] + where T : AsWellKnown { + + type IntoWellKnownError = T::IntoWellKnownError; + + type WellKnownSer<'s> = Vec> where Self: 's, T : 's; + + #[inline] + fn as_well_known<'s>(&'s self) -> Result,Self::IntoWellKnownError> { + self.iter().map(T::as_well_known).collect::>() + } + + #[inline] + fn fmt_err(error : Self::IntoWellKnownError) -> E { + T::fmt_err(error) + } + + fn serialize_from_wellknown(&self, serializer : S) -> Result { + let mut seq = serializer.serialize_seq(Some(self.len()))?; + + for i in self { + let tmp = i.as_well_known().map_err(T::fmt_err)?; + + serde::ser::SerializeSeq::serialize_element(&mut seq, &tmp)?; + } + + serde::ser::SerializeSeq::end(seq) + } +} + + +impl AsWellKnown for Vec + where T : AsWellKnown { + + type IntoWellKnownError = T::IntoWellKnownError; + + type WellKnownSer<'s> = Vec> where Self: 's, T : 's; + + #[inline] + fn as_well_known<'s>(&'s self) -> Result,Self::IntoWellKnownError> { + self.iter().map(T::as_well_known).collect::>() + } + + #[inline] + fn fmt_err(error : Self::IntoWellKnownError) -> E { + T::fmt_err(error) + } + + fn serialize_from_wellknown(&self, serializer : S) -> Result { + let mut seq = serializer.serialize_seq(Some(self.len()))?; + + for i in self { + let tmp = i.as_well_known() + .map_err(T::fmt_err)?; + + serde::ser::SerializeSeq::serialize_element(&mut seq, &tmp)?; + } + + serde::ser::SerializeSeq::end(seq) + } +} + +pub trait FromWellKnown: Sized { + type FromWellKnownError: std::fmt::Display; + type WellKnownDeser<'de>: Deserialize<'de> + 'de; + + fn from_well_known<'de>(wk : Self::WellKnownDeser<'de>) -> Result; + fn fmt_err(e : Self::FromWellKnownError) -> E { + E::custom(e) + } + + #[inline] + fn deserialize_from_well_known<'de,D : Deserializer<'de>>(deserializer : D) -> Result { + let wk = Self::WellKnownDeser::deserialize(deserializer)?; + Self::from_well_known(wk).map_err(Self::fmt_err) + } +} + +impl FromWellKnown for Option + where T : FromWellKnown { + type FromWellKnownError = T::FromWellKnownError; + + type WellKnownDeser<'de> = Option>; + + #[inline] + fn from_well_known<'de>(wk : Self::WellKnownDeser<'de>) -> Result { + wk.map(T::from_well_known).transpose() + } +} + +impl FromWellKnown for Vec + where T : FromWellKnown { + type FromWellKnownError = T::FromWellKnownError; + + type WellKnownDeser<'de> = Vec> where T::WellKnownDeser<'de>: 'de; + + #[inline] + fn from_well_known<'de>(wk : Self::WellKnownDeser<'de>) -> Result { + wk.into_iter().map(T::from_well_known).collect() + } +} \ No newline at end of file diff --git a/time/src/serde/timestamp.rs b/time/src/serde/timestamp.rs index 7592e5e96e..107a2ee83e 100644 --- a/time/src/serde/timestamp.rs +++ b/time/src/serde/timestamp.rs @@ -14,34 +14,85 @@ use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use crate::OffsetDateTime; use crate::PrimitiveDateTime; +use super::AsWellKnown; +use super::FromWellKnown; + /// Serialize an [`OffsetDateTime`] and [`PrimitiveDateTime`] as its Unix timestamp /// /// Also works with [`Option`], and [`Option`]. +#[inline(always)] pub fn serialize( - datetime: &T, + t: &T, serializer: S, ) -> Result - where for <'a> __private::Timestamp<&'a T> : Serialize { - Serialize::serialize(&__private::Timestamp(datetime),serializer) + where T : AsWellKnown { + t.serialize_from_wellknown(serializer) } /// Deserialize an `OffsetDateTime` from its Unix timestamp /// /// Also works with [`Option`], and [`Option`]. +#[inline(always)] pub fn deserialize<'a, D: Deserializer<'a>, T>(deserializer: D) -> Result - where __private::Timestamp : Deserialize<'a> { - let t = __private::Timestamp::deserialize(deserializer)?; - Ok(t.0) + where T : FromWellKnown { + T::deserialize_from_well_known(deserializer) +} + +pub struct Timestamp; + +impl AsWellKnown for OffsetDateTime { + type IntoWellKnownError = std::convert::Infallible; + + type WellKnownSer<'s> = i64 where Self: 's; + + fn as_well_known<'s>(&'s self) -> Result,Self::IntoWellKnownError> { + Ok(self.unix_timestamp()) + } +} + +impl FromWellKnown for OffsetDateTime { + type FromWellKnownError = crate::error::ComponentRange; + + type WellKnownDeser<'de> = i64; + + fn fmt_err(e : Self::FromWellKnownError) -> E { + E::invalid_value(serde::de::Unexpected::Signed(e.value),&e) + } + + fn from_well_known<'de>(wk : Self::WellKnownDeser<'de>) -> Result { + OffsetDateTime::from_unix_timestamp(wk) + } +} + + +impl AsWellKnown for PrimitiveDateTime { + type IntoWellKnownError = std::convert::Infallible; + + type WellKnownSer<'s> = i64 where Self: 's; + + fn as_well_known<'s>(&'s self) -> Result,Self::IntoWellKnownError> { + Ok(self.assume_utc().unix_timestamp()) + } } -fn drop_offset(v : OffsetDateTime) -> PrimitiveDateTime { - v.date().with_time(v.time()) +impl FromWellKnown for PrimitiveDateTime { + type FromWellKnownError = crate::error::ComponentRange; + + type WellKnownDeser<'de> = i64; + + fn from_well_known<'de>(wk : Self::WellKnownDeser<'de>) -> Result { + OffsetDateTime::from_unix_timestamp(wk) + .map( + |t| + t.date().with_time(t.time()) + ) + } } #[doc(hidden)] mod __private { - use super::*; + /* pub struct Timestamp(pub(super) T); impl<'de> Deserialize<'de> for Timestamp { @@ -181,7 +232,7 @@ mod __private { S: Serializer { Timestamp(&self.0[..]).serialize(serializer) } - } + }*/ } // Treat an [`OffsetDateTime`] as a [Unix timestamp (milliseconds)] for the purposes of serde. @@ -195,177 +246,236 @@ mod __private { pub mod millis { use super::*; - /// Serialize as a Unix timestamp in milliseconds + /// Serialize an [`OffsetDateTime`] and [`PrimitiveDateTime`] as its Unix timestamp in milliseconds + /// + /// Also works with [`Option`], and [`Option`]. + #[inline(always)] pub fn serialize( - datetime: &T, + t: &T, serializer: S, ) -> Result - where for <'a> private::TimestampMillis<&'a T> : Serialize { - Serialize::serialize(&private::TimestampMillis(datetime),serializer) + where T : AsWellKnown { + t.serialize_from_wellknown(serializer) } - /// Deserialize as a Unix timestamp in milliseconds + /// Deserialize an `OffsetDateTime` from its Unix timestamp in milliseconds + /// + /// Also works with [`Option`], and [`Option`]. + #[inline(always)] pub fn deserialize<'a, D: Deserializer<'a>, T>(deserializer: D) -> Result - where private::TimestampMillis : Deserialize<'a> { - let t = private::TimestampMillis::deserialize(deserializer)?; - Ok(t.0) + where T : FromWellKnown { + T::deserialize_from_well_known(deserializer) } - #[doc(hidden)] - mod private { - use super::*; + pub struct TimestampMillis; - fn from_i64(v : i64) -> Result { - let seconds = v / 1000; - let millis = v % 1000; + impl AsWellKnown for OffsetDateTime { + type IntoWellKnownError = std::convert::Infallible; - let d = - OffsetDateTime::from_unix_timestamp(seconds) - .map_err(|err| de::Error::invalid_value(de::Unexpected::Signed(err.value), &err))? - + crate::Duration::milliseconds(millis); - Ok(d) - } + type WellKnownSer<'s> = i64 where Self: 's; - fn to_i64(v : OffsetDateTime) -> i64 { - let seconds = v.unix_timestamp() * 1000; - seconds + v.millisecond() as i64 + fn as_well_known<'s>(&'s self) -> Result,Self::IntoWellKnownError> { + Ok((self.unix_timestamp_nanos() / 1_000_000) as i64) } + } - pub struct TimestampMillis(pub(super) T); + impl FromWellKnown for OffsetDateTime { + type FromWellKnownError = crate::error::ComponentRange; - impl<'de> Deserialize<'de> for TimestampMillis { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de> { - let timestamp : i64 = <_>::deserialize(deserializer)?; - - Ok(TimestampMillis(from_i64(timestamp)?)) - } + type WellKnownDeser<'de> = i64; + + fn fmt_err(e : Self::FromWellKnownError) -> E { + E::invalid_value(serde::de::Unexpected::Signed(e.value),&e) } - impl<'de> Deserialize<'de> for TimestampMillis> { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de> { - let d = Option::deserialize(deserializer)? - .map(from_i64) - .transpose()?; + fn from_well_known<'de>(timestamp : Self::WellKnownDeser<'de>) -> Result { + let secs = timestamp / 1_000; + let millis = timestamp % 1000; - Ok(TimestampMillis(d)) - } + Ok( + OffsetDateTime::from_unix_timestamp(secs)? + + crate::Duration::milliseconds(millis) + ) } + } - impl<'de> Deserialize<'de> for TimestampMillis> { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de> { - let t = Vec::deserialize(deserializer)?; - - Ok(TimestampMillis(t.into_iter().map(from_i64).collect::,_>>()?)) - } - } + impl AsWellKnown for PrimitiveDateTime { + type IntoWellKnownError = std::convert::Infallible; - impl<'a> Serialize for TimestampMillis<&'a OffsetDateTime> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer { - to_i64(*self.0).serialize(serializer) - } - } + type WellKnownSer<'s> = i64 where Self: 's; - impl<'a> Serialize for TimestampMillis<&'a Option> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer { - self.0.map(to_i64).serialize(serializer) - } + #[inline] + fn as_well_known<'s>(&'s self) -> Result,Self::IntoWellKnownError> { + Ok((self.assume_utc().unix_timestamp_nanos() / 1_000_000) as i64 ) } + } - impl<'a> Serialize for TimestampMillis<&'a [OffsetDateTime]> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer { - let mut seq = serializer.serialize_seq(Some(self.0.len()))?; - for t in self.0 { - serde::ser::SerializeSeq::serialize_element(&mut seq, &TimestampMillis(t))?; - } - serde::ser::SerializeSeq::end(seq) - } - } - - impl<'a> Serialize for TimestampMillis<&'a Vec> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer { - TimestampMillis(&self.0[..]).serialize(serializer) - } - } + impl FromWellKnown for PrimitiveDateTime { + type FromWellKnownError = crate::error::ComponentRange; - impl<'de> Deserialize<'de> for TimestampMillis { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de> { - let t : TimestampMillis = <_>::deserialize(deserializer)?; - Ok(TimestampMillis(t.0.date().with_time(t.0.time()))) - } + type WellKnownDeser<'de> = i64; + + fn from_well_known<'de>(wk : Self::WellKnownDeser<'de>) -> Result { + let t = >::from_well_known(wk)?; + Ok(t.date().with_time(t.time())) } + } + + // #[doc(hidden)] + // mod private { + // use super::*; + + // fn from_i64(v : i64) -> Result { + // let seconds = v / 1000; + // let millis = v % 1000; + + // let d = + // OffsetDateTime::from_unix_timestamp(seconds) + // .map_err(|err| de::Error::invalid_value(de::Unexpected::Signed(err.value), &err))? + // + crate::Duration::milliseconds(millis); + // Ok(d) + // } + + // fn to_i64(v : OffsetDateTime) -> i64 { + // let seconds = v.unix_timestamp() * 1000; + // seconds + v.millisecond() as i64 + // } + + // pub struct TimestampMillis(pub(super) T); + + // impl<'de> Deserialize<'de> for TimestampMillis { + // fn deserialize(deserializer: D) -> Result + // where + // D: Deserializer<'de> { + // let timestamp : i64 = <_>::deserialize(deserializer)?; + + // Ok(TimestampMillis(from_i64(timestamp)?)) + // } + // } + + // impl<'de> Deserialize<'de> for TimestampMillis> { + // fn deserialize(deserializer: D) -> Result + // where + // D: Deserializer<'de> { + // let d = Option::deserialize(deserializer)? + // .map(from_i64) + // .transpose()?; + + // Ok(TimestampMillis(d)) + // } + // } + + // impl<'de> Deserialize<'de> for TimestampMillis> { + // fn deserialize(deserializer: D) -> Result + // where + // D: Deserializer<'de> { + // let t = Vec::deserialize(deserializer)?; - impl<'de> Deserialize<'de> for TimestampMillis> { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de> { - let t : TimestampMillis> = <_>::deserialize(deserializer)?; + // Ok(TimestampMillis(t.into_iter().map(from_i64).collect::,_>>()?)) + // } + // } + + // impl<'a> Serialize for TimestampMillis<&'a OffsetDateTime> { + // fn serialize(&self, serializer: S) -> Result + // where + // S: Serializer { + // to_i64(*self.0).serialize(serializer) + // } + // } + + // impl<'a> Serialize for TimestampMillis<&'a Option> { + // fn serialize(&self, serializer: S) -> Result + // where + // S: Serializer { + // self.0.map(to_i64).serialize(serializer) + // } + // } + + // impl<'a> Serialize for TimestampMillis<&'a [OffsetDateTime]> { + // fn serialize(&self, serializer: S) -> Result + // where + // S: Serializer { + // let mut seq = serializer.serialize_seq(Some(self.0.len()))?; + // for t in self.0 { + // serde::ser::SerializeSeq::serialize_element(&mut seq, &TimestampMillis(t))?; + // } + // serde::ser::SerializeSeq::end(seq) + // } + // } - Ok(TimestampMillis(t.0.map(|t| t.date().with_time(t.time())))) - } - } - - impl<'de> Deserialize<'de> for TimestampMillis> { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de> { - let t : TimestampMillis> = <_>::deserialize(deserializer)?; + // impl<'a> Serialize for TimestampMillis<&'a Vec> { + // fn serialize(&self, serializer: S) -> Result + // where + // S: Serializer { + // TimestampMillis(&self.0[..]).serialize(serializer) + // } + // } + + // impl<'de> Deserialize<'de> for TimestampMillis { + // fn deserialize(deserializer: D) -> Result + // where + // D: Deserializer<'de> { + // let t : TimestampMillis = <_>::deserialize(deserializer)?; + // Ok(TimestampMillis(t.0.date().with_time(t.0.time()))) + // } + // } - Ok(TimestampMillis(t.0.into_iter().map(drop_offset).collect())) - } - } + // impl<'de> Deserialize<'de> for TimestampMillis> { + // fn deserialize(deserializer: D) -> Result + // where + // D: Deserializer<'de> { + // let t : TimestampMillis> = <_>::deserialize(deserializer)?; - impl<'a> Serialize for TimestampMillis<&'a PrimitiveDateTime> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer { - TimestampMillis(&self.0.assume_utc()).serialize(serializer) - } - } + // Ok(TimestampMillis(t.0.map(|t| t.date().with_time(t.time())))) + // } + // } + + // impl<'de> Deserialize<'de> for TimestampMillis> { + // fn deserialize(deserializer: D) -> Result + // where + // D: Deserializer<'de> { + // let t : TimestampMillis> = <_>::deserialize(deserializer)?; - impl<'a> Serialize for TimestampMillis<&'a Option> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer { - TimestampMillis(&self.0.map(|t| t.assume_utc())).serialize(serializer) - } - } - - impl<'a> Serialize for TimestampMillis<&'a [PrimitiveDateTime]> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer { - let mut seq = serializer.serialize_seq(Some(self.0.len()))?; - for t in self.0 { - serde::ser::SerializeSeq::serialize_element(&mut seq, &TimestampMillis(t))?; - } - serde::ser::SerializeSeq::end(seq) - } - } + // Ok(TimestampMillis(t.0.into_iter().map(drop_offset).collect())) + // } + // } - impl<'a> Serialize for TimestampMillis<&'a Vec> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer { - TimestampMillis(&self.0[..]).serialize(serializer) - } - } - } + // impl<'a> Serialize for TimestampMillis<&'a PrimitiveDateTime> { + // fn serialize(&self, serializer: S) -> Result + // where + // S: Serializer { + // TimestampMillis(&self.0.assume_utc()).serialize(serializer) + // } + // } + + // impl<'a> Serialize for TimestampMillis<&'a Option> { + // fn serialize(&self, serializer: S) -> Result + // where + // S: Serializer { + // TimestampMillis(&self.0.map(|t| t.assume_utc())).serialize(serializer) + // } + // } + + // impl<'a> Serialize for TimestampMillis<&'a [PrimitiveDateTime]> { + // fn serialize(&self, serializer: S) -> Result + // where + // S: Serializer { + // let mut seq = serializer.serialize_seq(Some(self.0.len()))?; + // for t in self.0 { + // serde::ser::SerializeSeq::serialize_element(&mut seq, &TimestampMillis(t))?; + // } + // serde::ser::SerializeSeq::end(seq) + // } + // } + + // impl<'a> Serialize for TimestampMillis<&'a Vec> { + // fn serialize(&self, serializer: S) -> Result + // where + // S: Serializer { + // TimestampMillis(&self.0[..]).serialize(serializer) + // } + // } + // } } /// Treat an `Option` as a [Unix timestamp] for the purposes of From 8d8e6091babb2f5d0491fecac29b575883eec2c5 Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 18 May 2023 13:27:43 +1000 Subject: [PATCH 3/3] rustfmt and removed previous generic serde attemp --- time/src/serde/mod.rs | 85 ++++---- time/src/serde/timestamp.rs | 401 +++++------------------------------- 2 files changed, 100 insertions(+), 386 deletions(-) diff --git a/time/src/serde/mod.rs b/time/src/serde/mod.rs index f042a7b3d9..d06cb263fb 100644 --- a/time/src/serde/mod.rs +++ b/time/src/serde/mod.rs @@ -492,52 +492,56 @@ impl<'a> Deserialize<'a> for Month { pub trait AsWellKnown { type IntoWellKnownError: core::fmt::Display; - type WellKnownSer<'s>: Serialize where Self: 's; + type WellKnownSer<'s>: Serialize + where + Self: 's; - fn as_well_known<'s>(&'s self) -> Result,Self::IntoWellKnownError>; + fn as_well_known<'s>(&'s self) -> Result, Self::IntoWellKnownError>; - fn fmt_err(error : Self::IntoWellKnownError) -> E { + fn fmt_err(error: Self::IntoWellKnownError) -> E { E::custom(error) } #[inline] - fn serialize_from_wellknown(&self, serializer : S) -> Result { + fn serialize_from_wellknown(&self, serializer: S) -> Result { let wk = self.as_well_known().map_err(Self::fmt_err)?; wk.serialize(serializer) } } -impl AsWellKnown for Option - where T : AsWellKnown { - +impl AsWellKnown for Option +where + T: AsWellKnown, +{ type IntoWellKnownError = T::IntoWellKnownError; type WellKnownSer<'s> = Option> where Self: 's, T : 's; #[inline] - fn as_well_known<'s>(&'s self) -> Result,Self::IntoWellKnownError> { + fn as_well_known<'s>(&'s self) -> Result, Self::IntoWellKnownError> { self.as_ref().map(T::as_well_known).transpose() } } -impl AsWellKnown for [T] - where T : AsWellKnown { - +impl AsWellKnown for [T] +where + T: AsWellKnown, +{ type IntoWellKnownError = T::IntoWellKnownError; type WellKnownSer<'s> = Vec> where Self: 's, T : 's; #[inline] - fn as_well_known<'s>(&'s self) -> Result,Self::IntoWellKnownError> { - self.iter().map(T::as_well_known).collect::>() + fn as_well_known<'s>(&'s self) -> Result, Self::IntoWellKnownError> { + self.iter().map(T::as_well_known).collect::>() } #[inline] - fn fmt_err(error : Self::IntoWellKnownError) -> E { + fn fmt_err(error: Self::IntoWellKnownError) -> E { T::fmt_err(error) } - fn serialize_from_wellknown(&self, serializer : S) -> Result { + fn serialize_from_wellknown(&self, serializer: S) -> Result { let mut seq = serializer.serialize_seq(Some(self.len()))?; for i in self { @@ -550,30 +554,29 @@ impl AsWellKnown for [T] } } - -impl AsWellKnown for Vec - where T : AsWellKnown { - +impl AsWellKnown for Vec +where + T: AsWellKnown, +{ type IntoWellKnownError = T::IntoWellKnownError; type WellKnownSer<'s> = Vec> where Self: 's, T : 's; #[inline] - fn as_well_known<'s>(&'s self) -> Result,Self::IntoWellKnownError> { - self.iter().map(T::as_well_known).collect::>() + fn as_well_known<'s>(&'s self) -> Result, Self::IntoWellKnownError> { + self.iter().map(T::as_well_known).collect::>() } #[inline] - fn fmt_err(error : Self::IntoWellKnownError) -> E { + fn fmt_err(error: Self::IntoWellKnownError) -> E { T::fmt_err(error) } - fn serialize_from_wellknown(&self, serializer : S) -> Result { + fn serialize_from_wellknown(&self, serializer: S) -> Result { let mut seq = serializer.serialize_seq(Some(self.len()))?; for i in self { - let tmp = i.as_well_known() - .map_err(T::fmt_err)?; + let tmp = i.as_well_known().map_err(T::fmt_err)?; serde::ser::SerializeSeq::serialize_element(&mut seq, &tmp)?; } @@ -586,38 +589,50 @@ pub trait FromWellKnown: Sized { type FromWellKnownError: std::fmt::Display; type WellKnownDeser<'de>: Deserialize<'de> + 'de; - fn from_well_known<'de>(wk : Self::WellKnownDeser<'de>) -> Result; - fn fmt_err(e : Self::FromWellKnownError) -> E { + fn from_well_known<'de>( + wk: Self::WellKnownDeser<'de>, + ) -> Result; + fn fmt_err(e: Self::FromWellKnownError) -> E { E::custom(e) } #[inline] - fn deserialize_from_well_known<'de,D : Deserializer<'de>>(deserializer : D) -> Result { + fn deserialize_from_well_known<'de, D: Deserializer<'de>>( + deserializer: D, + ) -> Result { let wk = Self::WellKnownDeser::deserialize(deserializer)?; Self::from_well_known(wk).map_err(Self::fmt_err) } } -impl FromWellKnown for Option - where T : FromWellKnown { +impl FromWellKnown for Option +where + T: FromWellKnown, +{ type FromWellKnownError = T::FromWellKnownError; type WellKnownDeser<'de> = Option>; #[inline] - fn from_well_known<'de>(wk : Self::WellKnownDeser<'de>) -> Result { + fn from_well_known<'de>( + wk: Self::WellKnownDeser<'de>, + ) -> Result { wk.map(T::from_well_known).transpose() } } -impl FromWellKnown for Vec - where T : FromWellKnown { +impl FromWellKnown for Vec +where + T: FromWellKnown, +{ type FromWellKnownError = T::FromWellKnownError; type WellKnownDeser<'de> = Vec> where T::WellKnownDeser<'de>: 'de; #[inline] - fn from_well_known<'de>(wk : Self::WellKnownDeser<'de>) -> Result { + fn from_well_known<'de>( + wk: Self::WellKnownDeser<'de>, + ) -> Result { wk.into_iter().map(T::from_well_known).collect() } -} \ No newline at end of file +} diff --git a/time/src/serde/timestamp.rs b/time/src/serde/timestamp.rs index 107a2ee83e..46cdd221f0 100644 --- a/time/src/serde/timestamp.rs +++ b/time/src/serde/timestamp.rs @@ -1,9 +1,10 @@ -//! Treat an [`OffsetDateTime`] and [`PrimitiveDateTime`] as a [Unix timestamp] for the purposes of serde. +//! Treat an [`OffsetDateTime`] and [`PrimitiveDateTime`] as a [Unix timestamp] for the purposes of +//! serde. //! //! Use this module in combination with serde's [`#[with]`][with] attribute. //! //! When deserializing, the offset is assumed to be UTC. -//! +//! //! Also works with [`Option`], and [`Option`]. //! //! [Unix timestamp]: https://en.wikipedia.org/wiki/Unix_time @@ -11,30 +12,28 @@ use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; -use crate::OffsetDateTime; -use crate::PrimitiveDateTime; - -use super::AsWellKnown; -use super::FromWellKnown; +use super::{AsWellKnown, FromWellKnown}; +use crate::{OffsetDateTime, PrimitiveDateTime}; /// Serialize an [`OffsetDateTime`] and [`PrimitiveDateTime`] as its Unix timestamp -/// +/// /// Also works with [`Option`], and [`Option`]. #[inline(always)] -pub fn serialize( - t: &T, - serializer: S, -) -> Result - where T : AsWellKnown { +pub fn serialize(t: &T, serializer: S) -> Result +where + T: AsWellKnown, +{ t.serialize_from_wellknown(serializer) } /// Deserialize an `OffsetDateTime` from its Unix timestamp -/// +/// /// Also works with [`Option`], and [`Option`]. #[inline(always)] -pub fn deserialize<'a, D: Deserializer<'a>, T>(deserializer: D) -> Result - where T : FromWellKnown { +pub fn deserialize<'a, D: Deserializer<'a>, T>(deserializer: D) -> Result +where + T: FromWellKnown, +{ T::deserialize_from_well_known(deserializer) } @@ -45,7 +44,7 @@ impl AsWellKnown for OffsetDateTime { type WellKnownSer<'s> = i64 where Self: 's; - fn as_well_known<'s>(&'s self) -> Result,Self::IntoWellKnownError> { + fn as_well_known<'s>(&'s self) -> Result, Self::IntoWellKnownError> { Ok(self.unix_timestamp()) } } @@ -55,22 +54,23 @@ impl FromWellKnown for OffsetDateTime { type WellKnownDeser<'de> = i64; - fn fmt_err(e : Self::FromWellKnownError) -> E { - E::invalid_value(serde::de::Unexpected::Signed(e.value),&e) + fn fmt_err(e: Self::FromWellKnownError) -> E { + E::invalid_value(serde::de::Unexpected::Signed(e.value), &e) } - fn from_well_known<'de>(wk : Self::WellKnownDeser<'de>) -> Result { + fn from_well_known<'de>( + wk: Self::WellKnownDeser<'de>, + ) -> Result { OffsetDateTime::from_unix_timestamp(wk) } } - impl AsWellKnown for PrimitiveDateTime { type IntoWellKnownError = std::convert::Infallible; type WellKnownSer<'s> = i64 where Self: 's; - fn as_well_known<'s>(&'s self) -> Result,Self::IntoWellKnownError> { + fn as_well_known<'s>(&'s self) -> Result, Self::IntoWellKnownError> { Ok(self.assume_utc().unix_timestamp()) } } @@ -80,161 +80,13 @@ impl FromWellKnown for PrimitiveDateTime { type WellKnownDeser<'de> = i64; - fn from_well_known<'de>(wk : Self::WellKnownDeser<'de>) -> Result { - OffsetDateTime::from_unix_timestamp(wk) - .map( - |t| - t.date().with_time(t.time()) - ) + fn from_well_known<'de>( + wk: Self::WellKnownDeser<'de>, + ) -> Result { + OffsetDateTime::from_unix_timestamp(wk).map(|t| t.date().with_time(t.time())) } } -#[doc(hidden)] -mod __private { - - /* - pub struct Timestamp(pub(super) T); - - impl<'de> Deserialize<'de> for Timestamp { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de> { - let d = - OffsetDateTime::from_unix_timestamp(<_>::deserialize(deserializer)?) - .map_err(|err| de::Error::invalid_value(de::Unexpected::Signed(err.value), &err))?; - Ok(Timestamp(d)) - } - } - - impl<'de> Deserialize<'de> for Timestamp> { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de> { - let d = Option::deserialize(deserializer)? - .map(OffsetDateTime::from_unix_timestamp) - .transpose() - .map_err(|err| de::Error::invalid_value(de::Unexpected::Signed(err.value), &err))?; - - Ok(Timestamp(d)) - } - } - - impl<'de> Deserialize<'de> for Timestamp> { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de> { - let d = Vec::deserialize(deserializer)? - .into_iter() - .map(OffsetDateTime::from_unix_timestamp) - .collect::>() - .map_err(|err| de::Error::invalid_value(de::Unexpected::Signed(err.value), &err))?; - - Ok(Timestamp(d)) - } - } - - impl<'a> Serialize for Timestamp<&'a OffsetDateTime> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer { - self.0.unix_timestamp().serialize(serializer) - } - } - - impl<'a> Serialize for Timestamp<&'a Option> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer { - self.0.map(OffsetDateTime::unix_timestamp).serialize(serializer) - } - } - - impl<'a> Serialize for Timestamp<&'a [OffsetDateTime]> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer { - let mut seq = serializer.serialize_seq(Some(self.0.len()))?; - for t in self.0 { - serde::ser::SerializeSeq::serialize_element(&mut seq, &Timestamp(t))?; - } - serde::ser::SerializeSeq::end(seq) - } - } - - impl<'a> Serialize for Timestamp<&'a Vec> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer { - Timestamp(&self.0[..]).serialize(serializer) - } - } - - impl<'de> Deserialize<'de> for Timestamp { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de> { - let t : Timestamp = <_>::deserialize(deserializer)?; - Ok(Timestamp(t.0.date().with_time(t.0.time()))) - } - } - - impl<'de> Deserialize<'de> for Timestamp> { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de> { - let t : Timestamp> = <_>::deserialize(deserializer)?; - - Ok(Timestamp(t.0.map(|t| t.date().with_time(t.time())))) - } - } - - impl<'de> Deserialize<'de> for Timestamp> { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de> { - let t : Timestamp> = <_>::deserialize(deserializer)?; - - Ok(Timestamp(t.0.into_iter().map(|t| t.date().with_time(t.time())).collect())) - } - } - - impl<'a> Serialize for Timestamp<&'a PrimitiveDateTime> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer { - Timestamp(&self.0.assume_utc()).serialize(serializer) - } - } - - impl<'a> Serialize for Timestamp<&'a Option> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer { - Timestamp(&self.0.map(|t| t.assume_utc())).serialize(serializer) - } - } - - impl<'a> Serialize for Timestamp<&'a [PrimitiveDateTime]> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer { - let mut seq = serializer.serialize_seq(Some(self.0.len()))?; - for t in self.0 { - serde::ser::SerializeSeq::serialize_element(&mut seq, &Timestamp(t))?; - } - serde::ser::SerializeSeq::end(seq) - } - } - - impl<'a> Serialize for Timestamp<&'a Vec> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer { - Timestamp(&self.0[..]).serialize(serializer) - } - }*/ -} - // Treat an [`OffsetDateTime`] as a [Unix timestamp (milliseconds)] for the purposes of serde. // // Use this module in combination with serde's [`#[with]`][with] attribute. @@ -246,24 +98,26 @@ mod __private { pub mod millis { use super::*; - /// Serialize an [`OffsetDateTime`] and [`PrimitiveDateTime`] as its Unix timestamp in milliseconds - /// + /// Serialize an [`OffsetDateTime`] and [`PrimitiveDateTime`] as its Unix timestamp in + /// milliseconds + /// /// Also works with [`Option`], and [`Option`]. #[inline(always)] - pub fn serialize( - t: &T, - serializer: S, - ) -> Result - where T : AsWellKnown { + pub fn serialize(t: &T, serializer: S) -> Result + where + T: AsWellKnown, + { t.serialize_from_wellknown(serializer) } /// Deserialize an `OffsetDateTime` from its Unix timestamp in milliseconds - /// + /// /// Also works with [`Option`], and [`Option`]. #[inline(always)] - pub fn deserialize<'a, D: Deserializer<'a>, T>(deserializer: D) -> Result - where T : FromWellKnown { + pub fn deserialize<'a, D: Deserializer<'a>, T>(deserializer: D) -> Result + where + T: FromWellKnown, + { T::deserialize_from_well_known(deserializer) } @@ -274,7 +128,7 @@ pub mod millis { type WellKnownSer<'s> = i64 where Self: 's; - fn as_well_known<'s>(&'s self) -> Result,Self::IntoWellKnownError> { + fn as_well_known<'s>(&'s self) -> Result, Self::IntoWellKnownError> { Ok((self.unix_timestamp_nanos() / 1_000_000) as i64) } } @@ -284,18 +138,17 @@ pub mod millis { type WellKnownDeser<'de> = i64; - fn fmt_err(e : Self::FromWellKnownError) -> E { - E::invalid_value(serde::de::Unexpected::Signed(e.value),&e) + fn fmt_err(e: Self::FromWellKnownError) -> E { + E::invalid_value(serde::de::Unexpected::Signed(e.value), &e) } - fn from_well_known<'de>(timestamp : Self::WellKnownDeser<'de>) -> Result { + fn from_well_known<'de>( + timestamp: Self::WellKnownDeser<'de>, + ) -> Result { let secs = timestamp / 1_000; let millis = timestamp % 1000; - Ok( - OffsetDateTime::from_unix_timestamp(secs)? + - crate::Duration::milliseconds(millis) - ) + Ok(OffsetDateTime::from_unix_timestamp(secs)? + crate::Duration::milliseconds(millis)) } } @@ -305,8 +158,8 @@ pub mod millis { type WellKnownSer<'s> = i64 where Self: 's; #[inline] - fn as_well_known<'s>(&'s self) -> Result,Self::IntoWellKnownError> { - Ok((self.assume_utc().unix_timestamp_nanos() / 1_000_000) as i64 ) + fn as_well_known<'s>(&'s self) -> Result, Self::IntoWellKnownError> { + Ok((self.assume_utc().unix_timestamp_nanos() / 1_000_000) as i64) } } @@ -315,167 +168,13 @@ pub mod millis { type WellKnownDeser<'de> = i64; - fn from_well_known<'de>(wk : Self::WellKnownDeser<'de>) -> Result { + fn from_well_known<'de>( + wk: Self::WellKnownDeser<'de>, + ) -> Result { let t = >::from_well_known(wk)?; Ok(t.date().with_time(t.time())) } } - - // #[doc(hidden)] - // mod private { - // use super::*; - - // fn from_i64(v : i64) -> Result { - // let seconds = v / 1000; - // let millis = v % 1000; - - // let d = - // OffsetDateTime::from_unix_timestamp(seconds) - // .map_err(|err| de::Error::invalid_value(de::Unexpected::Signed(err.value), &err))? - // + crate::Duration::milliseconds(millis); - // Ok(d) - // } - - // fn to_i64(v : OffsetDateTime) -> i64 { - // let seconds = v.unix_timestamp() * 1000; - // seconds + v.millisecond() as i64 - // } - - // pub struct TimestampMillis(pub(super) T); - - // impl<'de> Deserialize<'de> for TimestampMillis { - // fn deserialize(deserializer: D) -> Result - // where - // D: Deserializer<'de> { - // let timestamp : i64 = <_>::deserialize(deserializer)?; - - // Ok(TimestampMillis(from_i64(timestamp)?)) - // } - // } - - // impl<'de> Deserialize<'de> for TimestampMillis> { - // fn deserialize(deserializer: D) -> Result - // where - // D: Deserializer<'de> { - // let d = Option::deserialize(deserializer)? - // .map(from_i64) - // .transpose()?; - - // Ok(TimestampMillis(d)) - // } - // } - - // impl<'de> Deserialize<'de> for TimestampMillis> { - // fn deserialize(deserializer: D) -> Result - // where - // D: Deserializer<'de> { - // let t = Vec::deserialize(deserializer)?; - - // Ok(TimestampMillis(t.into_iter().map(from_i64).collect::,_>>()?)) - // } - // } - - // impl<'a> Serialize for TimestampMillis<&'a OffsetDateTime> { - // fn serialize(&self, serializer: S) -> Result - // where - // S: Serializer { - // to_i64(*self.0).serialize(serializer) - // } - // } - - // impl<'a> Serialize for TimestampMillis<&'a Option> { - // fn serialize(&self, serializer: S) -> Result - // where - // S: Serializer { - // self.0.map(to_i64).serialize(serializer) - // } - // } - - // impl<'a> Serialize for TimestampMillis<&'a [OffsetDateTime]> { - // fn serialize(&self, serializer: S) -> Result - // where - // S: Serializer { - // let mut seq = serializer.serialize_seq(Some(self.0.len()))?; - // for t in self.0 { - // serde::ser::SerializeSeq::serialize_element(&mut seq, &TimestampMillis(t))?; - // } - // serde::ser::SerializeSeq::end(seq) - // } - // } - - // impl<'a> Serialize for TimestampMillis<&'a Vec> { - // fn serialize(&self, serializer: S) -> Result - // where - // S: Serializer { - // TimestampMillis(&self.0[..]).serialize(serializer) - // } - // } - - // impl<'de> Deserialize<'de> for TimestampMillis { - // fn deserialize(deserializer: D) -> Result - // where - // D: Deserializer<'de> { - // let t : TimestampMillis = <_>::deserialize(deserializer)?; - // Ok(TimestampMillis(t.0.date().with_time(t.0.time()))) - // } - // } - - // impl<'de> Deserialize<'de> for TimestampMillis> { - // fn deserialize(deserializer: D) -> Result - // where - // D: Deserializer<'de> { - // let t : TimestampMillis> = <_>::deserialize(deserializer)?; - - // Ok(TimestampMillis(t.0.map(|t| t.date().with_time(t.time())))) - // } - // } - - // impl<'de> Deserialize<'de> for TimestampMillis> { - // fn deserialize(deserializer: D) -> Result - // where - // D: Deserializer<'de> { - // let t : TimestampMillis> = <_>::deserialize(deserializer)?; - - // Ok(TimestampMillis(t.0.into_iter().map(drop_offset).collect())) - // } - // } - - // impl<'a> Serialize for TimestampMillis<&'a PrimitiveDateTime> { - // fn serialize(&self, serializer: S) -> Result - // where - // S: Serializer { - // TimestampMillis(&self.0.assume_utc()).serialize(serializer) - // } - // } - - // impl<'a> Serialize for TimestampMillis<&'a Option> { - // fn serialize(&self, serializer: S) -> Result - // where - // S: Serializer { - // TimestampMillis(&self.0.map(|t| t.assume_utc())).serialize(serializer) - // } - // } - - // impl<'a> Serialize for TimestampMillis<&'a [PrimitiveDateTime]> { - // fn serialize(&self, serializer: S) -> Result - // where - // S: Serializer { - // let mut seq = serializer.serialize_seq(Some(self.0.len()))?; - // for t in self.0 { - // serde::ser::SerializeSeq::serialize_element(&mut seq, &TimestampMillis(t))?; - // } - // serde::ser::SerializeSeq::end(seq) - // } - // } - - // impl<'a> Serialize for TimestampMillis<&'a Vec> { - // fn serialize(&self, serializer: S) -> Result - // where - // S: Serializer { - // TimestampMillis(&self.0[..]).serialize(serializer) - // } - // } - // } } /// Treat an `Option` as a [Unix timestamp] for the purposes of