{-# LANGUAGE BangPatterns #-}
-- | This module defines a type for mutable, integer-valued gauges.
-- Gauges are variable values and can be used to track e.g. the
-- current number of concurrent connections. All operations on gauges
-- are thread-safe.
module System.Remote.Gauge
    (
      Gauge
    , inc
    , dec
    , add
    , subtract
    , set
    , modify
    ) where

import Data.IORef (atomicModifyIORef)
import Prelude hiding (subtract)

import System.Remote.Gauge.Internal

-- | Increase the gauge by one.
inc :: Gauge -> IO ()
inc (C ref) = do
    !_ <- atomicModifyIORef ref $ \ n -> let n' = n + 1 in (n', n')
    return ()

-- | Decrease the gauge by one.
dec :: Gauge -> IO ()
dec (C ref) = do
    !_ <- atomicModifyIORef ref $ \ n -> let n' = n - 1 in (n', n')
    return ()

-- | Increase the gauge by the given amount.
add :: Gauge -> Int -> IO ()
add (C ref) i = do
    !_ <- atomicModifyIORef ref $ \ n -> let n' = n + i in (n', n')
    return ()

-- | Decrease the gauge by the given amount.
subtract :: Gauge -> Int -> IO ()
subtract (C ref) i = do
    !_ <- atomicModifyIORef ref $ \ n -> let n' = n - i in (n', n')
    return ()

-- | Set the gauge to the given value.
set :: Gauge -> Int -> IO ()
set (C ref) !i = atomicModifyIORef ref $ \ _ -> (i, ())

-- | Set the gauge to the result of applying the given function to the
-- value.
modify :: (Int -> Int) -> Gauge -> IO ()
modify f (C ref) = do
    !_ <- atomicModifyIORef ref $ \ i -> let i' = f i in (i', i')
    return ()