use crate::amount::Amount;
use crate::displayer::{DisplayProxy, DisplayerOf};
#[cfg(feature = "serde")]
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::cmp::Ordering;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
use std::ops::{Add, AddAssign, Div, Mul, MulAssign, Sub, SubAssign};
pub struct Instant<Unit, Repr>(Repr, PhantomData<std::sync::Mutex<Unit>>);
impl<Unit, Repr: Copy> Instant<Unit, Repr> {
pub fn get(&self) -> Repr {
self.0
}
}
impl<Unit, Repr> Instant<Unit, Repr> {
pub const fn new(repr: Repr) -> Instant<Unit, Repr> {
Instant(repr, PhantomData)
}
}
impl<Unit: Default, Repr: Copy> Instant<Unit, Repr> {
pub fn unit(&self) -> Unit {
Default::default()
}
}
impl<Unit, Repr> Instant<Unit, Repr>
where
Unit: DisplayerOf<Instant<Unit, Repr>>,
{
pub fn display(&self) -> DisplayProxy<'_, Self, Unit> {
DisplayProxy::new(self)
}
}
impl<Unit, Repr: Copy> From<Repr> for Instant<Unit, Repr> {
fn from(repr: Repr) -> Self {
Self::new(repr)
}
}
impl<Unit, Repr: Copy> Clone for Instant<Unit, Repr> {
fn clone(&self) -> Self {
Instant(self.0, PhantomData)
}
}
impl<Unit, Repr: Copy> Copy for Instant<Unit, Repr> {}
impl<Unit, Repr: PartialEq> PartialEq for Instant<Unit, Repr> {
fn eq(&self, rhs: &Self) -> bool {
self.0.eq(&rhs.0)
}
}
impl<Unit, Repr: Eq> Eq for Instant<Unit, Repr> {}
impl<Unit, Repr: PartialOrd> PartialOrd for Instant<Unit, Repr> {
fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
self.0.partial_cmp(&rhs.0)
}
}
impl<Unit, Repr: Ord> Ord for Instant<Unit, Repr> {
fn cmp(&self, rhs: &Self) -> Ordering {
self.0.cmp(&rhs.0)
}
}
impl<Unit, Repr: Hash> Hash for Instant<Unit, Repr> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.hash(state)
}
}
impl<Unit, Repr, Repr2> Add<Amount<Unit, Repr2>> for Instant<Unit, Repr>
where
Repr: AddAssign<Repr2> + Copy,
Repr2: Copy,
{
type Output = Self;
fn add(mut self, rhs: Amount<Unit, Repr2>) -> Self {
self.add_assign(rhs);
self
}
}
impl<Unit, Repr, Repr2> AddAssign<Amount<Unit, Repr2>> for Instant<Unit, Repr>
where
Repr: AddAssign<Repr2> + Copy,
Repr2: Copy,
{
fn add_assign(&mut self, rhs: Amount<Unit, Repr2>) {
self.0 += rhs.get()
}
}
impl<Unit, Repr, Repr2> SubAssign<Amount<Unit, Repr2>> for Instant<Unit, Repr>
where
Repr: SubAssign<Repr2> + Copy,
Repr2: Copy,
{
fn sub_assign(&mut self, rhs: Amount<Unit, Repr2>) {
self.0 -= rhs.get()
}
}
impl<Unit, Repr> Sub for Instant<Unit, Repr>
where
Repr: Sub + Copy,
{
type Output = Amount<Unit, <Repr as Sub>::Output>;
fn sub(self, rhs: Self) -> Self::Output {
Amount::<Unit, <Repr as Sub>::Output>::new(self.0 - rhs.0)
}
}
impl<Unit, Repr, Repr2> Sub<Amount<Unit, Repr2>> for Instant<Unit, Repr>
where
Repr: SubAssign<Repr2> + Copy,
Repr2: Copy,
{
type Output = Self;
fn sub(mut self, rhs: Amount<Unit, Repr2>) -> Self {
self.sub_assign(rhs);
self
}
}
impl<Unit, Repr> MulAssign<Repr> for Instant<Unit, Repr>
where
Repr: MulAssign + Copy,
{
fn mul_assign(&mut self, rhs: Repr) {
self.0 *= rhs;
}
}
impl<Unit, Repr> Mul<Repr> for Instant<Unit, Repr>
where
Repr: MulAssign + Copy,
{
type Output = Self;
fn mul(mut self, rhs: Repr) -> Self {
self.mul_assign(rhs);
self
}
}
impl<Unit, Repr> Div<Self> for Instant<Unit, Repr>
where
Repr: Div<Repr> + Copy,
{
type Output = <Repr as Div>::Output;
fn div(self, rhs: Self) -> Self::Output {
self.0.div(rhs.0)
}
}
impl<Unit, Repr> fmt::Debug for Instant<Unit, Repr>
where
Repr: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl<Unit, Repr> fmt::Display for Instant<Unit, Repr>
where
Repr: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
#[cfg(feature = "serde")]
impl<Unit, Repr: Serialize> Serialize for Instant<Unit, Repr> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
self.0.serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'de, Unit, Repr> Deserialize<'de> for Instant<Unit, Repr>
where
Repr: Deserialize<'de>,
{
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
Repr::deserialize(deserializer).map(Instant::<Unit, Repr>::new)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_complex_instant_arithmetics() {
enum Seconds {}
enum UTC {}
type Timestamp = Instant<Seconds, i64>;
type TsDiff = Amount<Seconds, i64>;
type Date = Instant<UTC, Timestamp>;
let epoch = Date::new(Timestamp::new(0));
let date = Date::new(Timestamp::new(123456789));
let span = Amount::<UTC, TsDiff>::new(TsDiff::from(123456789));
assert_eq!(date - epoch, span);
assert_eq!(date - span, epoch);
assert_eq!(epoch + span, date);
}
}