module Control.Concurrent.Strict
    (modifyVar', modifyVarIO'
    ,modifyVar, modifyVar_
    ,module Control.Concurrent.Extra
    ) where

import           Control.Concurrent.Extra hiding (modifyVar, modifyVar',
                                           modifyVar_)
import qualified Control.Concurrent.Extra as Extra
import           Control.Exception        (evaluate)
import           Control.Monad            (void)
import           Data.Tuple.Extra         (dupe)

-- | Strict modification that returns the new value
modifyVar' :: Extra.Var a -> (a -> a) -> IO a
modifyVar' :: forall a. Var a -> (a -> a) -> IO a
modifyVar' Var a
var a -> a
upd = forall a. Var a -> (a -> IO a) -> IO a
modifyVarIO' Var a
var (forall (f :: * -> *) a. Applicative f => a -> f a
pure forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> a
upd)

-- | Strict modification that returns the new value
modifyVarIO' :: Extra.Var a -> (a -> IO a) -> IO a
modifyVarIO' :: forall a. Var a -> (a -> IO a) -> IO a
modifyVarIO' Var a
var a -> IO a
upd = do
    a
res <- forall a b. Var a -> (a -> IO (a, b)) -> IO b
Extra.modifyVar Var a
var forall a b. (a -> b) -> a -> b
$ \a
v -> do
        a
v' <- a -> IO a
upd a
v
        forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall a. a -> (a, a)
dupe a
v'
    forall a. a -> IO a
evaluate a
res

modifyVar :: Extra.Var a -> (a -> IO (a, b)) -> IO b
modifyVar :: forall a b. Var a -> (a -> IO (a, b)) -> IO b
modifyVar Var a
var a -> IO (a, b)
upd = do
    (a
new, b
res) <- forall a b. Var a -> (a -> IO (a, b)) -> IO b
Extra.modifyVar Var a
var forall a b. (a -> b) -> a -> b
$ \a
old -> do
        (a
new,b
res) <- a -> IO (a, b)
upd a
old
        forall (m :: * -> *) a. Monad m => a -> m a
return (a
new, (a
new, b
res))
    forall (f :: * -> *) a. Functor f => f a -> f ()
void forall a b. (a -> b) -> a -> b
$ forall a. a -> IO a
evaluate a
new
    forall (m :: * -> *) a. Monad m => a -> m a
return b
res

modifyVar_ :: Extra.Var a -> (a -> IO a) -> IO ()
modifyVar_ :: forall a. Var a -> (a -> IO a) -> IO ()
modifyVar_ Var a
var a -> IO a
upd = forall (f :: * -> *) a. Functor f => f a -> f ()
void forall a b. (a -> b) -> a -> b
$ forall a. Var a -> (a -> IO a) -> IO a
modifyVarIO' Var a
var a -> IO a
upd