use std::fmt;
use std::fmt::Formatter;
use std::ops::Deref;
use crate::Instant;
use crate::display_ext::DisplayInstantExt;
#[derive(Debug, Clone, Copy)]
#[derive(PartialEq, Eq)]
#[derive(PartialOrd, Ord)]
pub struct SerdeInstant<I>
where I: Instant
{
inner: I,
}
impl<I> Deref for SerdeInstant<I>
where I: Instant
{
type Target = I;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<I> From<I> for SerdeInstant<I>
where I: Instant
{
fn from(inner: I) -> Self {
Self { inner }
}
}
impl<I> fmt::Display for SerdeInstant<I>
where I: Instant
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
self.inner.display().fmt(f)
}
}
impl<I> SerdeInstant<I>
where I: Instant
{
pub fn new(inner: I) -> Self {
Self { inner }
}
pub fn into_inner(self) -> I {
self.inner
}
}
#[cfg(feature = "serde")]
mod serde_impl {
use std::fmt;
use std::marker::PhantomData;
use std::time::SystemTime;
use chrono::DateTime;
use chrono::Utc;
use serde::Deserialize;
use serde::Deserializer;
use serde::Serialize;
use serde::Serializer;
use serde::de;
use serde::de::Visitor;
use super::SerdeInstant;
use crate::Instant;
impl<I> Serialize for SerdeInstant<I>
where I: Instant
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer {
let system_time = {
let sys_now = SystemTime::now();
let now = I::now();
if now >= self.inner {
let d = now - self.inner;
sys_now - d
} else {
let d = self.inner - now;
sys_now + d
}
};
let datetime: DateTime<Utc> = system_time.into();
let nano = datetime.timestamp_nanos_opt().ok_or(serde::ser::Error::custom("time out of range"))?;
serializer.serialize_u64(nano as u64)
}
}
impl<'de, I> Deserialize<'de> for SerdeInstant<I>
where I: Instant
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de> {
struct InstantVisitor<II: Instant>(PhantomData<II>);
impl<II: Instant> Visitor<'_> for InstantVisitor<II> {
type Value = SerdeInstant<II>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "an u64 generated with Datetime::timestamp_nanos_opt()",)
}
fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
where E: de::Error {
let datetime = DateTime::from_timestamp_nanos(value as i64);
let system_time: SystemTime = datetime.with_timezone(&Utc).into();
let sys_now = SystemTime::now();
let now = II::now();
let instant = if system_time > sys_now {
now + (system_time.duration_since(sys_now).unwrap())
} else {
now - (sys_now.duration_since(system_time).unwrap())
};
Ok(SerdeInstant { inner: instant })
}
}
deserializer.deserialize_u64(InstantVisitor::<I>(Default::default()))
}
}
#[cfg(test)]
mod tests {
use std::time::Duration;
use super::SerdeInstant;
use crate::engine::testing::UTConfig;
use crate::type_config::TypeConfigExt;
use crate::type_config::alias::SerdeInstantOf;
#[test]
fn test_serde_instant() {
let now = UTConfig::<()>::now();
let serde_instant = SerdeInstant::new(now);
let json = serde_json::to_string(&serde_instant).unwrap();
println!("json: {}", json);
println!("Now: {:?}", now);
let deserialized: SerdeInstantOf<UTConfig> = serde_json::from_str(&json).unwrap();
println!("Des: {:?}", *deserialized);
if now > *deserialized {
assert!((now - *deserialized) < Duration::from_millis(5));
} else {
assert!((*deserialized - now) < Duration::from_millis(5));
}
let nano = "1721829051211301916";
let deserialized: SerdeInstantOf<UTConfig> = serde_json::from_str(nano).unwrap();
let serialized = serde_json::to_string(&deserialized).unwrap();
assert_eq!(
nano[0..nano.len() - 6],
serialized[0..serialized.len() - 6],
"compare up to milli seconds: {}",
&nano[0..nano.len() - 6]
);
}
}
}