{-# LANGUAGE CPP #-}

module Network.Wai.Handler.Warp.Counter (
    Counter
  , newCounter
  , waitForZero
  , increase
  , decrease
  ) where

import Control.Concurrent.STM

import Network.Wai.Handler.Warp.Imports


newtype Counter = Counter (TVar Int)

newCounter :: IO Counter
newCounter :: IO Counter
newCounter = TVar Int -> Counter
Counter forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. a -> IO (TVar a)
newTVarIO Int
0

waitForZero :: Counter -> IO ()
waitForZero :: Counter -> IO ()
waitForZero (Counter TVar Int
ref) = forall a. STM a -> IO a
atomically forall a b. (a -> b) -> a -> b
$ do
    Int
x <- forall a. TVar a -> STM a
readTVar TVar Int
ref
    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (Int
x forall a. Eq a => a -> a -> Bool
== Int
0) forall a. STM a
retry

increase :: Counter -> IO ()
increase :: Counter -> IO ()
increase (Counter TVar Int
ref) = forall a. STM a -> IO a
atomically forall a b. (a -> b) -> a -> b
$ forall a. TVar a -> (a -> a) -> STM ()
modifyTVar' TVar Int
ref forall a b. (a -> b) -> a -> b
$ \Int
x -> Int
x forall a. Num a => a -> a -> a
+ Int
1

decrease :: Counter -> IO ()
decrease :: Counter -> IO ()
decrease (Counter TVar Int
ref) = forall a. STM a -> IO a
atomically forall a b. (a -> b) -> a -> b
$ forall a. TVar a -> (a -> a) -> STM ()
modifyTVar' TVar Int
ref forall a b. (a -> b) -> a -> b
$ \Int
x -> Int
x forall a. Num a => a -> a -> a
- Int
1