use std::fmt;
use serde::{
Serialize,
Serializer,
Deserialize,
Deserializer
};
use serde::de::{
Error,
Visitor,
};
use super::{
Point,
Span,
};
macro_rules! serialize_field {
($Type:ty, $field:ident) => {
impl Serialize for $Type {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
self.$field.serialize(serializer)
}
}
}
}
macro_rules! deserialize {
(
$Type:ty,
$Visitor:ident,
$expect:literal,
$f:ident,
$( $methods:item )+ ) =>
{
struct $Visitor;
impl<'de,> Visitor<'de> for $Visitor {
type Value = $Type;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str($expect)
}
$( $methods )+
}
impl<'de> Deserialize<'de> for $Type {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de>
{
deserializer.$f($Visitor)
}
}
}
}
serialize_field!(Point, timestamp);
deserialize!(
Point,
PointVisitor,
"a 64-bit timestamp",
deserialize_i64,
fn visit_i64<E: Error>(self, value: i64) -> Result<Self::Value, E> {
Ok(Point::from_epoch(value))
}
);
serialize_field!(Span, seconds);
deserialize!(
Span,
SpanVisitor,
"a 64-bit duration in seconds",
deserialize_u64,
fn visit_u64<E: Error>(self, value: u64) -> Result<Self::Value, E> {
Ok(Span::from_seconds(value))
}
fn visit_i64<E: Error>(self, value: i64) -> Result<Self::Value, E> {
value.try_into()
.map(Span::from_seconds)
.map_err(E::custom)
}
);
#[cfg(test)]
mod tests {
use std::fmt;
use serde::de::value;
use super::*;
struct FmtAbuser<T>(T);
impl<T: Serialize> fmt::Display for FmtAbuser<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.serialize(f)
}
}
macro_rules! assert_serialize_eq {
($a:expr, $b:expr) => {
assert_eq!(
FmtAbuser($a).to_string(),
FmtAbuser($b).to_string()
);
};
}
#[test]
fn point() {
type Ser = value::I64Deserializer<value::Error>;
let cases = [
i64::MIN,
i32::MIN.into(),
0,
Point::now().timestamp,
i32::MAX.into(),
u32::MAX.into(),
i64::MAX
];
for case in cases {
let before = Point::from_epoch(case);
let after = Point::deserialize(Ser::new(case)).unwrap();
assert_eq!(before, after);
assert_serialize_eq!(before, case);
}
}
#[test]
fn span() {
type Ser = value::U64Deserializer<value::Error>;
let cases = [
Span::ZERO,
Span::SECOND,
Span::MINUTE,
Span::HOUR,
Span::DAY,
Span::WEEK,
Span::from_seconds(u32::MAX.into()),
Span::from_seconds(u64::MAX),
];
for case in cases {
let after = Span::deserialize(Ser::new(case.seconds)).unwrap();
assert_eq!(case, after);
assert_serialize_eq!(case, case.seconds);
}
}
}