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' :: Var a -> (a -> a) -> IO a
modifyVar' Var a
var a -> a
upd = Var a -> (a -> IO a) -> IO a
forall a. Var a -> (a -> IO a) -> IO a
modifyVarIO' Var a
var (a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (a -> IO a) -> (a -> a) -> a -> IO a
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' :: Var a -> (a -> IO a) -> IO a
modifyVarIO' Var a
var a -> IO a
upd = do
    a
res <- Var a -> (a -> IO (a, a)) -> IO a
forall a b. Var a -> (a -> IO (a, b)) -> IO b
Extra.modifyVar Var a
var ((a -> IO (a, a)) -> IO a) -> (a -> IO (a, a)) -> IO a
forall a b. (a -> b) -> a -> b
$ \a
v -> do
        a
v' <- a -> IO a
upd a
v
        (a, a) -> IO (a, a)
forall (f :: * -> *) a. Applicative f => a -> f a
pure ((a, a) -> IO (a, a)) -> (a, a) -> IO (a, a)
forall a b. (a -> b) -> a -> b
$ a -> (a, a)
forall a. a -> (a, a)
dupe a
v'
    a -> IO a
forall a. a -> IO a
evaluate a
res

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

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