From 73e448b1e892ea9f969b7040e2be7d7d1e267871 Mon Sep 17 00:00:00 2001 From: Jens Nolte <git@queezle.net> Date: Sun, 25 Jul 2021 19:24:43 +0200 Subject: [PATCH] Move AsyncVar to Quasar.Awaitable and remove some helper functions --- src/Quasar/Awaitable.hs | 57 +++++++++++++++++++++++++++++++++++++++- src/Quasar/Core.hs | 51 ----------------------------------- test/Quasar/AsyncSpec.hs | 12 ++++----- 3 files changed, 62 insertions(+), 58 deletions(-) diff --git a/src/Quasar/Awaitable.hs b/src/Quasar/Awaitable.hs index 6933fb8..0f8d311 100644 --- a/src/Quasar/Awaitable.hs +++ b/src/Quasar/Awaitable.hs @@ -1,4 +1,5 @@ module Quasar.Awaitable ( + -- * Awaitable IsAwaitable(..), awaitSTM, Awaitable, @@ -7,8 +8,20 @@ module Quasar.Awaitable ( completedAwaitable, awaitableFromSTM, peekAwaitable, -) where + -- * AsyncVar + AsyncVar, + newAsyncVar, + newAsyncVarSTM, + putAsyncVarEither, + putAsyncVarEitherSTM, + putAsyncVar, + putAsyncVar_, + failAsyncVar, + failAsyncVar_, + putAsyncVarEither_, + putAsyncVarEitherSTM_, +) where import Control.Concurrent.STM import Control.Monad.Catch @@ -65,3 +78,45 @@ awaitableFromSTM fn = do pure value Right value -> pure value + + +-- ** AsyncVar + +-- | The default implementation for an `Awaitable` that can be fulfilled later. +newtype AsyncVar r = AsyncVar (TMVar (Either SomeException r)) + +instance IsAwaitable r (AsyncVar r) where + peekSTM (AsyncVar var) = tryReadTMVar var + + +newAsyncVarSTM :: STM (AsyncVar r) +newAsyncVarSTM = AsyncVar <$> newEmptyTMVar + +newAsyncVar :: MonadIO m => m (AsyncVar r) +newAsyncVar = liftIO $ AsyncVar <$> newEmptyTMVarIO + + +putAsyncVarEither :: forall a m. MonadIO m => AsyncVar a -> Either SomeException a -> m Bool +putAsyncVarEither var = liftIO . atomically . putAsyncVarEitherSTM var + +putAsyncVarEitherSTM :: AsyncVar a -> Either SomeException a -> STM Bool +putAsyncVarEitherSTM (AsyncVar var) = tryPutTMVar var + + +putAsyncVar :: MonadIO m => AsyncVar a -> a -> m Bool +putAsyncVar var = putAsyncVarEither var . Right + +putAsyncVar_ :: MonadIO m => AsyncVar a -> a -> m () +putAsyncVar_ var = void . putAsyncVar var + +failAsyncVar :: MonadIO m => AsyncVar a -> SomeException -> m Bool +failAsyncVar var = putAsyncVarEither var . Left + +failAsyncVar_ :: MonadIO m => AsyncVar a -> SomeException -> m () +failAsyncVar_ var = void . failAsyncVar var + +putAsyncVarEither_ :: MonadIO m => AsyncVar a -> Either SomeException a -> m () +putAsyncVarEither_ var = void . putAsyncVarEither var + +putAsyncVarEitherSTM_ :: AsyncVar a -> Either SomeException a -> STM () +putAsyncVarEitherSTM_ var = void . putAsyncVarEitherSTM var diff --git a/src/Quasar/Core.hs b/src/Quasar/Core.hs index 863b7e8..b5e56e4 100644 --- a/src/Quasar/Core.hs +++ b/src/Quasar/Core.hs @@ -6,11 +6,6 @@ module Quasar.Core ( runAsyncIO, awaitResult, - -- * AsyncVar - AsyncVar, - newAsyncVar, - putAsyncVar, - -- * Cancellation withCancellationToken, ) where @@ -136,52 +131,6 @@ awaitResult = (await =<<) -- asyncThread :: m r -> AsyncIO r --- * Async helpers - --- ** AsyncVar - --- | The default implementation for an `Awaitable` that can be fulfilled later. -newtype AsyncVar r = AsyncVar (TMVar (Either SomeException r)) - -instance IsAwaitable r (AsyncVar r) where - peekSTM (AsyncVar var) = tryReadTMVar var - -tryPutAsyncVarEitherSTM :: AsyncVar a -> Either SomeException a -> STM Bool -tryPutAsyncVarEitherSTM (AsyncVar var) = tryPutTMVar var - -tryPutAsyncVarEither :: forall a m. MonadIO m => AsyncVar a -> Either SomeException a -> m Bool -tryPutAsyncVarEither var = liftIO . atomically . tryPutAsyncVarEitherSTM var - - -newAsyncVarSTM :: STM (AsyncVar r) -newAsyncVarSTM = AsyncVar <$> newEmptyTMVar - -newAsyncVar :: MonadIO m => m (AsyncVar r) -newAsyncVar = liftIO $ AsyncVar <$> newEmptyTMVarIO - - -putAsyncVar :: MonadIO m => AsyncVar a -> a -> m () -putAsyncVar var = putAsyncVarEither var . Right - -tryPutAsyncVar :: MonadIO m => AsyncVar a -> a -> m Bool -tryPutAsyncVar var = tryPutAsyncVarEither var . Right - -tryPutAsyncVar_ :: MonadIO m => AsyncVar a -> a -> m () -tryPutAsyncVar_ var = void . tryPutAsyncVar var - -failAsyncVar :: MonadIO m => AsyncVar a -> SomeException -> m Bool -failAsyncVar var = tryPutAsyncVarEither var . Left - -failAsyncVar_ :: MonadIO m => AsyncVar a -> SomeException -> m () -failAsyncVar_ var = void . failAsyncVar var - -putAsyncVarEither :: MonadIO m => AsyncVar a -> Either SomeException a -> m () -putAsyncVarEither avar value = liftIO $ do - success <- tryPutAsyncVarEither avar value - unless success $ fail "An AsyncVar can only be fulfilled once" - -tryPutAsyncVarEither_ :: MonadIO m => AsyncVar a -> Either SomeException a -> m () -tryPutAsyncVarEither_ var = void . tryPutAsyncVarEither var -- * Awaiting multiple asyncs diff --git a/test/Quasar/AsyncSpec.hs b/test/Quasar/AsyncSpec.hs index 868a9fa..c1a00cc 100644 --- a/test/Quasar/AsyncSpec.hs +++ b/test/Quasar/AsyncSpec.hs @@ -2,7 +2,7 @@ module Quasar.AsyncSpec (spec) where import Control.Concurrent import Control.Concurrent.STM -import Control.Monad (void, (<=<)) +import Control.Monad (void) import Control.Monad.IO.Class import Prelude import Test.Hspec @@ -22,7 +22,7 @@ spec = parallel $ do it "accepts a value" $ do avar <- newAsyncVar :: IO (AsyncVar ()) - putAsyncVar avar () + putAsyncVar_ avar () describe "AsyncIO" $ do it "binds pure operations" $ do @@ -40,26 +40,26 @@ spec = parallel $ do it "can fmap the result of an already finished async" $ do avar <- newAsyncVar :: IO (AsyncVar ()) - putAsyncVar avar () + putAsyncVar_ avar () runAsyncIO (id <$> await avar) it "can fmap the result of an async that is completed later" $ do avar <- newAsyncVar :: IO (AsyncVar ()) void $ forkIO $ do threadDelay 100000 - putAsyncVar avar () + putAsyncVar_ avar () runAsyncIO (id <$> await avar) it "can bind the result of an already finished async" $ do avar <- newAsyncVar :: IO (AsyncVar ()) - putAsyncVar avar () + putAsyncVar_ avar () runAsyncIO (await avar >>= pure) it "can bind the result of an async that is completed later" $ do avar <- newAsyncVar :: IO (AsyncVar ()) void $ forkIO $ do threadDelay 100000 - putAsyncVar avar () + putAsyncVar_ avar () runAsyncIO (await avar >>= pure) it "can terminate when encountering an asynchronous exception" $ do -- GitLab