module Data.SequenceId
( checkSeqId
, incrementSeqId
, checkSeqIdM
, incrementSeqIdM
, lastSeqIdM
, SequenceIdT (..)
, runSequenceIdT
, execSequenceIdT
, evalSequenceIdT
, SequenceIdError (..)
, SequenceIdErrorType (..)
, SequenceId (..)
) where
import Control.Applicative (Applicative)
import Control.Monad.State.Class (MonadState, get, modify', put)
import Control.Monad.Trans.Class (MonadTrans)
import Control.Monad.Trans.State (StateT (..), evalStateT, execStateT)
import Data.Word (Word32)
newtype SequenceIdT m a = SequenceIdT { unSequenceIdT :: StateT SequenceId m a }
deriving (Monad, Applicative, Functor, MonadState SequenceId, MonadTrans)
newtype SequenceId = SequenceId { unSequenceId :: Word32 }
deriving (Eq, Ord, Num, Integral, Real, Enum)
instance Show SequenceId where
show (SequenceId n) = show n
evalSequenceIdT :: Monad m => SequenceIdT m b -> SequenceId -> m b
evalSequenceIdT = evalStateT . unSequenceIdT
execSequenceIdT :: Monad m => SequenceIdT m b -> SequenceId -> m SequenceId
execSequenceIdT = execStateT . unSequenceIdT
runSequenceIdT :: Monad m => SequenceIdT m b -> SequenceId -> m (b, SequenceId)
runSequenceIdT = runStateT . unSequenceIdT
data SequenceIdError =
SequenceIdError
{ errType :: !SequenceIdErrorType
, lastSeqId :: !SequenceId
, currSeqId :: !SequenceId
} deriving (Eq, Show)
data SequenceIdErrorType
= SequenceIdDropped
| SequenceIdDuplicated
deriving (Eq, Show)
checkSeqIdM :: Monad m => SequenceId
-> (SequenceIdT m) (Maybe SequenceIdError)
checkSeqIdM currSeq = do
lastSeq <- get
put $ max lastSeq currSeq
return $ checkSeqId lastSeq currSeq
checkSeqId :: SequenceId
-> SequenceId
-> Maybe SequenceIdError
checkSeqId lastSeq currSeq
| delta lastSeq currSeq > 1 = Just $ SequenceIdError SequenceIdDropped lastSeq currSeq
| delta lastSeq currSeq < 1 = Just $ SequenceIdError SequenceIdDuplicated lastSeq currSeq
| otherwise = Nothing
delta :: SequenceId -> SequenceId -> Int
delta lastSeq currSeq = fromIntegral currSeq fromIntegral lastSeq
incrementSeqIdM :: Monad m => SequenceIdT m SequenceId
incrementSeqIdM = modify' incrementSeqId >> get
incrementSeqId :: SequenceId
-> SequenceId
incrementSeqId = (+1)
lastSeqIdM :: Monad m => SequenceIdT m SequenceId
lastSeqIdM = get