-- | Functions and types for safely working with 'IO.Handle's in 'Scoped' blocks
module Control.Monad.Scoped.Handle
  ( -- * Scoped 'IO.Handle'
    ScopedHandle

    -- * Allocating a new 'ScopedHandle' in a 'Scoped' block
  , file

    -- * Working with 'ScopedHandle'
  , IO.IOMode (..)
  , hPutStrLn
  , hPutStr
  , hGetLine
  , hGetContents
  )
where

import Control.Monad.Scoped.Internal (Scoped (UnsafeMkScoped), ScopedResource (UnsafeMkScopedResource, unsafeUnwrapScopedResource))
import Data.Text (Text)
import Data.Text.IO qualified as TIO
import System.IO qualified as IO
import UnliftIO (MonadIO (liftIO), MonadUnliftIO)
import UnliftIO.IO qualified as IOU

-- | Just like 'IO.Handle' but bound to a 'Scoped' block
type ScopedHandle s = ScopedResource s IO.Handle

-- | Given a 'FilePath', safely allocates and deallocates a 'ScopedHandle' in a 'Scoped' block
file :: MonadUnliftIO m => FilePath -> IO.IOMode -> Scoped s m (ScopedHandle s)
file :: forall {k} (m :: Type -> Type) (s :: k).
MonadUnliftIO m =>
FilePath -> IOMode -> Scoped s m (ScopedHandle s)
file FilePath
path IOMode
mode = (forall b. (ScopedHandle s -> m b) -> m b)
-> Scoped s m (ScopedHandle s)
forall {l} {k} (s :: l) (m :: k -> Type) a.
(forall (b :: k). (a -> m b) -> m b) -> Scoped s m a
UnsafeMkScoped \ScopedHandle s -> m b
k -> FilePath -> IOMode -> (Handle -> m b) -> m b
forall (m :: Type -> Type) a.
MonadUnliftIO m =>
FilePath -> IOMode -> (Handle -> m a) -> m a
IOU.withFile FilePath
path IOMode
mode (ScopedHandle s -> m b
k (ScopedHandle s -> m b)
-> (Handle -> ScopedHandle s) -> Handle -> m b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> ScopedHandle s
forall {k} (s :: k) a. a -> ScopedResource s a
UnsafeMkScopedResource)

-- | Like 'IO.hPutStrLn' but for 'ScopedHandle'
hPutStrLn :: MonadIO m => ScopedHandle s -> Text -> Scoped s m ()
hPutStrLn :: forall {l} (m :: Type -> Type) (s :: l).
MonadIO m =>
ScopedHandle s -> Text -> Scoped s m ()
hPutStrLn ScopedHandle s
h Text
s = IO () -> Scoped s m ()
forall a. IO a -> Scoped s m a
forall (m :: Type -> Type) a. MonadIO m => IO a -> m a
liftIO (Handle -> Text -> IO ()
TIO.hPutStrLn (ScopedHandle s -> Handle
forall {k} (s :: k) a. ScopedResource s a -> a
unsafeUnwrapScopedResource ScopedHandle s
h) Text
s)

-- | Like 'IO.hPutStr' but for 'ScopedHandle'
hPutStr :: MonadIO m => ScopedHandle s -> Text -> Scoped s m ()
hPutStr :: forall {l} (m :: Type -> Type) (s :: l).
MonadIO m =>
ScopedHandle s -> Text -> Scoped s m ()
hPutStr ScopedHandle s
h Text
s = IO () -> Scoped s m ()
forall a. IO a -> Scoped s m a
forall (m :: Type -> Type) a. MonadIO m => IO a -> m a
liftIO (Handle -> Text -> IO ()
TIO.hPutStr (ScopedHandle s -> Handle
forall {k} (s :: k) a. ScopedResource s a -> a
unsafeUnwrapScopedResource ScopedHandle s
h) Text
s)

-- | Like 'IO.hGetLine' but for 'ScopedHandle'
hGetLine :: MonadIO m => ScopedHandle s -> Scoped s m Text
hGetLine :: forall {l} (m :: Type -> Type) (s :: l).
MonadIO m =>
ScopedHandle s -> Scoped s m Text
hGetLine ScopedHandle s
h = IO Text -> Scoped s m Text
forall a. IO a -> Scoped s m a
forall (m :: Type -> Type) a. MonadIO m => IO a -> m a
liftIO (Handle -> IO Text
TIO.hGetLine (ScopedHandle s -> Handle
forall {k} (s :: k) a. ScopedResource s a -> a
unsafeUnwrapScopedResource ScopedHandle s
h))

-- | Like 'IO.hGetContents' but for 'ScopedHandle'
hGetContents :: MonadIO m => ScopedHandle s -> Scoped s m Text
hGetContents :: forall {l} (m :: Type -> Type) (s :: l).
MonadIO m =>
ScopedHandle s -> Scoped s m Text
hGetContents ScopedHandle s
h = IO Text -> Scoped s m Text
forall a. IO a -> Scoped s m a
forall (m :: Type -> Type) a. MonadIO m => IO a -> m a
liftIO (Handle -> IO Text
TIO.hGetContents (ScopedHandle s -> Handle
forall {k} (s :: k) a. ScopedResource s a -> a
unsafeUnwrapScopedResource ScopedHandle s
h))