module Data.MediaBus.Sequence ( SeqNum(..) , type SeqNum8 , type SeqNum16 , type SeqNum32 , type SeqNum64 , HasSeqNumT(..) , HasSeqNum(..) , fromSeqNum , synchronizeToSeqNum ) where import Test.QuickCheck ( Arbitrary(..) ) import Conduit import Data.MediaBus.Monotone import Data.MediaBus.Series import Control.Lens import Control.Monad.State.Strict import Data.Default import Text.Printf import GHC.Generics ( Generic ) import Control.DeepSeq import System.Random import Data.Word class SetSeqNum t (GetSeqNum t) ~ t => HasSeqNumT t where type GetSeqNum t type SetSeqNum t s class HasSeqNumT t => HasSeqNum t where seqNum :: Lens t (SetSeqNum t s) (GetSeqNum t) s instance (HasSeqNumT a, HasSeqNumT b, GetSeqNum a ~ GetSeqNum b) => HasSeqNumT (Series a b) where type GetSeqNum (Series a b) = GetSeqNum a type SetSeqNum (Series a b) t = Series (SetSeqNum a t) (SetSeqNum b t) instance (HasSeqNum a, HasSeqNum b, GetSeqNum a ~ GetSeqNum b) => HasSeqNum (Series a b) where seqNum f (Start !a) = Start <$> seqNum f a seqNum f (Next !b) = Next <$> seqNum f b newtype SeqNum s = MkSeqNum { _fromSeqNum :: s } deriving (Num, Eq, Bounded, Enum, LocalOrd, Arbitrary, Default, Generic, Random) type SeqNum8 = SeqNum Word8 type SeqNum16 = SeqNum Word16 type SeqNum32 = SeqNum Word32 type SeqNum64 = SeqNum Word64 instance NFData s => NFData (SeqNum s) makeLenses ''SeqNum instance HasSeqNumT (SeqNum s) where type GetSeqNum (SeqNum s) = s type SetSeqNum (SeqNum s) s' = SeqNum s' instance HasSeqNum (SeqNum s) where seqNum = fromSeqNum instance Show s => Show (SeqNum s) where show (MkSeqNum s) = printf "SEQNUM: %10s" (show s) instance (Eq a, LocalOrd a) => Ord (SeqNum a) where compare !x !y | x == y = EQ | x `succeeds` y = GT | otherwise = LT deriving instance (Real a, Num a, Eq a, LocalOrd a) => Real (SeqNum a) deriving instance (Integral a, Enum a, Real a, Eq a, LocalOrd a) => Integral (SeqNum a) synchronizeToSeqNum :: (HasSeqNum a, Monad m, Integral i) => i -> Conduit a m (SetSeqNum a i) synchronizeToSeqNum startSeq = evalStateC startSeq (awaitForever yieldSeq) where yieldSeq !a = do !nextSeq <- get modify (+ 1) yield (a & seqNum .~ nextSeq)