mirror of
https://github.com/zap-proto/haskell.git
synced 2026-10-30 15:05:00 +00:00
65 lines
2.7 KiB
Haskell
65 lines
2.7 KiB
Haskell
{-# LANGUAGE DataKinds #-}
|
|
{-# LANGUAGE DuplicateRecordFields #-}
|
|
{-# LANGUAGE FlexibleContexts #-}
|
|
{-# LANGUAGE OverloadedStrings #-}
|
|
{-# LANGUAGE TypeFamilies #-}
|
|
-- |
|
|
-- Module: Capnp.GenHelpers.Rpc
|
|
-- Description: Rpc-system helpers for genrated code.
|
|
--
|
|
-- This module defines various helpers used by generated code. Users
|
|
-- of the library are not expected to use this module directly.
|
|
module Capnp.GenHelpers.Rpc where
|
|
|
|
import Control.Exception.Safe (fromException, tryAny)
|
|
import Control.Monad.Catch (MonadThrow (..))
|
|
import Data.Default (def)
|
|
|
|
import Capnp.Classes (Decerialize (..), FromPtr (..))
|
|
import Capnp.Message (Mutability (..))
|
|
import Capnp.TraversalLimit (evalLimitT)
|
|
|
|
import qualified Capnp.Errors as E
|
|
import qualified Capnp.GenHelpers.Pure as PH
|
|
import qualified Capnp.Message as M
|
|
import qualified Capnp.Rpc.Promise as Promise
|
|
import qualified Capnp.Rpc.Untyped as Rpc
|
|
import qualified Capnp.Untyped as U
|
|
|
|
handleMethod server method paramContent fulfiller = do
|
|
ret <- tryAny $ do
|
|
content <- evalLimitT maxBound $
|
|
fromPtr M.empty paramContent >>= decerialize
|
|
results <- method content server
|
|
evalLimitT maxBound $ PH.convertValue results
|
|
case ret of
|
|
Right resultStruct ->
|
|
Promise.fulfill fulfiller resultStruct
|
|
Left e ->
|
|
case fromException e of
|
|
Just exn ->
|
|
Promise.breakPromise fulfiller exn
|
|
Nothing ->
|
|
Promise.breakPromise fulfiller def
|
|
{ Rpc.type_ = Rpc.Exception'Type'failed
|
|
, Rpc.reason = "Method threw an unhandled exception."
|
|
}
|
|
|
|
-- | A valid implementation of 'fromPtr' for any type that implements 'IsClient'.
|
|
--
|
|
-- GHC gets very confused if we try to just define a single instance
|
|
-- @IsClient a => FromPtr msg a@, so instead we define this helper function and
|
|
-- emit a trivial instance for each type from the code generator.
|
|
isClientFromPtr :: (Rpc.IsClient a, U.ReadCtx m mut) => M.Message mut -> Maybe (U.Ptr mut) -> m a
|
|
isClientFromPtr _ Nothing = pure $ Rpc.fromClient Rpc.nullClient
|
|
isClientFromPtr _ (Just (U.PtrCap cap)) = Rpc.fromClient <$> U.getClient cap
|
|
isClientFromPtr _ (Just _) = throwM $ E.SchemaViolationError "Expected capability pointer"
|
|
|
|
-- | A valid implementation of 'toPtr' for any type that implements 'IsClient'.
|
|
--
|
|
-- See the notes for 'isClientFromPtr'.
|
|
isClientToPtr :: (Rpc.IsClient a, M.WriteCtx m s) => M.Message ('Mut s) -> a -> m (Maybe (U.Ptr ('Mut s)))
|
|
isClientToPtr msg client = do
|
|
cap <- U.appendCap msg (Rpc.toClient client)
|
|
pure $ Just $ U.PtrCap cap
|