mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-28 12:15:40 +08:00
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Co-authored-by: Gnanasundari24 <118818938+Gnanasundari24@users.noreply.github.com>
298 lines
10 KiB
Rust
298 lines
10 KiB
Rust
//! Custom serialization/deserialization implementations.
|
|
|
|
/// Use the well-known ISO 8601 format when serializing and deserializing an
|
|
/// [`PrimitiveDateTime`][PrimitiveDateTime].
|
|
///
|
|
/// [PrimitiveDateTime]: ::time::PrimitiveDateTime
|
|
pub mod iso8601 {
|
|
use std::num::NonZeroU8;
|
|
|
|
use serde::{ser::Error as _, Deserializer, Serialize, Serializer};
|
|
use time::{
|
|
format_description::well_known::{
|
|
iso8601::{Config, EncodedConfig, TimePrecision},
|
|
Iso8601,
|
|
},
|
|
serde::iso8601,
|
|
PrimitiveDateTime, UtcOffset,
|
|
};
|
|
|
|
const FORMAT_CONFIG: EncodedConfig = Config::DEFAULT
|
|
.set_time_precision(TimePrecision::Second {
|
|
decimal_digits: NonZeroU8::new(3),
|
|
})
|
|
.encode();
|
|
|
|
/// Serialize a [`PrimitiveDateTime`] using the well-known ISO 8601 format.
|
|
pub fn serialize<S>(date_time: &PrimitiveDateTime, serializer: S) -> Result<S::Ok, S::Error>
|
|
where
|
|
S: Serializer,
|
|
{
|
|
date_time
|
|
.assume_utc()
|
|
.format(&Iso8601::<FORMAT_CONFIG>)
|
|
.map_err(S::Error::custom)?
|
|
.serialize(serializer)
|
|
}
|
|
|
|
/// Deserialize an [`PrimitiveDateTime`] from its ISO 8601 representation.
|
|
pub fn deserialize<'a, D>(deserializer: D) -> Result<PrimitiveDateTime, D::Error>
|
|
where
|
|
D: Deserializer<'a>,
|
|
{
|
|
iso8601::deserialize(deserializer).map(|offset_date_time| {
|
|
let utc_date_time = offset_date_time.to_offset(UtcOffset::UTC);
|
|
PrimitiveDateTime::new(utc_date_time.date(), utc_date_time.time())
|
|
})
|
|
}
|
|
|
|
/// Use the well-known ISO 8601 format when serializing and deserializing an
|
|
/// [`Option<PrimitiveDateTime>`][PrimitiveDateTime].
|
|
///
|
|
/// [PrimitiveDateTime]: ::time::PrimitiveDateTime
|
|
pub mod option {
|
|
use serde::Serialize;
|
|
use time::format_description::well_known::Iso8601;
|
|
|
|
use super::*;
|
|
|
|
/// Serialize an [`Option<PrimitiveDateTime>`] using the well-known ISO 8601 format.
|
|
pub fn serialize<S>(
|
|
date_time: &Option<PrimitiveDateTime>,
|
|
serializer: S,
|
|
) -> Result<S::Ok, S::Error>
|
|
where
|
|
S: Serializer,
|
|
{
|
|
date_time
|
|
.map(|date_time| date_time.assume_utc().format(&Iso8601::<FORMAT_CONFIG>))
|
|
.transpose()
|
|
.map_err(S::Error::custom)?
|
|
.serialize(serializer)
|
|
}
|
|
|
|
/// Deserialize an [`Option<PrimitiveDateTime>`] from its ISO 8601 representation.
|
|
pub fn deserialize<'a, D>(deserializer: D) -> Result<Option<PrimitiveDateTime>, D::Error>
|
|
where
|
|
D: Deserializer<'a>,
|
|
{
|
|
iso8601::option::deserialize(deserializer).map(|option_offset_date_time| {
|
|
option_offset_date_time.map(|offset_date_time| {
|
|
let utc_date_time = offset_date_time.to_offset(UtcOffset::UTC);
|
|
PrimitiveDateTime::new(utc_date_time.date(), utc_date_time.time())
|
|
})
|
|
})
|
|
}
|
|
}
|
|
/// Use the well-known ISO 8601 format which is without timezone when serializing and deserializing an
|
|
/// [`Option<PrimitiveDateTime>`][PrimitiveDateTime].
|
|
///
|
|
/// [PrimitiveDateTime]: ::time::PrimitiveDateTime
|
|
pub mod option_without_timezone {
|
|
use serde::{de, Deserialize, Serialize};
|
|
use time::macros::format_description;
|
|
|
|
use super::*;
|
|
|
|
/// Serialize an [`Option<PrimitiveDateTime>`] using the well-known ISO 8601 format which is without timezone.
|
|
pub fn serialize<S>(
|
|
date_time: &Option<PrimitiveDateTime>,
|
|
serializer: S,
|
|
) -> Result<S::Ok, S::Error>
|
|
where
|
|
S: Serializer,
|
|
{
|
|
date_time
|
|
.map(|date_time| {
|
|
let format =
|
|
format_description!("[year]-[month]-[day]T[hour]:[minute]:[second]");
|
|
date_time.assume_utc().format(format)
|
|
})
|
|
.transpose()
|
|
.map_err(S::Error::custom)?
|
|
.serialize(serializer)
|
|
}
|
|
|
|
/// Deserialize an [`Option<PrimitiveDateTime>`] from its ISO 8601 representation.
|
|
pub fn deserialize<'a, D>(deserializer: D) -> Result<Option<PrimitiveDateTime>, D::Error>
|
|
where
|
|
D: Deserializer<'a>,
|
|
{
|
|
Option::deserialize(deserializer)?
|
|
.map(|time_string| {
|
|
let format =
|
|
format_description!("[year]-[month]-[day]T[hour]:[minute]:[second]");
|
|
PrimitiveDateTime::parse(time_string, format).map_err(|_| {
|
|
de::Error::custom(format!(
|
|
"Failed to parse PrimitiveDateTime from {time_string}"
|
|
))
|
|
})
|
|
})
|
|
.transpose()
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Use the UNIX timestamp when serializing and deserializing an
|
|
/// [`PrimitiveDateTime`][PrimitiveDateTime].
|
|
///
|
|
/// [PrimitiveDateTime]: ::time::PrimitiveDateTime
|
|
pub mod timestamp {
|
|
|
|
use serde::{Deserializer, Serialize, Serializer};
|
|
use time::{serde::timestamp, PrimitiveDateTime, UtcOffset};
|
|
|
|
/// Serialize a [`PrimitiveDateTime`] using UNIX timestamp.
|
|
pub fn serialize<S>(date_time: &PrimitiveDateTime, serializer: S) -> Result<S::Ok, S::Error>
|
|
where
|
|
S: Serializer,
|
|
{
|
|
date_time
|
|
.assume_utc()
|
|
.unix_timestamp()
|
|
.serialize(serializer)
|
|
}
|
|
|
|
/// Deserialize an [`PrimitiveDateTime`] from UNIX timestamp.
|
|
pub fn deserialize<'a, D>(deserializer: D) -> Result<PrimitiveDateTime, D::Error>
|
|
where
|
|
D: Deserializer<'a>,
|
|
{
|
|
timestamp::deserialize(deserializer).map(|offset_date_time| {
|
|
let utc_date_time = offset_date_time.to_offset(UtcOffset::UTC);
|
|
PrimitiveDateTime::new(utc_date_time.date(), utc_date_time.time())
|
|
})
|
|
}
|
|
|
|
/// Use the UNIX timestamp when serializing and deserializing an
|
|
/// [`Option<PrimitiveDateTime>`][PrimitiveDateTime].
|
|
///
|
|
/// [PrimitiveDateTime]: ::time::PrimitiveDateTime
|
|
pub mod option {
|
|
use serde::Serialize;
|
|
|
|
use super::*;
|
|
|
|
/// Serialize an [`Option<PrimitiveDateTime>`] from UNIX timestamp.
|
|
pub fn serialize<S>(
|
|
date_time: &Option<PrimitiveDateTime>,
|
|
serializer: S,
|
|
) -> Result<S::Ok, S::Error>
|
|
where
|
|
S: Serializer,
|
|
{
|
|
date_time
|
|
.map(|date_time| date_time.assume_utc().unix_timestamp())
|
|
.serialize(serializer)
|
|
}
|
|
|
|
/// Deserialize an [`Option<PrimitiveDateTime>`] from UNIX timestamp.
|
|
pub fn deserialize<'a, D>(deserializer: D) -> Result<Option<PrimitiveDateTime>, D::Error>
|
|
where
|
|
D: Deserializer<'a>,
|
|
{
|
|
timestamp::option::deserialize(deserializer).map(|option_offset_date_time| {
|
|
option_offset_date_time.map(|offset_date_time| {
|
|
let utc_date_time = offset_date_time.to_offset(UtcOffset::UTC);
|
|
PrimitiveDateTime::new(utc_date_time.date(), utc_date_time.time())
|
|
})
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <https://github.com/serde-rs/serde/issues/994#issuecomment-316895860>
|
|
pub mod json_string {
|
|
use serde::{
|
|
de::{self, Deserialize, DeserializeOwned, Deserializer},
|
|
ser::{self, Serialize, Serializer},
|
|
};
|
|
|
|
/// Serialize a type to json_string format
|
|
pub fn serialize<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
|
|
where
|
|
T: Serialize,
|
|
S: Serializer,
|
|
{
|
|
let j = serde_json::to_string(value).map_err(ser::Error::custom)?;
|
|
j.serialize(serializer)
|
|
}
|
|
|
|
/// Deserialize a string which is in json format
|
|
pub fn deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error>
|
|
where
|
|
T: DeserializeOwned,
|
|
D: Deserializer<'de>,
|
|
{
|
|
let j = String::deserialize(deserializer)?;
|
|
serde_json::from_str(&j).map_err(de::Error::custom)
|
|
}
|
|
}
|
|
|
|
/// Use a custom ISO 8601 format when serializing and deserializing
|
|
/// [`PrimitiveDateTime`][PrimitiveDateTime].
|
|
///
|
|
/// [PrimitiveDateTime]: ::time::PrimitiveDateTime
|
|
pub mod iso8601custom {
|
|
|
|
use serde::{ser::Error as _, Deserializer, Serialize, Serializer};
|
|
use time::{
|
|
format_description::well_known::{
|
|
iso8601::{Config, EncodedConfig, TimePrecision},
|
|
Iso8601,
|
|
},
|
|
serde::iso8601,
|
|
PrimitiveDateTime, UtcOffset,
|
|
};
|
|
|
|
const FORMAT_CONFIG: EncodedConfig = Config::DEFAULT
|
|
.set_time_precision(TimePrecision::Second {
|
|
decimal_digits: None,
|
|
})
|
|
.encode();
|
|
|
|
/// Serialize a [`PrimitiveDateTime`] using the well-known ISO 8601 format.
|
|
pub fn serialize<S>(date_time: &PrimitiveDateTime, serializer: S) -> Result<S::Ok, S::Error>
|
|
where
|
|
S: Serializer,
|
|
{
|
|
date_time
|
|
.assume_utc()
|
|
.format(&Iso8601::<FORMAT_CONFIG>)
|
|
.map_err(S::Error::custom)?
|
|
.replace('T', " ")
|
|
.replace('Z', "")
|
|
.serialize(serializer)
|
|
}
|
|
|
|
/// Deserialize an [`PrimitiveDateTime`] from its ISO 8601 representation.
|
|
pub fn deserialize<'a, D>(deserializer: D) -> Result<PrimitiveDateTime, D::Error>
|
|
where
|
|
D: Deserializer<'a>,
|
|
{
|
|
iso8601::deserialize(deserializer).map(|offset_date_time| {
|
|
let utc_date_time = offset_date_time.to_offset(UtcOffset::UTC);
|
|
PrimitiveDateTime::new(utc_date_time.date(), utc_date_time.time())
|
|
})
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use serde::{Deserialize, Serialize};
|
|
use serde_json::json;
|
|
|
|
#[test]
|
|
fn test_leap_second_parse() {
|
|
#[derive(Serialize, Deserialize)]
|
|
struct Try {
|
|
#[serde(with = "crate::custom_serde::iso8601")]
|
|
f: time::PrimitiveDateTime,
|
|
}
|
|
let leap_second_date_time = json!({"f": "2023-12-31T23:59:60.000Z"});
|
|
let deser = serde_json::from_value::<Try>(leap_second_date_time);
|
|
|
|
assert!(deser.is_ok())
|
|
}
|
|
}
|