module Control.Concurrent.STM.TMVar.Extras where

import Control.Concurrent.STM
import Control.Concurrent.STM.TMVar

-- | Non-blocking swap of TMVar irreguardless if it previously contained a value or not.
-- Returns what was in the TMVar (if exists)
forceSwapTMVar :: TMVar a -> a -> STM (Maybe a)
forceSwapTMVar v a = (Just <$> swapTMVar v a) `orElse` (const Nothing <$> putTMVar v a)
{-# INLINABLE forceSwapTMVar #-}

-- | Block until TMVar is empty.
-- The argument a is used to try to put into TMVar, but is taken out again in the same
-- transaction
waitTillEmptyTMVar :: TMVar a -> a -> STM ()
waitTillEmptyTMVar v a = putTMVar v a >> takeTMVar v >> pure ()
{-# INLINABLE waitTillEmptyTMVar #-}

-- | Block until TMVar is full.
waitTillFullTMVar :: TMVar a -> STM ()
waitTillFullTMVar v = takeTMVar v >>= putTMVar v
{-# INLINABLE waitTillFullTMVar #-}