#![doc = r#"Module with serde helpers and utilities."#]
pub mod naive_time {
use chrono::NaiveTime;
use serde::{de::Error, Deserialize, Deserializer, Serializer};
pub fn get_raw_value(t: &NaiveTime) -> String {
let mut st = t.to_string();
st.push('Z');
st
}
pub fn serialize<S: Serializer>(t: &NaiveTime, ser: S) -> Result<S::Ok, S::Error> {
ser.serialize_str(get_raw_value(t).as_str())
}
pub fn deserialize<'de, D: Deserializer<'de>>(de: D) -> Result<NaiveTime, D::Error> {
let st = String::deserialize(de)?;
if let Some(s) = st.strip_suffix('Z') {
match s.parse() {
Err(e) => Err(D::Error::custom(e)),
Ok(v) => Ok(v),
}
} else {
Err(D::Error::custom("Expected 'Z' tz suffix"))
}
}
}
pub mod naive_time_opt {
use super::naive_time;
use chrono::NaiveTime;
use serde::{de::{Error, Visitor}, Deserializer, Serializer};
use core::fmt;
type SerdeType = Option<NaiveTime>;
pub fn serialize<S: Serializer>(t: &SerdeType, ser: S) -> Result<S::Ok, S::Error> {
match t.as_ref() {
Some(v) => ser.serialize_some(naive_time::get_raw_value(v).as_str()),
None => ser.serialize_none(),
}
}
pub fn deserialize<'de, D: Deserializer<'de>>(de: D) -> Result<SerdeType, D::Error> {
de.deserialize_option(NtVisitor)
}
struct NtVisitor;
impl<'de> Visitor<'de> for NtVisitor {
type Value = SerdeType;
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("optional chrono::NaiveTime")
}
fn visit_none<E: Error>(self) -> Result<SerdeType, E> {
Ok(None)
}
fn visit_some<D: Deserializer<'de>>(self, deserializer: D) -> Result<SerdeType, D::Error> {
naive_time::deserialize(deserializer).map(|v| Some(v))
}
}
}
pub mod time_delta {
use std::str::FromStr;
use chrono::TimeDelta;
use iso8601::Duration;
use serde::{de::Error, Deserialize, Deserializer, Serializer};
pub fn get_raw_value(t: &TimeDelta) -> String {
t.to_string()
}
pub fn serialize<S: Serializer>(t: &TimeDelta, ser: S) -> Result<S::Ok, S::Error> {
ser.serialize_str(get_raw_value(t).as_str())
}
pub fn deserialize<'de, D: Deserializer<'de>>(de: D) -> Result<TimeDelta, D::Error> {
let time_string = String::deserialize(de)?;
const SECS_PER_DAY: i64 = 3600 * 24;
const SECS_PER_HOUR: i64 = 3600;
const SECS_PER_MIN: i64 = 60;
const AVG_DAYS_PER_YEAR: f64 = 365.24237;
const AVG_DAYS_PER_MONTH: f64 = AVG_DAYS_PER_YEAR / 12.0;
const AVG_SECS_PER_YEAR: i64 = (AVG_DAYS_PER_YEAR * SECS_PER_DAY as f64) as _;
const AVG_SECS_PER_MONTH: i64 = (AVG_DAYS_PER_MONTH * SECS_PER_DAY as f64) as _;
const MAX_SECS_FOR_MILLIS: i64 = 9223372032559808;
match Duration::from_str(&time_string) {
Ok(d) => {
Ok(match d {
Duration::YMDHMS { year, month, day, hour, minute, second, millisecond } => {
let total_secs = year as i64 * AVG_SECS_PER_YEAR
+ month as i64 * AVG_SECS_PER_MONTH
+ day as i64 * SECS_PER_DAY
+ hour as i64 * SECS_PER_HOUR
+ minute as i64 * SECS_PER_MIN
+ second as i64;
if total_secs <= MAX_SECS_FOR_MILLIS {
let total_msec = total_secs * 1000 + millisecond as i64;
TimeDelta::milliseconds(total_msec)
} else {
TimeDelta::seconds(total_secs)
}
}
Duration::Weeks(w) => TimeDelta::weeks(w as _),
})
}
Err(e) => Err(D::Error::custom(e))
}
}
}
pub mod time_delta_opt {
use super::time_delta;
use core::fmt;
use chrono::TimeDelta;
use serde::{de::{Error, Visitor}, Deserializer, Serializer};
type SerdeType = Option<TimeDelta>;
pub fn serialize<S: Serializer>(t: &SerdeType, ser: S) -> Result<S::Ok, S::Error> {
match t.as_ref() {
Some(v) => ser.serialize_some(time_delta::get_raw_value(v).as_str()),
None => ser.serialize_none(),
}
}
pub fn deserialize<'de, D: Deserializer<'de>>(de: D) -> Result<SerdeType, D::Error> {
de.deserialize_option(TdVisitor)
}
struct TdVisitor;
impl<'de> Visitor<'de> for TdVisitor {
type Value = SerdeType;
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("optional chrono::TimeDelta")
}
fn visit_none<E: Error>(self) -> Result<SerdeType, E> {
Ok(None)
}
fn visit_some<D: Deserializer<'de>>(self, deserializer: D) -> Result<SerdeType, D::Error> {
time_delta::deserialize(deserializer).map(|v| Some(v))
}
}
}
pub mod time_delta_vec {
use super::time_delta;
use core::fmt;
use chrono::TimeDelta;
use serde::{
de::{SeqAccess, Visitor},
ser::SerializeSeq,
Deserializer,
Serializer
};
type SerdeType = Vec<TimeDelta>;
pub fn serialize<S: Serializer>(t: &SerdeType, ser: S) -> Result<S::Ok, S::Error> {
let mut seq = ser.serialize_seq(Some(t.len()))?;
for v in t.iter() {
let rv = time_delta::get_raw_value(v);
seq.serialize_element(rv.as_str())?;
}
seq.end()
}
pub fn deserialize<'de, D: Deserializer<'de>>(de: D) -> Result<SerdeType, D::Error> {
de.deserialize_seq(TdVisitor)
}
struct TdVisitor;
impl<'de> Visitor<'de> for TdVisitor {
type Value = SerdeType;
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("sequence of chrono::TimeDelta")
}
fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<SerdeType, A::Error> {
let mut values = match seq.size_hint() {
Some(s) => Vec::with_capacity(s),
None => Vec::new(),
};
while let Some(v) = seq.next_element()? {
values.push(v);
}
Ok(values)
}
}
}
#[macro_export]
macro_rules! choice_convert_impls {
{
$en_name:ident - $serde_name:ident
$(
$vnt_name:ident $(,)?
)+
} => {
impl TryFrom<$serde_name> for $en_name {
type Error = &'static str;
fn try_from(value: $serde_name) -> Result<Self, Self::Error> {
use paste::paste;
let mut count = 0;
let err = Err("Choice type expects one variant only.");
let mut ret = None;
$(
if let Some(v) = paste![value . $vnt_name] {
ret = Some(paste![$en_name :: $vnt_name (v)]);
count += 1;
}
)+
if count != 1 {
err
} else {
Ok(ret.unwrap())
}
}
}
impl Into<$serde_name> for $en_name {
fn into(self) -> $serde_name {
use paste::paste;
type IntoType = $serde_name;
match self {
$(
paste! [$en_name :: $vnt_name (v)] => { IntoType {
$vnt_name: Some(v),
..IntoType::default()
}}
),+
}
}
}
};
}
#[macro_export]
macro_rules! abstract_convert_impls {
{
$en_name:ident - $serde_name:ident
$(
$vnt_name:ident $(,)?
)+
} => {
impl TryFrom<$serde_name> for $en_name {
type Error = &'static str;
fn try_from(value: $serde_name) -> Result<Self, Self::Error> {
use paste::paste;
let mut count = 0;
let err = Err("Choice type expects one variant only.");
let mut ret = None;
$(
if let Some(v) = paste![value . $vnt_name] {
ret = Some(paste![$en_name :: $vnt_name (Box::new(v))]);
count += 1;
}
)+
if count != 1 {
err
} else {
Ok(ret.unwrap())
}
}
}
impl Into<$serde_name> for $en_name {
fn into(self) -> $serde_name {
use paste::paste;
type IntoType = $serde_name;
match self {
$(
paste! [$en_name :: $vnt_name (v)] => { IntoType {
$vnt_name: Some(*v),
..IntoType::default()
}}
),+
}
}
}
};
}