module Control.Concurrent.Chan.Unagi.Unboxed (
    -- * Creating channels
      newChan
    , InChan(), OutChan()
    , UnagiPrim(..)
    -- * Channel operations
    -- ** Reading
    , readChan
    , readChanOnException
    , tryReadChan
    , Element(..)
    , getChanContents
    -- ** Writing
    , writeChan
    , writeList2Chan
    -- ** Broadcasting
    , dupChan
    ) where

-- Forked from src/Control/Concurrent/Chan/Unagi/Internal.hs at 443465
--
-- TODO additonal functions:
--   - write functions optimized for single-writer
--   - faster write/read-many that increments counter by N
--   - this could be used (or forked) to implement an efficient MPSC concurrent
--     ByteString or Text queue (where writes could be variable-sized chunks
--     and we incrCounter accordingly) without too much trouble. Useful?
--       - likewise a SPMC concurrent bytestring consumer?
--   - ...or interop with 'vector' lib

import Control.Concurrent.Chan.Unagi.Unboxed.Internal
import Control.Concurrent.Chan.Unagi.NoBlocking.Types
-- For 'writeList2Chan', as in vanilla Chan
import System.IO.Unsafe ( unsafeInterleaveIO ) 


-- | Create a new channel, returning its write and read ends.
newChan :: UnagiPrim a=> IO (InChan a, OutChan a)
newChan = newChanStarting (maxBound - 10) 
    -- lets us test counter overflow in tests and normal course of operation

-- | Return a lazy list representing the contents of the supplied OutChan, much
-- like System.IO.hGetContents.
getChanContents :: UnagiPrim a=> OutChan a -> IO [a]
getChanContents ch = unsafeInterleaveIO (do
                            x  <- unsafeInterleaveIO $ readChan ch
                            xs <- getChanContents ch
                            return (x:xs)
                        )

-- | Write an entire list of items to a chan type. Writes here from multiple
-- threads may be interleaved, and infinite lists are supported.
writeList2Chan :: UnagiPrim a=> InChan a -> [a] -> IO ()
{-# INLINABLE writeList2Chan #-}
writeList2Chan ch = sequence_ . map (writeChan ch)