    -- |
    -- Module      : Foundation.Timing
    -- License     : BSD-style
    -- Maintainer  : Foundation maintainers
    --
    -- An implementation of a timing framework
    --
    {-# LANGUAGE DataKinds #-}
    {-# LANGUAGE GeneralizedNewtypeDeriving #-}
    module Foundation.Time.Types
        ( NanoSeconds(..)
        , Seconds(..)
        ) where

    import           Data.Proxy
    import           Basement.Imports
    import           Basement.PrimType
    import           Foundation.Numerical
    import           Data.Coerce

    -- | An amount of nanoseconds
    newtype NanoSeconds = NanoSeconds Word64
        deriving (Int -> NanoSeconds -> ShowS
    [NanoSeconds] -> ShowS
    NanoSeconds -> String
    (Int -> NanoSeconds -> ShowS)
    -> (NanoSeconds -> String)
    -> ([NanoSeconds] -> ShowS)
    -> Show NanoSeconds
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> NanoSeconds -> ShowS
    showsPrec :: Int -> NanoSeconds -> ShowS
    $cshow :: NanoSeconds -> String
    show :: NanoSeconds -> String
    $cshowList :: [NanoSeconds] -> ShowS
    showList :: [NanoSeconds] -> ShowS
    Show,NanoSeconds -> NanoSeconds -> Bool
    (NanoSeconds -> NanoSeconds -> Bool)
    -> (NanoSeconds -> NanoSeconds -> Bool) -> Eq NanoSeconds
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: NanoSeconds -> NanoSeconds -> Bool
    == :: NanoSeconds -> NanoSeconds -> Bool
    $c/= :: NanoSeconds -> NanoSeconds -> Bool
    /= :: NanoSeconds -> NanoSeconds -> Bool
    Eq,Eq NanoSeconds
    Eq NanoSeconds
    -> (NanoSeconds -> NanoSeconds -> Ordering)
    -> (NanoSeconds -> NanoSeconds -> Bool)
    -> (NanoSeconds -> NanoSeconds -> Bool)
    -> (NanoSeconds -> NanoSeconds -> Bool)
    -> (NanoSeconds -> NanoSeconds -> Bool)
    -> (NanoSeconds -> NanoSeconds -> NanoSeconds)
    -> (NanoSeconds -> NanoSeconds -> NanoSeconds)
    -> Ord NanoSeconds
    NanoSeconds -> NanoSeconds -> Bool
    NanoSeconds -> NanoSeconds -> Ordering
    NanoSeconds -> NanoSeconds -> NanoSeconds
    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
    $ccompare :: NanoSeconds -> NanoSeconds -> Ordering
    compare :: NanoSeconds -> NanoSeconds -> Ordering
    $c< :: NanoSeconds -> NanoSeconds -> Bool
    < :: NanoSeconds -> NanoSeconds -> Bool
    $c<= :: NanoSeconds -> NanoSeconds -> Bool
    <= :: NanoSeconds -> NanoSeconds -> Bool
    $c> :: NanoSeconds -> NanoSeconds -> Bool
    > :: NanoSeconds -> NanoSeconds -> Bool
    $c>= :: NanoSeconds -> NanoSeconds -> Bool
    >= :: NanoSeconds -> NanoSeconds -> Bool
    $cmax :: NanoSeconds -> NanoSeconds -> NanoSeconds
    max :: NanoSeconds -> NanoSeconds -> NanoSeconds
    $cmin :: NanoSeconds -> NanoSeconds -> NanoSeconds
    min :: NanoSeconds -> NanoSeconds -> NanoSeconds
    Ord,NanoSeconds
    NanoSeconds -> NanoSeconds -> NanoSeconds
    NanoSeconds
    -> (NanoSeconds -> NanoSeconds -> NanoSeconds)
    -> (forall n. IsNatural n => n -> NanoSeconds -> NanoSeconds)
    -> Additive NanoSeconds
    forall a.
    a
    -> (a -> a -> a)
    -> (forall n. IsNatural n => n -> a -> a)
    -> Additive a
    forall n. IsNatural n => n -> NanoSeconds -> NanoSeconds
    $cazero :: NanoSeconds
    azero :: NanoSeconds
    $c+ :: NanoSeconds -> NanoSeconds -> NanoSeconds
    + :: NanoSeconds -> NanoSeconds -> NanoSeconds
    $cscale :: forall n. IsNatural n => n -> NanoSeconds -> NanoSeconds
    scale :: forall n. IsNatural n => n -> NanoSeconds -> NanoSeconds
    Additive,Int -> NanoSeconds
    NanoSeconds -> Int
    NanoSeconds -> [NanoSeconds]
    NanoSeconds -> NanoSeconds
    NanoSeconds -> NanoSeconds -> [NanoSeconds]
    NanoSeconds -> NanoSeconds -> NanoSeconds -> [NanoSeconds]
    (NanoSeconds -> NanoSeconds)
    -> (NanoSeconds -> NanoSeconds)
    -> (Int -> NanoSeconds)
    -> (NanoSeconds -> Int)
    -> (NanoSeconds -> [NanoSeconds])
    -> (NanoSeconds -> NanoSeconds -> [NanoSeconds])
    -> (NanoSeconds -> NanoSeconds -> [NanoSeconds])
    -> (NanoSeconds -> NanoSeconds -> NanoSeconds -> [NanoSeconds])
    -> Enum NanoSeconds
    forall a.
    (a -> a)
    -> (a -> a)
    -> (Int -> a)
    -> (a -> Int)
    -> (a -> [a])
    -> (a -> a -> [a])
    -> (a -> a -> [a])
    -> (a -> a -> a -> [a])
    -> Enum a
    $csucc :: NanoSeconds -> NanoSeconds
    succ :: NanoSeconds -> NanoSeconds
    $cpred :: NanoSeconds -> NanoSeconds
    pred :: NanoSeconds -> NanoSeconds
    $ctoEnum :: Int -> NanoSeconds
    toEnum :: Int -> NanoSeconds
    $cfromEnum :: NanoSeconds -> Int
    fromEnum :: NanoSeconds -> Int
    $cenumFrom :: NanoSeconds -> [NanoSeconds]
    enumFrom :: NanoSeconds -> [NanoSeconds]
    $cenumFromThen :: NanoSeconds -> NanoSeconds -> [NanoSeconds]
    enumFromThen :: NanoSeconds -> NanoSeconds -> [NanoSeconds]
    $cenumFromTo :: NanoSeconds -> NanoSeconds -> [NanoSeconds]
    enumFromTo :: NanoSeconds -> NanoSeconds -> [NanoSeconds]
    $cenumFromThenTo :: NanoSeconds -> NanoSeconds -> NanoSeconds -> [NanoSeconds]
    enumFromThenTo :: NanoSeconds -> NanoSeconds -> NanoSeconds -> [NanoSeconds]
    Enum,NanoSeconds
    NanoSeconds -> NanoSeconds -> Bounded NanoSeconds
    forall a. a -> a -> Bounded a
    $cminBound :: NanoSeconds
    minBound :: NanoSeconds
    $cmaxBound :: NanoSeconds
    maxBound :: NanoSeconds
    Bounded)

    instance PrimType NanoSeconds where
        type PrimSize NanoSeconds = 8
        primSizeInBytes :: Proxy NanoSeconds -> CountOf Word8
    primSizeInBytes Proxy NanoSeconds
    _        = Proxy Word64 -> CountOf Word8
    forall ty. PrimType ty => Proxy ty -> CountOf Word8
    primSizeInBytes (Proxy Word64
    forall {k} (t :: k). Proxy t
    Proxy :: Proxy Word64)
        primShiftToBytes :: Proxy NanoSeconds -> Int
    primShiftToBytes Proxy NanoSeconds
    _       = Proxy Word64 -> Int
    forall ty. PrimType ty => Proxy ty -> Int
    primShiftToBytes (Proxy Word64
    forall {k} (t :: k). Proxy t
    Proxy :: Proxy Word64)
        primBaUIndex :: ByteArray# -> Offset NanoSeconds -> NanoSeconds
    primBaUIndex ByteArray#
    ba Offset NanoSeconds
    ofs      = ByteArray# -> Offset NanoSeconds -> NanoSeconds
    forall ty. PrimType ty => ByteArray# -> Offset ty -> ty
    primBaUIndex ByteArray#
    ba (Offset NanoSeconds -> Offset NanoSeconds
    forall a b. Coercible a b => a -> b
    coerce Offset NanoSeconds
    ofs)
        primMbaURead :: forall (prim :: * -> *).
    PrimMonad prim =>
    MutableByteArray# (PrimState prim)
    -> Offset NanoSeconds -> prim NanoSeconds
    primMbaURead MutableByteArray# (PrimState prim)
    mba Offset NanoSeconds
    ofs     = MutableByteArray# (PrimState prim)
    -> Offset NanoSeconds -> prim NanoSeconds
    forall ty (prim :: * -> *).
    (PrimType ty, PrimMonad prim) =>
    MutableByteArray# (PrimState prim) -> Offset ty -> prim ty
    forall (prim :: * -> *).
    PrimMonad prim =>
    MutableByteArray# (PrimState prim)
    -> Offset NanoSeconds -> prim NanoSeconds
    primMbaURead MutableByteArray# (PrimState prim)
    mba (Offset NanoSeconds -> Offset NanoSeconds
    forall a b. Coercible a b => a -> b
    coerce Offset NanoSeconds
    ofs)
        primMbaUWrite :: forall (prim :: * -> *).
    PrimMonad prim =>
    MutableByteArray# (PrimState prim)
    -> Offset NanoSeconds -> NanoSeconds -> prim ()
    primMbaUWrite MutableByteArray# (PrimState prim)
    mba Offset NanoSeconds
    ofs NanoSeconds
    v  = MutableByteArray# (PrimState prim)
    -> Offset Word64 -> Word64 -> prim ()
    forall ty (prim :: * -> *).
    (PrimType ty, PrimMonad prim) =>
    MutableByteArray# (PrimState prim) -> Offset ty -> ty -> prim ()
    forall (prim :: * -> *).
    PrimMonad prim =>
    MutableByteArray# (PrimState prim)
    -> Offset Word64 -> Word64 -> prim ()
    primMbaUWrite MutableByteArray# (PrimState prim)
    mba (Offset NanoSeconds -> Offset Word64
    forall a b. Coercible a b => a -> b
    coerce Offset NanoSeconds
    ofs) (NanoSeconds -> Word64
    forall a b. Coercible a b => a -> b
    coerce NanoSeconds
    v :: Word64)
        primAddrIndex :: Addr# -> Offset NanoSeconds -> NanoSeconds
    primAddrIndex Addr#
    addr Offset NanoSeconds
    ofs   = Addr# -> Offset NanoSeconds -> NanoSeconds
    forall ty. PrimType ty => Addr# -> Offset ty -> ty
    primAddrIndex Addr#
    addr (Offset NanoSeconds -> Offset NanoSeconds
    forall a b. Coercible a b => a -> b
    coerce Offset NanoSeconds
    ofs)
        primAddrRead :: forall (prim :: * -> *).
    PrimMonad prim =>
    Addr# -> Offset NanoSeconds -> prim NanoSeconds
    primAddrRead Addr#
    addr Offset NanoSeconds
    ofs    = Addr# -> Offset NanoSeconds -> prim NanoSeconds
    forall ty (prim :: * -> *).
    (PrimType ty, PrimMonad prim) =>
    Addr# -> Offset ty -> prim ty
    forall (prim :: * -> *).
    PrimMonad prim =>
    Addr# -> Offset NanoSeconds -> prim NanoSeconds
    primAddrRead Addr#
    addr (Offset NanoSeconds -> Offset NanoSeconds
    forall a b. Coercible a b => a -> b
    coerce Offset NanoSeconds
    ofs)
        primAddrWrite :: forall (prim :: * -> *).
    PrimMonad prim =>
    Addr# -> Offset NanoSeconds -> NanoSeconds -> prim ()
    primAddrWrite Addr#
    addr Offset NanoSeconds
    ofs NanoSeconds
    v = Addr# -> Offset Word64 -> Word64 -> prim ()
    forall ty (prim :: * -> *).
    (PrimType ty, PrimMonad prim) =>
    Addr# -> Offset ty -> ty -> prim ()
    forall (prim :: * -> *).
    PrimMonad prim =>
    Addr# -> Offset Word64 -> Word64 -> prim ()
    primAddrWrite Addr#
    addr (Offset NanoSeconds -> Offset Word64
    forall a b. Coercible a b => a -> b
    coerce Offset NanoSeconds
    ofs) (NanoSeconds -> Word64
    forall a b. Coercible a b => a -> b
    coerce NanoSeconds
    v :: Word64)

    -- | An amount of seconds
    newtype Seconds = Seconds Word64
        deriving (Int -> Seconds -> ShowS
    [Seconds] -> ShowS
    Seconds -> String
    (Int -> Seconds -> ShowS)
    -> (Seconds -> String) -> ([Seconds] -> ShowS) -> Show Seconds
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> Seconds -> ShowS
    showsPrec :: Int -> Seconds -> ShowS
    $cshow :: Seconds -> String
    show :: Seconds -> String
    $cshowList :: [Seconds] -> ShowS
    showList :: [Seconds] -> ShowS
    Show,Seconds -> Seconds -> Bool
    (Seconds -> Seconds -> Bool)
    -> (Seconds -> Seconds -> Bool) -> Eq Seconds
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: Seconds -> Seconds -> Bool
    == :: Seconds -> Seconds -> Bool
    $c/= :: Seconds -> Seconds -> Bool
    /= :: Seconds -> Seconds -> Bool
    Eq,Eq Seconds
    Eq Seconds
    -> (Seconds -> Seconds -> Ordering)
    -> (Seconds -> Seconds -> Bool)
    -> (Seconds -> Seconds -> Bool)
    -> (Seconds -> Seconds -> Bool)
    -> (Seconds -> Seconds -> Bool)
    -> (Seconds -> Seconds -> Seconds)
    -> (Seconds -> Seconds -> Seconds)
    -> Ord Seconds
    Seconds -> Seconds -> Bool
    Seconds -> Seconds -> Ordering
    Seconds -> Seconds -> Seconds
    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
    $ccompare :: Seconds -> Seconds -> Ordering
    compare :: Seconds -> Seconds -> Ordering
    $c< :: Seconds -> Seconds -> Bool
    < :: Seconds -> Seconds -> Bool
    $c<= :: Seconds -> Seconds -> Bool
    <= :: Seconds -> Seconds -> Bool
    $c> :: Seconds -> Seconds -> Bool
    > :: Seconds -> Seconds -> Bool
    $c>= :: Seconds -> Seconds -> Bool
    >= :: Seconds -> Seconds -> Bool
    $cmax :: Seconds -> Seconds -> Seconds
    max :: Seconds -> Seconds -> Seconds
    $cmin :: Seconds -> Seconds -> Seconds
    min :: Seconds -> Seconds -> Seconds
    Ord,Seconds
    Seconds -> Seconds -> Seconds
    Seconds
    -> (Seconds -> Seconds -> Seconds)
    -> (forall n. IsNatural n => n -> Seconds -> Seconds)
    -> Additive Seconds
    forall a.
    a
    -> (a -> a -> a)
    -> (forall n. IsNatural n => n -> a -> a)
    -> Additive a
    forall n. IsNatural n => n -> Seconds -> Seconds
    $cazero :: Seconds
    azero :: Seconds
    $c+ :: Seconds -> Seconds -> Seconds
    + :: Seconds -> Seconds -> Seconds
    $cscale :: forall n. IsNatural n => n -> Seconds -> Seconds
    scale :: forall n. IsNatural n => n -> Seconds -> Seconds
    Additive,Int -> Seconds
    Seconds -> Int
    Seconds -> [Seconds]
    Seconds -> Seconds
    Seconds -> Seconds -> [Seconds]
    Seconds -> Seconds -> Seconds -> [Seconds]
    (Seconds -> Seconds)
    -> (Seconds -> Seconds)
    -> (Int -> Seconds)
    -> (Seconds -> Int)
    -> (Seconds -> [Seconds])
    -> (Seconds -> Seconds -> [Seconds])
    -> (Seconds -> Seconds -> [Seconds])
    -> (Seconds -> Seconds -> Seconds -> [Seconds])
    -> Enum Seconds
    forall a.
    (a -> a)
    -> (a -> a)
    -> (Int -> a)
    -> (a -> Int)
    -> (a -> [a])
    -> (a -> a -> [a])
    -> (a -> a -> [a])
    -> (a -> a -> a -> [a])
    -> Enum a
    $csucc :: Seconds -> Seconds
    succ :: Seconds -> Seconds
    $cpred :: Seconds -> Seconds
    pred :: Seconds -> Seconds
    $ctoEnum :: Int -> Seconds
    toEnum :: Int -> Seconds
    $cfromEnum :: Seconds -> Int
    fromEnum :: Seconds -> Int
    $cenumFrom :: Seconds -> [Seconds]
    enumFrom :: Seconds -> [Seconds]
    $cenumFromThen :: Seconds -> Seconds -> [Seconds]
    enumFromThen :: Seconds -> Seconds -> [Seconds]
    $cenumFromTo :: Seconds -> Seconds -> [Seconds]
    enumFromTo :: Seconds -> Seconds -> [Seconds]
    $cenumFromThenTo :: Seconds -> Seconds -> Seconds -> [Seconds]
    enumFromThenTo :: Seconds -> Seconds -> Seconds -> [Seconds]
    Enum,Seconds
    Seconds -> Seconds -> Bounded Seconds
    forall a. a -> a -> Bounded a
    $cminBound :: Seconds
    minBound :: Seconds
    $cmaxBound :: Seconds
    maxBound :: Seconds
    Bounded)

    instance PrimType Seconds where
        type PrimSize Seconds    = 8
        primSizeInBytes :: Proxy Seconds -> CountOf Word8
    primSizeInBytes Proxy Seconds
    _        = Proxy Word64 -> CountOf Word8
    forall ty. PrimType ty => Proxy ty -> CountOf Word8
    primSizeInBytes (Proxy Word64
    forall {k} (t :: k). Proxy t
    Proxy :: Proxy Word64)
        primShiftToBytes :: Proxy Seconds -> Int
    primShiftToBytes Proxy Seconds
    _       = Proxy Word64 -> Int
    forall ty. PrimType ty => Proxy ty -> Int
    primShiftToBytes (Proxy Word64
    forall {k} (t :: k). Proxy t
    Proxy :: Proxy Word64)
        primBaUIndex :: ByteArray# -> Offset Seconds -> Seconds
    primBaUIndex ByteArray#
    ba Offset Seconds
    ofs      = ByteArray# -> Offset Seconds -> Seconds
    forall ty. PrimType ty => ByteArray# -> Offset ty -> ty
    primBaUIndex ByteArray#
    ba (Offset Seconds -> Offset Seconds
    forall a b. Coercible a b => a -> b
    coerce Offset Seconds
    ofs)
        primMbaURead :: forall (prim :: * -> *).
    PrimMonad prim =>
    MutableByteArray# (PrimState prim)
    -> Offset Seconds -> prim Seconds
    primMbaURead MutableByteArray# (PrimState prim)
    mba Offset Seconds
    ofs     = MutableByteArray# (PrimState prim)
    -> Offset Seconds -> prim Seconds
    forall ty (prim :: * -> *).
    (PrimType ty, PrimMonad prim) =>
    MutableByteArray# (PrimState prim) -> Offset ty -> prim ty
    forall (prim :: * -> *).
    PrimMonad prim =>
    MutableByteArray# (PrimState prim)
    -> Offset Seconds -> prim Seconds
    primMbaURead MutableByteArray# (PrimState prim)
    mba (Offset Seconds -> Offset Seconds
    forall a b. Coercible a b => a -> b
    coerce Offset Seconds
    ofs)
        primMbaUWrite :: forall (prim :: * -> *).
    PrimMonad prim =>
    MutableByteArray# (PrimState prim)
    -> Offset Seconds -> Seconds -> prim ()
    primMbaUWrite MutableByteArray# (PrimState prim)
    mba Offset Seconds
    ofs Seconds
    v  = MutableByteArray# (PrimState prim)
    -> Offset Word64 -> Word64 -> prim ()
    forall ty (prim :: * -> *).
    (PrimType ty, PrimMonad prim) =>
    MutableByteArray# (PrimState prim) -> Offset ty -> ty -> prim ()
    forall (prim :: * -> *).
    PrimMonad prim =>
    MutableByteArray# (PrimState prim)
    -> Offset Word64 -> Word64 -> prim ()
    primMbaUWrite MutableByteArray# (PrimState prim)
    mba (Offset Seconds -> Offset Word64
    forall a b. Coercible a b => a -> b
    coerce Offset Seconds
    ofs) (Seconds -> Word64
    forall a b. Coercible a b => a -> b
    coerce Seconds
    v :: Word64)
        primAddrIndex :: Addr# -> Offset Seconds -> Seconds
    primAddrIndex Addr#
    addr Offset Seconds
    ofs   = Addr# -> Offset Seconds -> Seconds
    forall ty. PrimType ty => Addr# -> Offset ty -> ty
    primAddrIndex Addr#
    addr (Offset Seconds -> Offset Seconds
    forall a b. Coercible a b => a -> b
    coerce Offset Seconds
    ofs)
        primAddrRead :: forall (prim :: * -> *).
    PrimMonad prim =>
    Addr# -> Offset Seconds -> prim Seconds
    primAddrRead Addr#
    addr Offset Seconds
    ofs    = Addr# -> Offset Seconds -> prim Seconds
    forall ty (prim :: * -> *).
    (PrimType ty, PrimMonad prim) =>
    Addr# -> Offset ty -> prim ty
    forall (prim :: * -> *).
    PrimMonad prim =>
    Addr# -> Offset Seconds -> prim Seconds
    primAddrRead Addr#
    addr (Offset Seconds -> Offset Seconds
    forall a b. Coercible a b => a -> b
    coerce Offset Seconds
    ofs)
        primAddrWrite :: forall (prim :: * -> *).
    PrimMonad prim =>
    Addr# -> Offset Seconds -> Seconds -> prim ()
    primAddrWrite Addr#
    addr Offset Seconds
    ofs Seconds
    v = Addr# -> Offset Word64 -> Word64 -> prim ()
    forall ty (prim :: * -> *).
    (PrimType ty, PrimMonad prim) =>
    Addr# -> Offset ty -> ty -> prim ()
    forall (prim :: * -> *).
    PrimMonad prim =>
    Addr# -> Offset Word64 -> Word64 -> prim ()
    primAddrWrite Addr#
    addr (Offset Seconds -> Offset Word64
    forall a b. Coercible a b => a -> b
    coerce Offset Seconds
    ofs) (Seconds -> Word64
    forall a b. Coercible a b => a -> b
    coerce Seconds
    v :: Word64)