-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Reduce code duplication for serving IO methods.
The downside is that the IO-ness of the server method is now part of the interface, but callers don't really care because they are already in a MonadIO.
- Loading branch information
Showing
9 changed files
with
245 additions
and
328 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,148 @@ | ||
module Network.MessagePack.Interface | ||
( Returns | ||
, Interface | ||
, interface | ||
, call | ||
, concrete | ||
, method | ||
, methodIO | ||
, Doc (Arg, Ret) | ||
) where | ||
|
||
import Network.MessagePack.Interface.Internal | ||
{-# LANGUAGE FlexibleContexts #-} | ||
{-# LANGUAGE FlexibleInstances #-} | ||
{-# LANGUAGE InstanceSigs #-} | ||
{-# LANGUAGE MultiParamTypeClasses #-} | ||
{-# LANGUAGE OverloadedStrings #-} | ||
{-# LANGUAGE Safe #-} | ||
{-# LANGUAGE ScopedTypeVariables #-} | ||
{-# LANGUAGE StandaloneDeriving #-} | ||
{-# LANGUAGE TypeFamilies #-} | ||
module Network.MessagePack.Interface where | ||
|
||
import Control.Monad.Catch (MonadThrow) | ||
import Control.Monad.Trans (MonadIO) | ||
import Data.Text (Text) | ||
import qualified Data.Text as Text | ||
import Data.Typeable (Typeable) | ||
import qualified Data.Typeable as Typeable | ||
|
||
import qualified Network.MessagePack.Types.Client as Client | ||
import Network.MessagePack.Types.Server (Method, MethodDocs (..), | ||
MethodVal (..)) | ||
import qualified Network.MessagePack.Types.Server as Server | ||
|
||
|
||
data Interface f = Interface | ||
{ name :: !Text | ||
, docs :: !(Doc f) | ||
} | ||
|
||
|
||
newtype InterfaceM (m :: * -> *) f = InterfaceM | ||
{ nameM :: Text | ||
} | ||
|
||
|
||
interface :: Text -> Doc f -> Interface f | ||
interface = Interface | ||
|
||
|
||
concrete :: Interface f -> InterfaceM m f | ||
concrete = InterfaceM . name | ||
|
||
|
||
-------------------------------------------------------------------------------- | ||
-- | ||
-- :: Documentation | ||
-- | ||
-------------------------------------------------------------------------------- | ||
|
||
|
||
class IsDocType f where | ||
data Doc f | ||
flatDoc :: Doc f -> MethodDocs | ||
|
||
data Returns r | ||
|
||
instance Typeable r => IsDocType (Returns r) where | ||
data Doc (Returns r) = Ret Text | ||
deriving (Eq, Read, Show) | ||
flatDoc (Ret retName) = | ||
MethodDocs [] (MethodVal retName (typeName (undefined :: r))) | ||
|
||
data ReturnsM (m :: * -> *) r | ||
|
||
instance Typeable r => IsDocType (ReturnsM m r) where | ||
data Doc (ReturnsM m r) = RetM Text | ||
deriving (Eq, Read, Show) | ||
flatDoc (RetM retName) = | ||
MethodDocs [] (MethodVal retName (typeName (undefined :: r))) | ||
|
||
instance (Typeable o, IsDocType r) => IsDocType (o -> r) where | ||
data Doc (o -> r) = Arg Text (Doc r) | ||
flatDoc (Arg o r) = | ||
let doc = flatDoc r in | ||
let ty = typeName (undefined :: o) in | ||
doc { methodArgs = MethodVal o ty : methodArgs doc } | ||
|
||
deriving instance Eq (Doc r) => Eq (Doc (o -> r)) | ||
deriving instance Read (Doc r) => Read (Doc (o -> r)) | ||
deriving instance Show (Doc r) => Show (Doc (o -> r)) | ||
|
||
|
||
typeName :: Typeable a => a -> Text | ||
typeName = Text.replace "[Char]" "String" . Text.pack . show . Typeable.typeOf | ||
|
||
|
||
-------------------------------------------------------------------------------- | ||
-- | ||
-- :: Client | ||
-- | ||
-------------------------------------------------------------------------------- | ||
|
||
|
||
class IsClientType (m :: * -> *) f where | ||
type ClientType m f | ||
|
||
instance IsClientType m r => IsClientType m (o -> r) where | ||
type ClientType m (o -> r) = o -> ClientType m r | ||
|
||
|
||
call :: Client.RpcType (ClientType m f) => InterfaceM m f -> ClientType m f | ||
call = Client.call . nameM | ||
|
||
|
||
-------------------------------------------------------------------------------- | ||
-- | ||
-- :: Server | ||
-- | ||
-------------------------------------------------------------------------------- | ||
|
||
|
||
class IsReturnType (m :: * -> *) f where | ||
type HaskellType f | ||
type ServerType m f | ||
|
||
implement :: InterfaceM m f -> HaskellType f -> ServerType m f | ||
|
||
|
||
instance IsReturnType m r => IsReturnType m (o -> r) where | ||
type HaskellType (o -> r) = o -> HaskellType r | ||
type ServerType m (o -> r) = o -> ServerType m r | ||
|
||
implement i f a = next (coerce i) (f a) | ||
where | ||
next :: InterfaceM m r -> HaskellType r -> ServerType m r | ||
next = implement | ||
|
||
coerce :: InterfaceM m a -> InterfaceM m b | ||
coerce = InterfaceM . nameM | ||
|
||
|
||
methodM | ||
:: ( Server.MethodType m (ServerType m f) | ||
, IsDocType f | ||
, IsReturnType m f | ||
, MonadThrow m | ||
) | ||
=> InterfaceM m f -> Doc f -> HaskellType f -> Method m | ||
methodM i doc f = Server.method (nameM i) (flatDoc doc) (implement i f) | ||
|
||
|
||
method | ||
:: ( MonadThrow m | ||
, Server.MethodType m (ServerType m f) | ||
, IsDocType f | ||
, IsReturnType m f) | ||
=> Interface f -> HaskellType f -> Method m | ||
method i = methodM (concrete i) (docs i) |
Oops, something went wrong.