packages feed

typed-session-0.3.0.1: test/Book3/Main.hs

{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE QualifiedDo #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# OPTIONS_GHC -Wno-unused-do-bind #-}

module Book3.Main where

import Book3.Peer
import Book3.Protocol
import Book3.Type
import Control.Carrier.Lift (runM, sendM)
import Control.Carrier.Random.Gen (runRandom)
import Control.Concurrent.Class.MonadSTM
import Control.Monad
import Control.Monad.Class.MonadFork (MonadFork, forkIO)
import Control.Monad.Class.MonadSay
import Control.Monad.Class.MonadThrow (MonadThrow)
import Control.Monad.Class.MonadTimer (MonadDelay)
import Control.Monad.IOSim
import System.Random (StdGen, split)
import TypedSession.Codec
import TypedSession.Core
import TypedSession.Driver

mvarsAsChannel
  :: (MonadSTM m)
  => TMVar m a
  -> TMVar m a
  -> Channel m a
mvarsAsChannel bufferRead bufferWrite =
  Channel{send, recv}
 where
  send x = atomically (putTMVar bufferWrite x)
  recv = atomically (Just <$> takeTMVar bufferRead)

myTracer :: (MonadSay m) => String -> Tracer BookRole Book m
myTracer st v = say (st <> show v)

runAll
  :: forall n
   . ( Monad n
     , MonadSTM n
     , MonadSay n
     , MonadThrow n
     , MonadFork n
     , MonadDelay n
     )
  => StdGen
  -> n ()
runAll g = do
  buyerTMVar <- newEmptyTMVarIO @n @(AnyMsg BookRole Book)
  buyer2TMVar <- newEmptyTMVarIO @n @(AnyMsg BookRole Book)
  sellerTMVar <- newEmptyTMVarIO @n @(AnyMsg BookRole Book)

  buyerDriver <-
    driverSimple
      (myTracer "buyer :")
      encodeMsg
      (Decode decodeMsg)
      [ (SomeRole SSeller, mvarsAsChannel buyerTMVar sellerTMVar)
      , (SomeRole SBuyer2, mvarsAsChannel buyerTMVar buyer2TMVar)
      ]
      sendM

  buyer2Driver <-
    driverSimple
      (myTracer "buyer2 :")
      encodeMsg
      (Decode decodeMsg)
      [(SomeRole SBuyer, mvarsAsChannel buyer2TMVar buyerTMVar)]
      sendM

  sellerDriver <-
    driverSimple
      (myTracer "seller :")
      encodeMsg
      (Decode decodeMsg)
      [(SomeRole SBuyer, mvarsAsChannel sellerTMVar buyerTMVar)]
      sendM

  let (g0, g1) = split g
      (g2, g3) = split g0

  resultTMVar1 <- newEmptyTMVarIO
  resultTMVar2 <- newEmptyTMVarIO

  -- fork seller Peer thread
  forkIO $ do
    runM $ runRandom g1 $ runPeerWithDriver sellerDriver sellerPeer
    atomically $ writeTMVar resultTMVar1 ()

  -- fork buyer2 Peer thread
  forkIO $ do
    runM $ runRandom g2 $ runPeerWithDriver buyer2Driver buyer2Peer
    atomically $ writeTMVar resultTMVar2 ()

  -- run buyer Peer
  void $ runM $ runRandom g3 $ runPeerWithDriver buyerDriver buyerPeer

  -- wait seller, buyer
  atomically $ do
    takeTMVar resultTMVar1
    takeTMVar resultTMVar2

book3Prop :: StdGen -> Either Failure ()
book3Prop v = runSim (runAll v)