packages feed

ribosome-host-0.9.9.9: lib/Ribosome/Host/Interpreter/Responses.hs

module Ribosome.Host.Interpreter.Responses where

import qualified Data.Map.Strict as Map
import Exon (exon)
import Conc (interpretAtomic)

import qualified Ribosome.Host.Data.RpcError as RpcError
import Ribosome.Host.Data.RpcError (RpcError)
import Ribosome.Host.Effect.Responses (Responses (Add, Respond, Wait))
import Ribosome.Host.Interpreter.Id (interpretInputNum)

failAbsentKey ::
  Show k =>
  Member (Stop RpcError) r =>
  k ->
  (a -> Sem r b) ->
  Maybe a ->
  Sem r b
failAbsentKey k f = \case
  Just resp ->
    f resp
  Nothing ->
    stop (RpcError.Unexpected [exon|No response registered for #{show k}|])

waitAndRemove ::
  Ord k =>
  Members [AtomicState (Map k (MVar v)), Embed IO] r =>
  k ->
  MVar v ->
  Sem r v
waitAndRemove k mv = do
  v <- embed (takeMVar mv)
  v <$ atomicModify' (Map.delete k)

interpretResponsesAtomic ::
  ∀ k v r .
  Ord k =>
  Show k =>
  Members [Input k, AtomicState (Map k (MVar v)), Embed IO] r =>
  InterpreterFor (Responses k v !! RpcError) r
interpretResponsesAtomic =
  interpretResumable \case
    Add -> do
      k <- input
      resp <- embed newEmptyMVar
      k <$ atomicModify' (Map.insert k resp)
    Wait k -> do
      v <- atomicGets (Map.lookup k)
      failAbsentKey k (waitAndRemove k) v
    Respond k v -> do
      stored <- atomicGets (Map.lookup k)
      failAbsentKey k (void . embed . flip tryPutMVar v) stored

interpretResponses ::
  ∀ k v r .
  Ord k =>
  Num k =>
  Show k =>
  Member (Embed IO) r =>
  InterpreterFor (Responses k v !! RpcError) r
interpretResponses =
  interpretAtomic (mempty :: Map k (MVar v)) .
  interpretInputNum .
  interpretResponsesAtomic .
  raiseUnder2