{-# LANGUAGE DerivingVia #-}

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

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

-- 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)
  deriving
    (HandleD Handle
HandleD Handle -> Handle Handle
forall (h :: Effects -> *). HandleD h -> Handle h
$chandleImpl :: HandleD Handle
handleImpl :: HandleD Handle
Bluefin.Internal.Handle)
    via Bluefin.Internal.OneWayCoercibleHandle Handle

instance (e :> es) => OneWayCoercible (Handle e) (Handle es) where
  oneWayCoercibleImpl :: OneWayCoercibleD (Handle e) (Handle es)
oneWayCoercibleImpl = (forall (e' :: Effects) (es' :: Effects).
 (e' :> es') =>
 Handle e' -> Handle es')
-> OneWayCoercibleD (Handle e) (Handle es)
forall (e :: Effects) (es :: Effects) (h :: Effects -> *).
(e :> es) =>
(forall (e' :: Effects) (es' :: Effects).
 (e' :> es') =>
 h e' -> h es')
-> OneWayCoercibleD (h e) (h es)
oneWayCoercibleTrustMe ((forall (e' :: Effects) (es' :: Effects).
  (e' :> es') =>
  Handle e' -> Handle es')
 -> OneWayCoercibleD (Handle e) (Handle es))
-> (forall (e' :: Effects) (es' :: Effects).
    (e' :> es') =>
    Handle e' -> Handle es')
-> OneWayCoercibleD (Handle e) (Handle es)
forall a b. (a -> b) -> a -> b
$ \(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 (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 (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)