module Entry (Entry (..), Checksum, Timestamp, FieldSize, Key, Value, matchChecksum, nanosSinceEpoch, buildEntry, getEntryLength) where

import qualified Data.ByteString.Lazy as B
import qualified Data.ByteString.Lazy.UTF8 as BU
import Data.Digest.CRC32 (crc32)
import Data.Int (Int64)
import Data.String.Interpolate (i)
import Data.Time (nominalDiffTimeToSeconds)
import Data.Time.Clock.POSIX (getPOSIXTime)
import Data.Word (Word32)

type Checksum = Word32

type Timestamp = Int64

type FieldSize = Int64

type Key = B.ByteString

type Value = B.ByteString

data Entry = Entry Checksum Timestamp FieldSize FieldSize Key Value
  deriving (Entry -> Entry -> Bool
(Entry -> Entry -> Bool) -> (Entry -> Entry -> Bool) -> Eq Entry
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Entry -> Entry -> Bool
== :: Entry -> Entry -> Bool
$c/= :: Entry -> Entry -> Bool
/= :: Entry -> Entry -> Bool
Eq)

instance Show Entry where
  show :: Entry -> String
show (Entry Checksum
fileid FieldSize
timestamp FieldSize
ksize FieldSize
vsize Key
key Key
value) =
    [i|#{fileid'} #{timestamp'} #{ksize'} #{vsize'} #{key'} #{value'}|]
    where
      fileid' :: String
fileid' = Checksum -> String
forall a. Show a => a -> String
show Checksum
fileid
      timestamp' :: String
timestamp' = FieldSize -> String
forall a. Show a => a -> String
show FieldSize
timestamp
      ksize' :: String
ksize' = FieldSize -> String
forall a. Show a => a -> String
show FieldSize
ksize
      vsize' :: String
vsize' = FieldSize -> String
forall a. Show a => a -> String
show FieldSize
vsize
      key' :: String
key' = Key -> String
BU.toString Key
key
      value' :: String
value' = Key -> String
BU.toString Key
value

nanosSinceEpoch :: IO Timestamp
nanosSinceEpoch :: IO FieldSize
nanosSinceEpoch = do
  POSIXTime
t <- IO POSIXTime
getPOSIXTime
  FieldSize -> IO FieldSize
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (FieldSize -> IO FieldSize) -> FieldSize -> IO FieldSize
forall a b. (a -> b) -> a -> b
$ Pico -> FieldSize
forall b. Integral b => Pico -> b
forall a b. (RealFrac a, Integral b) => a -> b
floor (Pico -> FieldSize) -> Pico -> FieldSize
forall a b. (a -> b) -> a -> b
$ Pico
1e9 Pico -> Pico -> Pico
forall a. Num a => a -> a -> a
* POSIXTime -> Pico
nominalDiffTimeToSeconds POSIXTime
t

buildEntry :: Timestamp -> Key -> Value -> Entry
buildEntry :: FieldSize -> Key -> Key -> Entry
buildEntry FieldSize
timestamp Key
key Key
value = Checksum
-> FieldSize -> FieldSize -> FieldSize -> Key -> Key -> Entry
Entry Checksum
checksum FieldSize
timestamp FieldSize
keyl FieldSize
valuel Key
key Key
value
  where
    checksum :: Checksum
checksum = Key -> Checksum
forall a. CRC32 a => a -> Checksum
crc32 (Key -> Checksum) -> Key -> Checksum
forall a b. (a -> b) -> a -> b
$ String -> Key
BU.fromString (String -> Key) -> String -> Key
forall a b. (a -> b) -> a -> b
$ FieldSize -> String
forall a. Show a => a -> String
show FieldSize
timestamp String -> ShowS
forall a. [a] -> [a] -> [a]
++ FieldSize -> String
forall a. Show a => a -> String
show FieldSize
keyl String -> ShowS
forall a. [a] -> [a] -> [a]
++ FieldSize -> String
forall a. Show a => a -> String
show FieldSize
valuel String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
key' String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
value'
    keyl :: FieldSize
keyl = Key -> FieldSize
B.length Key
key
    valuel :: FieldSize
valuel = Key -> FieldSize
B.length Key
value
    key' :: String
key' = Key -> String
BU.toString Key
key
    value' :: String
value' = Key -> String
BU.toString Key
value

getEntryLength :: Entry -> Int
getEntryLength :: Entry -> Int
getEntryLength (Entry Checksum
_ FieldSize
_ FieldSize
ksize FieldSize
vsize Key
_ Key
_) = FieldSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (FieldSize -> Int) -> FieldSize -> Int
forall a b. (a -> b) -> a -> b
$ FieldSize
4 FieldSize -> FieldSize -> FieldSize
forall a. Num a => a -> a -> a
+ FieldSize
8 FieldSize -> FieldSize -> FieldSize
forall a. Num a => a -> a -> a
+ FieldSize
8 FieldSize -> FieldSize -> FieldSize
forall a. Num a => a -> a -> a
+ FieldSize
8 FieldSize -> FieldSize -> FieldSize
forall a. Num a => a -> a -> a
+ FieldSize
ksize FieldSize -> FieldSize -> FieldSize
forall a. Num a => a -> a -> a
+ FieldSize
vsize

matchChecksum :: Entry -> Bool
matchChecksum :: Entry -> Bool
matchChecksum (Entry Checksum
checksum FieldSize
timestamp FieldSize
ksize FieldSize
vsize Key
k Key
v) = Checksum
checksum Checksum -> Checksum -> Bool
forall a. Eq a => a -> a -> Bool
== Checksum
checksum'
  where
    checksum' :: Checksum
checksum' = Key -> Checksum
forall a. CRC32 a => a -> Checksum
crc32 (Key -> Checksum) -> Key -> Checksum
forall a b. (a -> b) -> a -> b
$ String -> Key
BU.fromString (String -> Key) -> String -> Key
forall a b. (a -> b) -> a -> b
$ FieldSize -> String
forall a. Show a => a -> String
show FieldSize
timestamp String -> ShowS
forall a. [a] -> [a] -> [a]
++ FieldSize -> String
forall a. Show a => a -> String
show FieldSize
ksize String -> ShowS
forall a. [a] -> [a] -> [a]
++ FieldSize -> String
forall a. Show a => a -> String
show FieldSize
vsize String -> ShowS
forall a. [a] -> [a] -> [a]
++ Key -> String
BU.toString Key
k String -> ShowS
forall a. [a] -> [a] -> [a]
++ Key -> String
BU.toString Key
v