packages feed

chan-split 0.4.0 → 0.5.0

raw patch · 3 files changed

+266/−10 lines, 3 filesdep +stmPVP ok

version bump matches the API change (PVP)

Dependencies added: stm

API changes (from Hackage documentation)

+ Control.Concurrent.STM.TChan.Class: class SplitTChan i o => NewSplitTChan i o
+ Control.Concurrent.STM.TChan.Class: class SplitTChan i o | i -> o, o -> i
+ Control.Concurrent.STM.TChan.Class: instance NewSplitTChan TChan TChan
+ Control.Concurrent.STM.TChan.Class: instance NewSplitTChan TMVar TMVar
+ Control.Concurrent.STM.TChan.Class: instance SplitTChan TChan TChan
+ Control.Concurrent.STM.TChan.Class: instance SplitTChan TMVar TMVar
+ Control.Concurrent.STM.TChan.Class: isEmptyTChan :: SplitTChan i o => o a -> STM Bool
+ Control.Concurrent.STM.TChan.Class: newSplitTChan :: NewSplitTChan i o => STM (i a, o a)
+ Control.Concurrent.STM.TChan.Class: peekTChan :: SplitTChan i o => o a -> STM a
+ Control.Concurrent.STM.TChan.Class: readTChan :: SplitTChan i o => o a -> STM a
+ Control.Concurrent.STM.TChan.Class: tryPeekTChan :: SplitTChan i o => o a -> STM (Maybe a)
+ Control.Concurrent.STM.TChan.Class: tryReadTChan :: SplitTChan i o => o a -> STM (Maybe a)
+ Control.Concurrent.STM.TChan.Class: writeTChan :: SplitTChan i o => i a -> a -> STM ()
+ Control.Concurrent.STM.TChan.Split: cloneTChan :: OutTChan a -> STM (OutTChan a)
+ Control.Concurrent.STM.TChan.Split: data InTChan a
+ Control.Concurrent.STM.TChan.Split: data OutTChan a
+ Control.Concurrent.STM.TChan.Split: dupTChan :: InTChan a -> STM (OutTChan a)
+ Control.Concurrent.STM.TChan.Split: instance Eq (InTChan a)
+ Control.Concurrent.STM.TChan.Split: instance Eq (OutTChan a)
+ Control.Concurrent.STM.TChan.Split: instance NewSplitTChan InTChan OutTChan
+ Control.Concurrent.STM.TChan.Split: instance SplitTChan InTChan OutTChan
+ Control.Concurrent.STM.TChan.Split: instance Typeable1 InTChan
+ Control.Concurrent.STM.TChan.Split: instance Typeable1 OutTChan
+ Control.Concurrent.STM.TChan.Split: newInTChan :: STM (InTChan a)
+ Control.Concurrent.STM.TChan.Split: newInTChanIO :: IO (InTChan a)
+ Control.Concurrent.STM.TChan.Split: newSplitTChanIO :: IO (OutTChan a, InTChan a)
+ Control.Concurrent.STM.TChan.Split: unGetTChan :: OutTChan a -> a -> STM ()

Files

+ Control/Concurrent/STM/TChan/Class.hs view
@@ -0,0 +1,63 @@+{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies #-}+module Control.Concurrent.STM.TChan.Class +    where++import qualified Control.Concurrent.STM.TChan as C+import Control.Concurrent.STM+++-- | A class capturing Chan operations in STM.+class SplitTChan i o | i -> o, o -> i where+    -- | Write a value to the in chan.+    writeTChan :: i a -> a -> STM ()+    -- | Read the next value from the out chan.+    readTChan :: o a -> STM a+    -- | Get the next value from the @TChan@ without removing it,+    -- retrying if the channel is empty.+    peekTChan :: o a -> STM a+    -- | A version of 'peekTChan' which does not retry. Instead it+    -- returns @Nothing@ if no value is available.+    tryPeekTChan :: o a -> STM (Maybe a)+    -- | A version of 'readTChan' which does not retry. Instead it+    -- returns @Nothing@ if no value is available.+    tryReadTChan :: o a -> STM (Maybe a)+    -- |Returns 'True' if the supplied 'TChan' is empty.+    isEmptyTChan :: o a -> STM Bool++++-- | A class for 'SplitTChan' types that can be instantiated without programmer+-- input. /e.g./ the standard haskell @TChan@ is a member of this class, however+-- a bounded chan type that took an @Int@ to define the buffer size would not.+class (SplitTChan i o)=> NewSplitTChan i o where+    newSplitTChan :: STM (i a, o a)++++-- instances -- +++-- one-bounded chan:+instance SplitTChan TMVar TMVar where+    readTChan = takeTMVar+    writeTChan = putTMVar+    peekTChan = readTMVar+    tryReadTChan = tryTakeTMVar+    tryPeekTChan = tryReadTMVar+    isEmptyTChan = isEmptyTMVar++instance SplitTChan C.TChan C.TChan where+    writeTChan = C.writeTChan+    readTChan = C.readTChan+    peekTChan = C.peekTChan+    tryReadTChan = C.tryReadTChan+    tryPeekTChan = C.tryPeekTChan+    isEmptyTChan = C.isEmptyTChan++instance NewSplitTChan TMVar TMVar where+    newSplitTChan = do v <- newEmptyTMVar+                       return (v,v)++instance NewSplitTChan TChan TChan where+    newSplitTChan = do v <- C.newTChan+                       return (v,v)
+ Control/Concurrent/STM/TChan/Split.hs view
@@ -0,0 +1,192 @@+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}+{-# LANGUAGE DeriveDataTypeable #-}++module Control.Concurrent.STM.TChan.Split (+    -- | Much of the STM chan functionality exists in the 'SplitTChan' and class,+    -- which you should see for documentation.+	+	-- * TChan pairs+	InTChan,+	OutTChan,++    -- ** Construction+    -- | See also the 'NewSplitTChan' class.+	+	--newBroadcastTChan, --replaced by...+	newInTChan,+	-- *** In IO+	newSplitTChanIO,+	--newBroadcastTChanIO, --replaced by...+	newInTChanIO,++    -- ** Putting values back+    unGetTChan,+    +    -- ** Duplication+    dupTChan,+    cloneTChan+  ) where++import GHC.Conc++import Data.Typeable (Typeable)++import Control.Concurrent.STM.TChan.Class++-- | The input side of an unbounded FIFO channel.+newtype InTChan a = InTChan (TVar (TVarList a))+  deriving (Eq, Typeable)++-- | The output side of an unbounded FIFO channel.+newtype OutTChan a = OutTChan (TVar (TVarList a))+  deriving (Eq, Typeable)++type TVarList a = TVar (TList a)+data TList a = TNil | TCons a {-# UNPACK #-} !(TVarList a)++instance NewSplitTChan InTChan OutTChan where +    newSplitTChan = do+      hole <- newTVar TNil+      read <- newTVar hole+      write <- newTVar hole+      return (InTChan write, OutTChan read)++instance SplitTChan InTChan OutTChan where+    writeTChan (InTChan write) a = do+      listend <- readTVar write -- listend == TVar pointing to TNil+      new_listend <- newTVar TNil+      writeTVar listend (TCons a new_listend)+      writeTVar write new_listend++    readTChan (OutTChan read) = do+      listhead <- readTVar read+      head <- readTVar listhead+      case head of+        TNil -> retry+        TCons a tail -> do+        writeTVar read tail+        return a++    tryReadTChan (OutTChan read) = do+      listhead <- readTVar read+      head <- readTVar listhead+      case head of+        TNil       -> return Nothing+        TCons a tl -> do+          writeTVar read tl+          return (Just a)++    peekTChan (OutTChan read) = do+      listhead <- readTVar read+      head <- readTVar listhead+      case head of+        TNil      -> retry+        TCons a _ -> return a++    tryPeekTChan (OutTChan read) = do+      listhead <- readTVar read+      head <- readTVar listhead+      case head of+        TNil      -> return Nothing+        TCons a _ -> return (Just a)++    isEmptyTChan (OutTChan read) = do+      listhead <- readTVar read+      head <- readTVar listhead+      case head of+        TNil -> return True+        TCons _ _ -> return False+++-- |@IO@ version of 'newTChan'.  This is useful for creating top-level+-- 'TChan's using 'System.IO.Unsafe.unsafePerformIO', because using+-- 'atomically' inside 'System.IO.Unsafe.unsafePerformIO' isn't+-- possible.+newSplitTChanIO :: IO (OutTChan a, InTChan a)+newSplitTChanIO = do+  hole <- newTVarIO TNil+  read <- newTVarIO hole+  write <- newTVarIO hole+  return (OutTChan read, InTChan write)+++-- -- | Create a write-only 'TChan'.  More precisely, 'readTChan' will 'retry'+-- -- even after items have been written to the channel.  The only way to read+-- -- a broadcast channel is to duplicate it with 'dupTChan'.+-- --+-- -- Consider a server that broadcasts messages to clients:+-- --+-- -- >serve :: TChan Message -> Client -> IO loop+-- -- >serve broadcastChan client = do+-- -- >    myChan <- dupTChan broadcastChan+-- -- >    forever $ do+-- -- >        message <- readTChan myChan+-- -- >        send client message+-- --+-- -- The problem with using 'newTChan' to create the broadcast channel is that if+-- -- it is only written to and never read, items will pile up in memory.  By+-- -- using 'newBroadcastTChan' to create the broadcast channel, items can be+-- -- garbage collected after clients have seen them.+-- newBroadcastTChan :: STM (TChan a)+-- newBroadcastTChan = do+--     dummy_hole <- newTVar TNil+--     write_hole <- newTVar TNil+--     read <- newTVar dummy_hole+--     write <- newTVar write_hole+--     return (TChan read write)++-- -- | @IO@ version of 'newBroadcastTChan'.+-- newBroadcastTChanIO :: IO (TChan a)+-- newBroadcastTChanIO = do+--     dummy_hole <- newTVarIO TNil+--     write_hole <- newTVarIO TNil+--     read <- newTVarIO dummy_hole+--     write <- newTVarIO write_hole+--     return (TChan read write)++-- ------------------------------+-- NOTE: functions above are useful, but description of usage isn't relevant I don't +-- think; messages should be garbage collected once the read end is GC'd (i.e.+-- in the scenarion where there are only writers and no readers.+--+-- The equivalent functions are still useful to have though:+-- ------------------------------++-- | Create a new write end of a TChan. Use 'dupTChan' to get an 'OutChan' that+-- values can be read from.+newInTChan :: STM (InTChan a)+newInTChan = do+    write_hole <- newTVar TNil+    write <- newTVar write_hole+    return (InTChan write)+++-- | @IO@ version of 'newInTChan'.+newInTChanIO :: IO (InTChan a)+newInTChanIO = do+    write_hole <- newTVarIO TNil+    write <- newTVarIO write_hole+    return (InTChan write)++-- |Create a duplicate 'OutChan' from an 'InChan'. The 'OutChan' starts +-- empty but will receive a copy of all subsequent values written.+dupTChan :: InTChan a -> STM (OutTChan a)+dupTChan (InTChan write) = do+  hole <- readTVar write  +  new_read <- newTVar hole+  return (OutTChan new_read)++-- |Put a data item back onto a channel, where it will be the next item read.+unGetTChan :: OutTChan a -> a -> STM ()+unGetTChan (OutTChan read) a = do+   listhead <- readTVar read+   newhead <- newTVar (TCons a listhead)+   writeTVar read newhead++-- |Clone a 'TChan': similar to dupTChan, but the cloned channel starts with the+-- same content available as the original channel.+cloneTChan :: OutTChan a -> STM (OutTChan a)+cloneTChan (OutTChan read) = do+  readpos <- readTVar read+  new_read <- newTVar readpos+  return (OutTChan new_read)
chan-split.cabal view
@@ -3,12 +3,12 @@ -- http://www.haskell.org/cabal/release/cabal-latest/doc/users-guide/authors.html#pkg-descr. -- The name of the package. Name:                chan-split-Homepage:            http://coder.bsimmons.name/blog/2011/07/module-chan-split-released/+Homepage:            http://brandon.si/code/module-chan-split-released/  -- The package version. See the Haskell package versioning policy -- (http://www.haskell.org/haskellwiki/Package_versioning_policy) for -- standards guiding when and how versions should be incremented.-Version:             0.4.0+Version:             0.5.0  -- A short (one-line) description of the package. Synopsis:            Concurrent Chans as read/write pairs. Also provides generic@@ -51,13 +51,13 @@                      .                      This module is used internally by the "simple-actors" package.                      .-                     /CHANGES/: 0.3.0 -> 0.4.0  -                     . -                     - In\/OutChans now implemented from scratch (after Leon P Smith's implementation)-                     . -                     - no longer implement Functor\/Contravariant instances; drop contravariant dependency+                     /CHANGES/: 0.4.0 -> 0.5.0                        . -                     - implement Eq and Typeable instances+                     - modify TChan v2.4 code into split version+                     .+                     - depend on STM+                     .+                     - clean up Extensions section and broken links                      .   @@ -97,13 +97,14 @@                      -- for the split chan class:   Extensions:          MultiParamTypeClasses                      , FunctionalDependencies -                     -- for Functor / Contravariant instances:-                     , GADTs    Exposed-modules:     Control.Concurrent.Chan.Split                      , Control.Concurrent.Chan.Class+                     , Control.Concurrent.STM.TChan.Class+                     , Control.Concurrent.STM.TChan.Split      Build-depends:       base >= 4 && < 5+                     , stm > 2 && < 3      ghc-options:        -Wall