-- | Lifted "Data.IORef".
--
-- /Note:/ it requires 'Prim' because @MutVar@ from the @primitive@ library is a
-- generalization of 'IORef'.
--
-- @since 2.4.0.0
module Effectful.Prim.IORef
  ( -- * Effect
    Prim

    -- ** Handlers
  , runPrim

    -- * IORef
  , IORef
  , newIORef
  , readIORef
  , writeIORef
  , modifyIORef
  , modifyIORef'
  , atomicModifyIORef
  , atomicModifyIORef'
  , atomicWriteIORef
  , mkWeakIORef
  ) where

import Data.IORef (IORef)
import Data.IORef qualified as Ref
import System.Mem.Weak (Weak)

import Effectful
import Effectful.Dispatch.Static
import Effectful.Dispatch.Static.Primitive
import Effectful.Prim

-- | Lifted 'Ref.newIORef'.
newIORef :: Prim :> es => a -> Eff es (IORef a)
newIORef :: forall (es :: [Effect]) a. (Prim :> 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)
Ref.newIORef

-- | Lifted 'Ref.readIORef'.
readIORef :: Prim :> es => IORef a -> Eff es a
readIORef :: forall (es :: [Effect]) a. (Prim :> 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
Ref.readIORef

-- | Lifted 'Ref.writeIORef'.
writeIORef :: Prim :> es => IORef a -> a -> Eff es ()
writeIORef :: forall (es :: [Effect]) a.
(Prim :> es) =>
IORef a -> a -> Eff es ()
writeIORef IORef a
var = 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 ()
Ref.writeIORef IORef a
var

-- | Lifted 'Ref.modifyIORef'.
modifyIORef :: Prim :> es => IORef a -> (a -> a) -> Eff es ()
modifyIORef :: forall (es :: [Effect]) a.
(Prim :> es) =>
IORef a -> (a -> a) -> Eff es ()
modifyIORef IORef a
var = 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 ()
Ref.modifyIORef IORef a
var

-- | Lifted 'Ref.modifyIORef''.
modifyIORef' :: Prim :> es => IORef a -> (a -> a) -> Eff es ()
modifyIORef' :: forall (es :: [Effect]) a.
(Prim :> es) =>
IORef a -> (a -> a) -> Eff es ()
modifyIORef' IORef a
var = 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 ()
Ref.modifyIORef' IORef a
var

-- | Lifted 'Ref.atomicModifyIORef'.
atomicModifyIORef :: Prim :> es => IORef a -> (a -> (a, b)) -> Eff es b
atomicModifyIORef :: forall (es :: [Effect]) a b.
(Prim :> es) =>
IORef a -> (a -> (a, b)) -> Eff es b
atomicModifyIORef IORef a
var = 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
Ref.atomicModifyIORef IORef a
var

-- | Lifted 'Ref.atomicModifyIORef''.
atomicModifyIORef' :: Prim :> es => IORef a -> (a -> (a, b)) -> Eff es b
atomicModifyIORef' :: forall (es :: [Effect]) a b.
(Prim :> es) =>
IORef a -> (a -> (a, b)) -> Eff es b
atomicModifyIORef' IORef a
var = 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
Ref.atomicModifyIORef' IORef a
var

-- | Lifted 'Ref.atomicWriteIORef''.
atomicWriteIORef :: Prim :> es => IORef a -> a -> Eff es ()
atomicWriteIORef :: forall (es :: [Effect]) a.
(Prim :> es) =>
IORef a -> a -> Eff es ()
atomicWriteIORef IORef a
var = 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 ()
Ref.atomicWriteIORef IORef a
var

-- | Lifted 'Ref.mkWeakIORef'.
--
-- /Note:/ the finalizer will run a cloned environment, so any changes it makes
-- to thread local data will not be visible outside of it.
mkWeakIORef
  :: (HasCallStack, Prim :> es)
  => IORef a
  -> Eff es ()
  -> Eff es (Weak (IORef a))
mkWeakIORef :: forall (es :: [Effect]) a.
(HasCallStack, Prim :> es) =>
IORef a -> Eff es () -> Eff es (Weak (IORef a))
mkWeakIORef IORef a
var Eff es ()
f = (Env es -> IO (Weak (IORef a))) -> Eff es (Weak (IORef a))
forall (es :: [Effect]) a. (Env es -> IO a) -> Eff es a
unsafeEff ((Env es -> IO (Weak (IORef a))) -> Eff es (Weak (IORef a)))
-> (Env es -> IO (Weak (IORef a))) -> Eff es (Weak (IORef a))
forall a b. (a -> b) -> a -> b
$ \Env es
es -> do
  -- The finalizer can run at any point and in any thread.
  IORef a -> IO () -> IO (Weak (IORef a))
forall a. IORef a -> IO () -> IO (Weak (IORef a))
Ref.mkWeakIORef IORef a
var (IO () -> IO (Weak (IORef a)))
-> (Env es -> IO ()) -> Env es -> IO (Weak (IORef a))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Eff es () -> Env es -> IO ()
forall (es :: [Effect]) a. Eff es a -> Env es -> IO a
unEff Eff es ()
f (Env es -> IO (Weak (IORef a)))
-> IO (Env es) -> IO (Weak (IORef a))
forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
=<< Env es -> IO (Env es)
forall (es :: [Effect]). HasCallStack => Env es -> IO (Env es)
cloneEnv Env es
es