{-# LANGUAGE CPP #-}
{-# LANGUAGE UndecidableInstances #-}
module Effectful.Time.TimeSpec
(
TimeSpec (..),
fromSeconds,
fromNanoSeconds,
toSeconds,
toNanoSeconds,
diffTimeSpec,
normalizeTimeSpec,
ASemigroup (..),
AMonoid (..),
MSemiSpace (..),
MSpace (..),
Semimodule,
SemivectorSpace,
Normed (..),
LowerBounded (..),
UpperBoundless,
)
where
import Control.DeepSeq (NFData)
import Data.Bounds (LowerBounded (lowerBound), UpperBoundless)
#if MIN_VERSION_base(4,17,0)
import GHC.Float (properFractionDouble)
#endif
import GHC.Generics (Generic)
import GHC.Natural (Natural)
import Numeric.Algebra
( AMonoid (zero),
ASemigroup ((.+.)),
MSemiSpace ((.*)),
MSpace ((.%)),
Normed (norm, sgn),
Semimodule,
SemivectorSpace,
)
import Optics.Core (A_Lens, LabelOptic (labelOptic), lensVL)
data TimeSpec = MkTimeSpec
{
TimeSpec -> Natural
sec :: !Natural,
TimeSpec -> Natural
nsec :: !Natural
}
deriving stock
(
(forall x. TimeSpec -> Rep TimeSpec x)
-> (forall x. Rep TimeSpec x -> TimeSpec) -> Generic TimeSpec
forall x. Rep TimeSpec x -> TimeSpec
forall x. TimeSpec -> Rep TimeSpec x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. TimeSpec -> Rep TimeSpec x
from :: forall x. TimeSpec -> Rep TimeSpec x
$cto :: forall x. Rep TimeSpec x -> TimeSpec
to :: forall x. Rep TimeSpec x -> TimeSpec
Generic,
Int -> TimeSpec -> ShowS
[TimeSpec] -> ShowS
TimeSpec -> String
(Int -> TimeSpec -> ShowS)
-> (TimeSpec -> String) -> ([TimeSpec] -> ShowS) -> Show TimeSpec
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> TimeSpec -> ShowS
showsPrec :: Int -> TimeSpec -> ShowS
$cshow :: TimeSpec -> String
show :: TimeSpec -> String
$cshowList :: [TimeSpec] -> ShowS
showList :: [TimeSpec] -> ShowS
Show
)
deriving anyclass
(
TimeSpec -> ()
(TimeSpec -> ()) -> NFData TimeSpec
forall a. (a -> ()) -> NFData a
$crnf :: TimeSpec -> ()
rnf :: TimeSpec -> ()
NFData
)
instance
(k ~ A_Lens, a ~ Natural, b ~ Natural) =>
LabelOptic "sec" k TimeSpec TimeSpec a b
where
labelOptic :: Optic k NoIx TimeSpec TimeSpec a b
labelOptic = LensVL TimeSpec TimeSpec a b -> Lens TimeSpec TimeSpec a b
forall s t a b. LensVL s t a b -> Lens s t a b
lensVL (LensVL TimeSpec TimeSpec a b -> Lens TimeSpec TimeSpec a b)
-> LensVL TimeSpec TimeSpec a b -> Lens TimeSpec TimeSpec a b
forall a b. (a -> b) -> a -> b
$ \a -> f b
f (MkTimeSpec Natural
a1 Natural
a2) ->
(Natural -> TimeSpec) -> f Natural -> f TimeSpec
forall a b. (a -> b) -> f a -> f b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\Natural
b -> Natural -> Natural -> TimeSpec
MkTimeSpec Natural
b Natural
a2) (a -> f b
f a
Natural
a1)
{-# INLINE labelOptic #-}
instance
(k ~ A_Lens, a ~ Natural, b ~ Natural) =>
LabelOptic "nsec" k TimeSpec TimeSpec a b
where
labelOptic :: Optic k NoIx TimeSpec TimeSpec a b
labelOptic = LensVL TimeSpec TimeSpec a b -> Lens TimeSpec TimeSpec a b
forall s t a b. LensVL s t a b -> Lens s t a b
lensVL (LensVL TimeSpec TimeSpec a b -> Lens TimeSpec TimeSpec a b)
-> LensVL TimeSpec TimeSpec a b -> Lens TimeSpec TimeSpec a b
forall a b. (a -> b) -> a -> b
$ \a -> f b
f (MkTimeSpec Natural
a1 Natural
a2) ->
(Natural -> TimeSpec) -> f Natural -> f TimeSpec
forall a b. (a -> b) -> f a -> f b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\Natural
b -> Natural -> Natural -> TimeSpec
MkTimeSpec Natural
a1 Natural
b) (a -> f b
f a
Natural
a2)
{-# INLINE labelOptic #-}
instance Eq TimeSpec where
TimeSpec
l == :: TimeSpec -> TimeSpec -> Bool
== TimeSpec
r = TimeSpec -> Natural
toNanoSeconds TimeSpec
l Natural -> Natural -> Bool
forall a. Eq a => a -> a -> Bool
== TimeSpec -> Natural
toNanoSeconds TimeSpec
r
instance Ord TimeSpec where
TimeSpec
l <= :: TimeSpec -> TimeSpec -> Bool
<= TimeSpec
r = TimeSpec -> Natural
toNanoSeconds TimeSpec
l Natural -> Natural -> Bool
forall a. Ord a => a -> a -> Bool
<= TimeSpec -> Natural
toNanoSeconds TimeSpec
r
instance LowerBounded TimeSpec where
lowerBound :: TimeSpec
lowerBound = Natural -> Natural -> TimeSpec
MkTimeSpec Natural
0 Natural
0
instance UpperBoundless TimeSpec
instance ASemigroup TimeSpec where
MkTimeSpec Natural
ls Natural
ln .+. :: TimeSpec -> TimeSpec -> TimeSpec
.+. MkTimeSpec Natural
rs Natural
rn = Natural -> Natural -> TimeSpec
MkTimeSpec (Natural
ls Natural -> Natural -> Natural
forall a. Num a => a -> a -> a
+ Natural
rs) (Natural
ln Natural -> Natural -> Natural
forall a. Num a => a -> a -> a
+ Natural
rn)
instance AMonoid TimeSpec where
zero :: TimeSpec
zero = Natural -> Natural -> TimeSpec
MkTimeSpec Natural
0 Natural
0
instance MSemiSpace TimeSpec Natural where
MkTimeSpec Natural
s Natural
n .* :: TimeSpec -> Natural -> TimeSpec
.* Natural
k = Natural -> Natural -> TimeSpec
MkTimeSpec (Natural
s Natural -> Natural -> Natural
forall a. Num a => a -> a -> a
* Natural
k) (Natural
n Natural -> Natural -> Natural
forall a. Num a => a -> a -> a
* Natural
k)
instance MSpace TimeSpec Natural where
TimeSpec
ts .% :: TimeSpec -> Natural -> TimeSpec
.% Natural
k = Double -> TimeSpec
fromSeconds (TimeSpec -> Double
toSeconds TimeSpec
ts Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Natural -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Natural
k)
instance Semimodule TimeSpec Natural
instance SemivectorSpace TimeSpec Natural
instance Normed TimeSpec where
norm :: TimeSpec -> TimeSpec
norm = TimeSpec -> TimeSpec
forall a. a -> a
id
sgn :: TimeSpec -> TimeSpec
sgn TimeSpec
x
| TimeSpec
x TimeSpec -> TimeSpec -> Bool
forall a. Eq a => a -> a -> Bool
== TimeSpec
forall m. AMonoid m => m
zero = TimeSpec
forall m. AMonoid m => m
zero
| Bool
otherwise = Natural -> Natural -> TimeSpec
MkTimeSpec Natural
1 Natural
0
fromSeconds :: Double -> TimeSpec
fromSeconds :: Double -> TimeSpec
fromSeconds Double
d =
MkTimeSpec
{ sec :: Natural
sec = Natural
seconds,
nsec :: Natural
nsec = Natural
nanoseconds
}
where
(Natural
seconds, Double
remainder) = Double -> (Natural, Double)
forall b. Integral b => Double -> (b, Double)
properFractionDouble Double
d
nanoseconds :: Natural
nanoseconds = Double -> Natural
forall b. Integral b => Double -> b
forall a b. (RealFrac a, Integral b) => a -> b
floor (Double -> Natural) -> Double -> Natural
forall a b. (a -> b) -> a -> b
$ Double
remainder Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
1_000_000_000
fromNanoSeconds :: Natural -> TimeSpec
fromNanoSeconds :: Natural -> TimeSpec
fromNanoSeconds Natural
nanoseconds = Natural -> Natural -> TimeSpec
MkTimeSpec Natural
s Natural
ns
where
(Natural
s, Natural
ns) = Natural -> Natural -> (Natural, Natural)
forall a. Integral a => a -> a -> (a, a)
quotRem Natural
nanoseconds Natural
1_000_000_000
toSeconds :: TimeSpec -> Double
toSeconds :: TimeSpec -> Double
toSeconds (MkTimeSpec Natural
s Natural
n) =
Natural -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Natural
s Double -> Double -> Double
forall a. Num a => a -> a -> a
+ (Natural -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Natural
n Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
1_000_000_000)
toNanoSeconds :: TimeSpec -> Natural
toNanoSeconds :: TimeSpec -> Natural
toNanoSeconds (MkTimeSpec Natural
s Natural
n) = (Natural
s Natural -> Natural -> Natural
forall a. Num a => a -> a -> a
* Natural
1_000_000_000) Natural -> Natural -> Natural
forall a. Num a => a -> a -> a
+ Natural
n
diffTimeSpec :: TimeSpec -> TimeSpec -> TimeSpec
diffTimeSpec :: TimeSpec -> TimeSpec -> TimeSpec
diffTimeSpec TimeSpec
t1 TimeSpec
t2
| Natural
t1' Natural -> Natural -> Bool
forall a. Ord a => a -> a -> Bool
>= Natural
t2' = Natural -> TimeSpec
fromNanoSeconds (Natural
t1' Natural -> Natural -> Natural
forall a. Num a => a -> a -> a
- Natural
t2')
| Bool
otherwise = Natural -> TimeSpec
fromNanoSeconds (Natural
t2' Natural -> Natural -> Natural
forall a. Num a => a -> a -> a
- Natural
t1')
where
t1' :: Natural
t1' = TimeSpec -> Natural
toNanoSeconds TimeSpec
t1
t2' :: Natural
t2' = TimeSpec -> Natural
toNanoSeconds TimeSpec
t2
normalizeTimeSpec :: TimeSpec -> TimeSpec
normalizeTimeSpec :: TimeSpec -> TimeSpec
normalizeTimeSpec = Natural -> TimeSpec
fromNanoSeconds (Natural -> TimeSpec)
-> (TimeSpec -> Natural) -> TimeSpec -> TimeSpec
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TimeSpec -> Natural
toNanoSeconds
#if !MIN_VERSION_base(4,17,0)
properFractionDouble :: Integral b => Double -> (b, Double)
{-# NOINLINE [1] properFractionDouble #-}
properFractionDouble x =
case decodeFloat x of
(m, n) ->
if n >= 0
then (fromInteger m * 2 ^ n, 0.0)
else case quotRem m (2 ^ negate n) of
(w, r) ->
(fromInteger w, encodeFloat r n)
#endif