use std::fmt::{self, Display, Formatter};
use std::ops::Add;
use std::time::SystemTime;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Ord, Eq, Hash)]
pub struct UnixTimestamp(u64);
impl UnixTimestamp {
#[must_use]
pub const fn from_secs(secs: u64) -> Self {
Self(secs)
}
#[must_use]
pub fn now() -> Self {
let secs = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.map(|d| d.as_secs())
.unwrap_or_default();
Self(secs)
}
#[must_use]
pub const fn as_secs(self) -> u64 {
self.0
}
}
impl Display for UnixTimestamp {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Display::fmt(&self.0, f)
}
}
impl Add<u64> for UnixTimestamp {
type Output = Self;
fn add(self, rhs: u64) -> Self::Output {
Self(self.0.saturating_add(rhs))
}
}
impl Serialize for UnixTimestamp {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.collect_str(&self.0)
}
}
impl<'de> Deserialize<'de> for UnixTimestamp {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
struct Visitor;
impl serde::de::Visitor<'_> for Visitor {
type Value = UnixTimestamp;
fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.write_str("a non-negative integer or its string representation")
}
fn visit_u64<E: serde::de::Error>(self, v: u64) -> Result<Self::Value, E> {
Ok(UnixTimestamp(v))
}
fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Self::Value, E> {
v.parse::<u64>()
.map(UnixTimestamp)
.map_err(|_| E::custom("expected non-negative integer"))
}
}
deserializer.deserialize_any(Visitor)
}
}