module Control.Concurrent.Availability
    ( Availability
    , newToken
    , starting
    , available
    ) where

import Control.Concurrent (MVar, newEmptyMVar, putMVar, takeMVar)
import Control.Monad.IO.Class (MonadIO, liftIO)

-- | A semaphore-like construct whereby a service can signal to
-- another thread that it's finished its startup phase, and is now
-- available to use.
newtype Availability =
    Availability (MVar ())

newToken :: MonadIO m => m Availability
newToken :: m Availability
newToken = MVar () -> Availability
Availability (MVar () -> Availability) -> m (MVar ()) -> m Availability
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO (MVar ()) -> m (MVar ())
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO (MVar ())
forall a. IO (MVar a)
newEmptyMVar

starting :: MonadIO m => Availability -> m ()
starting :: Availability -> m ()
starting (Availability MVar ()
mvar) = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> IO () -> m ()
forall a b. (a -> b) -> a -> b
$ MVar () -> IO ()
forall a. MVar a -> IO a
takeMVar MVar ()
mvar

available :: MonadIO m => Availability -> m ()
available :: Availability -> m ()
available (Availability MVar ()
mvar) = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> IO () -> m ()
forall a b. (a -> b) -> a -> b
$ MVar () -> () -> IO ()
forall a. MVar a -> a -> IO ()
putMVar MVar ()
mvar ()