{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
module Time.Flick
(
Flicks(..)
, flicksPerSecond, secnd
, approxFlicks
, periodForFreq
, timeSpecToFlicks
, flicksToDiffTime
, flicksNow
, threadDelayFlicks
) where
import Control.Concurrent (threadDelay)
import Data.Fixed
import Data.Int
import Data.Proxy
import Data.Ratio
import Data.Time.Clock
import System.Clock
newtype Flicks = Flicks { unFlicks :: Int64 }
deriving newtype (Eq, Ord, Show, Num, Enum, Integral, Real)
flicksPerSecond :: Num a => a
flicksPerSecond = 705600000
secnd :: Flicks
secnd = flicksPerSecond
approxFlicks :: Rational -> Flicks
approxFlicks t = Flicks . truncate $ t * flicksPerSecond
periodForFreq :: Rational -> Flicks
periodForFreq = approxFlicks . recip
timeSpecToFlicks :: TimeSpec -> Flicks
timeSpecToFlicks TimeSpec{sec, nsec} = Flicks (secPart + nsecPart)
where
secPart = flicksPerSecond * sec
nsecPart = (flicksPerSecond * nsec) `quot` 10^9
flicksToFixed :: forall r. HasResolution r => Flicks -> Fixed r
flicksToFixed (Flicks t) = MkFixed val
where
val = fromIntegral t * resolution (Proxy @r) `quot` flicksPerSecond
flicksToDiffTime :: Flicks -> DiffTime
flicksToDiffTime t = picosecondsToDiffTime picos
where
MkFixed picos = flicksToFixed t :: Fixed E12
flicksNow :: Clock -> IO Flicks
flicksNow clockTy = timeSpecToFlicks <$> getTime clockTy
threadDelayFlicks :: Flicks -> IO ()
threadDelayFlicks (Flicks t) = do
let micros = fromIntegral $ (10^6 * t) `quot` flicksPerSecond
threadDelay micros