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

    -- |
    -- Module      : Data.Primitive.MVar
    -- License     : BSD2
    -- Portability : non-portable
    --
    -- Primitive operations on 'MVar'. This module provides a similar interface
    -- to "Control.Concurrent.MVar". However, the functions are generalized to
    -- work in any 'PrimMonad' instead of only working in 'IO'. Note that all
    -- of the functions here are completely deterministic. Users of 'MVar' are
    -- responsible for designing abstractions that guarantee determinism in
    -- the presence of multi-threading.
    --
    -- For a more detailed explanation, see "Control.Concurrent.MVar".
    --
    -- @since 0.6.4.0

    module Data.Primitive.MVar
      ( MVar(..)
      , newMVar
      , isEmptyMVar
      , newEmptyMVar
      , putMVar
      , readMVar
      , takeMVar
      , tryPutMVar
      , tryReadMVar
      , tryTakeMVar
      ) where

    import Control.Monad.Primitive
    import GHC.Exts
      ( MVar#, newMVar#, takeMVar#, sameMVar#, putMVar#, tryTakeMVar#, isEmptyMVar#, tryPutMVar#, (/=#)
      , readMVar#, tryReadMVar#, isTrue# )

    -- | A synchronizing variable, used for communication between concurrent threads.
    -- It can be thought of as a box, which may be empty or full.
    data MVar s a = MVar (MVar# s a)

    instance Eq (MVar s a) where
      MVar MVar# s a
    mvar1# == :: MVar s a -> MVar s a -> Bool
    == MVar MVar# s a
    mvar2# = Int# -> Bool
    isTrue# (MVar# s a -> MVar# s a -> Int#
    forall s a. MVar# s a -> MVar# s a -> Int#
    sameMVar# MVar# s a
    mvar1# MVar# s a
    mvar2#)

    -- | Create a new 'MVar' that is initially empty.
    newEmptyMVar :: PrimMonad m => m (MVar (PrimState m) a)
    newEmptyMVar :: forall (m :: * -> *) a. PrimMonad m => m (MVar (PrimState m) a)
    newEmptyMVar = (State# (PrimState m)
     -> (# State# (PrimState m), MVar (PrimState m) a #))
    -> m (MVar (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), MVar (PrimState m) a #))
     -> m (MVar (PrimState m) a))
    -> (State# (PrimState m)
        -> (# State# (PrimState m), MVar (PrimState m) a #))
    -> m (MVar (PrimState m) a)
    forall a b. (a -> b) -> a -> b
    $ \ State# (PrimState m)
    s# ->
      case State# (PrimState m)
    -> (# State# (PrimState m), MVar# (PrimState m) a #)
    forall d a. State# d -> (# State# d, MVar# d a #)
    newMVar# State# (PrimState m)
    s# of
        (# State# (PrimState m)
    s2#, MVar# (PrimState m) a
    svar# #) -> (# State# (PrimState m)
    s2#, MVar# (PrimState m) a -> MVar (PrimState m) a
    forall s a. MVar# s a -> MVar s a
    MVar MVar# (PrimState m) a
    svar# #)

    -- | Create a new 'MVar' that holds the supplied argument.
    newMVar :: PrimMonad m => a -> m (MVar (PrimState m) a)
    newMVar :: forall (m :: * -> *) a.
    PrimMonad m =>
    a -> m (MVar (PrimState m) a)
    newMVar a
    value = do
      mvar <- m (MVar (PrimState m) a)
    forall (m :: * -> *) a. PrimMonad m => m (MVar (PrimState m) a)
    newEmptyMVar
      putMVar mvar value
      return mvar

    -- | Return the contents of the 'MVar'. If the 'MVar' is currently
    -- empty, 'takeMVar' will wait until it is full. After a 'takeMVar',
    -- the 'MVar' is left empty.
    --
    -- There are two further important properties of 'takeMVar':
    --
    -- * 'takeMVar' is single-wakeup. That is, if there are multiple
    --   threads blocked in 'takeMVar', and the 'MVar' becomes full,
    --   only one thread will be woken up. The runtime guarantees that
    --   the woken thread completes its 'takeMVar' operation.
    -- * When multiple threads are blocked on an 'MVar', they are
    --   woken up in FIFO order. This is useful for providing
    --   fairness properties of abstractions built using 'MVar's.
    takeMVar :: PrimMonad m => MVar (PrimState m) a -> m a
    takeMVar :: forall (m :: * -> *) a. PrimMonad m => MVar (PrimState m) a -> m a
    takeMVar (MVar MVar# (PrimState m) a
    mvar#) = (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 ((State# (PrimState m) -> (# State# (PrimState m), a #)) -> m a)
    -> (State# (PrimState m) -> (# State# (PrimState m), a #)) -> m a
    forall a b. (a -> b) -> a -> b
    $ \ State# (PrimState m)
    s# -> MVar# (PrimState m) a
    -> State# (PrimState m) -> (# State# (PrimState m), a #)
    forall d a. MVar# d a -> State# d -> (# State# d, a #)
    takeMVar# MVar# (PrimState m) a
    mvar# State# (PrimState m)
    s#

    -- | Atomically read the contents of an 'MVar'. If the 'MVar' is
    -- currently empty, 'readMVar' will wait until it is full.
    -- 'readMVar' is guaranteed to receive the next 'putMVar'.
    --
    -- /Multiple Wakeup:/ 'readMVar' is multiple-wakeup, so when multiple readers
    -- are blocked on an 'MVar', all of them are woken up at the same time.
    --
    -- * It is single-wakeup instead of multiple-wakeup.
    -- * It might not receive the value from the next call to 'putMVar' if
    --   there is already a pending thread blocked on 'takeMVar'.
    -- * If another thread puts a value in the 'MVar' in between the
    --   calls to 'takeMVar' and 'putMVar', that value may be overridden.
    readMVar :: PrimMonad m => MVar (PrimState m) a -> m a
    readMVar :: forall (m :: * -> *) a. PrimMonad m => MVar (PrimState m) a -> m a
    readMVar (MVar MVar# (PrimState m) a
    mvar#) = (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 ((State# (PrimState m) -> (# State# (PrimState m), a #)) -> m a)
    -> (State# (PrimState m) -> (# State# (PrimState m), a #)) -> m a
    forall a b. (a -> b) -> a -> b
    $ \ State# (PrimState m)
    s# -> MVar# (PrimState m) a
    -> State# (PrimState m) -> (# State# (PrimState m), a #)
    forall d a. MVar# d a -> State# d -> (# State# d, a #)
    readMVar# MVar# (PrimState m) a
    mvar# State# (PrimState m)
    s#

    -- | Put a value into an 'MVar'. If the 'MVar' is currently full,
    -- 'putMVar' will wait until it becomes empty.
    --
    -- There are two further important properties of 'putMVar':
    --
    -- * 'putMVar' is single-wakeup. That is, if there are multiple
    --   threads blocked in 'putMVar', and the 'MVar' becomes empty,
    --   only one thread will be woken up. The runtime guarantees that
    --   the woken thread completes its 'putMVar' operation.
    -- * When multiple threads are blocked on an 'MVar', they are
    --   woken up in FIFO order. This is useful for providing
    --   fairness properties of abstractions built using 'MVar's.
    putMVar :: PrimMonad m => MVar (PrimState m) a -> a -> m ()
    putMVar :: forall (m :: * -> *) a.
    PrimMonad m =>
    MVar (PrimState m) a -> a -> m ()
    putMVar (MVar MVar# (PrimState m) a
    mvar#) a
    x = (State# (PrimState m) -> State# (PrimState m)) -> m ()
    forall (m :: * -> *).
    PrimMonad m =>
    (State# (PrimState m) -> State# (PrimState m)) -> m ()
    primitive_ (MVar# (PrimState m) a
    -> a -> State# (PrimState m) -> State# (PrimState m)
    forall d a. MVar# d a -> a -> State# d -> State# d
    putMVar# MVar# (PrimState m) a
    mvar# a
    x)

    -- | A non-blocking version of 'takeMVar'. The 'tryTakeMVar' function
    -- returns immediately, with 'Nothing' if the 'MVar' was empty, or
    -- @'Just' a@ if the 'MVar' was full with contents @a@. After 'tryTakeMVar',
    -- the 'MVar' is left empty.
    tryTakeMVar :: PrimMonad m => MVar (PrimState m) a -> m (Maybe a)
    tryTakeMVar :: forall (m :: * -> *) a.
    PrimMonad m =>
    MVar (PrimState m) a -> m (Maybe a)
    tryTakeMVar (MVar MVar# (PrimState m) a
    m) = (State# (PrimState m) -> (# State# (PrimState m), Maybe a #))
    -> m (Maybe 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), Maybe a #))
     -> m (Maybe a))
    -> (State# (PrimState m) -> (# State# (PrimState m), Maybe a #))
    -> m (Maybe a)
    forall a b. (a -> b) -> a -> b
    $ \ State# (PrimState m)
    s ->
      case MVar# (PrimState m) a
    -> State# (PrimState m) -> (# State# (PrimState m), Int#, a #)
    forall d a. MVar# d a -> State# d -> (# State# d, Int#, a #)
    tryTakeMVar# MVar# (PrimState m) a
    m State# (PrimState m)
    s of
        (# State# (PrimState m)
    s', Int#
    0#, a
    _ #) -> (# State# (PrimState m)
    s', Maybe a
    forall a. Maybe a
    Nothing #) -- MVar is empty
        (# State# (PrimState m)
    s', Int#
    _,  a
    a #) -> (# State# (PrimState m)
    s', a -> Maybe a
    forall a. a -> Maybe a
    Just a
    a  #) -- MVar is full

    -- | A non-blocking version of 'putMVar'. The 'tryPutMVar' function
    -- attempts to put the value @a@ into the 'MVar', returning 'True' if
    -- it was successful, or 'False' otherwise.
    tryPutMVar :: PrimMonad m => MVar (PrimState m) a -> a -> m Bool
    tryPutMVar :: forall (m :: * -> *) a.
    PrimMonad m =>
    MVar (PrimState m) a -> a -> m Bool
    tryPutMVar (MVar MVar# (PrimState m) a
    mvar#) a
    x = (State# (PrimState m) -> (# State# (PrimState m), Bool #))
    -> m Bool
    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), Bool #))
     -> m Bool)
    -> (State# (PrimState m) -> (# State# (PrimState m), Bool #))
    -> m Bool
    forall a b. (a -> b) -> a -> b
    $ \ State# (PrimState m)
    s# ->
        case MVar# (PrimState m) a
    -> a -> State# (PrimState m) -> (# State# (PrimState m), Int# #)
    forall d a. MVar# d a -> a -> State# d -> (# State# d, Int# #)
    tryPutMVar# MVar# (PrimState m) a
    mvar# a
    x State# (PrimState m)
    s# of
            (# State# (PrimState m)
    s, Int#
    0# #) -> (# State# (PrimState m)
    s, Bool
    False #)
            (# State# (PrimState m)
    s, Int#
    _  #) -> (# State# (PrimState m)
    s, Bool
    True #)

    -- | A non-blocking version of 'readMVar'. The 'tryReadMVar' function
    -- returns immediately, with 'Nothing' if the 'MVar' was empty, or
    -- @'Just' a@ if the 'MVar' was full with contents @a@.
    --
    -- * It is single-wakeup instead of multiple-wakeup.
    -- * In the presence of other threads calling 'putMVar', 'tryReadMVar'
    --   may block.
    -- * If another thread puts a value in the 'MVar' in between the
    --   calls to 'tryTakeMVar' and 'putMVar', that value may be overridden.
    tryReadMVar :: PrimMonad m => MVar (PrimState m) a -> m (Maybe a)
    tryReadMVar :: forall (m :: * -> *) a.
    PrimMonad m =>
    MVar (PrimState m) a -> m (Maybe a)
    tryReadMVar (MVar MVar# (PrimState m) a
    m) = (State# (PrimState m) -> (# State# (PrimState m), Maybe a #))
    -> m (Maybe 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), Maybe a #))
     -> m (Maybe a))
    -> (State# (PrimState m) -> (# State# (PrimState m), Maybe a #))
    -> m (Maybe a)
    forall a b. (a -> b) -> a -> b
    $ \ State# (PrimState m)
    s ->
        case MVar# (PrimState m) a
    -> State# (PrimState m) -> (# State# (PrimState m), Int#, a #)
    forall d a. MVar# d a -> State# d -> (# State# d, Int#, a #)
    tryReadMVar# MVar# (PrimState m) a
    m State# (PrimState m)
    s of
            (# State# (PrimState m)
    s', Int#
    0#, a
    _ #) -> (# State# (PrimState m)
    s', Maybe a
    forall a. Maybe a
    Nothing #)      -- MVar is empty
            (# State# (PrimState m)
    s', Int#
    _,  a
    a #) -> (# State# (PrimState m)
    s', a -> Maybe a
    forall a. a -> Maybe a
    Just a
    a  #)      -- MVar is full

    -- | Check whether a given 'MVar' is empty.
    --
    -- Notice that the boolean value returned is just a snapshot of
    -- the state of the 'MVar'. By the time you get to react on its result,
    -- the 'MVar' may have been filled (or emptied) - so be extremely
    -- careful when using this operation. Use 'tryTakeMVar' instead if possible.
    isEmptyMVar :: PrimMonad m => MVar (PrimState m) a -> m Bool
    isEmptyMVar :: forall (m :: * -> *) a.
    PrimMonad m =>
    MVar (PrimState m) a -> m Bool
    isEmptyMVar (MVar MVar# (PrimState m) a
    mv#) = (State# (PrimState m) -> (# State# (PrimState m), Bool #))
    -> m Bool
    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), Bool #))
     -> m Bool)
    -> (State# (PrimState m) -> (# State# (PrimState m), Bool #))
    -> m Bool
    forall a b. (a -> b) -> a -> b
    $ \ State# (PrimState m)
    s# ->
      case MVar# (PrimState m) a
    -> State# (PrimState m) -> (# State# (PrimState m), Int# #)
    forall d a. MVar# d a -> State# d -> (# State# d, Int# #)
    isEmptyMVar# MVar# (PrimState m) a
    mv# State# (PrimState m)
    s# of
        (# State# (PrimState m)
    s2#, Int#
    flg #) -> (# State# (PrimState m)
    s2#, Int# -> Bool
    isTrue# (Int#
    flg Int# -> Int# -> Int#
    /=# Int#
    0#) #)