{-# LANGUAGE CPP          #-}
{-# LANGUAGE TypeFamilies #-}
module Data.IOData where

import           Control.Monad                 (liftM)
import           Control.Monad.IO.Class
import qualified Data.ByteString               as ByteString
import qualified Data.ByteString.Char8         as ByteString8
import qualified Data.ByteString.Lazy          as LByteString
import           Data.ByteString.Lazy.Internal (defaultChunkSize)
import qualified Data.Text                     as Text
import qualified Data.Text.IO                  as Text
import qualified Data.Text.Lazy                as LText
import qualified Data.Text.Lazy.IO             as LText
import           Prelude                       (Char, flip, ($), (.), FilePath)
import qualified Prelude
import           System.IO                     (Handle)
import qualified System.IO

#if !MIN_VERSION_text(0, 11, 3)
import           Control.Exception             (handle, throwIO)
import           System.IO.Error               (isEOFError)
#endif

-- | Data which can be read to and from files and handles.
--
-- Note that, for lazy sequences, these operations may perform
-- lazy I\/O.
class IOData a where
    readFile     :: MonadIO m => FilePath -> m a
    writeFile    :: MonadIO m => FilePath -> a -> m ()
    getLine      :: MonadIO m => m a
    hGetContents :: MonadIO m => Handle -> m a
    hGetLine     :: MonadIO m => Handle -> m a
    hPut         :: MonadIO m => Handle -> a -> m ()
    hPutStrLn    :: MonadIO m => Handle -> a -> m ()
    hGetChunk    :: MonadIO m => Handle -> m a
instance IOData ByteString.ByteString where
    readFile :: FilePath -> m ByteString
readFile = IO ByteString -> m ByteString
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO ByteString -> m ByteString)
-> (FilePath -> IO ByteString) -> FilePath -> m ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> IO ByteString
ByteString.readFile
    writeFile :: FilePath -> ByteString -> m ()
writeFile FilePath
fp = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> (ByteString -> IO ()) -> ByteString -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> ByteString -> IO ()
ByteString.writeFile FilePath
fp
    getLine :: m ByteString
getLine = IO ByteString -> m ByteString
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO ByteString
ByteString.getLine
    hGetContents :: Handle -> m ByteString
hGetContents = IO ByteString -> m ByteString
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO ByteString -> m ByteString)
-> (Handle -> IO ByteString) -> Handle -> m ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> IO ByteString
ByteString.hGetContents
    hGetLine :: Handle -> m ByteString
hGetLine = IO ByteString -> m ByteString
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO ByteString -> m ByteString)
-> (Handle -> IO ByteString) -> Handle -> m ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> IO ByteString
ByteString.hGetLine
    hPut :: Handle -> ByteString -> m ()
hPut Handle
h = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> (ByteString -> IO ()) -> ByteString -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> ByteString -> IO ()
ByteString.hPut Handle
h
    hPutStrLn :: Handle -> ByteString -> m ()
hPutStrLn Handle
h = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> (ByteString -> IO ()) -> ByteString -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> ByteString -> IO ()
ByteString8.hPutStrLn Handle
h
    hGetChunk :: Handle -> m ByteString
hGetChunk = IO ByteString -> m ByteString
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO ByteString -> m ByteString)
-> (Handle -> IO ByteString) -> Handle -> m ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Handle -> Int -> IO ByteString) -> Int -> Handle -> IO ByteString
forall a b c. (a -> b -> c) -> b -> a -> c
flip Handle -> Int -> IO ByteString
ByteString.hGetSome Int
defaultChunkSize
instance IOData LByteString.ByteString where
    readFile :: FilePath -> m ByteString
readFile = IO ByteString -> m ByteString
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO ByteString -> m ByteString)
-> (FilePath -> IO ByteString) -> FilePath -> m ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> IO ByteString
LByteString.readFile
    writeFile :: FilePath -> ByteString -> m ()
writeFile FilePath
fp = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> (ByteString -> IO ()) -> ByteString -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> ByteString -> IO ()
LByteString.writeFile FilePath
fp
    getLine :: m ByteString
getLine = (ByteString -> ByteString) -> m ByteString -> m ByteString
forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM ByteString -> ByteString
LByteString.fromStrict (IO ByteString -> m ByteString
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO ByteString
ByteString.getLine)
    hGetContents :: Handle -> m ByteString
hGetContents = IO ByteString -> m ByteString
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO ByteString -> m ByteString)
-> (Handle -> IO ByteString) -> Handle -> m ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> IO ByteString
LByteString.hGetContents
    hGetLine :: Handle -> m ByteString
hGetLine = (ByteString -> ByteString) -> m ByteString -> m ByteString
forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM ByteString -> ByteString
LByteString.fromStrict (m ByteString -> m ByteString)
-> (Handle -> m ByteString) -> Handle -> m ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IO ByteString -> m ByteString
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO ByteString -> m ByteString)
-> (Handle -> IO ByteString) -> Handle -> m ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> IO ByteString
ByteString.hGetLine
    hPut :: Handle -> ByteString -> m ()
hPut Handle
h = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> (ByteString -> IO ()) -> ByteString -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> ByteString -> IO ()
LByteString.hPut Handle
h
    hPutStrLn :: Handle -> ByteString -> m ()
hPutStrLn Handle
h ByteString
lbs = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> IO () -> m ()
forall a b. (a -> b) -> a -> b
$ do
        Handle -> ByteString -> IO ()
LByteString.hPutStr Handle
h ByteString
lbs
        Handle -> ByteString -> IO ()
ByteString8.hPutStrLn Handle
h ByteString
ByteString.empty
    hGetChunk :: Handle -> m ByteString
hGetChunk = (ByteString -> ByteString) -> m ByteString -> m ByteString
forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM ByteString -> ByteString
LByteString.fromStrict (m ByteString -> m ByteString)
-> (Handle -> m ByteString) -> Handle -> m ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> m ByteString
forall a (m :: * -> *). (IOData a, MonadIO m) => Handle -> m a
hGetChunk
instance IOData Text.Text where
    readFile :: FilePath -> m Text
readFile = IO Text -> m Text
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Text -> m Text) -> (FilePath -> IO Text) -> FilePath -> m Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> IO Text
Text.readFile
    writeFile :: FilePath -> Text -> m ()
writeFile FilePath
fp = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> (Text -> IO ()) -> Text -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> Text -> IO ()
Text.writeFile FilePath
fp
    getLine :: m Text
getLine = IO Text -> m Text
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO Text
Text.getLine
    hGetContents :: Handle -> m Text
hGetContents = IO Text -> m Text
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Text -> m Text) -> (Handle -> IO Text) -> Handle -> m Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> IO Text
Text.hGetContents
    hGetLine :: Handle -> m Text
hGetLine = IO Text -> m Text
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Text -> m Text) -> (Handle -> IO Text) -> Handle -> m Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> IO Text
Text.hGetLine
    hPut :: Handle -> Text -> m ()
hPut Handle
h = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> (Text -> IO ()) -> Text -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> Text -> IO ()
Text.hPutStr Handle
h
    hPutStrLn :: Handle -> Text -> m ()
hPutStrLn Handle
h = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> (Text -> IO ()) -> Text -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> Text -> IO ()
Text.hPutStrLn Handle
h
#if MIN_VERSION_text(0, 11, 3)
    hGetChunk :: Handle -> m Text
hGetChunk = IO Text -> m Text
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Text -> m Text) -> (Handle -> IO Text) -> Handle -> m Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> IO Text
Text.hGetChunk
#else
    -- Dangerously inefficient!
    hGetChunk =
        liftIO . handleEOF . liftM Text.singleton . System.IO.hGetChar
      where
        handleEOF = handle $ \e ->
            if isEOFError e
                then Prelude.return Text.empty
                else throwIO e
#endif
instance IOData LText.Text where
    readFile :: FilePath -> m Text
readFile = IO Text -> m Text
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Text -> m Text) -> (FilePath -> IO Text) -> FilePath -> m Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> IO Text
LText.readFile
    writeFile :: FilePath -> Text -> m ()
writeFile FilePath
fp = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> (Text -> IO ()) -> Text -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> Text -> IO ()
LText.writeFile FilePath
fp
    getLine :: m Text
getLine = IO Text -> m Text
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO Text
LText.getLine
    hGetContents :: Handle -> m Text
hGetContents = IO Text -> m Text
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Text -> m Text) -> (Handle -> IO Text) -> Handle -> m Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> IO Text
LText.hGetContents
    hGetLine :: Handle -> m Text
hGetLine = IO Text -> m Text
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Text -> m Text) -> (Handle -> IO Text) -> Handle -> m Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> IO Text
LText.hGetLine
    hPut :: Handle -> Text -> m ()
hPut Handle
h = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> (Text -> IO ()) -> Text -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> Text -> IO ()
LText.hPutStr Handle
h
    hPutStrLn :: Handle -> Text -> m ()
hPutStrLn Handle
h = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> (Text -> IO ()) -> Text -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> Text -> IO ()
LText.hPutStrLn Handle
h
    hGetChunk :: Handle -> m Text
hGetChunk = (Text -> Text) -> m Text -> m Text
forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM Text -> Text
LText.fromStrict (m Text -> m Text) -> (Handle -> m Text) -> Handle -> m Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> m Text
forall a (m :: * -> *). (IOData a, MonadIO m) => Handle -> m a
hGetChunk
instance (Char ~ c) => IOData [c] where
    readFile :: FilePath -> m [c]
readFile = IO FilePath -> m FilePath
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO FilePath -> m FilePath)
-> (FilePath -> IO FilePath) -> FilePath -> m FilePath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> IO FilePath
Prelude.readFile
    writeFile :: FilePath -> [c] -> m ()
writeFile FilePath
fp = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> (FilePath -> IO ()) -> FilePath -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> FilePath -> IO ()
Prelude.writeFile FilePath
fp
    getLine :: m [c]
getLine = IO FilePath -> m FilePath
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO FilePath
Prelude.getLine
    hGetContents :: Handle -> m [c]
hGetContents = IO FilePath -> m FilePath
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO FilePath -> m FilePath)
-> (Handle -> IO FilePath) -> Handle -> m FilePath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> IO FilePath
System.IO.hGetContents
    hGetLine :: Handle -> m [c]
hGetLine = IO FilePath -> m FilePath
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO FilePath -> m FilePath)
-> (Handle -> IO FilePath) -> Handle -> m FilePath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> IO FilePath
System.IO.hGetLine
    hPut :: Handle -> [c] -> m ()
hPut Handle
h = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> (FilePath -> IO ()) -> FilePath -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> FilePath -> IO ()
System.IO.hPutStr Handle
h
    hPutStrLn :: Handle -> [c] -> m ()
hPutStrLn Handle
h = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> (FilePath -> IO ()) -> FilePath -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> FilePath -> IO ()
System.IO.hPutStrLn Handle
h
    hGetChunk :: Handle -> m [c]
hGetChunk = (Text -> FilePath) -> m Text -> m FilePath
forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM Text -> FilePath
Text.unpack (m Text -> m FilePath)
-> (Handle -> m Text) -> Handle -> m FilePath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> m Text
forall a (m :: * -> *). (IOData a, MonadIO m) => Handle -> m a
hGetChunk