    -- | Simple resource management functions

    {-# LANGUAGE RankNTypes #-}

    module Pipes.Safe.Prelude (
        -- * Handle management
        withFile,

        -- * String I/O
        -- $strings
        readFile,
        writeFile
        ) where

    import Control.Monad.IO.Class (MonadIO(liftIO))
    import Pipes (Producer', Consumer')
    import Pipes.Safe (bracket, MonadSafe)
    import qualified Pipes.Prelude as P
    import qualified System.IO as IO
    import Prelude hiding (readFile, writeFile)

    -- | Acquire a 'IO.Handle' within 'MonadSafe'
    withFile :: (MonadSafe m) => FilePath -> IO.IOMode -> (IO.Handle -> m r) -> m r
    withFile file ioMode = bracket (liftIO $ IO.openFile file ioMode) (liftIO . IO.hClose)
    {-# INLINABLE withFile #-}

    {- $strings
        Note that 'String's are very inefficient, and I will release future separate
        packages with 'Data.ByteString.ByteString' and 'Data.Text.Text' operations.
        I only provide these to allow users to test simple I/O without requiring any
        additional library dependencies.
    -}

    {-| Read lines from a file, automatically opening and closing the file as
        necessary
    -}
    readFile :: (MonadSafe m) => FilePath -> Producer' String m ()
    readFile file = withFile file IO.ReadMode P.fromHandle
    {-# INLINABLE readFile #-}

    {-| Write lines to a file, automatically opening and closing the file as
        necessary
    -}
    writeFile :: (MonadSafe m) => FilePath -> Consumer' String m r
    writeFile file = withFile file IO.WriteMode P.toHandle
    {-# INLINABLE writeFile #-}