use core::fmt;
use core::ops::{Add, AddAssign, Sub, SubAssign};
#[cfg(feature = "dev")]
use arbitrary::Arbitrary;
#[cfg(feature = "std")]
use hifitime::HifitimeError;
use hifitime::{Duration, Epoch, J2000_REF_EPOCH};
use order_theory::{
GreatestElement, LeastElement, LowerSemilattice, PredecessorExceptForLeast,
SuccessorExceptForGreatest, TryPredecessor, TrySuccessor, UpperSemilattice,
};
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default, Hash, Debug)]
#[cfg_attr(feature = "dev", derive(Arbitrary))]
pub struct Timestamp(u64);
impl fmt::Display for Timestamp {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
Epoch::from(*self).fmt(f)
}
}
impl From<u64> for Timestamp {
fn from(value: u64) -> Self {
Self(value)
}
}
impl From<Timestamp> for u64 {
fn from(value: Timestamp) -> Self {
value.0
}
}
impl AsRef<u64> for Timestamp {
fn as_ref(&self) -> &u64 {
&self.0
}
}
impl AsMut<u64> for Timestamp {
fn as_mut(&mut self) -> &mut u64 {
&mut self.0
}
}
impl TryFrom<Epoch> for Timestamp {
type Error = <i128 as TryInto<u64>>::Error;
fn try_from(value: Epoch) -> Result<Self, Self::Error> {
let diff = value - J2000_REF_EPOCH;
let microseconds = diff.total_nanoseconds() / 1000;
Ok(Self(microseconds.try_into()?))
}
}
impl From<Timestamp> for Epoch {
fn from(value: Timestamp) -> Self {
let duration_from_j2000 = Duration::from(value);
J2000_REF_EPOCH + duration_from_j2000
}
}
impl TryFrom<Duration> for Timestamp {
type Error = <i128 as TryInto<u64>>::Error;
fn try_from(value: Duration) -> Result<Self, Self::Error> {
Ok(Self((value.total_nanoseconds() / 1000).try_into()?))
}
}
impl From<Timestamp> for Duration {
fn from(value: Timestamp) -> Self {
Duration::from_total_nanoseconds((value.0 as i128) * 1000)
}
}
impl Timestamp {
#[cfg(feature = "std")]
pub fn now() -> Result<Self, HifitimeError> {
Self::try_from(Epoch::now()?).map_err(|_| HifitimeError::SystemTimeError)
}
}
impl Add<Duration> for Timestamp {
type Output = Self;
fn add(self, rhs: Duration) -> Self::Output {
(Duration::from(self) + rhs)
.try_into()
.expect("timestamp overflow")
}
}
impl AddAssign<Duration> for Timestamp {
fn add_assign(&mut self, rhs: Duration) {
*self = *self + rhs;
}
}
impl Add for Timestamp {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self(self.0 + rhs.0)
}
}
impl AddAssign for Timestamp {
fn add_assign(&mut self, rhs: Self) {
*self = Self(self.0 + rhs.0);
}
}
impl Sub<Duration> for Timestamp {
type Output = Self;
fn sub(self, rhs: Duration) -> Self::Output {
(Duration::from(self) - rhs)
.try_into()
.expect("timestamp overflow")
}
}
impl SubAssign<Duration> for Timestamp {
fn sub_assign(&mut self, rhs: Duration) {
*self = *self - rhs;
}
}
impl Sub for Timestamp {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self(self.0 - rhs.0)
}
}
impl SubAssign for Timestamp {
fn sub_assign(&mut self, rhs: Self) {
*self = Self(self.0 - rhs.0);
}
}
impl LeastElement for Timestamp {
fn least() -> Self {
u64::least().into()
}
}
impl GreatestElement for Timestamp {
fn greatest() -> Self {
u64::greatest().into()
}
}
impl LowerSemilattice for Timestamp {
fn greatest_lower_bound(&self, other: &Self) -> Self {
self.0.greatest_lower_bound(other.as_ref()).into()
}
}
impl UpperSemilattice for Timestamp {
fn least_upper_bound(&self, other: &Self) -> Self {
self.0.least_upper_bound(other.as_ref()).into()
}
}
impl TryPredecessor for Timestamp {
fn try_predecessor(&self) -> Option<Self> {
self.0.try_predecessor().map(Self)
}
}
impl TrySuccessor for Timestamp {
fn try_successor(&self) -> Option<Self> {
self.0.try_successor().map(Self)
}
}
impl PredecessorExceptForLeast for Timestamp {}
impl SuccessorExceptForGreatest for Timestamp {}