{-# LANGUAGE MagicHash, UnboxedTuples, DeriveDataTypeable, CPP #-}
module Data.Primitive.MutVar (
  MutVar(..),
  newMutVar,
  readMutVar,
  writeMutVar,
  atomicModifyMutVar,
  atomicModifyMutVar',
  modifyMutVar,
  modifyMutVar'
) where
import Control.Monad.Primitive ( PrimMonad(..), primitive_ )
#if MIN_VERSION_base(4,11,0)
import GHC.Exts ( MutVar#, sameMutVar#, newMutVar#,
                  readMutVar#, writeMutVar#, atomicModifyMutVar# )
#else
import GHC.Prim ( MutVar#, sameMutVar#, newMutVar#,
                  readMutVar#, writeMutVar#, atomicModifyMutVar# )
#endif
import Data.Primitive.Internal.Compat ( isTrue# )
import Data.Typeable ( Typeable )
data MutVar s a = MutVar (MutVar# s a)
  deriving ( Typeable )
instance Eq (MutVar s a) where
  MutVar mva# == MutVar mvb# = isTrue# (sameMutVar# mva# mvb#)
newMutVar :: PrimMonad m => a -> m (MutVar (PrimState m) a)
{-# INLINE newMutVar #-}
newMutVar initialValue = primitive $ \s# ->
  case newMutVar# initialValue s# of
    (# s'#, mv# #) -> (# s'#, MutVar mv# #)
readMutVar :: PrimMonad m => MutVar (PrimState m) a -> m a
{-# INLINE readMutVar #-}
readMutVar (MutVar mv#) = primitive (readMutVar# mv#)
writeMutVar :: PrimMonad m => MutVar (PrimState m) a -> a -> m ()
{-# INLINE writeMutVar #-}
writeMutVar (MutVar mv#) newValue = primitive_ (writeMutVar# mv# newValue)
atomicModifyMutVar :: PrimMonad m => MutVar (PrimState m) a -> (a -> (a,b)) -> m b
{-# INLINE atomicModifyMutVar #-}
atomicModifyMutVar (MutVar mv#) f = primitive $ atomicModifyMutVar# mv# f
atomicModifyMutVar' :: PrimMonad m => MutVar (PrimState m) a -> (a -> (a, b)) -> m b
{-# INLINE atomicModifyMutVar' #-}
atomicModifyMutVar' mv f = do
  b <- atomicModifyMutVar mv force
  b `seq` return b
  where
    force x = let (a, b) = f x in (a, a `seq` b)
modifyMutVar :: PrimMonad m => MutVar (PrimState m) a -> (a -> a) -> m ()
{-# INLINE modifyMutVar #-}
modifyMutVar (MutVar mv#) g = primitive_ $ \s# ->
  case readMutVar# mv# s# of
    (# s'#, a #) -> writeMutVar# mv# (g a) s'#
modifyMutVar' :: PrimMonad m => MutVar (PrimState m) a -> (a -> a) -> m ()
{-# INLINE modifyMutVar' #-}
modifyMutVar' (MutVar mv#) g = primitive_ $ \s# ->
  case readMutVar# mv# s# of
    (# s'#, a #) -> let a' = g a in a' `seq` writeMutVar# mv# a' s'#