module Database.Haskey.Utils.IO where

import Data.ByteString (ByteString, packCStringLen)
import Data.ByteString.Unsafe (unsafeUseAsCString)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BL

import Foreign (allocaBytes, castPtr, plusPtr)

import qualified FileIO as IO

import System.IO.Error (mkIOError, eofErrorType, ioeSetErrorString)

readByteString :: IO.FHandle -> Int -> IO ByteString
readByteString fd n = allocaBytes n $ \buf -> do
    go 0 buf
    packCStringLen (castPtr buf, fromIntegral n)
  where
    go c buf
        | c == n = return ()
        | otherwise = do
            rc <- IO.read fd buf (fromIntegral (n - c))
            case rc of
                0 -> ioError (ioeSetErrorString (mkIOError eofErrorType "getByteString" Nothing Nothing) "EOF")
                n' -> go (c + fromIntegral n') (buf `plusPtr` fromIntegral n')

writeByteString :: IO.FHandle -> ByteString -> IO ()
writeByteString fd bs = unsafeUseAsCString bs $ \buf -> go 0 buf
  where
    n = BS.length bs
    go c buf
        | c == n = return ()
        | otherwise = do
            n' <- IO.write fd (castPtr buf) (fromIntegral (n - c))
            go (c + fromIntegral n') (buf `plusPtr` fromIntegral n')

writeLazyByteString :: IO.FHandle -> BL.ByteString -> IO ()
writeLazyByteString fh bs = mapM_ (writeByteString fh) (BL.toChunks bs)