-- | -- Module : Data.IVar.Simple.IChan -- Copyright : (c) 2008-2020 Bertram Felgenhauer -- License : MIT -- -- Maintainer : Bertram Felgenhauer <int-e@gmx.de> -- Stability : experimental -- Portability : ghc -- -- An 'IChan's is a type of multicast channel built on top of 'IVar.IVar's. -- It supports multiple readers. The channel is represented as a linked -- list. The 'IChan' data type represents the head of a channel. -- -- Writing to an 'IChan' head has write-once semantics similar to 'IVar.IVar's: -- only the first of several attempts to write to the head will succeed, -- returning a new 'IChan' head for writing more values. -- module Data.IVar.Simple.IChan ( IChan, new, read, uncons, write, tryWrite, ) where import Prelude hiding (read) import qualified Data.IVar.Simple as IVar import Control.Monad import Control.Concurrent.MVar -- | A channel head newtype IChan a = IChan (IVar.IVar (a, IChan a)) deriving Eq -- | Create a new channel. new :: IO (IChan a) new = IChan `fmap` IVar.new -- | Returns the contents of a channel as a list, starting at the channel -- head. -- -- This is a pure computation. Forcing elements of the list may, however, -- block. read :: IChan a -> [a] read ic = let (a, ic') = uncons ic in a : read ic' -- | Split channel into head and tail. -- -- This is a pure operation, but it may block. -- -- @since 0.3.3 uncons :: IChan a -> (a, IChan a) uncons (IChan as) = IVar.read as -- | Write a single value to the channel. -- -- Raises a 'BlockedIndefinitelyOnIVar' exception if a value has already -- been written to the channel. Otherwise, returns a new channel head for -- writing further values. write :: IChan a -> a -> IO (IChan a) write (IChan as) a = do ic <- new IVar.write as (a, ic) return ic -- | Attempts to write a single value to the channel. -- -- If a value has already been written, returns 'Nothing'. Otherwise, -- returns a new channel head for writing further values. tryWrite :: IChan a -> a -> IO (Maybe (IChan a)) tryWrite (IChan as) a = do ic <- new success <- IVar.tryWrite as (a, ic) return (guard success >> return ic)