Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
Q
quasar-network
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package Registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Jens Nolte
quasar-network
Commits
962db62b
Commit
962db62b
authored
3 years ago
by
Jens Nolte
Browse files
Options
Downloads
Patches
Plain Diff
Implement extendable codegen interface
parent
cfa5fe3b
No related branches found
No related tags found
No related merge requests found
Pipeline
#2303
passed
3 years ago
Changes
2
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
src/Quasar/Network/Runtime.hs
+2
-2
2 additions, 2 deletions
src/Quasar/Network/Runtime.hs
src/Quasar/Network/TH.hs
+216
-138
216 additions, 138 deletions
src/Quasar/Network/TH.hs
with
218 additions
and
140 deletions
src/Quasar/Network/Runtime.hs
+
2
−
2
View file @
962db62b
...
...
@@ -63,7 +63,7 @@ type ProtocolResponseWrapper p = (MessageId, ProtocolResponse p)
class
RpcProtocol
p
=>
HasProtocolImpl
p
where
type
ProtocolImpl
p
handle
Message
::
ProtocolImpl
p
->
[
Channel
]
->
ProtocolRequest
p
->
IO
(
Maybe
(
ProtocolResponse
p
))
handle
Request
::
ProtocolImpl
p
->
Channel
->
ProtocolRequest
p
->
[
Channel
]
->
IO
(
Maybe
(
ProtocolResponse
p
))
data
Client
p
=
Client
{
...
...
@@ -126,7 +126,7 @@ serverHandleChannelMessage protocolImpl channel resources msg = case decodeOrFai
Right
(
leftovers
,
_
,
_
)
->
channelReportProtocolError
channel
(
"Request parser pureed unexpected leftovers: "
<>
show
(
BSL
.
length
leftovers
))
where
serverHandleChannelRequest
::
[
Channel
]
->
ProtocolRequest
p
->
IO
()
serverHandleChannelRequest
channels
req
=
handle
Message
@
p
protocolImpl
channel
s
req
>>=
maybe
(
pure
()
)
serverSendResponse
serverHandleChannelRequest
channels
req
=
handle
Request
@
p
protocolImpl
channel
req
channels
>>=
maybe
(
pure
()
)
serverSendResponse
serverSendResponse
::
ProtocolResponse
p
->
IO
()
serverSendResponse
response
=
channelSendSimple
channel
(
encode
wrappedResponse
)
where
...
...
This diff is collapsed.
Click to expand it.
src/Quasar/Network/TH.hs
+
216
−
138
View file @
962db62b
...
...
@@ -20,7 +20,7 @@ import Control.Monad.State (State, execState)
import
qualified
Control.Monad.State
as
State
import
Data.Binary
(
Binary
)
import
Data.Maybe
(
isNothing
)
import
GHC.
Generics
import
GHC.
Records.Compat
(
HasField
)
import
Language.Haskell.TH
hiding
(
interruptible
)
import
Language.Haskell.TH.Syntax
import
Quasar.Network.Multiplexer
...
...
@@ -88,10 +88,12 @@ setFixedHandler handler = State.modify (\fun -> fun{fixedHandler = Just handler}
-- | Generates rpc protocol types, rpc client and rpc server
makeRpc
::
RpcApi
->
Q
[
Dec
]
makeRpc
api
=
mconcat
<$>
sequence
[
makeProtocol
api
,
makeClient
api
,
makeServer
api
]
makeRpc
api
=
do
code
<-
mconcat
<$>
sequence
(
generateFunction
api
<$>
api
.
functions
)
mconcat
<$>
sequence
[
makeProtocol
api
code
,
makeClient
code
,
makeServer
api
code
]
makeProtocol
::
RpcApi
->
Q
[
Dec
]
makeProtocol
api
@
RpcApi
{
functions
}
=
sequence
[
protocolDec
,
protocolInstanceDec
,
message
Dec
,
responseDec
]
makeProtocol
::
RpcApi
->
Code
->
Q
[
Dec
]
makeProtocol
api
code
=
sequence
[
protocolDec
,
protocolInstanceDec
,
request
Dec
,
responseDec
]
where
protocolDec
::
Q
Dec
protocolDec
=
dataD
(
pure
[]
)
(
protocolTypeName
api
)
[]
Nothing
[]
[]
...
...
@@ -102,34 +104,199 @@ makeProtocol api@RpcApi{functions} = sequence [protocolDec, protocolInstanceDec,
tySynInstD
(
tySynEqn
Nothing
(
appT
(
conT
''ProtocolResponse
)
(
protocolType
api
))
(
conT
(
responseTypeName
api
)))
]
message
Dec
::
Q
Dec
message
Dec
=
dataD
(
pure
[]
)
(
requestTypeName
api
)
[]
Nothing
(
message
Con
<$>
function
s
)
serializableTypeDerivClauses
request
Dec
::
Q
Dec
request
Dec
=
dataD
(
pure
[]
)
(
requestTypeName
api
)
[]
Nothing
(
request
Con
<$>
code
.
request
s
)
serializableTypeDerivClauses
where
messageCon
::
RpcFunction
->
Q
Con
messageCon
fun
=
normalC
(
requestFunctionCtorName
api
fun
)
(
messageConVar
<$>
fun
.
arguments
)
where
messageConVar
::
RpcArgument
->
Q
BangType
messageConVar
(
RpcArgument
_name
ty
)
=
defaultBangType
ty
requestCon
::
Request
->
Q
Con
requestCon
req
=
normalC
(
requestConName
api
req
)
(
defaultBangType
.
(
.
ty
)
<$>
req
.
fields
)
responseDec
::
Q
Dec
responseDec
=
dataD
(
pure
[]
)
(
responseTypeName
api
)
[]
Nothing
(
responseCon
<$>
filter
hasResult
functions
)
serializableTypeDerivClauses
responseDec
=
do
dataD
(
pure
[]
)
(
responseTypeName
api
)
[]
Nothing
(
responseCon
<$>
catMaybes
((
.
mResponse
)
<$>
code
.
requests
))
serializableTypeDerivClauses
where
responseCon
::
RpcFunction
->
Q
Con
responseCon
fun
=
normalC
(
responseFunctionCtorName
api
fun
)
[
defaultBangType
(
resultTupleType
fun
)]
resultTupleType
::
RpcFunction
->
Q
Type
resultTupleType
fun
=
buildTupleType
(
sequence
((
.
ty
)
<$>
fun
.
results
))
responseCon
::
Response
->
Q
Con
responseCon
resp
=
normalC
(
responseConName
api
resp
)
(
defaultBangType
.
(
.
ty
)
<$>
resp
.
fields
)
serializableTypeDerivClauses
::
[
Q
DerivClause
]
serializableTypeDerivClauses
=
[
derivClause
Nothing
[
[
t
|
Eq
|]
,
[
t
|
Show
|]
,
[
t
|
Generic
|]
,
[
t
|
Binary
|]
]
]
makeClient
::
RpcApi
->
Q
[
Dec
]
makeClient
api
@
RpcApi
{
functions
}
=
do
mconcat
<$>
mapM
makeClientFunction
functions
makeClient
::
Code
->
Q
[
Dec
]
makeClient
code
=
sequence
code
.
stubDecs
makeServer
::
RpcApi
->
Code
->
Q
[
Dec
]
makeServer
api
@
RpcApi
{
functions
}
code
=
sequence
[
protocolImplDec
,
logicInstanceDec
]
where
makeClientFunction
::
RpcFunction
->
Q
[
Dec
]
makeClientFunction
fun
=
do
protocolImplDec
::
Q
Dec
protocolImplDec
=
do
dataD
(
pure
[]
)
(
implTypeName
api
)
[]
Nothing
[
recC
(
implTypeName
api
)
code
.
serverImplFields
]
[]
functionImplType
::
RpcFunction
->
Q
Type
functionImplType
fun
=
do
argumentTypes
<-
functionArgumentTypes
fun
streamTypes
<-
serverStreamTypes
buildFunctionType
(
pure
(
argumentTypes
<>
streamTypes
))
[
t
|
IO $(buildTupleType (functionResultTypes fun))
|]
where
serverStreamTypes
::
Q
[
Type
]
serverStreamTypes
=
sequence
$
(
\
stream
->
[
t
|
Stream $(stream.tyDown) $(stream.tyUp)
|]
)
<$>
fun
.
streams
logicInstanceDec
::
Q
Dec
logicInstanceDec
=
instanceD
(
cxt
[]
)
[
t
|
HasProtocolImpl $(protocolType api)
|]
[
tySynInstD
(
tySynEqn
Nothing
[
t
|
ProtocolImpl $(protocolType api)
|]
(
implType
api
)),
requestHandler
]
requestHandler
::
Q
Dec
requestHandler
=
do
requestHandlerPrimeName
<-
newName
"handleRequest"
implRecordName
<-
newName
"implementation"
channelName
<-
newName
"onChannel"
funD
'handleRequest
[
clause
[
varP
implRecordName
,
varP
channelName
]
(
normalB
(
varE
requestHandlerPrimeName
))
[
funD
requestHandlerPrimeName
(
requestHandlerClauses
implRecordName
channelName
)]]
where
requestHandlerClauses
::
Name
->
Name
->
[
Q
Clause
]
requestHandlerClauses
implRecordName
channelName
=
(
mconcat
$
(
requestClauses
implRecordName
channelName
)
<$>
code
.
requests
)
requestClauses
::
Name
->
Name
->
Request
->
[
Q
Clause
]
requestClauses
implRecordName
channelName
req
=
[
mainClause
,
invalidChannelCountClause
]
where
mainClause
::
Q
Clause
mainClause
=
do
channelNames
<-
sequence
$
newName
.
(
"channel"
<>
)
.
show
<$>
[
0
..
(
req
.
numPipelinedChannels
-
1
)]
fieldNames
<-
sequence
$
newName
.
(
.
name
)
<$>
req
.
fields
let
requestConP
=
conP
(
requestConName
api
req
)
(
varP
<$>
fieldNames
)
ctx
=
RequestHandlerContext
{
implRecordE
=
varE
implRecordName
,
argumentEs
=
(
varE
<$>
fieldNames
),
channelEs
=
(
varE
<$>
channelNames
)
}
clause
[
requestConP
,
listP
(
varP
<$>
channelNames
)]
(
normalB
(
packResponse
req
.
mResponse
(
req
.
handlerE
ctx
)))
[]
invalidChannelCountClause
::
Q
Clause
invalidChannelCountClause
=
do
channelsName
<-
newName
"newChannels"
let
requestConP
=
conP
(
requestConName
api
req
)
(
replicate
(
length
req
.
fields
)
wildP
)
clause
[
requestConP
,
varP
channelsName
]
(
normalB
[
|$
(
varE
'reportInvalidChannelCount
)
$
(
litE
(
integerL
(
toInteger
req
.
numPipelinedChannels
)))
$
(
varE
channelsName
)
$
(
varE
channelName
)
|
])
[]
packResponse
::
Maybe
Response
->
Q
Exp
->
Q
Exp
packResponse
Nothing
handlerE
=
[
|
Nothing
<$
$
(
handlerE
)
|
]
packResponse
(
Just
response
)
handlerE
=
[
|
Just
.
$
(
conE
(
responseConName
api
response
))
<$>
$
handlerE
|
]
-- * Pluggable codegen interface
data
Code
=
Code
{
stubDecs
::
[
Q
Dec
],
serverImplFields
::
[
Q
VarBangType
],
requests
::
[
Request
]
}
instance
Semigroup
Code
where
x
<>
y
=
Code
{
stubDecs
=
x
.
stubDecs
<>
y
.
stubDecs
,
serverImplFields
=
x
.
serverImplFields
<>
y
.
serverImplFields
,
requests
=
x
.
requests
<>
y
.
requests
}
instance
Monoid
Code
where
mempty
=
Code
{
stubDecs
=
[]
,
serverImplFields
=
[]
,
requests
=
[]
}
data
Request
=
Request
{
name
::
String
,
fields
::
[
Field
],
numPipelinedChannels
::
Int
,
mResponse
::
Maybe
Response
,
handlerE
::
RequestHandlerContext
->
Q
Exp
}
data
Response
=
Response
{
name
::
String
,
fields
::
[
Field
]
--numCreatedChannels :: Int
}
data
Field
=
Field
{
name
::
String
,
ty
::
Q
Type
}
toField
::
(
HasField
"name"
a
String
,
HasField
"ty"
a
(
Q
Type
))
=>
a
->
Field
toField
x
=
Field
{
name
=
x
.
name
,
ty
=
x
.
ty
}
data
RequestHandlerContext
=
RequestHandlerContext
{
implRecordE
::
Q
Exp
,
argumentEs
::
[
Q
Exp
],
channelEs
::
[
Q
Exp
]
}
-- * Rpc function code generator
generateFunction
::
RpcApi
->
RpcFunction
->
Q
Code
generateFunction
api
fun
=
do
stubDecs
<-
clientFunctionStub
pure
Code
{
stubDecs
,
serverImplFields
=
if
isNothing
fun
.
fixedHandler
then
[
varDefaultBangType
implFieldName
implSig
]
else
[]
,
requests
=
[
request
]
}
where
request
::
Request
request
=
Request
{
name
=
fun
.
name
,
fields
=
toField
<$>
fun
.
arguments
,
numPipelinedChannels
=
length
fun
.
streams
,
mResponse
=
if
hasResult
fun
then
Just
response
else
Nothing
,
handlerE
=
serverRequestHandlerE
}
response
::
Response
response
=
Response
{
name
=
fun
.
name
,
-- TODO unpack?
fields
=
[
Field
{
name
=
"packedResponse"
,
ty
=
buildTupleType
(
sequence
((
.
ty
)
<$>
fun
.
results
))
}
]
--numCreatedChannels = undefined
}
implFieldName
::
Name
implFieldName
=
functionImplFieldName
api
fun
implSig
::
Q
Type
implSig
=
do
argumentTypes
<-
functionArgumentTypes
fun
streamTypes
<-
serverStreamTypes
buildFunctionType
(
pure
(
argumentTypes
<>
streamTypes
))
[
t
|
IO $(buildTupleType (functionResultTypes fun))
|]
where
serverStreamTypes
::
Q
[
Type
]
serverStreamTypes
=
sequence
$
(
\
stream
->
[
t
|
Stream $(stream.tyDown) $(stream.tyUp)
|]
)
<$>
fun
.
streams
serverRequestHandlerE
::
RequestHandlerContext
->
Q
Exp
serverRequestHandlerE
ctx
=
applyChannels
ctx
.
channelEs
(
applyArgs
(
implFieldE
ctx
.
implRecordE
))
where
implFieldE
::
Q
Exp
->
Q
Exp
implFieldE
implRecordE
=
case
fun
.
fixedHandler
of
Nothing
->
[
|$
(
varE
implFieldName
)
$
implRecordE
|
]
Just
handler
->
[
|$
(
handler
)
::
$
implSig
|
]
applyArgs
::
Q
Exp
->
Q
Exp
applyArgs
implE
=
foldl
appE
implE
ctx
.
argumentEs
applyChannels
::
[
Q
Exp
]
->
Q
Exp
->
Q
Exp
applyChannels
[]
implE
=
implE
applyChannels
(
channel0E
:
channelEs
)
implE
=
varE
'join
`
appE
`
foldl
(
\
x
y
->
[
|$
x
<*>
$
y
|
])
([
|$
implE
<$>
$
(
createStream
channel0E
)
|
])
(
createStream
<$>
channelEs
)
where
createStream
::
Q
Exp
->
Q
Exp
createStream
=
(
varE
'newStream
`
appE
`)
clientFunctionStub
::
Q
[
Q
Dec
]
clientFunctionStub
=
do
clientVarName
<-
newName
"client"
argNames
<-
sequence
(
newName
.
(
.
name
)
<$>
fun
.
arguments
)
channelNames
<-
sequence
(
newName
.
(
<>
"Channel"
)
.
(
.
name
)
<$>
fun
.
streams
)
...
...
@@ -138,13 +305,13 @@ makeClient api@RpcApi{functions} = do
where
funName
::
Name
funName
=
mkName
fun
.
name
makeClientFunction'
::
Name
->
[
Name
]
->
[
Name
]
->
[
Name
]
->
Q
[
Dec
]
makeClientFunction'
::
Name
->
[
Name
]
->
[
Name
]
->
[
Name
]
->
Q
[
Q
Dec
]
makeClientFunction'
clientVarName
argNames
channelNames
streamNames
=
do
funArgTypes
<-
functionArgumentTypes
fun
clientType
<-
[
t
|
Client $(protocolType api)
|]
resultType
<-
optionalResultType
streamTypes
<-
clientStreamTypes
sequenc
e
[
pur
e
[
sigD
funName
(
buildFunctionType
(
pure
([
clientType
]
<>
funArgTypes
))
[
t
|
IO $(buildTupleType (pure (resultType <> streamTypes)))
|]
),
funD
funName
[
clause
([
varP
clientVarName
]
<>
varPats
)
body
[]
]
]
...
...
@@ -161,10 +328,12 @@ makeClient api@RpcApi{functions} = do
varPats
=
varP
<$>
argNames
body
::
Q
Body
body
|
hasResult
fun
=
normalB
$
doE
$
|
hasResult
fun
=
do
responseName
<-
newName
"response"
normalB
$
doE
$
[
bindS
[
p
|
(response, resources)
|]
(
requestE
requestDataE
),
bindS
[
p
|
result
|]
(
checkResult
[
|
response
|
]
)
bindS
[
p
|
(
$(varP
response
Name)
, resources)
|]
(
requestE
requestDataE
),
bindS
[
p
|
result
|]
(
checkResult
(
varE
response
Name
)
)
]
<>
createStreams
[
|
resources
.
createdChannels
|
]
<>
[
noBindS
[
|
pure
$
(
buildTuple
(
liftA2
(
:
)
[
|
result
|
]
streamsE
))
|
]]
...
...
@@ -173,7 +342,7 @@ makeClient api@RpcApi{functions} = do
createStreams
[
|
resources
.
createdChannels
|
]
<>
[
noBindS
[
|
pure
$
(
buildTuple
streamsE
)
|
]]
requestDataE
::
Q
Exp
requestDataE
=
applyVars
(
conE
(
requestFunctionC
tor
Name
api
fun
))
requestDataE
=
applyVars
(
conE
(
requestFunctionC
on
Name
api
fun
))
createStreams
::
Q
Exp
->
[
Q
Stmt
]
createStreams
channelsE
=
if
length
fun
.
streams
>
0
then
[
assignChannels
]
<>
go
channelNames
streamNames
else
[
verifyNoChannels
]
where
...
...
@@ -223,111 +392,6 @@ makeClient api@RpcApi{functions} = do
typedRequest
::
Q
Exp
typedRequest
=
appTypeE
(
varE
'clientRequestBlocking
)
(
protocolType
api
)
makeServer
::
RpcApi
->
Q
[
Dec
]
makeServer
api
@
RpcApi
{
functions
}
=
sequence
[
handlerRecordDec
,
logicInstanceDec
]
where
handlerRecordDec
::
Q
Dec
handlerRecordDec
=
dataD
(
pure
[]
)
(
implTypeName
api
)
[]
Nothing
[
recC
(
implTypeName
api
)
(
handlerRecordField
<$>
functionsWithoutBuiltinHandler
)]
[]
functionsWithoutBuiltinHandler
::
[
RpcFunction
]
functionsWithoutBuiltinHandler
=
filter
(
isNothing
.
fixedHandler
)
functions
handlerRecordField
::
RpcFunction
->
Q
VarBangType
handlerRecordField
fun
=
varDefaultBangType
(
implFieldName
api
fun
)
(
handlerFunctionType
fun
)
handlerFunctionType
::
RpcFunction
->
Q
Type
handlerFunctionType
fun
=
do
argumentTypes
<-
functionArgumentTypes
fun
streamTypes
<-
serverStreamTypes
buildFunctionType
(
pure
(
argumentTypes
<>
streamTypes
))
[
t
|
IO $(buildTupleType (functionResultTypes fun))
|]
where
serverStreamTypes
::
Q
[
Type
]
serverStreamTypes
=
sequence
$
(
\
stream
->
[
t
|
Stream $(stream.tyDown) $(stream.tyUp)
|]
)
<$>
fun
.
streams
logicInstanceDec
::
Q
Dec
logicInstanceDec
=
instanceD
(
cxt
[]
)
[
t
|
HasProtocolImpl $(protocolType api)
|]
[
tySynInstD
(
tySynEqn
Nothing
[
t
|
ProtocolImpl $(protocolType api)
|]
(
implType
api
)),
messageHandler
]
messageHandler
::
Q
Dec
messageHandler
=
do
handleMessagePrimeName
<-
newName
"handleMessage"
implName
<-
newName
"impl"
channelsName
<-
newName
"channels"
funD
'handleMessage
[
clause
[
varP
implName
,
varP
channelsName
]
(
normalB
(
varE
handleMessagePrimeName
))
[
handleMessagePrimeDec
handleMessagePrimeName
(
varE
implName
)
(
varE
channelsName
)]]
where
handleMessagePrimeDec
::
Name
->
Q
Exp
->
Q
Exp
->
Q
Dec
handleMessagePrimeDec
handleMessagePrimeName
implE
channelsE
=
funD
handleMessagePrimeName
(
handlerFunctionClause
<$>
functions
)
where
handlerFunctionClause
::
RpcFunction
->
Q
Clause
handlerFunctionClause
fun
=
do
argNames
<-
sequence
(
newName
.
(
.
name
)
<$>
fun
.
arguments
)
channelNames
<-
sequence
(
newName
.
(
<>
"Channel"
)
.
(
.
name
)
<$>
fun
.
streams
)
streamNames
<-
sequence
(
newName
.
(
.
name
)
<$>
fun
.
streams
)
serverLogicHandlerFunctionClause'
argNames
channelNames
streamNames
where
serverLogicHandlerFunctionClause'
::
[
Name
]
->
[
Name
]
->
[
Name
]
->
Q
Clause
serverLogicHandlerFunctionClause'
argNames
channelNames
streamNames
=
clause
[
conP
(
requestFunctionCtorName
api
fun
)
varPats
]
body
[]
where
varPats
::
[
Q
Pat
]
varPats
=
varP
<$>
argNames
body
::
Q
Body
body
=
normalB
$
doE
$
createStreams
<>
[
callImplementation
]
createStreams
::
[
Q
Stmt
]
createStreams
=
if
length
fun
.
streams
>
0
then
[
assignChannels
]
<>
go
channelNames
streamNames
else
[
verifyNoChannels
]
where
verifyNoChannels
::
Q
Stmt
verifyNoChannels
=
noBindS
[
|
unless
(
null
$
(
channelsE
))
(
fail
"Received invalid channel count"
)
|
]
-- TODO channelReportProtocolError
assignChannels
::
Q
Stmt
assignChannels
=
bindS
(
tupP
(
varP
<$>
channelNames
))
$
caseE
channelsE
[
match
(
listP
(
varP
<$>
channelNames
))
(
normalB
[
|
pure
$
(
tupE
(
varE
<$>
channelNames
))
|
])
[]
,
match
[
p
|
_
|]
(
normalB
[
|
fail
"Received invalid channel count"
|
])
[]
-- TODO channelReportProtocolError
]
go
::
[
Name
]
->
[
Name
]
->
[
Q
Stmt
]
go
[]
[]
=
[]
go
(
cn
:
cns
)
(
sn
:
sns
)
=
createStream
cn
sn
:
go
cns
sns
go
_
_
=
fail
"Logic error: lists have different lengths"
createStream
::
Name
->
Name
->
Q
Stmt
createStream
channelName
streamName
=
bindS
(
varP
streamName
)
[
|$
(
varE
'newStream
)
$
(
varE
channelName
)
|
]
callImplementation
::
Q
Stmt
callImplementation
=
noBindS
callImplementationE
callImplementationE
::
Q
Exp
callImplementationE
|
hasResult
fun
=
[
|
Just
<$>
$
(
packResponse
(
applyStreams
(
applyArguments
implExp
)))
|
]
|
otherwise
=
[
|
Nothing
<$
$
(
applyStreams
(
applyArguments
implExp
))
|
]
packResponse
::
Q
Exp
->
Q
Exp
packResponse
=
fmapE
(
conE
(
responseFunctionCtorName
api
fun
))
applyArguments
::
Q
Exp
->
Q
Exp
applyArguments
=
go
argNames
where
go
::
[
Name
]
->
Q
Exp
->
Q
Exp
go
[]
ex
=
ex
go
(
n
:
ns
)
ex
=
go
ns
(
appE
ex
(
varE
n
))
applyStreams
::
Q
Exp
->
Q
Exp
applyStreams
=
go
streamNames
where
go
::
[
Name
]
->
Q
Exp
->
Q
Exp
go
[]
ex
=
ex
go
(
sn
:
sns
)
ex
=
go
sns
(
appE
ex
(
varE
sn
))
implExp
::
Q
Exp
implExp
=
implExp'
fun
.
fixedHandler
where
implExp'
::
Maybe
(
Q
Exp
)
->
Q
Exp
implExp'
Nothing
=
varE
(
implFieldName
api
fun
)
`
appE
`
implE
implExp'
(
Just
handler
)
=
[
|
let
impl
::
$
(
implSig
)
impl
=
$
(
handler
)
in
impl
|
]
implSig
::
Q
Type
implSig
=
handlerFunctionType
fun
-- * Internal
-- ** Protocol generator helpers
functionArgumentTypes
::
RpcFunction
->
Q
[
Type
]
functionArgumentTypes
fun
=
sequence
$
(
.
ty
)
<$>
fun
.
arguments
functionResultTypes
::
RpcFunction
->
Q
[
Type
]
...
...
@@ -337,7 +401,7 @@ hasResult :: RpcFunction -> Bool
hasResult
fun
=
not
(
null
fun
.
results
)
-- **
*
Name helper functions
-- ** Name helper functions
protocolTypeName
::
RpcApi
->
Name
protocolTypeName
RpcApi
{
name
}
=
mkName
(
name
<>
"Protocol"
)
...
...
@@ -351,8 +415,11 @@ requestTypeIdentifier RpcApi{name} = name <> "ProtocolRequest"
requestTypeName
::
RpcApi
->
Name
requestTypeName
=
mkName
.
requestTypeIdentifier
requestFunctionCtorName
::
RpcApi
->
RpcFunction
->
Name
requestFunctionCtorName
api
fun
=
mkName
(
requestTypeIdentifier
api
<>
"_"
<>
fun
.
name
)
requestFunctionConName
::
RpcApi
->
RpcFunction
->
Name
requestFunctionConName
api
fun
=
mkName
(
requestTypeIdentifier
api
<>
"_"
<>
fun
.
name
)
requestConName
::
RpcApi
->
Request
->
Name
requestConName
api
req
=
mkName
(
requestTypeIdentifier
api
<>
"_"
<>
req
.
name
)
responseTypeIdentifier
::
RpcApi
->
String
responseTypeIdentifier
RpcApi
{
name
}
=
name
<>
"ProtocolResponse"
...
...
@@ -363,16 +430,19 @@ responseTypeName = mkName . responseTypeIdentifier
responseFunctionCtorName
::
RpcApi
->
RpcFunction
->
Name
responseFunctionCtorName
api
fun
=
mkName
(
responseTypeIdentifier
api
<>
"_"
<>
fun
.
name
)
responseConName
::
RpcApi
->
Response
->
Name
responseConName
api
resp
=
mkName
(
responseTypeIdentifier
api
<>
"_"
<>
resp
.
name
)
implTypeName
::
RpcApi
->
Name
implTypeName
RpcApi
{
name
}
=
mkName
$
name
<>
"ProtocolImpl"
implType
::
RpcApi
->
Q
Type
implType
=
conT
.
implTypeName
i
mplFieldName
::
RpcApi
->
RpcFunction
->
Name
i
mplFieldName
_api
fun
=
mkName
(
fun
.
name
<>
"Impl"
)
functionI
mplFieldName
::
RpcApi
->
RpcFunction
->
Name
functionI
mplFieldName
_api
fun
=
mkName
(
fun
.
name
<>
"Impl"
)
-- *
*
Template Haskell helper functions
-- * Template Haskell helper functions
funT
::
Q
Type
->
Q
Type
->
Q
Type
funT
x
=
appT
(
appT
arrowT
x
)
...
...
@@ -412,3 +482,11 @@ varDefaultBangType name qType = varBangType name $ bangType (bang noSourceUnpack
fmapE
::
Q
Exp
->
Q
Exp
->
Q
Exp
fmapE
f
e
=
[
|$
(
f
)
<$>
$
(
e
)
|
]
-- * Error reporting
reportInvalidChannelCount
::
Int
->
[
Channel
]
->
Channel
->
IO
a
reportInvalidChannelCount
expectedCount
newChannels
onChannel
=
channelReportProtocolError
onChannel
msg
where
msg
=
mconcat
parts
parts
=
[
"Received "
,
show
(
length
newChannels
),
" new channels, but expected "
,
show
expectedCount
]
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment