{-# OPTIONS_HADDOCK not-home #-}
module MagicWormhole.Internal.Sequential
( Sequential
, sequenceBy
, insert
, next
) where
import Protolude
import Control.Concurrent.STM.TVar
( TVar
, modifyTVar'
, newTVar
, readTVar
)
import qualified Data.HashMap.Lazy as HashMap
data Sequential counter item
= Sequential
{
current :: TVar counter
,
buffer :: TVar (HashMap.HashMap counter item)
,
rank :: item -> counter
}
sequenceBy
:: (Hashable counter, Eq counter)
=> (a -> counter)
-> counter
-> STM (Sequential counter a)
sequenceBy rank' initial = Sequential <$> newTVar initial <*> newTVar mempty <*> pure rank'
insert
:: (Ord counter, Enum counter, Hashable counter, Eq counter)
=> Sequential counter a
-> a
-> STM Bool
insert sequential msg = do
cur <- readTVar (current sequential)
let msgRank = rank sequential msg
if msgRank < cur
then pure False
else do
modifyTVar' (buffer sequential) (HashMap.insert (rank sequential msg) msg)
pure True
next
:: (Enum counter, Eq counter, Hashable counter)
=> Sequential counter a
-> STM a
next thingy = do
i <- readTVar (current thingy)
q <- readTVar (buffer thingy)
case HashMap.lookup i q of
Nothing -> retry
Just msg -> do
modifyTVar' (current thingy) succ
modifyTVar' (buffer thingy) (HashMap.delete i)
pure msg