Refactor RequestBroker to support context aware use - introduction of BrokerContext

This commit is contained in:
NagyZoltanPeter 2025-12-17 00:36:03 +01:00
parent 3323325526
commit 07a35f8bd0
No known key found for this signature in database
GPG Key ID: 3E1F97CF4A7B6F42
3 changed files with 497 additions and 41 deletions

View File

@ -203,6 +203,104 @@ suite "RequestBroker macro (async mode)":
DualResponse.clearProvider()
test "supports keyed providers (async, zero-arg)":
SimpleResponse.clearProvider()
check SimpleResponse
.setProvider(
proc(): Future[Result[SimpleResponse, string]] {.async.} =
ok(SimpleResponse(value: "default"))
)
.isOk()
check SimpleResponse
.setProvider(
BrokerContext(0x11111111'u32),
proc(): Future[Result[SimpleResponse, string]] {.async.} =
ok(SimpleResponse(value: "one")),
)
.isOk()
check SimpleResponse
.setProvider(
BrokerContext(0x22222222'u32),
proc(): Future[Result[SimpleResponse, string]] {.async.} =
ok(SimpleResponse(value: "two")),
)
.isOk()
let defaultRes = waitFor SimpleResponse.request()
check defaultRes.isOk()
check defaultRes.value.value == "default"
let res1 = waitFor SimpleResponse.request(BrokerContext(0x11111111'u32))
check res1.isOk()
check res1.value.value == "one"
let res2 = waitFor SimpleResponse.request(BrokerContext(0x22222222'u32))
check res2.isOk()
check res2.value.value == "two"
let missing = waitFor SimpleResponse.request(BrokerContext(0x33333333'u32))
check missing.isErr()
check missing.error.contains("no provider registered for broker context")
check SimpleResponse
.setProvider(
BrokerContext(0x11111111'u32),
proc(): Future[Result[SimpleResponse, string]] {.async.} =
ok(SimpleResponse(value: "dup")),
)
.isErr()
SimpleResponse.clearProvider()
test "supports keyed providers (async, with args)":
KeyedResponse.clearProvider()
check KeyedResponse
.setProvider(
proc(key: string, subKey: int): Future[Result[KeyedResponse, string]] {.async.} =
ok(KeyedResponse(key: "default-" & key, payload: $subKey))
)
.isOk()
check KeyedResponse
.setProvider(
BrokerContext(0xABCDEF01'u32),
proc(key: string, subKey: int): Future[Result[KeyedResponse, string]] {.async.} =
ok(KeyedResponse(key: "k1-" & key, payload: "p" & $subKey)),
)
.isOk()
check KeyedResponse
.setProvider(
BrokerContext(0xABCDEF02'u32),
proc(key: string, subKey: int): Future[Result[KeyedResponse, string]] {.async.} =
ok(KeyedResponse(key: "k2-" & key, payload: "q" & $subKey)),
)
.isOk()
let d = waitFor KeyedResponse.request("topic", 7)
check d.isOk()
check d.value.key == "default-topic"
let k1 = waitFor KeyedResponse.request(BrokerContext(0xABCDEF01'u32), "topic", 7)
check k1.isOk()
check k1.value.key == "k1-topic"
check k1.value.payload == "p7"
let k2 = waitFor KeyedResponse.request(BrokerContext(0xABCDEF02'u32), "topic", 7)
check k2.isOk()
check k2.value.key == "k2-topic"
check k2.value.payload == "q7"
let miss = waitFor KeyedResponse.request(BrokerContext(0xDEADBEEF'u32), "topic", 7)
check miss.isErr()
check miss.error.contains("no provider registered for broker context")
KeyedResponse.clearProvider()
## ---------------------------------------------------------------------------
## Sync-mode brokers + tests
## ---------------------------------------------------------------------------
@ -370,6 +468,71 @@ suite "RequestBroker macro (sync mode)":
ImplicitResponseSync.clearProvider()
test "supports keyed providers (sync, zero-arg)":
SimpleResponseSync.clearProvider()
check SimpleResponseSync
.setProvider(
proc(): Result[SimpleResponseSync, string] =
ok(SimpleResponseSync(value: "default"))
)
.isOk()
check SimpleResponseSync
.setProvider(
BrokerContext(0x10101010'u32),
proc(): Result[SimpleResponseSync, string] =
ok(SimpleResponseSync(value: "ten")),
)
.isOk()
let defaultRes = SimpleResponseSync.request()
check defaultRes.isOk()
check defaultRes.value.value == "default"
let keyedRes = SimpleResponseSync.request(BrokerContext(0x10101010'u32))
check keyedRes.isOk()
check keyedRes.value.value == "ten"
let miss = SimpleResponseSync.request(BrokerContext(0x20202020'u32))
check miss.isErr()
check miss.error.contains("no provider registered for broker context")
SimpleResponseSync.clearProvider()
test "supports keyed providers (sync, with args)":
KeyedResponseSync.clearProvider()
check KeyedResponseSync
.setProvider(
proc(key: string, subKey: int): Result[KeyedResponseSync, string] =
ok(KeyedResponseSync(key: "default-" & key, payload: $subKey))
)
.isOk()
check KeyedResponseSync
.setProvider(
BrokerContext(0xA0A0A0A0'u32),
proc(key: string, subKey: int): Result[KeyedResponseSync, string] =
ok(KeyedResponseSync(key: "k-" & key, payload: "p" & $subKey)),
)
.isOk()
let d = KeyedResponseSync.request("topic", 2)
check d.isOk()
check d.value.key == "default-topic"
let keyed = KeyedResponseSync.request(BrokerContext(0xA0A0A0A0'u32), "topic", 2)
check keyed.isOk()
check keyed.value.key == "k-topic"
check keyed.value.payload == "p2"
let miss = KeyedResponseSync.request(BrokerContext(0xB0B0B0B0'u32), "topic", 2)
check miss.isErr()
check miss.error.contains("no provider registered for broker context")
KeyedResponseSync.clearProvider()
## ---------------------------------------------------------------------------
## POD / external type brokers + tests (distinct/alias behavior)
## ---------------------------------------------------------------------------

View File

@ -0,0 +1,26 @@
import std/[strutils, sysrand]
type BrokerContext* = distinct uint32
func `==`*(a, b: BrokerContext): bool {.borrow.}
func `$`*(bc: BrokerContext): string =
toHex(uint32(bc), 8)
const DefaultBrokerContext* = BrokerContext(0xCAFFE14E'u32)
proc NewBrokerContext*(): BrokerContext =
## Generates a random non-default broker context (as a raw uint32).
##
## The default broker context is reserved for the provider at index 0.
## This helper never returns that value.
for _ in 0 ..< 16:
let b = urandom(4)
if b.len != 4:
continue
let key =
(uint32(b[0]) shl 24) or (uint32(b[1]) shl 16) or (uint32(b[2]) shl 8) or
uint32(b[3])
if key != uint32(DefaultBrokerContext):
return BrokerContext(key)
BrokerContext(1'u32)

View File

@ -16,6 +16,18 @@
## `async` mode is better to be used when you request date that may involve some long IO operation
## or action.
##
## Default vs. context aware use:
## Every generated broker is a thread-local global instance. This means each RequestBroker enables decoupled
## data exchange threadwise. Sometimes we use brokers inside a context - like inside a component that has many modules or subsystems.
## In case you would instantiate multiple such components in a single thread, and each component must has its own provider for the same RequestBroker type,
## in order to avoid provider collision, you can use context aware RequestBroker.
## Context awareness is supported through the `BrokerContext` argument for `setProvider`, `request`, `clearProvider` interfaces.
## Suce use requires generating a new unique `BrokerContext` value per component instance, and spread it to all modules using the brokers.
## Example, store the `BrokerContext` as a field inside the top level component instance, and spread around at initialization of the subcomponents..
##
## Default broker context is defined as `DefaultBrokerContext` constant. But if you don't need context awareness, you can use the
## interfaces without context argument.
##
## Usage:
## Declare your desired request type inside a `RequestBroker` macro, add any number of fields.
## Define the provider signature, that is enforced at compile time.
@ -89,7 +101,13 @@
## After this, you can register a provider anywhere in your code with
## `TypeName.setProvider(...)`, which returns error if already having a provider.
## Providers are async procs/lambdas in default mode and sync procs in sync mode.
## Only one provider can be registered at a time per signature type (zero arg and/or multi arg).
##
## Providers are stored as a broker-context keyed list:
## - the default provider is always stored at index 0 (reserved broker context: 0)
## - additional providers can be registered under arbitrary non-zero broker contexts
##
## The original `setProvider(handler)` / `request(...)` APIs continue to operate
## on the default provider (broker context 0) for backward compatibility.
##
## Requests can be made from anywhere with no direct dependency on the provider by
## calling `TypeName.request()` - with arguments respecting the signature(s).
@ -139,11 +157,12 @@
## automatically, so the caller only needs to provide the type definition.
import std/[macros, strutils]
from std/sequtils import keepItIf
import chronos
import results
import ./helper/broker_utils
import ./helper/broker_utils, broker_context
export results, chronos
export results, chronos, keepItIf, broker_context
proc errorFuture[T](message: string): Future[Result[T, string]] {.inline.} =
## Build a future that is already completed with an error result.
@ -329,11 +348,9 @@ proc generateRequestBroker(body: NimNode, mode: RequestBrokerMode): NimNode =
let typeNameLit = newLit(typeDisplayName)
var zeroArgSig: NimNode = nil
var zeroArgProviderName: NimNode = nil
var zeroArgFieldName: NimNode = nil
var argSig: NimNode = nil
var argParams: seq[NimNode] = @[]
var argProviderName: NimNode = nil
var argFieldName: NimNode = nil
for stmt in body:
case stmt.kind
@ -368,7 +385,6 @@ proc generateRequestBroker(body: NimNode, mode: RequestBrokerMode): NimNode =
error("Only one zero-argument signature is allowed", stmt)
zeroArgSig = stmt
zeroArgProviderName = ident(sanitizeIdentName(typeIdent) & "ProviderNoArgs")
zeroArgFieldName = ident("providerNoArgs")
elif paramCount >= 1:
if argSig != nil:
error("Only one argument-based signature is allowed", stmt)
@ -391,7 +407,6 @@ proc generateRequestBroker(body: NimNode, mode: RequestBrokerMode): NimNode =
error("Signature parameter must declare a name", paramDef)
argParams.add(copyNimTree(paramDef))
argProviderName = ident(sanitizeIdentName(typeIdent) & "ProviderWithArgs")
argFieldName = ident("providerWithArgs")
of nnkTypeSection, nnkEmpty:
discard
else:
@ -400,7 +415,6 @@ proc generateRequestBroker(body: NimNode, mode: RequestBrokerMode): NimNode =
if zeroArgSig.isNil() and argSig.isNil():
zeroArgSig = newEmptyNode()
zeroArgProviderName = ident(sanitizeIdentName(typeIdent) & "ProviderNoArgs")
zeroArgFieldName = ident("providerNoArgs")
var typeSection = newTree(nnkTypeSection)
typeSection.add(newTree(nnkTypeDef, exportedTypeIdent, newEmptyNode(), objectDef))
@ -423,12 +437,29 @@ proc generateRequestBroker(body: NimNode, mode: RequestBrokerMode): NimNode =
var brokerRecList = newTree(nnkRecList)
if not zeroArgSig.isNil():
let zeroArgProvidersFieldName = ident("providersNoArgs")
let zeroArgProvidersTupleTy = newTree(
nnkTupleTy,
newTree(nnkIdentDefs, ident("brokerCtx"), ident("BrokerContext"), newEmptyNode()),
newTree(nnkIdentDefs, ident("handler"), zeroArgProviderName, newEmptyNode()),
)
let zeroArgProvidersSeqTy =
newTree(nnkBracketExpr, ident("seq"), zeroArgProvidersTupleTy)
brokerRecList.add(
newTree(nnkIdentDefs, zeroArgFieldName, zeroArgProviderName, newEmptyNode())
newTree(
nnkIdentDefs, zeroArgProvidersFieldName, zeroArgProvidersSeqTy, newEmptyNode()
)
)
if not argSig.isNil():
let argProvidersFieldName = ident("providersWithArgs")
let argProvidersTupleTy = newTree(
nnkTupleTy,
newTree(nnkIdentDefs, ident("brokerCtx"), ident("BrokerContext"), newEmptyNode()),
newTree(nnkIdentDefs, ident("handler"), argProviderName, newEmptyNode()),
)
let argProvidersSeqTy = newTree(nnkBracketExpr, ident("seq"), argProvidersTupleTy)
brokerRecList.add(
newTree(nnkIdentDefs, argFieldName, argProviderName, newEmptyNode())
newTree(nnkIdentDefs, argProvidersFieldName, argProvidersSeqTy, newEmptyNode())
)
let brokerTypeIdent = ident(sanitizeIdentName(typeIdent) & "Broker")
let brokerTypeDef = newTree(
@ -443,31 +474,97 @@ proc generateRequestBroker(body: NimNode, mode: RequestBrokerMode): NimNode =
let globalVarIdent = ident("g" & sanitizeIdentName(typeIdent) & "Broker")
let accessProcIdent = ident("access" & sanitizeIdentName(typeIdent) & "Broker")
var brokerNewBody = newStmtList()
if not zeroArgSig.isNil():
brokerNewBody.add(
quote do:
result.providersNoArgs =
@[(brokerCtx: DefaultBrokerContext, handler: default(`zeroArgProviderName`))]
)
if not argSig.isNil():
brokerNewBody.add(
quote do:
result.providersWithArgs =
@[(brokerCtx: DefaultBrokerContext, handler: default(`argProviderName`))]
)
var brokerInitChecks = newStmtList()
if not zeroArgSig.isNil():
brokerInitChecks.add(
quote do:
if `globalVarIdent`.providersNoArgs.len == 0:
`globalVarIdent` = `brokerTypeIdent`.new()
)
if not argSig.isNil():
brokerInitChecks.add(
quote do:
if `globalVarIdent`.providersWithArgs.len == 0:
`globalVarIdent` = `brokerTypeIdent`.new()
)
result.add(
quote do:
var `globalVarIdent` {.threadvar.}: `brokerTypeIdent`
proc new(_: type `brokerTypeIdent`): `brokerTypeIdent` =
result = `brokerTypeIdent`()
`brokerNewBody`
proc `accessProcIdent`(): var `brokerTypeIdent` =
`brokerInitChecks`
`globalVarIdent`
)
var clearBody = newStmtList()
var clearBodyKeyed = newStmtList()
let brokerCtxParamIdent = ident("brokerCtx")
if not zeroArgSig.isNil():
let zeroArgProvidersFieldName = ident("providersNoArgs")
result.add(
quote do:
proc setProvider*(
_: typedesc[`typeIdent`], handler: `zeroArgProviderName`
): Result[void, string] =
if not `accessProcIdent`().`zeroArgFieldName`.isNil():
if not `accessProcIdent`().`zeroArgProvidersFieldName`[0].handler.isNil():
return err("Zero-arg provider already set")
`accessProcIdent`().`zeroArgFieldName` = handler
`accessProcIdent`().`zeroArgProvidersFieldName`[0].handler = handler
return ok()
)
clearBody.add(
result.add(
quote do:
`accessProcIdent`().`zeroArgFieldName` = nil
proc setProvider*(
_: typedesc[`typeIdent`],
brokerCtx: BrokerContext,
handler: `zeroArgProviderName`,
): Result[void, string] =
if brokerCtx == DefaultBrokerContext:
return setProvider(`typeIdent`, handler)
for entry in `accessProcIdent`().`zeroArgProvidersFieldName`:
if entry.brokerCtx == brokerCtx:
return err(
"RequestBroker(" & `typeNameLit` &
"): provider already set for broker context " & $brokerCtx
)
`accessProcIdent`().`zeroArgProvidersFieldName`.add(
(brokerCtx: brokerCtx, handler: handler)
)
return ok()
)
clearBodyKeyed.add(
quote do:
if `brokerCtxParamIdent` == DefaultBrokerContext:
`accessProcIdent`().`zeroArgProvidersFieldName`[0].handler =
default(`zeroArgProviderName`)
else:
`accessProcIdent`().`zeroArgProvidersFieldName`.keepItIf(
it.brokerCtx != `brokerCtxParamIdent`
)
)
case mode
of rbAsync:
@ -476,11 +573,34 @@ proc generateRequestBroker(body: NimNode, mode: RequestBrokerMode): NimNode =
proc request*(
_: typedesc[`typeIdent`]
): Future[Result[`typeIdent`, string]] {.async: (raises: []).} =
let provider = `accessProcIdent`().`zeroArgFieldName`
return await request(`typeIdent`, DefaultBrokerContext)
)
result.add(
quote do:
proc request*(
_: typedesc[`typeIdent`], brokerCtx: BrokerContext
): Future[Result[`typeIdent`, string]] {.async: (raises: []).} =
var provider: `zeroArgProviderName`
if brokerCtx == DefaultBrokerContext:
provider = `accessProcIdent`().`zeroArgProvidersFieldName`[0].handler
else:
for entry in `accessProcIdent`().`zeroArgProvidersFieldName`:
if entry.brokerCtx == brokerCtx:
provider = entry.handler
break
if provider.isNil():
if brokerCtx == DefaultBrokerContext:
return err(
"RequestBroker(" & `typeNameLit` & "): no zero-arg provider registered"
)
return err(
"RequestBroker(" & `typeNameLit` & "): no zero-arg provider registered"
"RequestBroker(" & `typeNameLit` &
"): no provider registered for broker context " & $brokerCtx
)
let catchedRes = catch:
await provider()
@ -507,10 +627,32 @@ proc generateRequestBroker(body: NimNode, mode: RequestBrokerMode): NimNode =
proc request*(
_: typedesc[`typeIdent`]
): Result[`typeIdent`, string] {.gcsafe, raises: [].} =
let provider = `accessProcIdent`().`zeroArgFieldName`
return request(`typeIdent`, DefaultBrokerContext)
)
result.add(
quote do:
proc request*(
_: typedesc[`typeIdent`], brokerCtx: BrokerContext
): Result[`typeIdent`, string] {.gcsafe, raises: [].} =
var provider: `zeroArgProviderName`
if brokerCtx == DefaultBrokerContext:
provider = `accessProcIdent`().`zeroArgProvidersFieldName`[0].handler
else:
for entry in `accessProcIdent`().`zeroArgProvidersFieldName`:
if entry.brokerCtx == brokerCtx:
provider = entry.handler
break
if provider.isNil():
if brokerCtx == DefaultBrokerContext:
return err(
"RequestBroker(" & `typeNameLit` & "): no zero-arg provider registered"
)
return err(
"RequestBroker(" & `typeNameLit` & "): no zero-arg provider registered"
"RequestBroker(" & `typeNameLit` &
"): no provider registered for broker context " & $brokerCtx
)
var providerRes: Result[`typeIdent`, string]
@ -533,24 +675,54 @@ proc generateRequestBroker(body: NimNode, mode: RequestBrokerMode): NimNode =
)
if not argSig.isNil():
let argProvidersFieldName = ident("providersWithArgs")
result.add(
quote do:
proc setProvider*(
_: typedesc[`typeIdent`], handler: `argProviderName`
): Result[void, string] =
if not `accessProcIdent`().`argFieldName`.isNil():
if not `accessProcIdent`().`argProvidersFieldName`[0].handler.isNil():
return err("Provider already set")
`accessProcIdent`().`argFieldName` = handler
`accessProcIdent`().`argProvidersFieldName`[0].handler = handler
return ok()
)
clearBody.add(
result.add(
quote do:
`accessProcIdent`().`argFieldName` = nil
proc setProvider*(
_: typedesc[`typeIdent`],
brokerCtx: BrokerContext,
handler: `argProviderName`,
): Result[void, string] =
if brokerCtx == DefaultBrokerContext:
return setProvider(`typeIdent`, handler)
for entry in `accessProcIdent`().`argProvidersFieldName`:
if entry.brokerCtx == brokerCtx:
return err(
"RequestBroker(" & `typeNameLit` &
"): provider already set for broker context " & $brokerCtx
)
`accessProcIdent`().`argProvidersFieldName`.add(
(brokerCtx: brokerCtx, handler: handler)
)
return ok()
)
clearBodyKeyed.add(
quote do:
if `brokerCtxParamIdent` == DefaultBrokerContext:
`accessProcIdent`().`argProvidersFieldName`[0].handler =
default(`argProviderName`)
else:
`accessProcIdent`().`argProvidersFieldName`.keepItIf(
it.brokerCtx != `brokerCtxParamIdent`
)
)
let requestParamDefs = cloneParams(argParams)
let argNameIdents = collectParamNames(requestParamDefs)
let providerSym = genSym(nskLet, "provider")
var formalParams = newTree(nnkFormalParams)
formalParams.add(copyNimTree(returnType))
formalParams.add(
@ -572,29 +744,96 @@ proc generateRequestBroker(body: NimNode, mode: RequestBrokerMode): NimNode =
of rbSync:
quote:
{.gcsafe, raises: [].}
var providerCall = newCall(providerSym)
var forwardCall = newCall(ident("request"))
forwardCall.add(copyNimTree(typeIdent))
forwardCall.add(ident("DefaultBrokerContext"))
for argName in argNameIdents:
providerCall.add(argName)
forwardCall.add(argName)
var requestBody = newStmtList()
requestBody.add(
quote do:
let `providerSym` = `accessProcIdent`().`argFieldName`
case mode
of rbAsync:
requestBody.add(
quote do:
return await `forwardCall`
)
of rbSync:
requestBody.add(
quote do:
return `forwardCall`
)
result.add(
newTree(
nnkProcDef,
postfix(ident("request"), "*"),
newEmptyNode(),
newEmptyNode(),
formalParams,
requestPragmas,
newEmptyNode(),
requestBody,
)
)
requestBody.add(
# Keyed request variant for the argument-based signature.
let requestParamDefsKeyed = cloneParams(argParams)
let argNameIdentsKeyed = collectParamNames(requestParamDefsKeyed)
let providerSymKeyed = genSym(nskVar, "provider")
var formalParamsKeyed = newTree(nnkFormalParams)
formalParamsKeyed.add(copyNimTree(returnType))
formalParamsKeyed.add(
newTree(
nnkIdentDefs,
ident("_"),
newTree(nnkBracketExpr, ident("typedesc"), copyNimTree(typeIdent)),
newEmptyNode(),
)
)
formalParamsKeyed.add(
newTree(nnkIdentDefs, ident("brokerCtx"), ident("BrokerContext"), newEmptyNode())
)
for paramDef in requestParamDefsKeyed:
formalParamsKeyed.add(paramDef)
let requestPragmasKeyed = requestPragmas
var providerCallKeyed = newCall(providerSymKeyed)
for argName in argNameIdentsKeyed:
providerCallKeyed.add(argName)
var requestBodyKeyed = newStmtList()
requestBodyKeyed.add(
quote do:
if `providerSym`.isNil():
var `providerSymKeyed`: `argProviderName`
if brokerCtx == DefaultBrokerContext:
`providerSymKeyed` = `accessProcIdent`().`argProvidersFieldName`[0].handler
else:
for entry in `accessProcIdent`().`argProvidersFieldName`:
if entry.brokerCtx == brokerCtx:
`providerSymKeyed` = entry.handler
break
)
requestBodyKeyed.add(
quote do:
if `providerSymKeyed`.isNil():
if brokerCtx == DefaultBrokerContext:
return err(
"RequestBroker(" & `typeNameLit` &
"): no provider registered for input signature"
)
return err(
"RequestBroker(" & `typeNameLit` &
"): no provider registered for input signature"
"): no provider registered for broker context " & $brokerCtx
)
)
case mode
of rbAsync:
requestBody.add(
requestBodyKeyed.add(
quote do:
let catchedRes = catch:
await `providerCall`
await `providerCallKeyed`
if catchedRes.isErr():
return err(
"RequestBroker(" & `typeNameLit` & "): provider threw exception: " &
@ -612,11 +851,11 @@ proc generateRequestBroker(body: NimNode, mode: RequestBrokerMode): NimNode =
return providerRes
)
of rbSync:
requestBody.add(
requestBodyKeyed.add(
quote do:
var providerRes: Result[`typeIdent`, string]
try:
providerRes = `providerCall`
providerRes = `providerCallKeyed`
except CatchableError as e:
return err(
"RequestBroker(" & `typeNameLit` & "): provider threw exception: " & e.msg
@ -631,24 +870,52 @@ proc generateRequestBroker(body: NimNode, mode: RequestBrokerMode): NimNode =
)
return providerRes
)
# requestBody.add(providerCall)
result.add(
newTree(
nnkProcDef,
postfix(ident("request"), "*"),
newEmptyNode(),
newEmptyNode(),
formalParams,
requestPragmas,
formalParamsKeyed,
requestPragmasKeyed,
newEmptyNode(),
requestBody,
requestBodyKeyed,
)
)
block:
var formalParamsClearKeyed = newTree(nnkFormalParams)
formalParamsClearKeyed.add(newEmptyNode())
formalParamsClearKeyed.add(
newTree(
nnkIdentDefs,
ident("_"),
newTree(nnkBracketExpr, ident("typedesc"), copyNimTree(typeIdent)),
newEmptyNode(),
)
)
formalParamsClearKeyed.add(
newTree(nnkIdentDefs, brokerCtxParamIdent, ident("BrokerContext"), newEmptyNode())
)
result.add(
newTree(
nnkProcDef,
postfix(ident("clearProvider"), "*"),
newEmptyNode(),
newEmptyNode(),
formalParamsClearKeyed,
newEmptyNode(),
newEmptyNode(),
clearBodyKeyed,
)
)
result.add(
quote do:
proc clearProvider*(_: typedesc[`typeIdent`]) =
`clearBody`
clearProvider(`typeIdent`, DefaultBrokerContext)
)