{-# LANGUAGE TypeApplications #-}

module Timestamp
  ( Timestamp (..),
    epoch,
    minus,
    now,
    plus,
    Timestamp.rem,
  )
where

import Data.Coerce (coerce)
import Data.Word (Word64)
import GHC.Clock (getMonotonicTimeNSec)
import Micros (Micros (..))

newtype Timestamp
  = Timestamp Word64
  deriving stock (Timestamp -> Timestamp -> Bool
(Timestamp -> Timestamp -> Bool)
-> (Timestamp -> Timestamp -> Bool) -> Eq Timestamp
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Timestamp -> Timestamp -> Bool
$c/= :: Timestamp -> Timestamp -> Bool
== :: Timestamp -> Timestamp -> Bool
$c== :: Timestamp -> Timestamp -> Bool
Eq, Eq Timestamp
Eq Timestamp
-> (Timestamp -> Timestamp -> Ordering)
-> (Timestamp -> Timestamp -> Bool)
-> (Timestamp -> Timestamp -> Bool)
-> (Timestamp -> Timestamp -> Bool)
-> (Timestamp -> Timestamp -> Bool)
-> (Timestamp -> Timestamp -> Timestamp)
-> (Timestamp -> Timestamp -> Timestamp)
-> Ord Timestamp
Timestamp -> Timestamp -> Bool
Timestamp -> Timestamp -> Ordering
Timestamp -> Timestamp -> Timestamp
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Timestamp -> Timestamp -> Timestamp
$cmin :: Timestamp -> Timestamp -> Timestamp
max :: Timestamp -> Timestamp -> Timestamp
$cmax :: Timestamp -> Timestamp -> Timestamp
>= :: Timestamp -> Timestamp -> Bool
$c>= :: Timestamp -> Timestamp -> Bool
> :: Timestamp -> Timestamp -> Bool
$c> :: Timestamp -> Timestamp -> Bool
<= :: Timestamp -> Timestamp -> Bool
$c<= :: Timestamp -> Timestamp -> Bool
< :: Timestamp -> Timestamp -> Bool
$c< :: Timestamp -> Timestamp -> Bool
compare :: Timestamp -> Timestamp -> Ordering
$ccompare :: Timestamp -> Timestamp -> Ordering
$cp1Ord :: Eq Timestamp
Ord)

-- Which epoch does this correspond to, if they are measured in chunks of the given number of milliseconds?
epoch :: Micros -> Timestamp -> Word64
epoch :: Micros -> Timestamp -> Word64
epoch (Micros Word64
chunk) (Timestamp Word64
timestamp) =
  Word64
timestamp Word64 -> Word64 -> Word64
forall a. Integral a => a -> a -> a
`div` Word64
chunk

minus :: Timestamp -> Timestamp -> Micros
minus :: Timestamp -> Timestamp -> Micros
minus =
  (Word64 -> Word64 -> Word64) -> Timestamp -> Timestamp -> Micros
coerce ((-) @Word64)

now :: IO Timestamp
now :: IO Timestamp
now = do
  Word64
nanos <- IO Word64
getMonotonicTimeNSec
  Timestamp -> IO Timestamp
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Word64 -> Timestamp
Timestamp (Word64
nanos Word64 -> Word64 -> Word64
forall a. Integral a => a -> a -> a
`div` Word64
1000))

plus :: Timestamp -> Micros -> Timestamp
plus :: Timestamp -> Micros -> Timestamp
plus =
  (Word64 -> Word64 -> Word64) -> Timestamp -> Micros -> Timestamp
coerce (Num Word64 => Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
(+) @Word64)

rem :: Timestamp -> Micros -> Micros
rem :: Timestamp -> Micros -> Micros
rem =
  (Word64 -> Word64 -> Word64) -> Timestamp -> Micros -> Micros
coerce (Integral Word64 => Word64 -> Word64 -> Word64
forall a. Integral a => a -> a -> a
Prelude.rem @Word64)