-- | Provides the 'MonadIORef' class.
--
-- @since 0.1
module Effects.IORef
  ( -- * Effect
    MonadIORef (..),

    -- * Functions
    atomicModifyIORef'_,

    -- * Reexports
    IORef,
  )
where

import Control.Monad.Trans.Class (MonadTrans (lift))
import Control.Monad.Trans.Reader (ReaderT)
import Data.IORef (IORef)
import Data.IORef qualified as IORef
import GHC.Stack (HasCallStack)

-- | 'IORef' effect.
--
-- @since 0.1
class (Monad m) => MonadIORef m where
  -- | Lifted 'IORef.newIORef'.
  --
  -- @since 0.1
  newIORef :: (HasCallStack) => a -> m (IORef a)

  -- | Lifted 'IORef.readIORef'.
  --
  -- @since 0.1
  readIORef :: (HasCallStack) => IORef a -> m a

  -- | Lifted 'IORef.writeIORef'.
  --
  -- @since 0.1
  writeIORef :: (HasCallStack) => IORef a -> a -> m ()

  -- | Lifted 'IORef.atomicWriteIORef'.
  --
  -- @since 0.1
  atomicWriteIORef :: (HasCallStack) => IORef a -> a -> m ()

  -- | Lifted 'IORef.modifyIORef''.
  --
  -- @since 0.1
  modifyIORef' :: (HasCallStack) => IORef a -> (a -> a) -> m ()

  -- | Lifted 'IORef.atomicModifyIORef''.
  --
  -- @since 0.1
  atomicModifyIORef' :: (HasCallStack) => IORef a -> (a -> (a, b)) -> m b

-- | @since 0.1
instance MonadIORef IO where
  newIORef :: forall a. HasCallStack => a -> IO (IORef a)
newIORef = a -> IO (IORef a)
forall a. a -> IO (IORef a)
IORef.newIORef
  {-# INLINEABLE newIORef #-}
  readIORef :: forall a. HasCallStack => IORef a -> IO a
readIORef = IORef a -> IO a
forall a. IORef a -> IO a
IORef.readIORef
  {-# INLINEABLE readIORef #-}
  writeIORef :: forall a. HasCallStack => IORef a -> a -> IO ()
writeIORef = IORef a -> a -> IO ()
forall a. IORef a -> a -> IO ()
IORef.writeIORef
  {-# INLINEABLE writeIORef #-}
  atomicWriteIORef :: forall a. HasCallStack => IORef a -> a -> IO ()
atomicWriteIORef = IORef a -> a -> IO ()
forall a. IORef a -> a -> IO ()
IORef.atomicWriteIORef
  {-# INLINEABLE atomicWriteIORef #-}
  modifyIORef' :: forall a. HasCallStack => IORef a -> (a -> a) -> IO ()
modifyIORef' = IORef a -> (a -> a) -> IO ()
forall a. IORef a -> (a -> a) -> IO ()
IORef.modifyIORef'
  {-# INLINEABLE modifyIORef' #-}
  atomicModifyIORef' :: forall a b. HasCallStack => IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef' = IORef a -> (a -> (a, b)) -> IO b
forall a b. IORef a -> (a -> (a, b)) -> IO b
IORef.atomicModifyIORef'
  {-# INLINEABLE atomicModifyIORef' #-}

-- | @since 0.1
instance (MonadIORef m) => MonadIORef (ReaderT e m) where
  newIORef :: forall a. HasCallStack => a -> ReaderT e m (IORef a)
newIORef = m (IORef a) -> ReaderT e m (IORef a)
forall (m :: * -> *) a. Monad m => m a -> ReaderT e m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m (IORef a) -> ReaderT e m (IORef a))
-> (a -> m (IORef a)) -> a -> ReaderT e m (IORef a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> m (IORef a)
forall a. HasCallStack => a -> m (IORef a)
forall (m :: * -> *) a.
(MonadIORef m, HasCallStack) =>
a -> m (IORef a)
newIORef
  {-# INLINEABLE newIORef #-}
  readIORef :: forall a. HasCallStack => IORef a -> ReaderT e m a
readIORef = m a -> ReaderT e m a
forall (m :: * -> *) a. Monad m => m a -> ReaderT e m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m a -> ReaderT e m a)
-> (IORef a -> m a) -> IORef a -> ReaderT e m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IORef a -> m a
forall a. HasCallStack => IORef a -> m a
forall (m :: * -> *) a.
(MonadIORef m, HasCallStack) =>
IORef a -> m a
readIORef
  {-# INLINEABLE readIORef #-}
  writeIORef :: forall a. HasCallStack => IORef a -> a -> ReaderT e m ()
writeIORef IORef a
r = m () -> ReaderT e m ()
forall (m :: * -> *) a. Monad m => m a -> ReaderT e m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m () -> ReaderT e m ()) -> (a -> m ()) -> a -> ReaderT e m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IORef a -> a -> m ()
forall a. HasCallStack => IORef a -> a -> m ()
forall (m :: * -> *) a.
(MonadIORef m, HasCallStack) =>
IORef a -> a -> m ()
writeIORef IORef a
r
  {-# INLINEABLE writeIORef #-}
  atomicWriteIORef :: forall a. HasCallStack => IORef a -> a -> ReaderT e m ()
atomicWriteIORef IORef a
r = m () -> ReaderT e m ()
forall (m :: * -> *) a. Monad m => m a -> ReaderT e m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m () -> ReaderT e m ()) -> (a -> m ()) -> a -> ReaderT e m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IORef a -> a -> m ()
forall a. HasCallStack => IORef a -> a -> m ()
forall (m :: * -> *) a.
(MonadIORef m, HasCallStack) =>
IORef a -> a -> m ()
atomicWriteIORef IORef a
r
  {-# INLINEABLE atomicWriteIORef #-}
  modifyIORef' :: forall a. HasCallStack => IORef a -> (a -> a) -> ReaderT e m ()
modifyIORef' IORef a
r = m () -> ReaderT e m ()
forall (m :: * -> *) a. Monad m => m a -> ReaderT e m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m () -> ReaderT e m ())
-> ((a -> a) -> m ()) -> (a -> a) -> ReaderT e m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IORef a -> (a -> a) -> m ()
forall a. HasCallStack => IORef a -> (a -> a) -> m ()
forall (m :: * -> *) a.
(MonadIORef m, HasCallStack) =>
IORef a -> (a -> a) -> m ()
modifyIORef' IORef a
r
  {-# INLINEABLE modifyIORef' #-}
  atomicModifyIORef' :: forall a b.
HasCallStack =>
IORef a -> (a -> (a, b)) -> ReaderT e m b
atomicModifyIORef' IORef a
r = m b -> ReaderT e m b
forall (m :: * -> *) a. Monad m => m a -> ReaderT e m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m b -> ReaderT e m b)
-> ((a -> (a, b)) -> m b) -> (a -> (a, b)) -> ReaderT e m b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IORef a -> (a -> (a, b)) -> m b
forall a b. HasCallStack => IORef a -> (a -> (a, b)) -> m b
forall (m :: * -> *) a b.
(MonadIORef m, HasCallStack) =>
IORef a -> (a -> (a, b)) -> m b
atomicModifyIORef' IORef a
r
  {-# INLINEABLE atomicModifyIORef' #-}

-- | Atomically apply a function to the contents of an 'IORef' and return the
-- old and new values. The result of the function is forced.
--
-- @since 0.1
atomicModifyIORef'_ :: (HasCallStack, MonadIORef m) => IORef a -> (a -> a) -> m ()
atomicModifyIORef'_ :: forall (m :: * -> *) a.
(HasCallStack, MonadIORef m) =>
IORef a -> (a -> a) -> m ()
atomicModifyIORef'_ IORef a
ref a -> a
f = IORef a -> (a -> (a, ())) -> m ()
forall a b. HasCallStack => IORef a -> (a -> (a, b)) -> m b
forall (m :: * -> *) a b.
(MonadIORef m, HasCallStack) =>
IORef a -> (a -> (a, b)) -> m b
atomicModifyIORef' IORef a
ref ((a -> (a, ())) -> m ()) -> (a -> (a, ())) -> m ()
forall a b. (a -> b) -> a -> b
$ \a
a -> (a -> a
f a
a, ())
{-# INLINEABLE atomicModifyIORef'_ #-}