Use explicit language extensions & remove extension fields from base.cabal
[ghc-base.git] / Control / Concurrent / Chan.hs
index 6b48e33..2255c4e 100644 (file)
@@ -1,3 +1,5 @@
+{-# LANGUAGE CPP #-}
+
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Control.Concurrent.Chan
@@ -6,7 +8,7 @@
 -- 
 -- Maintainer  :  libraries@haskell.org
 -- Stability   :  experimental
--- Portability :  non-portable (concurrency).
+-- Portability :  non-portable (concurrency)
 --
 -- Unbounded channels.
 --
 
 module Control.Concurrent.Chan
   ( 
-         -- * The 'Chan' type
-       Chan,                   -- abstract
-
-         -- * Operations
-       newChan,                -- :: IO (Chan a)
-       writeChan,              -- :: Chan a -> a -> IO ()
-       readChan,               -- :: Chan a -> IO a
-       dupChan,                -- :: Chan a -> IO (Chan a)
-       unGetChan,              -- :: Chan a -> a -> IO ()
-       isEmptyChan,            -- :: Chan a -> IO Bool
-
-         -- * Stream interface
-       getChanContents,        -- :: Chan a -> IO [a]
-       writeList2Chan,         -- :: Chan a -> [a] -> IO ()
+          -- * The 'Chan' type
+        Chan,                   -- abstract
+
+          -- * Operations
+        newChan,                -- :: IO (Chan a)
+        writeChan,              -- :: Chan a -> a -> IO ()
+        readChan,               -- :: Chan a -> IO a
+        dupChan,                -- :: Chan a -> IO (Chan a)
+        unGetChan,              -- :: Chan a -> a -> IO ()
+        isEmptyChan,            -- :: Chan a -> IO Bool
+
+          -- * Stream interface
+        getChanContents,        -- :: Chan a -> IO [a]
+        writeList2Chan,         -- :: Chan a -> [a] -> IO ()
    ) where
 
 import Prelude
 
-import System.IO.Unsafe                ( unsafeInterleaveIO )
+import System.IO.Unsafe         ( unsafeInterleaveIO )
 import Control.Concurrent.MVar
 import Data.Typeable
 
@@ -46,6 +48,7 @@ import Data.Typeable
 data Chan a
  = Chan (MVar (Stream a))
         (MVar (Stream a))
+   deriving Eq
 
 INSTANCE_TYPEABLE1(Chan,chanTc,"Chan")
 
@@ -63,9 +66,9 @@ data ChItem a = ChItem a (Stream a)
 newChan :: IO (Chan a)
 newChan = do
    hole  <- newEmptyMVar
-   read  <- newMVar hole
-   write <- newMVar hole
-   return (Chan read write)
+   readVar  <- newMVar hole
+   writeVar <- newMVar hole
+   return (Chan readVar writeVar)
 
 -- To put an element on a channel, a new hole at the write end is created.
 -- What was previously the empty @MVar@ at the back of the channel is then
@@ -74,46 +77,51 @@ newChan = do
 
 -- |Write a value to a 'Chan'.
 writeChan :: Chan a -> a -> IO ()
-writeChan (Chan _read write) val = do
+writeChan (Chan _ writeVar) val = do
   new_hole <- newEmptyMVar
-  modifyMVar_ write $ \old_hole -> do
+  modifyMVar_ writeVar $ \old_hole -> do
     putMVar old_hole (ChItem val new_hole)
     return new_hole
 
 -- |Read the next value from the 'Chan'.
 readChan :: Chan a -> IO a
-readChan (Chan read _write) = do
-  modifyMVar read $ \read_end -> do
+readChan (Chan readVar _) = do
+  modifyMVar readVar $ \read_end -> do
     (ChItem val new_read_end) <- readMVar read_end
-       -- Use readMVar here, not takeMVar,
-       -- else dupChan doesn't work
+        -- Use readMVar here, not takeMVar,
+        -- else dupChan doesn't work
     return (new_read_end, val)
 
 -- |Duplicate a 'Chan': the duplicate channel begins empty, but data written to
 -- either channel from then on will be available from both.  Hence this creates
 -- a kind of broadcast channel, where data written by anyone is seen by
 -- everyone else.
+--
+-- (Note that a duplicated channel is not equal to its original.
+-- So: @fmap (c /=) $ dupChan c@ returns @True@ for all @c@.)
 dupChan :: Chan a -> IO (Chan a)
-dupChan (Chan _read write) = do
-   hole     <- readMVar write
-   new_read <- newMVar hole
-   return (Chan new_read write)
+dupChan (Chan _ writeVar) = do
+   hole       <- readMVar writeVar
+   newReadVar <- newMVar hole
+   return (Chan newReadVar writeVar)
 
 -- |Put a data item back onto a channel, where it will be the next item read.
 unGetChan :: Chan a -> a -> IO ()
-unGetChan (Chan read _write) val = do
+unGetChan (Chan readVar _) val = do
    new_read_end <- newEmptyMVar
-   modifyMVar_ read $ \read_end -> do
+   modifyMVar_ readVar $ \read_end -> do
      putMVar new_read_end (ChItem val read_end)
      return new_read_end
+{-# DEPRECATED unGetChan "if you need this operation, use Control.Concurrent.STM.TChan instead.  See http://hackage.haskell.org/trac/ghc/ticket/4154 for details" #-}
 
 -- |Returns 'True' if the supplied 'Chan' is empty.
 isEmptyChan :: Chan a -> IO Bool
-isEmptyChan (Chan read write) = do
-   withMVar read $ \r -> do
-     w <- readMVar write
+isEmptyChan (Chan readVar writeVar) = do
+   withMVar readVar $ \r -> do
+     w <- readMVar writeVar
      let eq = r == w
      eq `seq` return eq
+{-# DEPRECATED isEmptyChan "if you need this operation, use Control.Concurrent.STM.TChan instead.  See http://hackage.haskell.org/trac/ghc/ticket/4154 for details" #-}
 
 -- Operators for interfacing with functional streams.
 
@@ -122,9 +130,9 @@ isEmptyChan (Chan read write) = do
 getChanContents :: Chan a -> IO [a]
 getChanContents ch
   = unsafeInterleaveIO (do
-       x  <- readChan ch
-       xs <- getChanContents ch
-       return (x:xs)
+        x  <- readChan ch
+        xs <- getChanContents ch
+        return (x:xs)
     )
 
 -- |Write an entire list of items to a 'Chan'.