{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
module Database.Immutable.Read
(
createDB
, readDB
, I.Name
, I.Indexes
, unindexed
, byteStringIndex
, word32Index
) where
import qualified Data.ByteString as B
import Data.Maybe (maybe)
import Data.Monoid ((<>))
import qualified Data.Serialize as S
import Data.Word
import qualified Data.Vector.Storable as VS
import qualified Data.Vector.Storable.Mutable as VSM
import qualified Multimap.ByteString as MMB
import qualified Multimap.Word32 as MMW
import GHC.TypeLits
import qualified Database.Immutable.Internal as I
unindexed :: I.Indexes '[] a
unindexed = I.Indexes (pure ())
word32Index
:: KnownSymbol s
=> I.Name s
-> (a -> b)
-> (b -> Word32)
-> I.Indexes indexes a
-> I.Indexes ('(s, I.Word32Index b):indexes) a
word32Index _ p f (I.Indexes indexes') = I.Indexes $ do
indexes <- indexes'
mm <- MMW.new
pure (mm, p, f, indexes)
byteStringIndex
:: KnownSymbol s
=> I.Name s
-> (a -> b)
-> (b -> B.ByteString)
-> I.Indexes indexes a
-> I.Indexes ('(s, I.ByteStringIndex b):indexes) a
byteStringIndex _ p f (I.Indexes indexes') = I.Indexes $ do
indexes <- indexes'
mm <- MMB.new
pure (mm, p, f, indexes)
createDB
:: forall indexes a
. S.Serialize a
=> I.InsertIndex indexes a
=> B.ByteString
-> Int
-> (Maybe (Int -> Int -> IO ()))
-> I.Indexes indexes a
-> IO (Either String (I.DB indexes a))
createDB contents count progress (I.Indexes indexes') = do
indexes <- indexes'
offsets <- VSM.new (fromIntegral count)
let go bs (!x) f
| not (B.null bs) = do
case f bs of
S.Fail e _ -> pure $ Left e
S.Partial _ -> pure $ Left "Unexpected Partial"
S.Done a bs' -> do
VSM.write offsets x (fromIntegral (B.length contents - B.length bs'))
I.insertIndex
(I.Indexes' indexes :: I.Indexes' indexes a)
(fromIntegral x)
a
maybe (pure ()) (\f' -> f' x (fromIntegral count)) progress
go bs' (x + 1) (S.runGetPartial S.get)
| otherwise = pure $ Right ()
r <- go contents 0 (S.runGetPartial S.get)
case r of
Left e -> pure $ Left e
Right () -> do
voffsets <- VS.unsafeFreeze offsets
pure $ Right (I.DB indexes contents voffsets)
readDB
:: forall indexes a
. S.Serialize a
=> I.InsertIndex indexes a
=> FilePath
-> (Maybe (Int -> Int -> IO ()))
-> I.Indexes indexes a
-> IO (Either String (I.DB indexes a))
readDB path progress indexes = do
meta <- B.readFile (path <> ".meta")
case S.decode meta of
Left e -> pure $ Left e
Right (count :: Word32) -> do
contents <- B.readFile path
createDB contents (fromIntegral count) progress indexes