module Bluefin.Internal.System.IO
  ( module Bluefin.Internal.System.IO,
    System.IO.IOMode (..),
  )
where

import Bluefin.Internal
  ( Eff,
    IOE,
    bracket,
    effIO,
    mapHandle,
    useImplIn,
    (:&),
    (:>),
  )
import qualified Bluefin.Internal
import qualified System.IO

-- We can probably get away without the IOE and just use
-- unsafeProvideIO on all Handle functions
data Handle e = UnsafeMkHandle System.IO.Handle (IOE e)

instance Bluefin.Internal.Handle Handle where
  mapHandle :: forall (e :: Effects) (es :: Effects).
(e :> es) =>
Handle e -> Handle es
mapHandle (UnsafeMkHandle Handle
h IOE e
io) = Handle -> IOE es -> Handle es
forall (e :: Effects). Handle -> IOE e -> Handle e
UnsafeMkHandle Handle
h (IOE e -> IOE es
forall (e :: Effects) (es :: Effects). (e :> es) => IOE e -> IOE es
forall (h :: Effects -> *) (e :: Effects) (es :: Effects).
(Handle h, e :> es) =>
h e -> h es
mapHandle IOE e
io)

withFile ::
  (e1 :> es) =>
  IOE e1 ->
  FilePath ->
  System.IO.IOMode ->
  (forall e. Handle e -> Eff (e :& es) r) ->
  -- | ͘
  Eff es r
withFile :: forall (e1 :: Effects) (es :: Effects) r.
(e1 :> es) =>
IOE e1
-> FilePath
-> IOMode
-> (forall (e :: Effects). Handle e -> Eff (e :& es) r)
-> Eff es r
withFile IOE e1
io FilePath
fp IOMode
iomode forall (e :: Effects). Handle e -> Eff (e :& es) r
k =
  Eff es Handle
-> (Handle -> Eff es ()) -> (Handle -> Eff es r) -> Eff es r
forall (es :: Effects) a b.
Eff es a -> (a -> Eff es ()) -> (a -> Eff es b) -> Eff es b
bracket
    ( IOE e1 -> IO Handle -> Eff es Handle
forall (e :: Effects) (es :: Effects) a.
(e :> es) =>
IOE e -> IO a -> Eff es a
effIO IOE e1
io (FilePath -> IOMode -> IO Handle
System.IO.openFile FilePath
fp IOMode
iomode)
    )
    ( \Handle
handle -> IOE e1 -> IO () -> Eff es ()
forall (e :: Effects) (es :: Effects) a.
(e :> es) =>
IOE e -> IO a -> Eff es a
effIO IOE e1
io (Handle -> IO ()
System.IO.hClose Handle
handle)
    )
    ( \Handle
handle -> (Handle es -> Eff (es :& es) r) -> Handle es -> Eff es r
forall (e :: Effects) (es :: Effects) t r.
(e :> es) =>
(t -> Eff (es :& e) r) -> t -> Eff es r
useImplIn Handle es -> Eff (es :& es) r
forall (e :: Effects). Handle e -> Eff (e :& es) r
k (Handle -> IOE es -> Handle es
forall (e :: Effects). Handle -> IOE e -> Handle e
UnsafeMkHandle Handle
handle (IOE e1 -> IOE es
forall (e :: Effects) (es :: Effects). (e :> es) => IOE e -> IOE es
forall (h :: Effects -> *) (e :: Effects) (es :: Effects).
(Handle h, e :> es) =>
h e -> h es
mapHandle IOE e1
io))
    )

hPutChar ::
  (e :> es) =>
  Handle e ->
  Char ->
  -- | ͘
  Eff es ()
hPutChar :: forall (e :: Effects) (es :: Effects).
(e :> es) =>
Handle e -> Char -> Eff es ()
hPutChar Handle e
h = Handle e -> (Handle -> IO ()) -> Eff es ()
forall (e1 :: Effects) (es :: Effects) r.
(e1 :> es) =>
Handle e1 -> (Handle -> IO r) -> Eff es r
unsafeWithHandle Handle e
h ((Handle -> IO ()) -> Eff es ())
-> (Char -> Handle -> IO ()) -> Char -> Eff es ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Handle -> Char -> IO ()) -> Char -> Handle -> IO ()
forall a b c. (a -> b -> c) -> b -> a -> c
flip Handle -> Char -> IO ()
System.IO.hPutChar

hPutStr ::
  (e :> es) =>
  Handle e ->
  String ->
  -- | ͘
  Eff es ()
hPutStr :: forall (e :: Effects) (es :: Effects).
(e :> es) =>
Handle e -> FilePath -> Eff es ()
hPutStr Handle e
h = Handle e -> (Handle -> IO ()) -> Eff es ()
forall (e1 :: Effects) (es :: Effects) r.
(e1 :> es) =>
Handle e1 -> (Handle -> IO r) -> Eff es r
unsafeWithHandle Handle e
h ((Handle -> IO ()) -> Eff es ())
-> (FilePath -> Handle -> IO ()) -> FilePath -> Eff es ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Handle -> FilePath -> IO ()) -> FilePath -> Handle -> IO ()
forall a b c. (a -> b -> c) -> b -> a -> c
flip Handle -> FilePath -> IO ()
System.IO.hPutStr

hPutStrLn ::
  (e :> es) =>
  Handle e ->
  String ->
  -- | ͘
  Eff es ()
hPutStrLn :: forall (e :: Effects) (es :: Effects).
(e :> es) =>
Handle e -> FilePath -> Eff es ()
hPutStrLn Handle e
h = Handle e -> (Handle -> IO ()) -> Eff es ()
forall (e1 :: Effects) (es :: Effects) r.
(e1 :> es) =>
Handle e1 -> (Handle -> IO r) -> Eff es r
unsafeWithHandle Handle e
h ((Handle -> IO ()) -> Eff es ())
-> (FilePath -> Handle -> IO ()) -> FilePath -> Eff es ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Handle -> FilePath -> IO ()) -> FilePath -> Handle -> IO ()
forall a b c. (a -> b -> c) -> b -> a -> c
flip Handle -> FilePath -> IO ()
System.IO.hPutStrLn

hFlush ::
  (e :> es) =>
  Handle e ->
  -- | ͘
  Eff es ()
hFlush :: forall (e :: Effects) (es :: Effects).
(e :> es) =>
Handle e -> Eff es ()
hFlush Handle e
h = Handle e -> (Handle -> IO ()) -> Eff es ()
forall (e1 :: Effects) (es :: Effects) r.
(e1 :> es) =>
Handle e1 -> (Handle -> IO r) -> Eff es r
unsafeWithHandle Handle e
h Handle -> IO ()
System.IO.hFlush

hGetLine ::
  (e :> es) =>
  Handle e ->
  -- | ͘
  Eff es String
hGetLine :: forall (e :: Effects) (es :: Effects).
(e :> es) =>
Handle e -> Eff es FilePath
hGetLine Handle e
h = Handle e -> (Handle -> IO FilePath) -> Eff es FilePath
forall (e1 :: Effects) (es :: Effects) r.
(e1 :> es) =>
Handle e1 -> (Handle -> IO r) -> Eff es r
unsafeWithHandle Handle e
h Handle -> IO FilePath
System.IO.hGetLine

hIsEOF ::
  (e :> es) =>
  Handle e ->
  -- | ͘
  Eff es Bool
hIsEOF :: forall (e :: Effects) (es :: Effects).
(e :> es) =>
Handle e -> Eff es Bool
hIsEOF Handle e
h = Handle e -> (Handle -> IO Bool) -> Eff es Bool
forall (e1 :: Effects) (es :: Effects) r.
(e1 :> es) =>
Handle e1 -> (Handle -> IO r) -> Eff es r
unsafeWithHandle Handle e
h Handle -> IO Bool
System.IO.hIsEOF

-- | If there's a "System.IO.Handle"-using function you need that
-- isn't included here then you can [open an
-- issue](https://github.com/tomjaguarpaw/bluefin/issues/new) to
-- request it be added.  In the meantime you can define it yourself with @unsafeWithHandle@.
unsafeWithHandle ::
  (e1 :> es) =>
  Handle e1 ->
  (System.IO.Handle -> IO r) ->
  Eff es r
unsafeWithHandle :: forall (e1 :: Effects) (es :: Effects) r.
(e1 :> es) =>
Handle e1 -> (Handle -> IO r) -> Eff es r
unsafeWithHandle (UnsafeMkHandle Handle
h IOE e1
io) Handle -> IO r
k = IOE e1 -> IO r -> Eff es r
forall (e :: Effects) (es :: Effects) a.
(e :> es) =>
IOE e -> IO a -> Eff es a
effIO IOE e1
io (Handle -> IO r
k Handle
h)