Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a utility for creating events based on STM actions #440

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions src/Reflex/TriggerEvent/Class.hs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@
-- new 'Event's that can be triggered from 'IO'.
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE UndecidableInstances #-}
module Reflex.TriggerEvent.Class
( TriggerEvent (..)
, newEventWithLazySTMTrigger
) where

import Reflex.Class

import Control.Applicative
import Control.Concurrent
import Control.Concurrent.STM
import Control.Monad.Reader
import Control.Monad.State
import qualified Control.Monad.State.Strict as Strict
Expand Down Expand Up @@ -53,3 +58,34 @@
newTriggerEvent = lift newTriggerEvent
newTriggerEventWithOnComplete = lift newTriggerEventWithOnComplete
newEventWithLazyTriggerWithOnComplete = lift . newEventWithLazyTriggerWithOnComplete

-- | Create an 'Event' which triggers each time a blocking 'STM' action
-- completes. This can be used to listen on a broadcast 'TChan' without leaking
-- memory by duplicating it only when the event is being listened to. Note that
-- the setup/teardown may happen multiple times, and there is no guarantee that
-- the teardown will be executed promptly, or even at all, in the case of
-- program termination.
newEventWithLazySTMTrigger
:: TriggerEvent t m
=> STM s
-- ^ Setup action returning state token, e.g. @/dupTChan eventBroadcastChan/@
-> (s -> STM ())
-- ^ Teardown action
-> (s -> STM a)
-- ^ Action to block on retrieving the next event value, e.g. 'readTChan'
-> m (Event t a)
newEventWithLazySTMTrigger setup teardown getNextValue =
newEventWithLazyTriggerWithOnComplete $ \fire -> do
doneVar <- newEmptyTMVarIO
stateToken <- atomically setup
let waitDone = Nothing <$ readTMVar doneVar
waitNext = Just <$> getNextValue stateToken
loop = atomically (waitDone <|> waitNext) >>= \case
Nothing -> return ()
Just a -> do
fire a $ return ()
loop
void $ forkIO loop

Check failure on line 88 in src/Reflex/TriggerEvent/Class.hs

View workflow job for this annotation

GitHub Actions / GHC 9.10.1 on ubuntu-latest

Variable not in scope: void :: IO ThreadId -> IO a0
return $ atomically $ do
putTMVar doneVar ()
teardown stateToken
Loading