{-# LANGUAGE CPP, MagicHash, UnboxedTuples #-}

#if __GLASGOW_HASKELL__ >= 701
{-# LANGUAGE Trustworthy #-}
#endif

-----------------------------------------------------------------------------
-- |
-- Module      :  Control.Concurrent.STM.TVar
-- Copyright   :  (c) The University of Glasgow 2004
-- License     :  BSD-style (see the file libraries/base/LICENSE)
--
-- Maintainer  :  libraries@haskell.org
-- Stability   :  experimental
-- Portability :  non-portable (requires STM)
--
-- TVar: Transactional variables
--
-----------------------------------------------------------------------------

module Control.Concurrent.STM.TVar (
        -- * TVars
        TVar,
        newTVar,
        newTVarIO,
        readTVar,
        readTVarIO,
        writeTVar,
        modifyTVar,
        modifyTVar',
        stateTVar,
        swapTVar,
#ifdef __GLASGOW_HASKELL__
        registerDelay,
#endif
        mkWeakTVar
  ) where

#ifdef __GLASGOW_HASKELL__
import GHC.Base
import GHC.Conc
import GHC.Weak
#else
import Control.Sequential.STM
#endif

-- Like 'modifyIORef' but for 'TVar'.
-- | Mutate the contents of a 'TVar'. /N.B./, this version is
-- non-strict.
--
-- @since 2.3
modifyTVar :: TVar a -> (a -> a) -> STM ()
modifyTVar :: forall a. TVar a -> (a -> a) -> STM ()
modifyTVar TVar a
var a -> a
f = do
    a
x <- TVar a -> STM a
forall a. TVar a -> STM a
readTVar TVar a
var
    TVar a -> a -> STM ()
forall a. TVar a -> a -> STM ()
writeTVar TVar a
var (a -> a
f a
x)
{-# INLINE modifyTVar #-}


-- | Strict version of 'modifyTVar'.
--
-- @since 2.3
modifyTVar' :: TVar a -> (a -> a) -> STM ()
modifyTVar' :: forall a. TVar a -> (a -> a) -> STM ()
modifyTVar' TVar a
var a -> a
f = do
    a
x <- TVar a -> STM a
forall a. TVar a -> STM a
readTVar TVar a
var
    TVar a -> a -> STM ()
forall a. TVar a -> a -> STM ()
writeTVar TVar a
var (a -> STM ()) -> a -> STM ()
forall a b. (a -> b) -> a -> b
$! a -> a
f a
x
{-# INLINE modifyTVar' #-}


-- | Like 'modifyTVar'' but the function is a simple state transition that can
-- return a side value which is passed on as the result of the 'STM'.
--
-- @since 2.5.0
stateTVar :: TVar s -> (s -> (a, s)) -> STM a
stateTVar :: forall s a. TVar s -> (s -> (a, s)) -> STM a
stateTVar TVar s
var s -> (a, s)
f = do
   s
s <- TVar s -> STM s
forall a. TVar a -> STM a
readTVar TVar s
var
   let (a
a, s
s') = s -> (a, s)
f s
s -- since we destructure this, we are strict in f
   TVar s -> s -> STM ()
forall a. TVar a -> a -> STM ()
writeTVar TVar s
var s
s'
   a -> STM a
forall (m :: * -> *) a. Monad m => a -> m a
return a
a
{-# INLINE stateTVar #-}


-- Like 'swapTMVar' but for 'TVar'.
-- | Swap the contents of a 'TVar' for a new value.
--
-- @since 2.3
swapTVar :: TVar a -> a -> STM a
swapTVar :: forall a. TVar a -> a -> STM a
swapTVar TVar a
var a
new = do
    a
old <- TVar a -> STM a
forall a. TVar a -> STM a
readTVar TVar a
var
    TVar a -> a -> STM ()
forall a. TVar a -> a -> STM ()
writeTVar TVar a
var a
new
    a -> STM a
forall (m :: * -> *) a. Monad m => a -> m a
return a
old
{-# INLINE swapTVar #-}


-- | Make a 'Weak' pointer to a 'TVar', using the second argument as
-- a finalizer to run when 'TVar' is garbage-collected
--
-- @since 2.4.3
mkWeakTVar :: TVar a -> IO () -> IO (Weak (TVar a))
mkWeakTVar :: forall a. TVar a -> IO () -> IO (Weak (TVar a))
mkWeakTVar t :: TVar a
t@(TVar TVar# RealWorld a
t#) (IO State# RealWorld -> (# State# RealWorld, () #)
finalizer) = (State# RealWorld -> (# State# RealWorld, Weak (TVar a) #))
-> IO (Weak (TVar a))
forall a. (State# RealWorld -> (# State# RealWorld, a #)) -> IO a
IO ((State# RealWorld -> (# State# RealWorld, Weak (TVar a) #))
 -> IO (Weak (TVar a)))
-> (State# RealWorld -> (# State# RealWorld, Weak (TVar a) #))
-> IO (Weak (TVar a))
forall a b. (a -> b) -> a -> b
$ \State# RealWorld
s ->
    case TVar# RealWorld a
-> TVar a
-> (State# RealWorld -> (# State# RealWorld, () #))
-> State# RealWorld
-> (# State# RealWorld, Weak# (TVar a) #)
mkWeak# TVar# RealWorld a
t# TVar a
t State# RealWorld -> (# State# RealWorld, () #)
finalizer State# RealWorld
s of (# State# RealWorld
s1, Weak# (TVar a)
w #) -> (# State# RealWorld
s1, Weak# (TVar a) -> Weak (TVar a)
forall v. Weak# v -> Weak v
Weak Weak# (TVar a)
w #)