module Ros.Internal.Util.RingChan (RingChan, newRingChan, writeChan,
readChan, getChanContents,
getBuffered) where
import Control.Monad (join)
import Control.Concurrent.MVar
import Control.Concurrent.SSem (SSem)
import qualified Control.Concurrent.SSem as Sem
import qualified Data.Foldable as F
import Data.Sequence (Seq, (|>), viewl, ViewL(..))
import qualified Data.Sequence as Seq
import System.IO.Unsafe (unsafeInterleaveIO)
type RingChan a = (Int, SSem, MVar (Seq a))
newRingChan :: Int -> IO (RingChan a)
newRingChan n = do sem <- Sem.new 0
q <- newMVar Seq.empty
return (n,sem,q)
writeChan :: RingChan a -> a -> IO ()
writeChan (n,sem,mv) x =
join $ modifyMVar mv (\q -> if Seq.length q < n
then return (q |> x, Sem.signal sem)
else let _ :< t = viewl q
in return (t |> x, return ()))
readChan :: RingChan a -> IO a
readChan (_,sem,mv) = do Sem.wait sem
modifyMVar mv (\q -> let h :< t = viewl q
in return (t,h))
getBuffered :: RingChan a -> IO [a]
getBuffered (_,_,xs) = F.toList `fmap` readMVar xs
getChanContents :: RingChan a -> IO [a]
getChanContents c = unsafeInterleaveIO $ do
x <- readChan c
xs <- getChanContents c
return (x:xs)