use core::cmp::Ordering;
use core::ops::{Add, AddAssign, Sub, SubAssign};
use core::time::Duration;
use derive_more::{Deref, DerefMut};
#[derive(Debug, Clone, Copy, Deref, DerefMut, Default)]
pub struct Dev(pub u32);
#[derive(Debug, Clone, Copy, Deref, DerefMut)]
pub struct Ino(pub u64);
#[derive(Debug, Clone, Copy, Deref, DerefMut)]
pub struct Mode(pub u16);
#[derive(Debug, Clone, Copy, Deref, DerefMut)]
pub struct Nlink(pub u32);
#[derive(Debug, Default, Clone, Copy, Deref, DerefMut)]
pub struct Uid(pub u32);
#[derive(Debug, Default, Clone, Copy, Deref, DerefMut)]
pub struct Gid(pub u32);
#[derive(Debug, Default, Clone, Copy, Deref, DerefMut)]
pub struct Off(pub isize);
#[derive(Debug, Clone, Copy, Deref, DerefMut)]
pub struct Blksize(pub isize);
#[derive(Debug, Clone, Copy, Deref, DerefMut)]
pub struct Blkcnt(pub i64);
#[derive(
Debug,
Clone,
Copy,
Deref,
DerefMut,
PartialEq,
Eq,
PartialOrd,
Ord,
derive_more::Add,
derive_more::AddAssign,
derive_more::Sub,
derive_more::SubAssign,
)]
pub struct Time(pub i64);
impl Add<i64> for Time {
type Output = Self;
fn add(self, rhs: i64) -> Self::Output {
Self(*self + rhs)
}
}
impl AddAssign<i64> for Time {
fn add_assign(&mut self, rhs: i64) {
*self = *self + rhs;
}
}
impl Sub<i64> for Time {
type Output = Self;
fn sub(self, rhs: i64) -> Self::Output {
Self(*self - rhs)
}
}
impl SubAssign<i64> for Time {
fn sub_assign(&mut self, rhs: i64) {
*self = *self - rhs;
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Timespec {
pub tv_sec: Time,
pub tv_nsec: u32,
}
impl PartialOrd for Timespec {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Timespec {
fn cmp(&self, other: &Self) -> Ordering {
match self.tv_sec.cmp(&other.tv_sec) {
Ordering::Less => Ordering::Less,
Ordering::Equal => self.tv_nsec.cmp(&other.tv_nsec),
Ordering::Greater => Ordering::Greater,
}
}
}
impl Add for Timespec {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self {
tv_sec: self.tv_sec + rhs.tv_sec + (i64::from(self.tv_nsec) + i64::from(rhs.tv_nsec)) / 1_000_000_000,
tv_nsec: (self.tv_nsec + rhs.tv_nsec) % 1_000_000_000,
}
}
}
impl Add<Time> for Timespec {
type Output = Self;
fn add(self, rhs: Time) -> Self::Output {
self + Self {
tv_sec: rhs,
tv_nsec: 0,
}
}
}
impl AddAssign<Time> for Timespec {
fn add_assign(&mut self, rhs: Time) {
*self = *self + rhs;
}
}
impl Sub for Timespec {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
let self_nsec_gte_rhs_nsec = self.tv_nsec >= rhs.tv_nsec;
Self {
tv_sec: self.tv_sec - rhs.tv_sec - i64::from(!self_nsec_gte_rhs_nsec),
tv_nsec: if self_nsec_gte_rhs_nsec {
self.tv_nsec - rhs.tv_nsec
} else {
1_000_000_000 - (rhs.tv_nsec - self.tv_nsec)
},
}
}
}
impl Sub<Time> for Timespec {
type Output = Self;
fn sub(self, rhs: Time) -> Self::Output {
self - Self {
tv_sec: rhs,
tv_nsec: 0,
}
}
}
impl SubAssign<Time> for Timespec {
fn sub_assign(&mut self, rhs: Time) {
*self = *self - rhs;
}
}
impl From<Duration> for Timespec {
fn from(value: Duration) -> Self {
Self {
tv_sec: Time(value.as_secs().try_into().expect("Cannot fit this duration on 63 bits")),
tv_nsec: unsafe { (u32::try_from(value.as_nanos() % 1_000_000_000)).unwrap_unchecked() },
}
}
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl From<std::time::SystemTime> for Timespec {
fn from(value: std::time::SystemTime) -> Self {
value
.duration_since(std::time::UNIX_EPOCH)
.expect("The given system time is before the UNIX epoch")
.into()
}
}
impl Timespec {
#[must_use]
pub fn canonical(self) -> Self {
Self {
tv_sec: self.tv_sec + (i64::from(self.tv_nsec) / 1_000_000_000),
tv_nsec: self.tv_nsec % 1_000_000_000,
}
}
#[allow(clippy::doc_link_with_quotes)]
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
#[must_use]
pub fn now() -> Self {
std::time::SystemTime::now().into()
}
}
#[cfg(test)]
mod test {
use crate::fs::types::{Time, Timespec};
#[test]
fn time_ops_add() {
assert_eq!(Time(100) + Time(100), Time(200));
assert_eq!(Time(100) + 100, Time(200));
let mut time = Time(100);
time += Time(100);
assert_eq!(time, Time(200));
let mut time = Time(100);
time += 100;
assert_eq!(time, Time(200));
}
#[test]
fn time_ops_sub() {
assert_eq!(Time(200) - Time(100), Time(100));
assert_eq!(Time(200) - 100, Time(100));
let mut time = Time(100);
time -= Time(200);
assert_eq!(time, Time(-100));
let mut time = Time(100);
time -= 200;
assert_eq!(time, Time(-100));
}
#[test]
fn timespec_ops_add() {
assert_eq!(
Timespec {
tv_sec: Time(100),
tv_nsec: 12
} + Timespec {
tv_sec: Time(200),
tv_nsec: 40
},
Timespec {
tv_sec: Time(300),
tv_nsec: 52
}
);
assert_eq!(
Timespec {
tv_sec: Time(100),
tv_nsec: 123
} + Timespec {
tv_sec: Time(200),
tv_nsec: 999_999_998
},
Timespec {
tv_sec: Time(301),
tv_nsec: 121
}
);
assert_eq!(
Timespec {
tv_sec: Time(100),
tv_nsec: 12
} + Time(200),
Timespec {
tv_sec: Time(300),
tv_nsec: 12
}
);
}
#[test]
fn timespec_ops_sub() {
assert_eq!(
Timespec {
tv_sec: Time(100),
tv_nsec: 12
} - Timespec {
tv_sec: Time(200),
tv_nsec: 10
},
Timespec {
tv_sec: Time(-100),
tv_nsec: 2
}
);
assert_eq!(
Timespec {
tv_sec: Time(200),
tv_nsec: 123
} - Timespec {
tv_sec: Time(100),
tv_nsec: 125
},
Timespec {
tv_sec: Time(99),
tv_nsec: 999_999_998
}
);
assert_eq!(
Timespec {
tv_sec: Time(100),
tv_nsec: 12
} - Time(200),
Timespec {
tv_sec: Time(-100),
tv_nsec: 12
}
);
}
}