module Effectful.Concurrent.MVar.Utils
  ( -- * Strict variants
    -- $strict
    newMVar',
    takeMVar',
    putMVar',
    tryTakeMVar',
    tryPutMVar',
    withMVar',
    withMVarMasked',
    modifyMVar',
    modifyMVar_',
    modifyMVarMasked',
    modifyMVarMasked_',
    tryReadMVar',
  )
where

import Control.Concurrent (MVar)
import Control.Monad ((>=>))
import Effectful (Eff, type (:>))
import Effectful.Concurrent (Concurrent)
import Effectful.Concurrent.MVar qualified as MVar
import Effectful.Exception (evaluate)

-- $strict
--
-- These functions are strict variants of the normal functions in the sense
-- that they act is if the MVar held its argument in WHNF e.g.
-- @MVar a = MVar !a@.
--
-- To that end, MVar values are evaluated before writes and after reads.
--
-- Note that these evaluations apply only to the value in the MVar e.g.
-- the @b@ in 'withMVar'' is not given any extra evaluation.

-- | @since 0.1
newMVar' :: (Concurrent :> es) => a -> Eff es (MVar a)
newMVar' :: forall (es :: [Effect]) a.
(Concurrent :> es) =>
a -> Eff es (MVar a)
newMVar' = a -> Eff es a
forall a (es :: [Effect]). a -> Eff es a
evaluate (a -> Eff es a) -> (a -> Eff es (MVar a)) -> a -> Eff es (MVar a)
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> a -> Eff es (MVar a)
forall (es :: [Effect]) a.
(Concurrent :> es) =>
a -> Eff es (MVar a)
MVar.newMVar

-- | @since 0.1
takeMVar' :: (Concurrent :> es) => MVar a -> Eff es a
takeMVar' :: forall (es :: [Effect]) a. (Concurrent :> es) => MVar a -> Eff es a
takeMVar' = MVar a -> Eff es a
forall (es :: [Effect]) a. (Concurrent :> es) => MVar a -> Eff es a
MVar.takeMVar (MVar a -> Eff es a) -> (a -> Eff es a) -> MVar a -> Eff es a
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> a -> Eff es a
forall a (es :: [Effect]). a -> Eff es a
evaluate

-- | @since 0.1
putMVar' :: (Concurrent :> es) => MVar a -> a -> Eff es ()
putMVar' :: forall (es :: [Effect]) a.
(Concurrent :> es) =>
MVar a -> a -> Eff es ()
putMVar' MVar a
v = 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
>=> MVar a -> a -> Eff es ()
forall (es :: [Effect]) a.
(Concurrent :> es) =>
MVar a -> a -> Eff es ()
MVar.putMVar MVar a
v

-- | @since 0.1
tryTakeMVar' :: (Concurrent :> es) => MVar a -> Eff es (Maybe a)
tryTakeMVar' :: forall (es :: [Effect]) a.
(Concurrent :> es) =>
MVar a -> Eff es (Maybe a)
tryTakeMVar' MVar a
v =
  MVar a -> Eff es (Maybe a)
forall (es :: [Effect]) a.
(Concurrent :> es) =>
MVar a -> Eff es (Maybe a)
MVar.tryTakeMVar MVar a
v Eff es (Maybe a)
-> (Maybe a -> Eff es (Maybe a)) -> Eff es (Maybe a)
forall a b. Eff es a -> (a -> Eff es b) -> Eff es b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
    Maybe a
Nothing -> Maybe a -> Eff es (Maybe a)
forall a. a -> Eff es a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe a
forall a. Maybe a
Nothing
    Just a
x -> a -> Maybe a
forall a. a -> Maybe a
Just (a -> Maybe a) -> Eff es a -> Eff es (Maybe a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> a -> Eff es a
forall a (es :: [Effect]). a -> Eff es a
evaluate a
x

-- | @since 0.1
tryPutMVar' :: (Concurrent :> es) => MVar a -> a -> Eff es Bool
tryPutMVar' :: forall (es :: [Effect]) a.
(Concurrent :> es) =>
MVar a -> a -> Eff es Bool
tryPutMVar' MVar a
v = a -> Eff es a
forall a (es :: [Effect]). a -> Eff es a
evaluate (a -> Eff es a) -> (a -> Eff es Bool) -> a -> Eff es Bool
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> MVar a -> a -> Eff es Bool
forall (es :: [Effect]) a.
(Concurrent :> es) =>
MVar a -> a -> Eff es Bool
MVar.tryPutMVar MVar a
v

-- | @since 0.1
withMVar' :: (Concurrent :> es) => MVar a -> (a -> Eff es b) -> Eff es b
withMVar' :: forall (es :: [Effect]) a b.
(Concurrent :> es) =>
MVar a -> (a -> Eff es b) -> Eff es b
withMVar' MVar a
v a -> Eff es b
f = MVar a -> (a -> Eff es b) -> Eff es b
forall (es :: [Effect]) a b.
(Concurrent :> es) =>
MVar a -> (a -> Eff es b) -> Eff es b
MVar.withMVar MVar a
v (a -> Eff es a
forall a (es :: [Effect]). a -> Eff es a
evaluate (a -> Eff es a) -> (a -> Eff es b) -> a -> Eff es b
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> a -> Eff es b
f)

-- | @since 0.1
withMVarMasked' :: (Concurrent :> es) => MVar a -> (a -> Eff es b) -> Eff es b
withMVarMasked' :: forall (es :: [Effect]) a b.
(Concurrent :> es) =>
MVar a -> (a -> Eff es b) -> Eff es b
withMVarMasked' MVar a
v a -> Eff es b
f = MVar a -> (a -> Eff es b) -> Eff es b
forall (es :: [Effect]) a b.
(Concurrent :> es) =>
MVar a -> (a -> Eff es b) -> Eff es b
MVar.withMVarMasked MVar a
v (a -> Eff es a
forall a (es :: [Effect]). a -> Eff es a
evaluate (a -> Eff es a) -> (a -> Eff es b) -> a -> Eff es b
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> a -> Eff es b
f)

-- | @since 0.1
modifyMVar_' :: (Concurrent :> es) => MVar a -> (a -> Eff es a) -> Eff es ()
modifyMVar_' :: forall (es :: [Effect]) a.
(Concurrent :> es) =>
MVar a -> (a -> Eff es a) -> Eff es ()
modifyMVar_' MVar a
v a -> Eff es a
f = MVar a -> (a -> Eff es a) -> Eff es ()
forall (es :: [Effect]) a.
(Concurrent :> es) =>
MVar a -> (a -> Eff es a) -> Eff es ()
MVar.modifyMVar_ MVar a
v (a -> Eff es a
f (a -> Eff es a) -> (a -> Eff es a) -> a -> Eff es a
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> a -> Eff es a
forall a (es :: [Effect]). a -> Eff es a
evaluate)

-- | @since 0.1
modifyMVar' :: (Concurrent :> es) => MVar a -> (a -> Eff es (a, b)) -> Eff es b
modifyMVar' :: forall (es :: [Effect]) a b.
(Concurrent :> es) =>
MVar a -> (a -> Eff es (a, b)) -> Eff es b
modifyMVar' MVar a
v a -> Eff es (a, b)
f = MVar a -> (a -> Eff es (a, b)) -> Eff es b
forall (es :: [Effect]) a b.
(Concurrent :> es) =>
MVar a -> (a -> Eff es (a, b)) -> Eff es b
MVar.modifyMVar MVar a
v ((a -> Eff es (a, b)) -> Eff es b)
-> (a -> Eff es (a, b)) -> Eff es b
forall a b. (a -> b) -> a -> b
$ \a
x -> do
  (a, b) <- a -> Eff es (a, b)
f a
x
  (,b) <$> evaluate a

-- | @since 0.1
modifyMVarMasked_' :: (Concurrent :> es) => MVar a -> (a -> Eff es a) -> Eff es ()
modifyMVarMasked_' :: forall (es :: [Effect]) a.
(Concurrent :> es) =>
MVar a -> (a -> Eff es a) -> Eff es ()
modifyMVarMasked_' MVar a
v a -> Eff es a
f = MVar a -> (a -> Eff es a) -> Eff es ()
forall (es :: [Effect]) a.
(Concurrent :> es) =>
MVar a -> (a -> Eff es a) -> Eff es ()
MVar.modifyMVarMasked_ MVar a
v (a -> Eff es a
f (a -> Eff es a) -> (a -> Eff es a) -> a -> Eff es a
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> a -> Eff es a
forall a (es :: [Effect]). a -> Eff es a
evaluate)

-- | @since 0.1
modifyMVarMasked' :: (Concurrent :> es) => MVar a -> (a -> Eff es (a, b)) -> Eff es b
modifyMVarMasked' :: forall (es :: [Effect]) a b.
(Concurrent :> es) =>
MVar a -> (a -> Eff es (a, b)) -> Eff es b
modifyMVarMasked' MVar a
v a -> Eff es (a, b)
f = MVar a -> (a -> Eff es (a, b)) -> Eff es b
forall (es :: [Effect]) a b.
(Concurrent :> es) =>
MVar a -> (a -> Eff es (a, b)) -> Eff es b
MVar.modifyMVarMasked MVar a
v ((a -> Eff es (a, b)) -> Eff es b)
-> (a -> Eff es (a, b)) -> Eff es b
forall a b. (a -> b) -> a -> b
$ \a
x -> do
  (a, b) <- a -> Eff es (a, b)
f a
x
  (,b) <$> evaluate a

-- | @since 0.1
tryReadMVar' :: (Concurrent :> es) => MVar a -> Eff es (Maybe a)
tryReadMVar' :: forall (es :: [Effect]) a.
(Concurrent :> es) =>
MVar a -> Eff es (Maybe a)
tryReadMVar' MVar a
v =
  MVar a -> Eff es (Maybe a)
forall (es :: [Effect]) a.
(Concurrent :> es) =>
MVar a -> Eff es (Maybe a)
MVar.tryReadMVar MVar a
v Eff es (Maybe a)
-> (Maybe a -> Eff es (Maybe a)) -> Eff es (Maybe a)
forall a b. Eff es a -> (a -> Eff es b) -> Eff es b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
    Maybe a
Nothing -> Maybe a -> Eff es (Maybe a)
forall a. a -> Eff es a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe a
forall a. Maybe a
Nothing
    Just a
x -> a -> Maybe a
forall a. a -> Maybe a
Just (a -> Maybe a) -> Eff es a -> Eff es (Maybe a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> a -> Eff es a
forall a (es :: [Effect]). a -> Eff es a
evaluate a
x