{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE RankNTypes #-}
module Control.Concurrent.Companion
( withCompanion
, onCompanionDone
, Companion
, Delay
, StopCompanion
) where
import RIO
type Companion m = Delay -> m ()
type Delay = forall mio. MonadIO mio => Int -> mio ()
type StopCompanion m = m ()
onCompanionDone
:: MonadUnliftIO m
=> m ()
-> m ()
-> m ()
onCompanionDone :: forall (m :: * -> *). MonadUnliftIO m => m () -> m () -> m ()
onCompanionDone m ()
theDelay m ()
theAction =
m ()
theDelay forall (m :: * -> *) e a b.
(MonadUnliftIO m, Exception e) =>
m a -> (e -> m b) -> m a
`withException` \CompanionDone
CompanionDone -> m ()
theAction
data CompanionDone = CompanionDone
deriving (Int -> CompanionDone -> ShowS
[CompanionDone] -> ShowS
CompanionDone -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [CompanionDone] -> ShowS
$cshowList :: [CompanionDone] -> ShowS
show :: CompanionDone -> String
$cshow :: CompanionDone -> String
showsPrec :: Int -> CompanionDone -> ShowS
$cshowsPrec :: Int -> CompanionDone -> ShowS
Show, Typeable)
instance Exception CompanionDone
withCompanion ::
forall m a. MonadUnliftIO m
=> Companion m
-> (StopCompanion m -> m a)
-> m a
withCompanion :: forall (m :: * -> *) a.
MonadUnliftIO m =>
Companion m -> (StopCompanion m -> m a) -> m a
withCompanion Companion m
companion StopCompanion m -> m a
inner = do
TVar Bool
shouldStopVar <- forall (m :: * -> *) a. MonadIO m => a -> m (TVar a)
newTVarIO Bool
False
let
stopCompanion :: StopCompanion m
stopCompanion = forall (m :: * -> *) a. MonadIO m => STM a -> m a
atomically forall a b. (a -> b) -> a -> b
$ forall a. TVar a -> a -> STM ()
writeTVar TVar Bool
shouldStopVar Bool
True
delay :: Delay
delay :: Delay
delay Int
usec = do
TVar Bool
delayDoneVar <- forall (m :: * -> *). MonadIO m => Int -> m (TVar Bool)
registerDelay Int
usec
forall (m :: * -> *) a. Monad m => m (m a) -> m a
join forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. MonadIO m => STM a -> m a
atomically forall a b. (a -> b) -> a -> b
$
(forall (f :: * -> *) a. Applicative f => a -> f a
pure () forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ (forall a. TVar a -> STM a
readTVar TVar Bool
delayDoneVar forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Bool -> STM ()
checkSTM)) forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|>
(forall (m :: * -> *) e a. (MonadIO m, Exception e) => e -> m a
throwIO CompanionDone
CompanionDone forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ (forall a. TVar a -> STM a
readTVar TVar Bool
shouldStopVar forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Bool -> STM ()
checkSTM))
forall (m :: * -> *) a. Concurrently m a -> m a
runConcurrently forall a b. (a -> b) -> a -> b
$
forall (m :: * -> *) a. m a -> Concurrently m a
Concurrently (Companion m
companion Delay
delay forall (m :: * -> *) e a.
(MonadUnliftIO m, Exception e) =>
m a -> (e -> m a) -> m a
`catch` \CompanionDone
CompanionDone -> forall (f :: * -> *) a. Applicative f => a -> f a
pure ()) forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*>
forall (m :: * -> *) a. m a -> Concurrently m a
Concurrently (StopCompanion m -> m a
inner StopCompanion m
stopCompanion forall (m :: * -> *) a b. MonadUnliftIO m => m a -> m b -> m a
`finally` StopCompanion m
stopCompanion)