packages feed

chan 0.0.3 → 0.0.4

raw patch · 8 files changed

+263/−483 lines, 8 filesdep ~basePVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: base

API changes (from Hackage documentation)

- Control.Concurrent.Chan.Typed: allowReading :: Writable scope => ChanRW scope a -> ChanRW 'ReadWrite a
- Control.Concurrent.Chan.Typed: allowWriting :: Readable scope => ChanRW scope a -> ChanRW 'ReadWrite a
- Control.Concurrent.Chan.Typed: readOnly :: Readable scope => ChanRW scope a -> ChanRW 'Read a
- Control.Concurrent.Chan.Typed: writeOnly :: Writable scope => ChanRW scope a -> ChanRW 'Write a
- Control.Concurrent.Chan.Typed.Extra: debounceStatic :: DiffNanosec -> ChanRW 'Read a -> IO (ChanRW 'Write a, Async ())
- Control.Concurrent.Chan.Typed.Extra: intersperseStatic :: DiffNanosec -> IO a -> ChanRW 'Read a -> IO (ChanRW 'Write a, Async (), Async ())
- Control.Concurrent.Chan.Typed.Extra: throttleStatic :: DiffNanosec -> ChanRW 'Read a -> IO (ChanRW 'Write a, Async ())
- Control.Concurrent.Chan.Typed.Extra: type DiffNanosec = Int
- Control.Concurrent.STM.TChan.Extra: debounceStatic :: DiffNanosec -> TChan a -> IO (TChan a, Async ())
- Control.Concurrent.STM.TChan.Extra: intersperseStatic :: DiffNanosec -> IO a -> TChan a -> IO (TChan a, Async (), Async ())
- Control.Concurrent.STM.TChan.Extra: throttleStatic :: DiffNanosec -> TChan a -> IO (TChan a, Async ())
- Control.Concurrent.STM.TChan.Extra: type DiffNanosec = Int
- Control.Concurrent.STM.TChan.Typed: allowReading :: Writable scope => TChanRW scope a -> TChanRW 'ReadWrite a
- Control.Concurrent.STM.TChan.Typed: allowWriting :: Readable scope => TChanRW scope a -> TChanRW 'ReadWrite a
- Control.Concurrent.STM.TChan.Typed: readOnly :: Readable scope => TChanRW scope a -> TChanRW 'Read a
- Control.Concurrent.STM.TChan.Typed: writeOnly :: Writable scope => TChanRW scope a -> TChanRW 'Write a
- Control.Concurrent.STM.TChan.Typed.Extra: debounceStatic :: DiffNanosec -> TChanRW 'Read a -> IO (TChanRW 'Write a, Async ())
- Control.Concurrent.STM.TChan.Typed.Extra: intersperseStatic :: DiffNanosec -> IO a -> TChanRW 'Read a -> IO (TChanRW 'Write a, Async (), Async ())
- Control.Concurrent.STM.TChan.Typed.Extra: throttleStatic :: DiffNanosec -> TChanRW 'Read a -> IO (TChanRW 'Write a, Async ())
- Control.Concurrent.STM.TChan.Typed.Extra: type DiffNanosec = Int
+ Control.Concurrent.Chan.Extra: allowReading :: (ChanScoped c, Writable scope) => c scope a -> c 'ReadWrite a
+ Control.Concurrent.Chan.Extra: allowWriting :: (ChanScoped c, Readable scope) => c scope a -> c 'ReadWrite a
+ Control.Concurrent.Chan.Extra: class ChanExtra (inputC :: * -> *) (outputC :: * -> *) | inputC -> outputC, outputC -> inputC
+ Control.Concurrent.Chan.Extra: class ChanScoped (c :: Scope -> * -> *)
+ Control.Concurrent.Chan.Extra: instance Control.Concurrent.Chan.Extra.ChanExtra (Control.Concurrent.Chan.Typed.ChanRW 'Control.Concurrent.Chan.Scope.Write) (Control.Concurrent.Chan.Typed.ChanRW 'Control.Concurrent.Chan.Scope.Read)
+ Control.Concurrent.Chan.Extra: instance Control.Concurrent.Chan.Extra.ChanExtra (Control.Concurrent.STM.TChan.Typed.TChanRW 'Control.Concurrent.Chan.Scope.Write) (Control.Concurrent.STM.TChan.Typed.TChanRW 'Control.Concurrent.Chan.Scope.Read)
+ Control.Concurrent.Chan.Extra: instance Control.Concurrent.Chan.Extra.ChanExtra Control.Concurrent.Chan.Chan Control.Concurrent.Chan.Chan
+ Control.Concurrent.Chan.Extra: instance Control.Concurrent.Chan.Extra.ChanExtra Control.Concurrent.STM.TChan.TChan Control.Concurrent.STM.TChan.TChan
+ Control.Concurrent.Chan.Extra: instance Control.Concurrent.Chan.Extra.ChanScoped Control.Concurrent.Chan.Typed.ChanRW
+ Control.Concurrent.Chan.Extra: instance Control.Concurrent.Chan.Extra.ChanScoped Control.Concurrent.STM.TChan.Typed.TChanRW
+ Control.Concurrent.Chan.Extra: readOnly :: (ChanScoped c, Readable scope) => c scope a -> c 'Read a
+ Control.Concurrent.Chan.Extra: writeOnly :: (ChanScoped c, Writable scope) => c scope a -> c 'Write a
- Control.Concurrent.Chan.Extra: debounceStatic :: DiffNanosec -> Chan a -> IO (Chan a, Async ())
+ Control.Concurrent.Chan.Extra: debounceStatic :: ChanExtra inputC outputC => DiffNanosec -> outputC a -> IO (inputC a, Async ())
- Control.Concurrent.Chan.Extra: intersperseStatic :: DiffNanosec -> IO a -> Chan a -> IO (Chan a, Async (), Async ())
+ Control.Concurrent.Chan.Extra: intersperseStatic :: ChanExtra inputC outputC => DiffNanosec -> IO a -> outputC a -> IO (inputC a, Async (), Async ())
- Control.Concurrent.Chan.Extra: throttleStatic :: DiffNanosec -> Chan a -> IO (Chan a, Async ())
+ Control.Concurrent.Chan.Extra: throttleStatic :: ChanExtra inputC outputC => DiffNanosec -> outputC a -> IO (inputC a, Async ())
- Control.Concurrent.Chan.Typed: ChanRW :: (Chan a) -> ChanRW a
+ Control.Concurrent.Chan.Typed: ChanRW :: Chan a -> ChanRW a
- Control.Concurrent.STM.TChan.Typed: TChanRW :: (TChan a) -> TChanRW a
+ Control.Concurrent.STM.TChan.Typed: TChanRW :: TChan a -> TChanRW a

Files

chan.cabal view
@@ -1,44 +1,59 @@-name:                chan-version:             0.0.3-synopsis:            Some extra kit for Chans--- description:-homepage:            https://github.com/athanclark/chan#readme-license:             BSD3-license-file:        LICENSE-author:              Athan Clark-maintainer:          athan.clark@gmail.com-copyright:           2017 Athan Clark-category:            Web-build-type:          Simple-extra-source-files:  README.md-cabal-version:       >=1.10+cabal-version: 1.12 -library-  hs-source-dirs:      src-  exposed-modules:     Control.Concurrent.Chan.Extra-                       Control.Concurrent.Chan.Scope-                       Control.Concurrent.Chan.Typed-                       Control.Concurrent.Chan.Typed.Extra-                       Control.Concurrent.STM.TChan.Extra-                       Control.Concurrent.STM.TChan.Typed-                       Control.Concurrent.STM.TChan.Typed.Extra-  build-depends:       base >= 4.7 && < 5-                     , async-                     , stm-                     -- , since-  default-language:    Haskell2010+-- This file has been generated from package.yaml by hpack version 0.31.0.+--+-- see: https://github.com/sol/hpack+--+-- hash: 9429247fea789bb683e6f4ed7fb173854b095d3e98824b896891eb68655e73a8 -test-suite chan-test-  type:                exitcode-stdio-1.0-  hs-source-dirs:      test-  main-is:             Spec.hs-  build-depends:       base-                     , chan-                     , async-                     , stm-  ghc-options:         -threaded -rtsopts -with-rtsopts=-N-  default-language:    Haskell2010+name:           chan+version:        0.0.4+synopsis:       Some extra kit for Chans+description:    Please see the README on Github at <https://github.com/athanclark/chan#readme>+category:       Concurrency+homepage:       https://github.com/athanclark/chan#readme+bug-reports:    https://github.com/athanclark/chan/issues+author:         Athan Clark+maintainer:     athan.clark@localcooking.com+copyright:      2018 Athan Clark+license:        BSD3+license-file:   LICENSE+build-type:     Simple+extra-source-files:+    README.md  source-repository head-  type:     git+  type: git   location: https://github.com/athanclark/chan++library+  exposed-modules:+      Control.Concurrent.Chan.Extra+      Control.Concurrent.Chan.Scope+      Control.Concurrent.Chan.Typed+      Control.Concurrent.STM.TChan.Typed+  other-modules:+      Paths_chan+  hs-source-dirs:+      src+  ghc-options: -Wall+  build-depends:+      async+    , base >=4.11 && <5.0+    , stm+  default-language: Haskell2010++test-suite chan-test+  type: exitcode-stdio-1.0+  main-is: Spec.hs+  other-modules:+      Paths_chan+  hs-source-dirs:+      test+  ghc-options: -Wall -threaded -rtsopts -Wall -with-rtsopts=-N+  build-depends:+      async+    , base+    , chan+    , stm+  default-language: Haskell2010
src/Control/Concurrent/Chan/Extra.hs view
@@ -1,20 +1,225 @@+{-# LANGUAGE+    DataKinds+  , KindSignatures+  , MultiParamTypeClasses+  , FunctionalDependencies+  , FlexibleInstances+  , ScopedTypeVariables+  , PartialTypeSignatures+  #-}+ module Control.Concurrent.Chan.Extra where +import Control.Concurrent.Chan.Typed+  ( ChanRW (..), writeChanRW, readChanRW, newChanRW)+import Control.Concurrent.STM.TChan.Typed+  ( TChanRW (..), writeTChanRW, readTChanRW, newTChanRW)+import Control.Concurrent.Chan.Scope (Scope (..), Writable, Readable)+ import Data.IORef (newIORef, readIORef, writeIORef)--- import Data.Time.Since (timeSince, newTimeSince) import Control.Monad (forever) import Control.Concurrent (threadDelay) import Control.Concurrent.MVar (newEmptyMVar, tryTakeMVar, putMVar) import Control.Concurrent.Chan (Chan, readChan, writeChan, newChan) import Control.Concurrent.Async (Async, async, cancel, wait)+import Control.Concurrent.STM+  (atomically, tryTakeTMVar, putTMVar, newEmptyTMVarIO)+import Control.Concurrent.STM.TChan (TChan)  +-- | Class for changing the access of a typed channel+class ChanScoped (c :: Scope -> * -> *) where+  readOnly :: Readable scope => c scope a -> c 'Read a+  writeOnly :: Writable scope => c scope a -> c 'Write a+  allowReading :: Writable scope => c scope a -> c 'ReadWrite a+  allowWriting :: Readable scope => c scope a -> c 'ReadWrite a + type DiffNanosec = Int --- type TotalNanosec = Int +-- | Class for extra channel techniques+class ChanExtra (inputC :: * -> *) (outputC :: * -> *)+      | inputC -> outputC, outputC -> inputC where+  -- | Throw away messages that meet the threshold+  debounceStatic :: DiffNanosec -- ^ Time to wait before attempting to send the message+                 -> outputC a -> IO (inputC a, Async ())+  -- | Refrain from relaying messages that meet the threshold+  throttleStatic :: DiffNanosec -- ^ Time to wait before sending the message, for every message+                 -> outputC a -> IO (inputC a, Async ())+  -- | Intercalate messages while threshold is met+  intersperseStatic :: DiffNanosec -- ^ Time to at-least wait to intersperse messages+                    -> IO a -- ^ Get a message to intersperse+                    -> outputC a+                    -> IO (inputC a, Async (), Async ()) ++instance ChanExtra Chan Chan where+  debounceStatic toWaitFurther outputChan = do+    (ChanRW inputChan, t) <- debounceStatic toWaitFurther (ChanRW outputChan :: ChanRW 'Read _)+    pure (inputChan, t)+  throttleStatic toWaitFurther outputChan = do+    (ChanRW inputChan, t) <- throttleStatic toWaitFurther (ChanRW outputChan :: ChanRW 'Read _)+    pure (inputChan, t)+  intersperseStatic timeBetween xM outputChan = do+    (ChanRW inputChan, writer, listener) <- intersperseStatic timeBetween xM (ChanRW outputChan :: ChanRW 'Read _)+    pure (inputChan, writer, listener)+++instance ChanExtra TChan TChan where+  debounceStatic toWaitFurther outputTChan = do+    (TChanRW inputTChan, t) <- debounceStatic toWaitFurther (TChanRW outputTChan :: TChanRW 'Read _)+    pure (inputTChan, t)+  throttleStatic toWaitFurther outputTChan = do+    (TChanRW inputTChan, t) <- throttleStatic toWaitFurther (TChanRW outputTChan :: TChanRW 'Read _)+    pure (inputTChan, t)+  intersperseStatic timeBetween xM outputTChan = do+    (TChanRW inputTChan, writer, listener) <- intersperseStatic timeBetween xM (TChanRW outputTChan :: TChanRW 'Read _)+    pure (inputTChan, writer, listener)++++instance ChanScoped TChanRW where+  readOnly (TChanRW x) = TChanRW x+  writeOnly (TChanRW x) = TChanRW x+  allowReading (TChanRW x) = TChanRW x+  allowWriting (TChanRW x) = TChanRW x++instance ChanExtra (TChanRW 'Write) (TChanRW 'Read) where+  debounceStatic toWaitFurther outputChan = do+    presentedChan <- atomically newTChanRW+    writingThread <- newEmptyTMVarIO++    writer <- async $ forever $ do+      x <- atomically (readTChanRW presentedChan)+      newWriter <- async $ do+        threadDelay toWaitFurther+        atomically (writeTChanRW (allowWriting outputChan) x)+      mInvoker <- atomically (tryTakeTMVar writingThread)+      case mInvoker of+        Nothing -> pure ()+        Just i -> cancel i -- kill the old without writing to output+      atomically (putTMVar writingThread newWriter)++    pure (writeOnly presentedChan, writer)++  throttleStatic toWaitFurther outputChan = do+    presentedChan <- atomically newTChanRW+    writingThread <- newEmptyTMVarIO++    writer <- async $ forever $ do+      x <- atomically (readTChanRW presentedChan)+      mInvoker <- atomically (tryTakeTMVar writingThread)+      case mInvoker of+        Nothing -> pure ()+        Just i -> wait i -- cascade invocations, waiting until output writes+      newWriter <- async $ do+        threadDelay toWaitFurther+        atomically (writeTChanRW (allowWriting outputChan) x)+      atomically (putTMVar writingThread newWriter)++    pure (writeOnly presentedChan, writer)++  intersperseStatic timeBetween xM outputChan = do+    presentedChan <- atomically newTChanRW+    writingThread <- newEmptyTMVarIO++    writer <- async $ forever $ do+      mInvoker <- atomically (tryTakeTMVar writingThread)+      case mInvoker of+        Nothing -> pure () -- continue immediately if nothing's waiting+        Just i -> wait i -- block until previous ping is sent+      newWriter <- async $ do+        threadDelay timeBetween+        x <- xM -- get new ping message+        atomically (writeTChanRW (allowWriting outputChan) x) -- send it+      atomically (putTMVar writingThread newWriter) -- register pinger++    listener <- async $ forever $ do+      y <- atomically (readTChanRW presentedChan)+      mInvoker <- atomically (tryTakeTMVar writingThread)+      case mInvoker of+        Nothing -> pure ()+        Just i -> cancel i -- kill pinger++      atomically (writeTChanRW (allowWriting outputChan) y) -- immediately send regular message++    pure (writeOnly presentedChan, writer, listener)+++instance ChanScoped ChanRW where+  readOnly (ChanRW x) = ChanRW x+  writeOnly (ChanRW x) = ChanRW x+  allowReading (ChanRW x) = ChanRW x+  allowWriting (ChanRW x) = ChanRW x++instance ChanExtra (ChanRW 'Write) (ChanRW 'Read) where+  debounceStatic toWaitFurther outputChan = do+    presentedChan <- newChanRW+    writingThread <- newEmptyMVar++    writer <- async $ forever $ do+      x <- readChanRW presentedChan++      newWriter <- async $ do+        threadDelay toWaitFurther+        writeChanRW (allowWriting outputChan) x++      mInvoker <- tryTakeMVar writingThread+      case mInvoker of+        Nothing -> pure ()+        Just i -> cancel i+      putMVar writingThread newWriter++    pure (writeOnly presentedChan, writer)++  throttleStatic toWaitFurther outputChan = do+    presentedChan <- newChanRW+    writingThread <- newEmptyMVar++    writer <- async $ forever $ do+      x <- readChanRW presentedChan++      mInvoker <- tryTakeMVar writingThread+      case mInvoker of+        Nothing -> pure ()+        Just i -> wait i+      newWriter <- async $ do+        threadDelay toWaitFurther+        writeChanRW (allowWriting outputChan) x+      putMVar writingThread newWriter++    pure (writeOnly presentedChan, writer)++  intersperseStatic timeBetween xM outputChan = do+    presentedChan <- newChanRW+    writingThread <- newEmptyMVar++    writer <- async $ forever $ do+      mInvoker <- tryTakeMVar writingThread+      case mInvoker of+        Nothing -> pure ()+        Just i -> wait i+      newWriter <- async $ do+        threadDelay timeBetween+        x <- xM+        writeChanRW (allowWriting outputChan) x+      putMVar writingThread newWriter++    listener <- async $ forever $ do+      y <- readChanRW presentedChan++      mInvoker <- tryTakeMVar writingThread+      case mInvoker of+        Nothing -> pure ()+        Just i -> cancel i++      writeChanRW (allowWriting outputChan) y++    pure (writeOnly presentedChan, writer, listener)+++ -- debounceDynamic :: (NominalDiffTime -> NominalDiffTime) -> Chan a -> IO (Chan a, Async ()) -- debounceDynamic toWait outputChan = do --   sinceRef <- newTimeSince@@ -50,79 +255,3 @@ --     putMVar writingThread newWriter  --   pure (presentedChan, writer)--debounceStatic :: DiffNanosec -> Chan a -> IO (Chan a, Async ())-debounceStatic toWaitFurther outputChan = do-  presentedChan <- newChan-  writingThread <- newEmptyMVar--  let invokeWrite x = do-        threadDelay toWaitFurther-        writeChan outputChan x--  writer <- async $ forever $ do-    x <- readChan presentedChan--    newWriter <- async (invokeWrite x)--    mInvoker <- tryTakeMVar writingThread-    case mInvoker of-      Nothing -> pure ()-      Just i -> cancel i-    putMVar writingThread newWriter--  pure (presentedChan, writer)----- | Like debounce, but lossless-throttleStatic :: DiffNanosec -> Chan a -> IO (Chan a, Async ())-throttleStatic toWaitFurther outputChan = do-  presentedChan <- newChan-  writingThread <- newEmptyMVar--  let invokeWrite x = do-        threadDelay toWaitFurther-        writeChan outputChan x--  writer <- async $ forever $ do-    x <- readChan presentedChan--    mInvoker <- tryTakeMVar writingThread-    case mInvoker of-      Nothing -> pure ()-      Just i -> wait i-    newWriter <- async (invokeWrite x)-    putMVar writingThread newWriter--  pure (presentedChan, writer)---intersperseStatic :: DiffNanosec -> IO a -> Chan a -> IO (Chan a, Async (), Async ())-intersperseStatic timeBetween xM outputChan = do-  presentedChan <- newChan-  writingThread <- newEmptyMVar--  let invokeWritePing = do-        threadDelay timeBetween-        x <- xM-        writeChan outputChan x--  writer <- async $ forever $ do-    mInvoker <- tryTakeMVar writingThread-    case mInvoker of-      Nothing -> pure ()-      Just i -> wait i-    newWriter <- async invokeWritePing-    putMVar writingThread newWriter--  listener <- async $ forever $ do-    y <- readChan presentedChan--    mInvoker <- tryTakeMVar writingThread-    case mInvoker of-      Nothing -> pure ()-      Just i -> cancel i--    writeChan outputChan y--  pure (presentedChan, writer, listener)
src/Control/Concurrent/Chan/Scope.hs view
@@ -10,14 +10,10 @@   class Readable (a :: Scope) where- instance Readable 'Read where- instance Readable 'ReadWrite where   class Writable (a :: Scope) where- instance Writable 'Write where- instance Writable 'ReadWrite where
src/Control/Concurrent/Chan/Typed.hs view
@@ -6,24 +6,12 @@ module Control.Concurrent.Chan.Typed where  import Control.Concurrent.Chan.Scope (Scope (..), Writable, Readable)+ import Control.Concurrent.Chan (Chan) import qualified Control.Concurrent.Chan as Chan   newtype ChanRW (scope :: Scope) a = ChanRW (Chan a)---readOnly :: Readable scope => ChanRW scope a -> ChanRW 'Read a-readOnly (ChanRW c) = ChanRW c--writeOnly :: Writable scope => ChanRW scope a -> ChanRW 'Write a-writeOnly (ChanRW c) = ChanRW c--allowReading :: Writable scope => ChanRW scope a -> ChanRW 'ReadWrite a-allowReading (ChanRW c) = ChanRW c--allowWriting :: Readable scope => ChanRW scope a -> ChanRW 'ReadWrite a-allowWriting (ChanRW c) = ChanRW c   newChanRW :: IO (ChanRW 'ReadWrite a)
− src/Control/Concurrent/Chan/Typed/Extra.hs
@@ -1,133 +0,0 @@-{-# LANGUAGE-    DataKinds-  #-}--module Control.Concurrent.Chan.Typed.Extra where--import Data.IORef (newIORef, readIORef, writeIORef)--- import Data.Time.Since (timeSince, newTimeSince)-import Control.Monad (forever)-import Control.Concurrent (threadDelay)-import Control.Concurrent.MVar (newEmptyMVar, tryTakeMVar, putMVar)-import Control.Concurrent.Chan.Scope (Scope (..))-import Control.Concurrent.Chan.Typed (ChanRW, readChanRW, writeChanRW, newChanRW, writeOnly, allowWriting)-import Control.Concurrent.Async (Async, async, cancel, wait)----type DiffNanosec = Int---- type TotalNanosec = Int----- debounceDynamic :: (NominalDiffTime -> NominalDiffTime) -> Chan a -> IO (Chan a, Async ())--- debounceDynamic toWait outputChan = do---   sinceRef <- newTimeSince---   totalWaited <- newIORef 0---   presentedChan <- newChan---   writingThread <- newEmptyMVar----   let invokeWrite x = do---         putStrLn "Being run.."----         waited <- readIORef totalWaited---         let toWaitFurther = toWait waited---         writeIORef totalWaited (waited + toWaitFurther)----         -- FIXME must use clocktime http://hackage.haskell.org/package/chan- overlayed invocations have---         -- no concept of time spent, only have knoweldge of invocations---         -- made----         threadDelay toWaitFurther---         putStrLn "waited done"---         writeChan outputChan x----   writer <- async $ forever $ do---     x <- readChan presentedChan----     newWriter <- async (invokeWrite x)----     mInvoker <- tryTakeMVar writingThread---     case mInvoker of---       Nothing -> pure ()---       Just i -> cancel i---     print "killed"---     putMVar writingThread newWriter----   pure (presentedChan, writer)--debounceStatic :: DiffNanosec -> ChanRW 'Read a -> IO (ChanRW 'Write a, Async ())-debounceStatic toWaitFurther outputChan = do-  presentedChan <- newChanRW-  writingThread <- newEmptyMVar--  let invokeWrite x = do-        threadDelay toWaitFurther-        writeChanRW (allowWriting outputChan) x--  writer <- async $ forever $ do-    x <- readChanRW presentedChan--    newWriter <- async (invokeWrite x)--    mInvoker <- tryTakeMVar writingThread-    case mInvoker of-      Nothing -> pure ()-      Just i -> cancel i-    putMVar writingThread newWriter--  pure (writeOnly presentedChan, writer)----- | Like debounce, but lossless-throttleStatic :: DiffNanosec -> ChanRW 'Read a -> IO (ChanRW 'Write a, Async ())-throttleStatic toWaitFurther outputChan = do-  presentedChan <- newChanRW-  writingThread <- newEmptyMVar--  let invokeWrite x = do-        threadDelay toWaitFurther-        writeChanRW (allowWriting outputChan) x--  writer <- async $ forever $ do-    x <- readChanRW presentedChan--    mInvoker <- tryTakeMVar writingThread-    case mInvoker of-      Nothing -> pure ()-      Just i -> wait i-    newWriter <- async (invokeWrite x)-    putMVar writingThread newWriter--  pure (writeOnly presentedChan, writer)---intersperseStatic :: DiffNanosec -> IO a -> ChanRW 'Read a -> IO (ChanRW 'Write a, Async (), Async ())-intersperseStatic timeBetween xM outputChan = do-  presentedChan <- newChanRW-  writingThread <- newEmptyMVar--  let invokeWritePing = do-        threadDelay timeBetween-        x <- xM-        writeChanRW (allowWriting outputChan) x--  writer <- async $ forever $ do-    mInvoker <- tryTakeMVar writingThread-    case mInvoker of-      Nothing -> pure ()-      Just i -> wait i-    newWriter <- async invokeWritePing-    putMVar writingThread newWriter--  listener <- async $ forever $ do-    y <- readChanRW presentedChan--    mInvoker <- tryTakeMVar writingThread-    case mInvoker of-      Nothing -> pure ()-      Just i -> cancel i--    writeChanRW (allowWriting outputChan) y--  pure (writeOnly presentedChan, writer, listener)
− src/Control/Concurrent/STM/TChan/Extra.hs
@@ -1,99 +0,0 @@-module Control.Concurrent.STM.TChan.Extra where--import Control.Monad (forever)-import Control.Concurrent (threadDelay)-import Control.Concurrent.STM (STM, atomically)--- import Control.Concurrent.STM.TVar (newTVar, readIORef, writeIORef)-import Control.Concurrent.STM.TMVar (newEmptyTMVar, tryTakeTMVar, putTMVar)-import Control.Concurrent.STM.TChan (TChan, readTChan, writeTChan, newTChan)-import Control.Concurrent.Async (Async, async, cancel, wait)----type DiffNanosec = Int----- | Note: In this model, even though we are using STM, a write to the--- outgoing channel does not imply a transactional write to the output--- channel; they are separated between a run IO layer, which means--- we cannot atomically debounce or interleave the system (because--- that depends on real-world time).-debounceStatic :: DiffNanosec -> TChan a -> IO (TChan a, Async ())-debounceStatic toWaitFurther outputChan = do-  (presentedChan,writingThread) <- atomically $ (,)-                                             <$> newTChan-                                             <*> newEmptyTMVar--  let invokeWrite x = do-        threadDelay toWaitFurther-        atomically $ writeTChan outputChan x--  writer <- async $ forever $ do-    x <- atomically $ readTChan presentedChan--    newWriter <- async (invokeWrite x)--    mInvoker <- atomically $ tryTakeTMVar writingThread-    case mInvoker of-      Nothing -> pure ()-      Just i -> cancel i-    atomically $ putTMVar writingThread newWriter--  pure (presentedChan, writer)---throttleStatic :: DiffNanosec -> TChan a -> IO (TChan a, Async ())-throttleStatic toWaitFurther outputChan = do-  (presentedChan,writingThread) <- atomically $ (,)-                                             <$> newTChan-                                             <*> newEmptyTMVar--  let invokeWrite x = do-        threadDelay toWaitFurther-        atomically $ writeTChan outputChan x--  writer <- async $ forever $ do-    x <- atomically $ readTChan presentedChan--    mInvoker <- atomically $ tryTakeTMVar writingThread-    case mInvoker of-      Nothing -> pure ()-      Just i -> wait i-    newWriter <- async (invokeWrite x)-    atomically $ putTMVar writingThread newWriter--  pure (presentedChan, writer)---intersperseStatic :: DiffNanosec -> IO a -> TChan a -> IO (TChan a, Async (), Async ())-intersperseStatic timeBetween xM outputChan = do-  (presentedChan,writingThread) <- atomically $ (,)-                                             <$> newTChan-                                             <*> newEmptyTMVar--  let invokeWritePing = do-        threadDelay timeBetween-        x <- xM-        atomically $ writeTChan outputChan x--  writer <- async $ forever $ do-    mInvoker <- atomically $ tryTakeTMVar writingThread-    case mInvoker of-      Nothing -> pure ()-      Just i -> wait i-    newWriter <- async invokeWritePing-    atomically $ putTMVar writingThread newWriter--  listener <- async $ forever $ do-    (y,mInvoker) <- atomically $ do-      y' <- readTChan presentedChan--      (\q -> (y',q)) <$> tryTakeTMVar writingThread--    case mInvoker of-      Nothing -> pure ()-      Just i -> cancel i--    atomically $ writeTChan outputChan y--  pure (presentedChan, writer, listener)
src/Control/Concurrent/STM/TChan/Typed.hs view
@@ -6,25 +6,13 @@ module Control.Concurrent.STM.TChan.Typed where  import Control.Concurrent.Chan.Scope (Scope (..), Writable, Readable)+ import Control.Concurrent.STM.TChan (TChan) import qualified Control.Concurrent.STM.TChan as TChan import Control.Concurrent.STM (STM)   newtype TChanRW (scope :: Scope) a = TChanRW (TChan a)---readOnly :: Readable scope => TChanRW scope a -> TChanRW 'Read a-readOnly (TChanRW c) = TChanRW c--writeOnly :: Writable scope => TChanRW scope a -> TChanRW 'Write a-writeOnly (TChanRW c) = TChanRW c--allowReading :: Writable scope => TChanRW scope a -> TChanRW 'ReadWrite a-allowReading (TChanRW c) = TChanRW c--allowWriting :: Readable scope => TChanRW scope a -> TChanRW 'ReadWrite a-allowWriting (TChanRW c) = TChanRW c   newTChanRW :: STM (TChanRW 'ReadWrite a)
− src/Control/Concurrent/STM/TChan/Typed/Extra.hs
@@ -1,104 +0,0 @@-{-# LANGUAGE-    DataKinds-  #-}--module Control.Concurrent.STM.TChan.Typed.Extra where--import Control.Monad (forever)-import Control.Concurrent (threadDelay)-import Control.Concurrent.STM (STM, atomically)--- import Control.Concurrent.STM.TVar (newTVar, readIORef, writeIORef)-import Control.Concurrent.STM.TMVar (newEmptyTMVar, tryTakeTMVar, putTMVar)-import Control.Concurrent.Chan.Scope (Scope (..))-import Control.Concurrent.STM.TChan.Typed (TChanRW, readTChanRW, writeTChanRW, newTChanRW, allowWriting, writeOnly)-import Control.Concurrent.Async (Async, async, cancel, wait)----type DiffNanosec = Int----- | Note: In this model, even though we are using STM, a write to the--- outgoing channel does not imply a transactional write to the output--- channel; they are separated between a run IO layer, which means--- we cannot atomically debounce or interleave the system (because--- that depends on real-world time).-debounceStatic :: DiffNanosec -> TChanRW 'Read a -> IO (TChanRW 'Write a, Async ())-debounceStatic toWaitFurther outputChan = do-  (presentedChan,writingThread) <- atomically $ (,)-                                             <$> newTChanRW-                                             <*> newEmptyTMVar--  let invokeWrite x = do-        threadDelay toWaitFurther-        atomically $ writeTChanRW (allowWriting outputChan) x--  writer <- async $ forever $ do-    x <- atomically $ readTChanRW presentedChan--    newWriter <- async (invokeWrite x)--    mInvoker <- atomically $ tryTakeTMVar writingThread-    case mInvoker of-      Nothing -> pure ()-      Just i -> cancel i-    atomically $ putTMVar writingThread newWriter--  pure (writeOnly presentedChan, writer)---throttleStatic :: DiffNanosec -> TChanRW 'Read a -> IO (TChanRW 'Write a, Async ())-throttleStatic toWaitFurther outputChan = do-  (presentedChan,writingThread) <- atomically $ (,)-                                             <$> newTChanRW-                                             <*> newEmptyTMVar--  let invokeWrite x = do-        threadDelay toWaitFurther-        atomically $ writeTChanRW (allowWriting outputChan) x--  writer <- async $ forever $ do-    x <- atomically $ readTChanRW presentedChan--    mInvoker <- atomically $ tryTakeTMVar writingThread-    case mInvoker of-      Nothing -> pure ()-      Just i -> wait i-    newWriter <- async (invokeWrite x)-    atomically $ putTMVar writingThread newWriter--  pure (writeOnly presentedChan, writer)---intersperseStatic :: DiffNanosec -> IO a -> TChanRW 'Read a -> IO (TChanRW 'Write a, Async (), Async ())-intersperseStatic timeBetween xM outputChan = do-  (presentedChan,writingThread) <- atomically $ (,)-                                             <$> newTChanRW-                                             <*> newEmptyTMVar--  let invokeWritePing = do-        threadDelay timeBetween-        x <- xM-        atomically $ writeTChanRW (allowWriting outputChan) x--  writer <- async $ forever $ do-    mInvoker <- atomically $ tryTakeTMVar writingThread-    case mInvoker of-      Nothing -> pure ()-      Just i -> wait i-    newWriter <- async invokeWritePing-    atomically $ putTMVar writingThread newWriter--  listener <- async $ forever $ do-    (y,mInvoker) <- atomically $ do-      y' <- readTChanRW presentedChan--      (\q -> (y',q)) <$> tryTakeTMVar writingThread--    case mInvoker of-      Nothing -> pure ()-      Just i -> cancel i--    atomically $ writeTChanRW (allowWriting outputChan) y--  pure (writeOnly presentedChan, writer, listener)