    {-# 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 ()