{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE Strict #-}
module VtUtils.IO
( IOWithFileException(..)
, ioWithFileBytes
, ioWithFileText
) where
import Prelude (Either(..), IO, Show, ($), return, show)
import Control.Exception (Exception, SomeException(..), throwIO, try)
import qualified Data.ByteString.Lazy as ByteStringLazy
import Data.Monoid ((<>))
import Data.Text (Text, unpack)
import Data.Text.Encoding.Error (lenientDecode)
import Data.Text.Lazy.Encoding (decodeUtf8With)
import qualified Data.Text.Lazy as TextLazy
import System.IO (IOMode(ReadMode), withBinaryFile)
import VtUtils.Error (errorShow)
import VtUtils.Text (textShow)
data IOWithFileException = IOWithFileException
{ filePath :: Text
, exception :: SomeException
}
instance Exception IOWithFileException
instance Show IOWithFileException where
show e@(IOWithFileException {filePath, exception}) = errorShow e $
"Error reading file,"
<> " path: [" <> filePath <> "],"
<> " exception: [" <> textShow(exception) <> "]"
ioWithFileBytes :: Text -> (ByteStringLazy.ByteString -> IO a) -> IO a
ioWithFileBytes path fun = do
outcome <- try $
withBinaryFile (unpack path) ReadMode $ \ha -> do
bs <- ByteStringLazy.hGetContents ha
res <- fun bs
return res
case outcome of
Left e -> throwIO $ IOWithFileException path e
Right res -> return res
ioWithFileText :: Text -> (TextLazy.Text -> IO a) -> IO a
ioWithFileText path fun =
ioWithFileBytes path $ \bs -> do
let tx = decodeUtf8With lenientDecode bs
res <- fun tx
return res