-- | Unlifted "System.IO".
--
-- @since 0.1.0.0
module UnliftIO.IO
  ( IOMode (..)
  , Handle
  , IO.stdin
  , IO.stdout
  , IO.stderr
  , withFile
  , withBinaryFile
  , hClose
  , hFlush
  , hFileSize
  , hSetFileSize
  , hIsEOF
  , IO.BufferMode (..)
  , hSetBuffering
  , hGetBuffering
  , hSeek
  , IO.SeekMode (..)
  , hTell
  , hIsOpen
  , hIsClosed
  , hIsReadable
  , hIsWritable
  , hIsSeekable
  , hIsTerminalDevice
  , hSetEcho
  , hGetEcho
  , hWaitForInput
  , hReady
  , getMonotonicTime
  ) where

import qualified System.IO as IO
import System.IO (Handle, IOMode (..))
import Control.Monad.IO.Unlift

import System.IO.Unsafe (unsafePerformIO)

-- | Unlifted version of 'IO.withFile'.
--
-- @since 0.1.0.0
withFile :: MonadUnliftIO m => FilePath -> IOMode -> (Handle -> m a) -> m a
withFile :: FilePath -> IOMode -> (Handle -> m a) -> m a
withFile FilePath
fp IOMode
mode Handle -> m a
inner = ((forall a. m a -> IO a) -> IO a) -> m a
forall (m :: * -> *) b.
MonadUnliftIO m =>
((forall a. m a -> IO a) -> IO b) -> m b
withRunInIO (((forall a. m a -> IO a) -> IO a) -> m a)
-> ((forall a. m a -> IO a) -> IO a) -> m a
forall a b. (a -> b) -> a -> b
$ \forall a. m a -> IO a
run -> FilePath -> IOMode -> (Handle -> IO a) -> IO a
forall r. FilePath -> IOMode -> (Handle -> IO r) -> IO r
IO.withFile FilePath
fp IOMode
mode ((Handle -> IO a) -> IO a) -> (Handle -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ m a -> IO a
forall a. m a -> IO a
run (m a -> IO a) -> (Handle -> m a) -> Handle -> IO a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> m a
inner

-- | Unlifted version of 'IO.withBinaryFile'.
--
-- @since 0.1.0.0
withBinaryFile :: MonadUnliftIO m => FilePath -> IOMode -> (Handle -> m a) -> m a
withBinaryFile :: FilePath -> IOMode -> (Handle -> m a) -> m a
withBinaryFile FilePath
fp IOMode
mode Handle -> m a
inner = ((forall a. m a -> IO a) -> IO a) -> m a
forall (m :: * -> *) b.
MonadUnliftIO m =>
((forall a. m a -> IO a) -> IO b) -> m b
withRunInIO (((forall a. m a -> IO a) -> IO a) -> m a)
-> ((forall a. m a -> IO a) -> IO a) -> m a
forall a b. (a -> b) -> a -> b
$ \forall a. m a -> IO a
run -> FilePath -> IOMode -> (Handle -> IO a) -> IO a
forall r. FilePath -> IOMode -> (Handle -> IO r) -> IO r
IO.withBinaryFile FilePath
fp IOMode
mode ((Handle -> IO a) -> IO a) -> (Handle -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ m a -> IO a
forall a. m a -> IO a
run (m a -> IO a) -> (Handle -> m a) -> Handle -> IO a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> m a
inner

-- | Lifted version of 'IO.hClose'
--
-- @since 0.2.1.0
hClose :: MonadIO m => Handle -> m ()
hClose :: Handle -> m ()
hClose = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> (Handle -> IO ()) -> Handle -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> IO ()
IO.hClose

-- | Lifted version of 'IO.hFlush'
--
-- @since 0.2.1.0
hFlush :: MonadIO m => Handle -> m ()
hFlush :: Handle -> m ()
hFlush = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> (Handle -> IO ()) -> Handle -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> IO ()
IO.hFlush

-- | Lifted version of 'IO.hFileSize'
--
-- @since 0.2.1.0
hFileSize :: MonadIO m => Handle -> m Integer
hFileSize :: Handle -> m Integer
hFileSize = IO Integer -> m Integer
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Integer -> m Integer)
-> (Handle -> IO Integer) -> Handle -> m Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> IO Integer
IO.hFileSize

-- | Lifted version of 'IO.hSetFileSize'
--
-- @since 0.2.1.0
hSetFileSize :: MonadIO m => Handle -> Integer -> m ()
hSetFileSize :: Handle -> Integer -> m ()
hSetFileSize Handle
h = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> (Integer -> IO ()) -> Integer -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> Integer -> IO ()
IO.hSetFileSize Handle
h

-- | Lifted version of 'IO.hIsEOF'
--
-- @since 0.2.1.0
hIsEOF :: MonadIO m => Handle -> m Bool
hIsEOF :: Handle -> m Bool
hIsEOF = IO Bool -> m Bool
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Bool -> m Bool) -> (Handle -> IO Bool) -> Handle -> m Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> IO Bool
IO.hIsEOF

-- | Lifted version of 'IO.hSetBuffering'
--
-- @since 0.2.1.0
hSetBuffering :: MonadIO m => Handle -> IO.BufferMode -> m ()
hSetBuffering :: Handle -> BufferMode -> m ()
hSetBuffering Handle
h = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> (BufferMode -> IO ()) -> BufferMode -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> BufferMode -> IO ()
IO.hSetBuffering Handle
h

-- | Lifted version of 'IO.hGetBuffering'
--
-- @since 0.2.1.0
hGetBuffering :: MonadIO m => Handle -> m IO.BufferMode
hGetBuffering :: Handle -> m BufferMode
hGetBuffering = IO BufferMode -> m BufferMode
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO BufferMode -> m BufferMode)
-> (Handle -> IO BufferMode) -> Handle -> m BufferMode
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> IO BufferMode
IO.hGetBuffering

-- | Lifted version of 'IO.hSeek'
--
-- @since 0.2.1.0
hSeek :: MonadIO m => Handle -> IO.SeekMode -> Integer -> m ()
hSeek :: Handle -> SeekMode -> Integer -> m ()
hSeek Handle
h SeekMode
s = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> (Integer -> IO ()) -> Integer -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> SeekMode -> Integer -> IO ()
IO.hSeek Handle
h SeekMode
s

-- | Lifted version of 'IO.hTell'
--
-- @since 0.2.1.0
hTell :: MonadIO m => Handle -> m Integer
hTell :: Handle -> m Integer
hTell = IO Integer -> m Integer
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Integer -> m Integer)
-> (Handle -> IO Integer) -> Handle -> m Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> IO Integer
IO.hTell

-- | Lifted version of 'IO.hIsOpen'
--
-- @since 0.2.1.0
hIsOpen :: MonadIO m => Handle -> m Bool
hIsOpen :: Handle -> m Bool
hIsOpen = IO Bool -> m Bool
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Bool -> m Bool) -> (Handle -> IO Bool) -> Handle -> m Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> IO Bool
IO.hIsOpen

-- | Lifted version of 'IO.hIsClosed'
--
-- @since 0.2.1.0
hIsClosed :: MonadIO m => Handle -> m Bool
hIsClosed :: Handle -> m Bool
hIsClosed = IO Bool -> m Bool
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Bool -> m Bool) -> (Handle -> IO Bool) -> Handle -> m Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> IO Bool
IO.hIsClosed

-- | Lifted version of 'IO.hIsReadable'
--
-- @since 0.2.1.0
hIsReadable :: MonadIO m => Handle -> m Bool
hIsReadable :: Handle -> m Bool
hIsReadable = IO Bool -> m Bool
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Bool -> m Bool) -> (Handle -> IO Bool) -> Handle -> m Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> IO Bool
IO.hIsReadable

-- | Lifted version of 'IO.hIsWritable'
--
-- @since 0.2.1.0
hIsWritable :: MonadIO m => Handle -> m Bool
hIsWritable :: Handle -> m Bool
hIsWritable = IO Bool -> m Bool
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Bool -> m Bool) -> (Handle -> IO Bool) -> Handle -> m Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> IO Bool
IO.hIsWritable

-- | Lifted version of 'IO.hIsSeekable'
--
-- @since 0.2.1.0
hIsSeekable :: MonadIO m => Handle -> m Bool
hIsSeekable :: Handle -> m Bool
hIsSeekable = IO Bool -> m Bool
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Bool -> m Bool) -> (Handle -> IO Bool) -> Handle -> m Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> IO Bool
IO.hIsSeekable

-- | Lifted version of 'IO.hIsTerminalDevice'
--
-- @since 0.2.1.0
hIsTerminalDevice :: MonadIO m => Handle -> m Bool
hIsTerminalDevice :: Handle -> m Bool
hIsTerminalDevice = IO Bool -> m Bool
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Bool -> m Bool) -> (Handle -> IO Bool) -> Handle -> m Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> IO Bool
IO.hIsTerminalDevice

-- | Lifted version of 'IO.hSetEcho'
--
-- @since 0.2.1.0
hSetEcho :: MonadIO m => Handle -> Bool -> m ()
hSetEcho :: Handle -> Bool -> m ()
hSetEcho Handle
h = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> (Bool -> IO ()) -> Bool -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> Bool -> IO ()
IO.hSetEcho Handle
h

-- | Lifted version of 'IO.hGetEcho'
--
-- @since 0.2.1.0
hGetEcho :: MonadIO m => Handle -> m Bool
hGetEcho :: Handle -> m Bool
hGetEcho = IO Bool -> m Bool
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Bool -> m Bool) -> (Handle -> IO Bool) -> Handle -> m Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> IO Bool
IO.hGetEcho

-- | Lifted version of 'IO.hWaitForInput'
--
-- @since 0.2.1.0
hWaitForInput :: MonadIO m => Handle -> Int -> m Bool
hWaitForInput :: Handle -> Int -> m Bool
hWaitForInput Handle
h = IO Bool -> m Bool
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Bool -> m Bool) -> (Int -> IO Bool) -> Int -> m Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> Int -> IO Bool
IO.hWaitForInput Handle
h

-- | Lifted version of 'IO.hReady'
--
-- @since 0.2.1.0
hReady :: MonadIO m => Handle -> m Bool
hReady :: Handle -> m Bool
hReady = IO Bool -> m Bool
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Bool -> m Bool) -> (Handle -> IO Bool) -> Handle -> m Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> IO Bool
IO.hReady

-- | Get the number of seconds which have passed since an arbitrary starting
-- time, useful for calculating runtime in a program.
--
-- @since 0.2.3.0
getMonotonicTime :: MonadIO m => m Double
getMonotonicTime :: m Double
getMonotonicTime = IO Double -> m Double
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Double -> m Double) -> IO Double -> m Double
forall a b. (a -> b) -> a -> b
$ ()
initted () -> IO Double -> IO Double
`seq` IO Double
getMonotonicTime'

-- | Set up time measurement.
foreign import ccall unsafe "unliftio_inittime" initializeTime :: IO ()

initted :: ()
initted :: ()
initted = IO () -> ()
forall a. IO a -> a
unsafePerformIO IO ()
initializeTime
{-# NOINLINE initted #-}

foreign import ccall unsafe "unliftio_gettime" getMonotonicTime' :: IO Double