use std::fmt::{self, Display};
use std::str::FromStr;
use crate::{Result, Error, error, err};
#[cfg(feature = "serde")]
use serde::{Serialize, Deserialize};
#[cfg(feature = "jiff")]
use jiff::Timestamp;
#[cfg(feature = "chrono")]
use chrono::{DateTime, Utc};
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(rename_all = "kebab-case"))]
pub struct Time
{
pub seconds: u64,
pub nanos: u64
}
impl FromStr for Time
{
type Err = Error;
fn from_str(s: &str) -> Result<Self>
{
if let Some(parts) = s.split_once(':')
{
Ok(Self {
seconds: parts.0.parse::<u64>().map_err(|e| err!(e))?,
nanos: parts.1.parse::<u64>().map_err(|e| err!(e))?
})
}
else
{
error!("expected two parts separated by ':', got '{s}'")
}
}
}
#[cfg(feature = "jiff")]
impl TryFrom<Time> for Timestamp
{
type Error = jiff::Error;
fn try_from(t: Time) -> Result<Timestamp, jiff::Error>
{
Timestamp::new(t.seconds as i64, t.nanos as i32)
}
}
#[cfg(feature = "chrono")]
impl TryFrom<Time> for DateTime<Utc>
{
type Error = std::io::Error;
fn try_from(t: Time) -> std::io::Result<DateTime<Utc>>
{
DateTime::<Utc>::from_timestamp(t.seconds as i64, t.nanos as u32)
.ok_or_else(|| std::io::Error::other(
format!("Time {}.{} is out of range for chrono::DateTime", t.seconds, t.nanos)
))
}
}
impl Time
{
#[cfg(feature = "jiff")]
pub fn into_timestamp(self) -> std::result::Result<Timestamp, Self>
{
Timestamp::try_from(self).map_err(|_| self)
}
#[cfg(feature = "jiff")]
pub fn to_timestamp(&self) -> std::result::Result<Timestamp, jiff::Error>
{
Timestamp::try_from(*self)
}
#[cfg(feature = "chrono")]
pub fn into_datetime(self) -> std::result::Result<DateTime<Utc>, Self>
{
DateTime::<Utc>::try_from(self).map_err(|_| self)
}
#[cfg(feature = "chrono")]
pub fn to_datetime(&self) -> std::io::Result<DateTime<Utc>>
{
DateTime::<Utc>::try_from(*self)
}
}
impl Display for Time
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
write!(f, "{}:{}", self.seconds, self.nanos)
}
}
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(crate) struct FileTime
{
pub access: Time,
pub change: Time,
pub modify: Time,
pub birth: Time
}
impl From<libc::stat> for FileTime
{
fn from(st: libc::stat) -> Self
{
Self
{
access: Time { seconds: st.st_atime as u64, nanos: st.st_atime_nsec as u64 },
change: Time { seconds: st.st_ctime as u64, nanos: st.st_ctime_nsec as u64 },
modify: Time { seconds: st.st_mtime as u64, nanos: st.st_mtime_nsec as u64 },
birth: Default::default()
}
}
}
impl From<&libc::stat> for FileTime
{
fn from(st: &libc::stat) -> Self
{
Self
{
access: Time { seconds: st.st_atime as u64, nanos: st.st_atime_nsec as u64 },
change: Time { seconds: st.st_ctime as u64, nanos: st.st_ctime_nsec as u64 },
modify: Time { seconds: st.st_mtime as u64, nanos: st.st_mtime_nsec as u64 },
birth: Default::default()
}
}
}