diff --git a/src/Quasar/Async.hs b/src/Quasar/Async.hs index e0fd507ed9297db939fe438fd1568ec7500e9092..8afbf94a2639ea2b6d9109059b8329341da22ab1 100644 --- a/src/Quasar/Async.hs +++ b/src/Quasar/Async.hs @@ -5,19 +5,6 @@ module Quasar.Async ( async_, asyncWithUnmask_, - -- * Task - Task, - cancelTask, - cancelTaskIO, - toTask, - completedTask, - successfulTask, - failedTask, - - -- ** Task exceptions - CancelTask(..), - TaskDisposed(..), - -- * Unmanaged forking forkTask, forkTask_, @@ -155,52 +142,3 @@ forkTaskWithUnmask_ action = toDisposable <$> forkTaskWithUnmask action --- | A task that is running asynchronously. It has a result and can fail. --- The result (or exception) can be aquired by using the `IsAwaitable` class (e.g. by calling `await` or `awaitIO`). --- It might be possible to cancel the task by using the `IsDisposable` class if the operation has not been completed. --- If the result is no longer required the task should be cancelled, to avoid leaking memory. -data Task r = Task Disposable (Awaitable r) - -instance IsAwaitable r (Task r) where - toAwaitable (Task _ awaitable) = awaitable - -instance IsDisposable (Task r) where - toDisposable (Task disposable _) = disposable - -instance Functor Task where - fmap fn (Task disposable awaitable) = Task disposable (fn <$> awaitable) - -instance Applicative Task where - pure value = Task noDisposable (pure value) - liftA2 fn (Task dx fx) (Task dy fy) = Task (dx <> dy) $ liftA2 fn fx fy - -cancelTask :: Task r -> IO (Awaitable ()) -cancelTask = dispose - -cancelTaskIO :: Task r -> IO () -cancelTaskIO = await <=< dispose - --- | Creates an `Task` from an `Awaitable`. --- The resulting task only depends on an external resource, so disposing it has no effect. -toTask :: IsAwaitable r a => a -> Task r -toTask result = Task noDisposable (toAwaitable result) - -completedTask :: Either SomeException r -> Task r -completedTask result = Task noDisposable (completedAwaitable result) - --- | Alias for `pure` -successfulTask :: r -> Task r -successfulTask = pure - -failedTask :: SomeException -> Task r -failedTask ex = Task noDisposable (failedAwaitable ex) - - - -data CancelTask = CancelTask - deriving stock Show -instance Exception CancelTask where - -data TaskDisposed = TaskDisposed - deriving stock Show -instance Exception TaskDisposed where diff --git a/src/Quasar/Disposable.hs b/src/Quasar/Disposable.hs index 3e805859621bb894be9e7577d29780a7ab04deac..a4ee3c2c812628fe43f6d5f16f6204b9d697409a 100644 --- a/src/Quasar/Disposable.hs +++ b/src/Quasar/Disposable.hs @@ -21,6 +21,19 @@ module Quasar.Disposable ( attachDisposeAction, attachDisposeAction_, disposeEventually, + + -- * Task + Task(..), + cancelTask, + toTask, + completedTask, + successfulTask, + failedTask, + + -- ** Task exceptions + CancelTask(..), + TaskDisposed(..), + ) where import Control.Concurrent (forkIOWithUnmask) @@ -402,3 +415,57 @@ disposeEventually resourceManager disposable = liftIO $ do peekAwaitable disposeCompleted >>= \case Just () -> pure () Nothing -> attachDisposable resourceManager disposable + + + + + + +-- | A task is an operation (e.g. a thread or a network request) that is running asynchronously and can be cancelled. +-- It has a result and can fail. +-- +-- The result (or exception) can be aquired by using the `IsAwaitable` class (e.g. by calling `await` or `awaitIO`). +-- It is possible to cancel the task by using `dispose` or `cancelTask` if the operation has not been completed. +data Task r = Task Disposable (Awaitable r) + +instance IsAwaitable r (Task r) where + toAwaitable (Task _ awaitable) = awaitable + +instance IsDisposable (Task r) where + toDisposable (Task disposable _) = disposable + +instance Functor Task where + fmap fn (Task disposable awaitable) = Task disposable (fn <$> awaitable) + +instance Applicative Task where + pure value = Task noDisposable (pure value) + liftA2 fn (Task dx fx) (Task dy fy) = Task (dx <> dy) $ liftA2 fn fx fy + +-- | Alias for `dispose`. +cancelTask :: Task r -> IO (Awaitable ()) +cancelTask = dispose + +-- | Creates an `Task` from an `Awaitable`. +-- The resulting task only depends on an external resource, so disposing it has no effect. +toTask :: IsAwaitable r a => a -> Task r +toTask result = Task noDisposable (toAwaitable result) + +completedTask :: Either SomeException r -> Task r +completedTask result = Task noDisposable (completedAwaitable result) + +-- | Alias for `pure` +successfulTask :: r -> Task r +successfulTask = pure + +failedTask :: SomeException -> Task r +failedTask ex = Task noDisposable (failedAwaitable ex) + + + +data CancelTask = CancelTask + deriving stock Show +instance Exception CancelTask where + +data TaskDisposed = TaskDisposed + deriving stock Show +instance Exception TaskDisposed where