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

    -- |
    -- Module      : Data.Primitive.MutVar
    -- Copyright   : (c) Justin Bonnar 2011, Roman Leshchinskiy 2011-2012
    -- License     : BSD-style
    --
    -- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
    -- Portability : non-portable
    --
    -- Primitive boxed mutable variables. This is a generalization of
    -- "Data.IORef", "Data.STRef" and "Data.STRef.Lazy" to work in
    -- any 'PrimMonad'.

    module Data.Primitive.MutVar (
      MutVar(..),

      newMutVar,
      readMutVar,
      writeMutVar,

      -- * Modify
      atomicModifyMutVar,
      atomicModifyMutVar',
      modifyMutVar,
      modifyMutVar',
      -- * Interop with STRef and IORef
      mutVarFromIORef,
      mutVarToIORef,
      mutVarFromSTRef,
      mutVarToSTRef
    ) where

    import Control.Monad.Primitive ( PrimMonad(..), primitive_ )
    import GHC.IORef (IORef(IORef))
    import GHC.STRef (STRef(STRef))
    import GHC.Exts ( MutVar#, sameMutVar#, newMutVar#
                    , readMutVar#, writeMutVar#, atomicModifyMutVar#
                    , isTrue#, RealWorld)
    import Data.Typeable ( Typeable )

    -- | A 'MutVar' behaves like a single-element mutable array associated
    -- with a primitive state token.
    data MutVar s a = MutVar (MutVar# s a)
      deriving ( Typeable )

    instance Eq (MutVar s a) where
      MutVar MutVar# s a
    mva# == :: MutVar s a -> MutVar s a -> Bool
    == MutVar MutVar# s a
    mvb# = Int# -> Bool
    isTrue# (MutVar# s a -> MutVar# s a -> Int#
    forall s a. MutVar# s a -> MutVar# s a -> Int#
    sameMutVar# MutVar# s a
    mva# MutVar# s a
    mvb#)

    -- | Create a new 'MutVar' with the specified initial value.
    newMutVar :: PrimMonad m => a -> m (MutVar (PrimState m) a)
    {-# INLINE newMutVar #-}
    newMutVar :: forall (m :: * -> *) a.
    PrimMonad m =>
    a -> m (MutVar (PrimState m) a)
    newMutVar a
    initialValue = (State# (PrimState m)
     -> (# State# (PrimState m), MutVar (PrimState m) a #))
    -> m (MutVar (PrimState m) a)
    forall a.
    (State# (PrimState m) -> (# State# (PrimState m), a #)) -> m a
    forall (m :: * -> *) a.
    PrimMonad m =>
    (State# (PrimState m) -> (# State# (PrimState m), a #)) -> m a
    primitive ((State# (PrimState m)
      -> (# State# (PrimState m), MutVar (PrimState m) a #))
     -> m (MutVar (PrimState m) a))
    -> (State# (PrimState m)
        -> (# State# (PrimState m), MutVar (PrimState m) a #))
    -> m (MutVar (PrimState m) a)
    forall a b. (a -> b) -> a -> b
    $ \State# (PrimState m)
    s# ->
      case a
    -> State# (PrimState m)
    -> (# State# (PrimState m), MutVar# (PrimState m) a #)
    forall a d. a -> State# d -> (# State# d, MutVar# d a #)
    newMutVar# a
    initialValue State# (PrimState m)
    s# of
        (# State# (PrimState m)
    s'#, MutVar# (PrimState m) a
    mv# #) -> (# State# (PrimState m)
    s'#, MutVar# (PrimState m) a -> MutVar (PrimState m) a
    forall s a. MutVar# s a -> MutVar s a
    MutVar MutVar# (PrimState m) a
    mv# #)

    -- | Read the value of a 'MutVar'.
    readMutVar :: PrimMonad m => MutVar (PrimState m) a -> m a
    {-# INLINE readMutVar #-}
    readMutVar :: forall (m :: * -> *) a.
    PrimMonad m =>
    MutVar (PrimState m) a -> m a
    readMutVar (MutVar MutVar# (PrimState m) a
    mv#) = (State# (PrimState m) -> (# State# (PrimState m), a #)) -> m a
    forall a.
    (State# (PrimState m) -> (# State# (PrimState m), a #)) -> m a
    forall (m :: * -> *) a.
    PrimMonad m =>
    (State# (PrimState m) -> (# State# (PrimState m), a #)) -> m a
    primitive (MutVar# (PrimState m) a
    -> State# (PrimState m) -> (# State# (PrimState m), a #)
    forall d a. MutVar# d a -> State# d -> (# State# d, a #)
    readMutVar# MutVar# (PrimState m) a
    mv#)

    -- | Write a new value into a 'MutVar'.
    writeMutVar :: PrimMonad m => MutVar (PrimState m) a -> a -> m ()
    {-# INLINE writeMutVar #-}
    writeMutVar :: forall (m :: * -> *) a.
    PrimMonad m =>
    MutVar (PrimState m) a -> a -> m ()
    writeMutVar (MutVar MutVar# (PrimState m) a
    mv#) a
    newValue = (State# (PrimState m) -> State# (PrimState m)) -> m ()
    forall (m :: * -> *).
    PrimMonad m =>
    (State# (PrimState m) -> State# (PrimState m)) -> m ()
    primitive_ (MutVar# (PrimState m) a
    -> a -> State# (PrimState m) -> State# (PrimState m)
    forall d a. MutVar# d a -> a -> State# d -> State# d
    writeMutVar# MutVar# (PrimState m) a
    mv# a
    newValue)

    -- | Atomically mutate the contents of a 'MutVar'.
    --
    -- This function is useful for using 'MutVar' in a safe way in a multithreaded program.
    -- If you only have one 'MutVar', then using 'atomicModifyMutVar' to access and modify
    -- it will prevent race conditions.
    --
    -- Extending the atomicity to multiple 'MutVar's is problematic,
    -- so if you need to do anything more complicated,
    -- using 'Data.Primitive.MVar.MVar' instead is a good idea.
    --
    -- 'atomicModifyMutVar' does not apply the function strictly. This means if a program
    -- calls 'atomicModifyMutVar' many times, but seldom uses the value, thunks will pile up
    -- in memory resulting in a space leak.
    -- To avoid this problem, use 'atomicModifyMutVar'' instead.
    atomicModifyMutVar :: PrimMonad m => MutVar (PrimState m) a -> (a -> (a, b)) -> m b
    {-# INLINE atomicModifyMutVar #-}
    atomicModifyMutVar :: forall (m :: * -> *) a b.
    PrimMonad m =>
    MutVar (PrimState m) a -> (a -> (a, b)) -> m b
    atomicModifyMutVar (MutVar MutVar# (PrimState m) a
    mv#) a -> (a, b)
    f = (State# (PrimState m) -> (# State# (PrimState m), b #)) -> m b
    forall a.
    (State# (PrimState m) -> (# State# (PrimState m), a #)) -> m a
    forall (m :: * -> *) a.
    PrimMonad m =>
    (State# (PrimState m) -> (# State# (PrimState m), a #)) -> m a
    primitive ((State# (PrimState m) -> (# State# (PrimState m), b #)) -> m b)
    -> (State# (PrimState m) -> (# State# (PrimState m), b #)) -> m b
    forall a b. (a -> b) -> a -> b
    $ MutVar# (PrimState m) a
    -> (a -> (a, b))
    -> State# (PrimState m)
    -> (# State# (PrimState m), b #)
    forall s a b c.
    MutVar# s a -> (a -> b) -> State# s -> (# State# s, c #)
    atomicModifyMutVar# MutVar# (PrimState m) a
    mv# a -> (a, b)
    f

    -- | Strict version of 'atomicModifyMutVar'. This forces both the value stored
    -- in the 'MutVar' as well as the value returned.
    atomicModifyMutVar' :: PrimMonad m => MutVar (PrimState m) a -> (a -> (a, b)) -> m b
    {-# INLINE atomicModifyMutVar' #-}
    atomicModifyMutVar' :: forall (m :: * -> *) a b.
    PrimMonad m =>
    MutVar (PrimState m) a -> (a -> (a, b)) -> m b
    atomicModifyMutVar' MutVar (PrimState m) a
    mv a -> (a, b)
    f = do
      b <- MutVar (PrimState m) a -> (a -> (a, b)) -> m b
    forall (m :: * -> *) a b.
    PrimMonad m =>
    MutVar (PrimState m) a -> (a -> (a, b)) -> m b
    atomicModifyMutVar MutVar (PrimState m) a
    mv a -> (a, b)
    force
      b `seq` return b
      where
        force :: a -> (a, b)
    force a
    x = case a -> (a, b)
    f a
    x of
                    v :: (a, b)
    v@(a
    x', b
    _) -> a
    x' a -> (a, b) -> (a, b)
    forall a b. a -> b -> b
    `seq` (a, b)
    v

    -- | Mutate the contents of a 'MutVar'.
    --
    -- 'modifyMutVar' does not apply the function strictly. This means if a program
    -- calls 'modifyMutVar' many times, but seldom uses the value, thunks will pile up
    -- in memory resulting in a space leak.
    -- To avoid this problem, use 'modifyMutVar'' instead.
    modifyMutVar :: PrimMonad m => MutVar (PrimState m) a -> (a -> a) -> m ()
    {-# INLINE modifyMutVar #-}
    modifyMutVar :: forall (m :: * -> *) a.
    PrimMonad m =>
    MutVar (PrimState m) a -> (a -> a) -> m ()
    modifyMutVar (MutVar MutVar# (PrimState m) a
    mv#) a -> a
    g = (State# (PrimState m) -> State# (PrimState m)) -> m ()
    forall (m :: * -> *).
    PrimMonad m =>
    (State# (PrimState m) -> State# (PrimState m)) -> m ()
    primitive_ ((State# (PrimState m) -> State# (PrimState m)) -> m ())
    -> (State# (PrimState m) -> State# (PrimState m)) -> m ()
    forall a b. (a -> b) -> a -> b
    $ \State# (PrimState m)
    s# ->
      case MutVar# (PrimState m) a
    -> State# (PrimState m) -> (# State# (PrimState m), a #)
    forall d a. MutVar# d a -> State# d -> (# State# d, a #)
    readMutVar# MutVar# (PrimState m) a
    mv# State# (PrimState m)
    s# of
        (# State# (PrimState m)
    s'#, a
    a #) -> MutVar# (PrimState m) a
    -> a -> State# (PrimState m) -> State# (PrimState m)
    forall d a. MutVar# d a -> a -> State# d -> State# d
    writeMutVar# MutVar# (PrimState m) a
    mv# (a -> a
    g a
    a) State# (PrimState m)
    s'#

    -- | Strict version of 'modifyMutVar'.
    modifyMutVar' :: PrimMonad m => MutVar (PrimState m) a -> (a -> a) -> m ()
    {-# INLINE modifyMutVar' #-}
    modifyMutVar' :: forall (m :: * -> *) a.
    PrimMonad m =>
    MutVar (PrimState m) a -> (a -> a) -> m ()
    modifyMutVar' (MutVar MutVar# (PrimState m) a
    mv#) a -> a
    g = (State# (PrimState m) -> State# (PrimState m)) -> m ()
    forall (m :: * -> *).
    PrimMonad m =>
    (State# (PrimState m) -> State# (PrimState m)) -> m ()
    primitive_ ((State# (PrimState m) -> State# (PrimState m)) -> m ())
    -> (State# (PrimState m) -> State# (PrimState m)) -> m ()
    forall a b. (a -> b) -> a -> b
    $ \State# (PrimState m)
    s# ->
      case MutVar# (PrimState m) a
    -> State# (PrimState m) -> (# State# (PrimState m), a #)
    forall d a. MutVar# d a -> State# d -> (# State# d, a #)
    readMutVar# MutVar# (PrimState m) a
    mv# State# (PrimState m)
    s# of
        (# State# (PrimState m)
    s'#, a
    a #) -> let a' :: a
    a' = a -> a
    g a
    a in a
    a' a -> State# (PrimState m) -> State# (PrimState m)
    forall a b. a -> b -> b
    `seq` MutVar# (PrimState m) a
    -> a -> State# (PrimState m) -> State# (PrimState m)
    forall d a. MutVar# d a -> a -> State# d -> State# d
    writeMutVar# MutVar# (PrimState m) a
    mv# a
    a' State# (PrimState m)
    s'#

    -- | Convert 'MutVar' to 'IORef'
    mutVarToIORef :: MutVar RealWorld a -> IORef a
    {-# INLINE mutVarToIORef #-}
    mutVarToIORef :: forall a. MutVar RealWorld a -> IORef a
    mutVarToIORef (MutVar MutVar# RealWorld a
    mv#) = STRef RealWorld a -> IORef a
    forall a. STRef RealWorld a -> IORef a
    IORef (MutVar# RealWorld a -> STRef RealWorld a
    forall s a. MutVar# s a -> STRef s a
    STRef MutVar# RealWorld a
    mv#)

    -- | Convert 'MutVar' to 'IORef'
    mutVarFromIORef :: IORef a -> MutVar RealWorld a
    {-# INLINE mutVarFromIORef #-}
    mutVarFromIORef :: forall a. IORef a -> MutVar RealWorld a
    mutVarFromIORef (IORef (STRef MutVar# RealWorld a
    mv#)) = MutVar# RealWorld a -> MutVar RealWorld a
    forall s a. MutVar# s a -> MutVar s a
    MutVar MutVar# RealWorld a
    mv#

    -- | Convert 'MutVar' to 'STRef'
    mutVarToSTRef :: MutVar s a -> STRef s a
    {-# INLINE mutVarToSTRef #-}
    mutVarToSTRef :: forall s a. MutVar s a -> STRef s a
    mutVarToSTRef (MutVar MutVar# s a
    mv#) = MutVar# s a -> STRef s a
    forall s a. MutVar# s a -> STRef s a
    STRef MutVar# s a
    mv#

    -- | Convert 'MutVar' to 'STRef'
    mutVarFromSTRef :: STRef s a -> MutVar s a
    {-# INLINE mutVarFromSTRef #-}
    mutVarFromSTRef :: forall s a. STRef s a -> MutVar s a
    mutVarFromSTRef (STRef MutVar# s a
    mv#) = MutVar# s a -> MutVar s a
    forall s a. MutVar# s a -> MutVar s a
    MutVar MutVar# s a
    mv#