module Effectful.FileSystem.HandleRW.Dynamic
  ( -- * Effect
    HandleRW (..),
    openBinaryFile,
    withBinaryFile,

    -- ** Handlers
    runHandleRW,

    -- * Reexports
    ByteString,
    Handle,
    HandleMode (HandleModeReadWrite),
    OsPath,
  )
where

import Data.ByteString (ByteString)
import Effectful
  ( Dispatch (Dynamic),
    DispatchOf,
    Eff,
    Effect,
    IOE,
    type (:>),
  )
import Effectful.Dispatch.Dynamic
  ( HasCallStack,
    localSeqUnlift,
    reinterpret,
    send,
  )
import Effectful.Dynamic.Utils (ShowEffect (showEffectCons))
import Effectful.FileSystem.Handle.Internal
  ( Handle,
    HandleMode (HandleModeReadWrite),
  )
import Effectful.FileSystem.HandleRW.Static qualified as Static
import FileSystem.OsPath (OsPath)

-- | @since 0.1
type instance DispatchOf HandleRW = Dynamic

-- | Dynamic effect for writing to a handle.
--
-- @since 0.1
data HandleRW :: Effect where
  OpenBinaryFile :: OsPath -> HandleRW m (Handle HandleModeReadWrite)
  WithBinaryFile :: OsPath -> (Handle HandleModeReadWrite -> m a) -> HandleRW m a

-- | @since 0.1
instance ShowEffect HandleRW where
  showEffectCons :: forall (m :: * -> *) a. HandleRW m a -> String
showEffectCons = \case
    OpenBinaryFile OsPath
_ -> String
"OpenBinaryFile"
    WithBinaryFile {} -> String
"WithBinaryFile"

-- | Runs 'HandleRW' in 'IO'.
--
-- @since 0.1
runHandleRW ::
  ( HasCallStack,
    IOE :> es
  ) =>
  Eff (HandleRW : es) a ->
  Eff es a
runHandleRW :: forall (es :: [(* -> *) -> * -> *]) a.
(HasCallStack, IOE :> es) =>
Eff (HandleRW : es) a -> Eff es a
runHandleRW = (Eff (HandleRW : es) a -> Eff es a)
-> EffectHandler HandleRW (HandleRW : es)
-> Eff (HandleRW : es) a
-> Eff es a
forall (e :: (* -> *) -> * -> *)
       (handlerEs :: [(* -> *) -> * -> *]) a (es :: [(* -> *) -> * -> *])
       b.
(HasCallStack, DispatchOf e ~ 'Dynamic) =>
(Eff handlerEs a -> Eff es b)
-> EffectHandler e handlerEs -> Eff (e : es) a -> Eff es b
reinterpret Eff (HandleRW : es) a -> Eff es a
forall (es :: [(* -> *) -> * -> *]) a.
(HasCallStack, IOE :> es) =>
Eff (HandleRW : es) a -> Eff es a
Static.runHandleRW (EffectHandler HandleRW (HandleRW : es)
 -> Eff (HandleRW : es) a -> Eff es a)
-> EffectHandler HandleRW (HandleRW : es)
-> Eff (HandleRW : es) a
-> Eff es a
forall a b. (a -> b) -> a -> b
$ \LocalEnv localEs
env -> \case
  OpenBinaryFile OsPath
p -> OsPath -> Eff (HandleRW : es) (Handle 'HandleModeReadWrite)
forall (es :: [(* -> *) -> * -> *]).
(HandleRW :> es, HasCallStack) =>
OsPath -> Eff es (Handle 'HandleModeReadWrite)
Static.openBinaryFile OsPath
p
  WithBinaryFile OsPath
p Handle 'HandleModeReadWrite -> Eff localEs a
f -> LocalEnv localEs
-> ((forall r. Eff localEs r -> Eff (HandleRW : es) r)
    -> Eff (HandleRW : es) a)
-> Eff (HandleRW : es) a
forall (localEs :: [(* -> *) -> * -> *])
       (es :: [(* -> *) -> * -> *]) a.
HasCallStack =>
LocalEnv localEs
-> ((forall r. Eff localEs r -> Eff es r) -> Eff es a) -> Eff es a
localSeqUnlift LocalEnv localEs
env (((forall r. Eff localEs r -> Eff (HandleRW : es) r)
  -> Eff (HandleRW : es) a)
 -> Eff (HandleRW : es) a)
-> ((forall r. Eff localEs r -> Eff (HandleRW : es) r)
    -> Eff (HandleRW : es) a)
-> Eff (HandleRW : es) a
forall a b. (a -> b) -> a -> b
$ \forall r. Eff localEs r -> Eff (HandleRW : es) r
unlift ->
    OsPath
-> (Handle 'HandleModeReadWrite -> Eff (HandleRW : es) a)
-> Eff (HandleRW : es) a
forall (es :: [(* -> *) -> * -> *]) a.
(HandleRW :> es, HasCallStack) =>
OsPath -> (Handle 'HandleModeReadWrite -> Eff es a) -> Eff es a
Static.withBinaryFile OsPath
p (Eff localEs a -> Eff (HandleRW : es) a
forall r. Eff localEs r -> Eff (HandleRW : es) r
unlift (Eff localEs a -> Eff (HandleRW : es) a)
-> (Handle 'HandleModeReadWrite -> Eff localEs a)
-> Handle 'HandleModeReadWrite
-> Eff (HandleRW : es) a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle 'HandleModeReadWrite -> Eff localEs a
f)

-- | Lifted 'IO.openBinaryFile'.
--
-- @since 0.1
openBinaryFile ::
  ( HandleRW :> es,
    HasCallStack
  ) =>
  OsPath ->
  Eff es (Handle HandleModeReadWrite)
openBinaryFile :: forall (es :: [(* -> *) -> * -> *]).
(HandleRW :> es, HasCallStack) =>
OsPath -> Eff es (Handle 'HandleModeReadWrite)
openBinaryFile = HandleRW (Eff es) (Handle 'HandleModeReadWrite)
-> Eff es (Handle 'HandleModeReadWrite)
forall (e :: (* -> *) -> * -> *) (es :: [(* -> *) -> * -> *]) a.
(HasCallStack, DispatchOf e ~ 'Dynamic, e :> es) =>
e (Eff es) a -> Eff es a
send (HandleRW (Eff es) (Handle 'HandleModeReadWrite)
 -> Eff es (Handle 'HandleModeReadWrite))
-> (OsPath -> HandleRW (Eff es) (Handle 'HandleModeReadWrite))
-> OsPath
-> Eff es (Handle 'HandleModeReadWrite)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. OsPath -> HandleRW (Eff es) (Handle 'HandleModeReadWrite)
forall (m :: * -> *).
OsPath -> HandleRW m (Handle 'HandleModeReadWrite)
OpenBinaryFile

-- | Lifted 'IO.openBinaryFile'.
--
-- @since 0.1
withBinaryFile ::
  ( HandleRW :> es,
    HasCallStack
  ) =>
  OsPath ->
  (Handle HandleModeReadWrite -> Eff es a) ->
  Eff es a
withBinaryFile :: forall (es :: [(* -> *) -> * -> *]) a.
(HandleRW :> es, HasCallStack) =>
OsPath -> (Handle 'HandleModeReadWrite -> Eff es a) -> Eff es a
withBinaryFile OsPath
p = HandleRW (Eff es) a -> Eff es a
forall (e :: (* -> *) -> * -> *) (es :: [(* -> *) -> * -> *]) a.
(HasCallStack, DispatchOf e ~ 'Dynamic, e :> es) =>
e (Eff es) a -> Eff es a
send (HandleRW (Eff es) a -> Eff es a)
-> ((Handle 'HandleModeReadWrite -> Eff es a)
    -> HandleRW (Eff es) a)
-> (Handle 'HandleModeReadWrite -> Eff es a)
-> Eff es a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. OsPath
-> (Handle 'HandleModeReadWrite -> Eff es a) -> HandleRW (Eff es) a
forall (m :: * -> *) a.
OsPath -> (Handle 'HandleModeReadWrite -> m a) -> HandleRW m a
WithBinaryFile OsPath
p