module Development.IDE.Types.Action ( DelayedAction (..), DelayedActionInternal, ActionQueue, newQueue, pushQueue, popQueue, doneQueue, peekInProgress, abortQueue,countQueue) where import Control.Concurrent.STM import Data.Hashable (Hashable (..)) import Data.HashSet (HashSet) import qualified Data.HashSet as Set import Data.Unique (Unique) import Development.IDE.Types.Logger import Development.Shake (Action) import Numeric.Natural data DelayedAction a = DelayedAction { uniqueID :: Maybe Unique, -- | Name we use for debugging actionName :: String, -- | Priority with which to log the action actionPriority :: Priority, -- | The payload getAction :: Action a } deriving (Functor) type DelayedActionInternal = DelayedAction () instance Eq (DelayedAction a) where a == b = uniqueID a == uniqueID b instance Hashable (DelayedAction a) where hashWithSalt s = hashWithSalt s . uniqueID instance Show (DelayedAction a) where show d = "DelayedAction: " ++ actionName d ------------------------------------------------------------------------------ data ActionQueue = ActionQueue { newActions :: TQueue DelayedActionInternal, inProgress :: TVar (HashSet DelayedActionInternal) } newQueue :: IO ActionQueue newQueue = atomically $ do newActions <- newTQueue inProgress <- newTVar mempty return ActionQueue {..} pushQueue :: DelayedActionInternal -> ActionQueue -> STM () pushQueue act ActionQueue {..} = writeTQueue newActions act -- | You must call 'doneQueue' to signal completion popQueue :: ActionQueue -> STM DelayedActionInternal popQueue ActionQueue {..} = do x <- readTQueue newActions modifyTVar inProgress (Set.insert x) return x -- | Completely remove an action from the queue abortQueue :: DelayedActionInternal -> ActionQueue -> STM () abortQueue x ActionQueue {..} = do qq <- flushTQueue newActions mapM_ (writeTQueue newActions) (filter (/= x) qq) modifyTVar inProgress (Set.delete x) -- | Mark an action as complete when called after 'popQueue'. -- Has no effect otherwise doneQueue :: DelayedActionInternal -> ActionQueue -> STM () doneQueue x ActionQueue {..} = do modifyTVar inProgress (Set.delete x) countQueue :: ActionQueue -> STM Natural countQueue ActionQueue{..} = do backlog <- flushTQueue newActions mapM_ (writeTQueue newActions) backlog m <- Set.size <$> readTVar inProgress return $ fromIntegral $ length backlog + m peekInProgress :: ActionQueue -> STM [DelayedActionInternal] peekInProgress ActionQueue {..} = Set.toList <$> readTVar inProgress