{-# OPTIONS_GHC -Wno-redundant-constraints #-}

-- | Provides a static effect for 'IORef'.
--
-- @since 0.1
module Effectful.IORef.Static
  ( -- * Effect
    IORefE,
    newIORef,
    newIORef',
    readIORef,
    writeIORef,
    writeIORef',
    modifyIORef',
    atomicModifyIORef',

    -- ** Handlers
    runIORef,

    -- * Utils
    atomicModifyIORef'_,

    -- * Re-exports
    IORef,
  )
where

import Control.Monad ((>=>))
import Data.IORef (IORef)
import Data.IORef qualified as IORef
import Effectful
  ( Dispatch (Static),
    DispatchOf,
    Eff,
    Effect,
    IOE,
    type (:>),
  )
import Effectful.Dispatch.Static
  ( SideEffects (WithSideEffects),
    StaticRep,
    evalStaticRep,
    unsafeEff_,
  )
import Effectful.Exception (evaluate)

-- | Static effect for 'IORef'.
--
-- @since 0.1
data IORefE :: Effect

type instance DispatchOf IORefE = Static WithSideEffects

data instance StaticRep IORefE = MkIORefEtatic

-- | Runs an IORefE effect.
--
-- @since 0.1
runIORef :: (IOE :> es) => Eff (IORefE : es) a -> Eff es a
runIORef :: forall (es :: [Effect]) a.
(IOE :> es) =>
Eff (IORefE : es) a -> Eff es a
runIORef = StaticRep IORefE -> Eff (IORefE : es) a -> Eff es a
forall (e :: Effect) (sideEffects :: SideEffects) (es :: [Effect])
       a.
(HasCallStack, DispatchOf e ~ 'Static sideEffects,
 MaybeIOE sideEffects es) =>
StaticRep e -> Eff (e : es) a -> Eff es a
evalStaticRep StaticRep IORefE
MkIORefEtatic

-- | Lifted 'IORef.newIORef'.
--
-- @since 0.1
newIORef :: (IORefE :> es) => a -> Eff es (IORef a)
newIORef :: forall (es :: [Effect]) a. (IORefE :> es) => a -> Eff es (IORef a)
newIORef = IO (IORef a) -> Eff es (IORef a)
forall a (es :: [Effect]). IO a -> Eff es a
unsafeEff_ (IO (IORef a) -> Eff es (IORef a))
-> (a -> IO (IORef a)) -> a -> Eff es (IORef a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> IO (IORef a)
forall a. a -> IO (IORef a)
IORef.newIORef

-- | Evaluates a to WHNF then calls 'newIORef'.
--
-- @since 0.1
newIORef' :: (IORefE :> es) => a -> Eff es (IORef a)
newIORef' :: forall (es :: [Effect]) a. (IORefE :> es) => a -> Eff es (IORef a)
newIORef' = a -> Eff es a
forall a (es :: [Effect]). a -> Eff es a
evaluate (a -> Eff es a) -> (a -> Eff es (IORef a)) -> a -> Eff es (IORef a)
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> a -> Eff es (IORef a)
forall (es :: [Effect]) a. (IORefE :> es) => a -> Eff es (IORef a)
newIORef

-- | Lifted 'IORef.readIORef'.
--
-- @since 0.1
readIORef :: (IORefE :> es) => IORef a -> Eff es a
readIORef :: forall (es :: [Effect]) a. (IORefE :> es) => IORef a -> Eff es a
readIORef = IO a -> Eff es a
forall a (es :: [Effect]). IO a -> Eff es a
unsafeEff_ (IO a -> Eff es a) -> (IORef a -> IO a) -> IORef a -> Eff es a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IORef a -> IO a
forall a. IORef a -> IO a
IORef.readIORef

-- | Lifted 'IORef.writeIORef'.
--
-- @since 0.1
writeIORef :: (IORefE :> es) => IORef a -> a -> Eff es ()
writeIORef :: forall (es :: [Effect]) a.
(IORefE :> es) =>
IORef a -> a -> Eff es ()
writeIORef IORef a
ref = IO () -> Eff es ()
forall a (es :: [Effect]). IO a -> Eff es a
unsafeEff_ (IO () -> Eff es ()) -> (a -> IO ()) -> a -> Eff es ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IORef a -> a -> IO ()
forall a. IORef a -> a -> IO ()
IORef.writeIORef IORef a
ref

-- | Evaluates a to WHNF before calling 'writeIORef'.
--
-- @since 0.1
writeIORef' :: (IORefE :> es) => IORef a -> a -> Eff es ()
writeIORef' :: forall (es :: [Effect]) a.
(IORefE :> es) =>
IORef a -> a -> Eff es ()
writeIORef' IORef a
ref = a -> Eff es a
forall a (es :: [Effect]). a -> Eff es a
evaluate (a -> Eff es a) -> (a -> Eff es ()) -> a -> Eff es ()
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> IORef a -> a -> Eff es ()
forall (es :: [Effect]) a.
(IORefE :> es) =>
IORef a -> a -> Eff es ()
writeIORef IORef a
ref

-- | Lifted 'IORef.modifyIORef''.
--
-- @since 0.1
modifyIORef' ::
  (IORefE :> es) =>
  IORef a ->
  (a -> a) ->
  Eff es ()
modifyIORef' :: forall (es :: [Effect]) a.
(IORefE :> es) =>
IORef a -> (a -> a) -> Eff es ()
modifyIORef' IORef a
ref = IO () -> Eff es ()
forall a (es :: [Effect]). IO a -> Eff es a
unsafeEff_ (IO () -> Eff es ())
-> ((a -> a) -> IO ()) -> (a -> a) -> Eff es ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IORef a -> (a -> a) -> IO ()
forall a. IORef a -> (a -> a) -> IO ()
IORef.modifyIORef' IORef a
ref

-- | Lifted 'IORef.atomicModifyIORef''.
--
-- @since 0.1
atomicModifyIORef' ::
  (IORefE :> es) =>
  IORef a ->
  (a -> (a, b)) ->
  Eff es b
atomicModifyIORef' :: forall (es :: [Effect]) a b.
(IORefE :> es) =>
IORef a -> (a -> (a, b)) -> Eff es b
atomicModifyIORef' IORef a
ref = IO b -> Eff es b
forall a (es :: [Effect]). IO a -> Eff es a
unsafeEff_ (IO b -> Eff es b)
-> ((a -> (a, b)) -> IO b) -> (a -> (a, b)) -> Eff es b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IORef a -> (a -> (a, b)) -> IO b
forall a b. IORef a -> (a -> (a, b)) -> IO b
IORef.atomicModifyIORef' IORef a
ref

-- | Variant of 'atomicModifyIORef'' which ignores the return value.
--
-- @since 0.1
atomicModifyIORef'_ ::
  (IORefE :> es) =>
  IORef a ->
  (a -> a) ->
  Eff es ()
atomicModifyIORef'_ :: forall (es :: [Effect]) a.
(IORefE :> es) =>
IORef a -> (a -> a) -> Eff es ()
atomicModifyIORef'_ IORef a
ref a -> a
f = IORef a -> (a -> (a, ())) -> Eff es ()
forall (es :: [Effect]) a b.
(IORefE :> es) =>
IORef a -> (a -> (a, b)) -> Eff es b
atomicModifyIORef' IORef a
ref ((a -> (a, ())) -> Eff es ()) -> (a -> (a, ())) -> Eff es ()
forall a b. (a -> b) -> a -> b
$ \a
a -> (a -> a
f a
a, ())