{-# LANGUAGE FlexibleContexts, MultiParamTypeClasses, TypeFamilies, FlexibleInstances #-} -- | In the IO monad, provides thread-safe 'MVar'-based wrappers for 'Queuelike' and 'MQueue' instances. module Data.MQueue.SyncQueue (SyncQ, SyncMQ) where import Data.Queue.Class import qualified Data.Queue.Class as Q import Data.MQueue.Class -- import Data.Tuple.HT import Control.Arrow import Control.Concurrent.MVar import Control.Monad.Trans import Control.Monad import Data.Maybe newtype SyncQ q = SyncQ (MVar q) newtype SyncMQ q = SyncMQ (MVar q) instance (MonadIO m, IQueue q) => MQueue (SyncQ q) m where {-# SPECIALIZE instance IQueue q => MQueue (SyncQ q) IO #-} type MQueueKey (SyncQ q) = QueueKey q newQueue = liftIO $ liftM SyncQ $ newMVar empty push (SyncQ var) k = liftIO $ modifyMVar_ var (return . insert k) peek = withSyncQ Q.top pop (SyncQ var) = liftIO $ modifyMVar var (\ q -> return ((maybe q snd &&& fmap fst) (extract q))) pop_ (SyncQ var) = liftIO $ modifyMVar_ var (return . (fromMaybe `ap` delete)) -- getSize = withSyncQ Q.size isEmpty = withSyncQ Q.null {-# INLINE withSyncQ #-} withSyncQ :: (MonadIO m, IQueue q) => (q -> a) -> SyncQ q -> m a withSyncQ f (SyncQ var) = liftIO $ withMVar var (return . f) instance (MonadIO m, MQueue q IO) => MQueue (SyncMQ q) m where {-# SPECIALIZE instance MQueue q IO => MQueue (SyncMQ q) IO #-} type MQueueKey (SyncMQ q) = MQueueKey q newQueue = liftIO $ liftM SyncMQ $ newQueue >>= newMVar q `push` k = onSyncMQ (`push` k) q q `pushAll` ks = onSyncMQ (`pushAll` ks) q peek = onSyncMQ peek pop = onSyncMQ pop pop_ = onSyncMQ pop_ -- getSize = onSyncMQ getSize isEmpty = onSyncMQ isEmpty {-# INLINE onSyncMQ #-} onSyncMQ :: (MonadIO m, MQueue q IO) => (q -> IO a) -> SyncMQ q -> m a onSyncMQ f (SyncMQ var) = liftIO $ withMVar var f -- let ext = extract q in return (maybe q snd ext, fmap snd ext)