use eva_common::Value;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::time::Duration;
#[allow(clippy::cast_possible_truncation)]
pub fn serialize_duration_as_micros<S>(t: &Duration, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
s.serialize_u64(t.as_micros() as u64)
}
#[allow(clippy::cast_possible_truncation)]
pub fn serialize_opt_duration_as_micros<S>(t: &Option<Duration>, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
if let Some(ref dur) = t {
s.serialize_u64(dur.as_micros() as u64)
} else {
s.serialize_none()
}
}
pub fn deserialize_duration_from_micros<'de, D>(deserializer: D) -> Result<Duration, D::Error>
where
D: Deserializer<'de>,
{
Ok(Duration::from_micros(u64::deserialize(deserializer)?))
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct Time {
sec: u64,
nsec: u64,
}
#[allow(clippy::module_name_repetitions)]
pub fn deserialize_time<'de, D>(deserializer: D) -> Result<Time, D::Error>
where
D: Deserializer<'de>,
{
Ok(Time::from_timestamp(f64::deserialize(deserializer)?))
}
impl Serialize for Time {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_f64(self.timestamp())
}
}
impl Time {
#[inline]
#[allow(clippy::cast_sign_loss)]
pub fn now() -> Self {
let t = nix::time::clock_gettime(nix::time::ClockId::CLOCK_REALTIME).unwrap();
Self {
sec: t.tv_sec() as u64,
nsec: t.tv_nsec() as u64,
}
}
#[inline]
pub fn from_timestamp_ns(timestamp_ns: u64) -> Self {
Self {
sec: timestamp_ns / 1_000_000_000,
nsec: timestamp_ns % 1_000_000_000,
}
}
#[allow(clippy::cast_sign_loss)]
#[allow(clippy::cast_possible_truncation)]
#[inline]
pub fn from_timestamp(timestamp: f64) -> Self {
Self {
sec: timestamp.trunc() as u64,
nsec: (timestamp.fract() * 1_000_000_000_f64) as u64,
}
}
#[allow(clippy::cast_precision_loss)]
#[inline]
pub fn timestamp(&self) -> f64 {
self.sec as f64 + self.nsec as f64 / 1_000_000_000.0
}
#[inline]
pub fn timestamp_ns(&self) -> u64 {
self.sec * 1_000_000_000 + self.nsec
}
}
impl From<Time> for Value {
#[inline]
fn from(t: Time) -> Value {
Value::F64(t.timestamp())
}
}
impl From<Time> for f64 {
#[inline]
fn from(t: Time) -> f64 {
t.timestamp()
}
}
#[allow(clippy::cast_sign_loss)]
pub fn monotonic() -> u64 {
nix::time::clock_gettime(nix::time::ClockId::CLOCK_MONOTONIC)
.unwrap()
.tv_sec() as u64
}
#[allow(clippy::cast_sign_loss)]
pub fn monotonic_ns() -> u64 {
let t = nix::time::clock_gettime(nix::time::ClockId::CLOCK_MONOTONIC).unwrap();
t.tv_sec() as u64 * 1_000_000_000 + t.tv_nsec() as u64
}
#[allow(clippy::cast_sign_loss)]
pub fn now() -> u64 {
nix::time::clock_gettime(nix::time::ClockId::CLOCK_REALTIME)
.unwrap()
.tv_sec() as u64
}
#[allow(clippy::cast_precision_loss)]
pub fn now_ns_float() -> f64 {
now_ns() as f64 / 1_000_000_000.0
}
#[allow(clippy::cast_sign_loss)]
pub fn now_ns() -> u64 {
let t = nix::time::clock_gettime(nix::time::ClockId::CLOCK_REALTIME).unwrap();
t.tv_sec() as u64 * 1_000_000_000 + t.tv_nsec() as u64
}
#[cfg(test)]
mod tests {
use super::Time;
#[test]
fn test_time() {
let timestamp = 1632093707.1893349;
let time = Time::from_timestamp(timestamp);
assert_eq!(time.timestamp(), timestamp);
assert_eq!(time.timestamp_ns(), 1632093707189334869);
let timestamp_ns = 1632093707123456789;
let time = Time::from_timestamp_ns(timestamp_ns);
assert_eq!(time.timestamp_ns(), timestamp_ns);
assert_eq!(time.timestamp(), 1632093707.123456789);
}
}