From 26f6dbefa2cec2a6f09d553a4991a88b29d1df37 Mon Sep 17 00:00:00 2001 From: NagyZoltanPeter <113987313+NagyZoltanPeter@users.noreply.github.com> Date: Wed, 17 Dec 2025 08:58:40 +0100 Subject: [PATCH] Move duplicated and common code into broker_utils from event- request- and multi_request_brokers --- waku/common/broker/event_broker.nim | 100 +----------- waku/common/broker/helper/broker_utils.nim | 163 ++++++++++++++++++++ waku/common/broker/multi_request_broker.nim | 117 +------------- waku/common/broker/request_broker.nim | 102 +----------- 4 files changed, 176 insertions(+), 306 deletions(-) diff --git a/waku/common/broker/event_broker.nim b/waku/common/broker/event_broker.nim index f694c2c98..779689f88 100644 --- a/waku/common/broker/event_broker.nim +++ b/waku/common/broker/event_broker.nim @@ -90,103 +90,15 @@ import ./helper/broker_utils, broker_context export chronicles, results, chronos, broker_context -proc ensureDistinctType(rhs: NimNode): NimNode = - ## For PODs / aliases / externally-defined types, wrap in `distinct` unless - ## it's already distinct. - if rhs.kind == nnkDistinctTy: - return rhs - newTree(nnkDistinctTy, copyNimTree(rhs)) - macro EventBroker*(body: untyped): untyped = when defined(eventBrokerDebug): echo body.treeRepr - var typeIdent: NimNode = nil - var objectDef: NimNode = nil - var fieldNames: seq[NimNode] = @[] - var fieldTypes: seq[NimNode] = @[] - var hasInlineFields = false - for stmt in body: - if stmt.kind == nnkTypeSection: - for def in stmt: - if def.kind != nnkTypeDef: - continue - let rhs = def[2] - if not typeIdent.isNil(): - error("Only one type may be declared inside EventBroker", def) - typeIdent = baseTypeIdent(def[0]) - - # Inline object/ref object definitions. - case rhs.kind - of nnkObjectTy: - let recList = rhs[2] - if recList.kind != nnkRecList: - error("EventBroker object must declare a standard field list", rhs) - var exportedRecList = newTree(nnkRecList) - for field in recList: - case field.kind - of nnkIdentDefs: - ensureFieldDef(field) - let fieldTypeNode = field[field.len - 2] - for i in 0 ..< field.len - 2: - let baseFieldIdent = baseTypeIdent(field[i]) - fieldNames.add(copyNimTree(baseFieldIdent)) - fieldTypes.add(copyNimTree(fieldTypeNode)) - var cloned = copyNimTree(field) - for i in 0 ..< cloned.len - 2: - cloned[i] = exportIdentNode(cloned[i]) - exportedRecList.add(cloned) - of nnkEmpty: - discard - else: - error( - "EventBroker object definition only supports simple field declarations", - field, - ) - let exportedObjectType = newTree( - nnkObjectTy, copyNimTree(rhs[0]), copyNimTree(rhs[1]), exportedRecList - ) - objectDef = exportedObjectType - hasInlineFields = true - of nnkRefTy: - if rhs.len != 1 or rhs[0].kind != nnkObjectTy: - error("EventBroker ref object must wrap a concrete object definition", rhs) - let obj = rhs[0] - let recList = obj[2] - if recList.kind != nnkRecList: - error("EventBroker object must declare a standard field list", obj) - var exportedRecList = newTree(nnkRecList) - for field in recList: - case field.kind - of nnkIdentDefs: - ensureFieldDef(field) - let fieldTypeNode = field[field.len - 2] - for i in 0 ..< field.len - 2: - let baseFieldIdent = baseTypeIdent(field[i]) - fieldNames.add(copyNimTree(baseFieldIdent)) - fieldTypes.add(copyNimTree(fieldTypeNode)) - var cloned = copyNimTree(field) - for i in 0 ..< cloned.len - 2: - cloned[i] = exportIdentNode(cloned[i]) - exportedRecList.add(cloned) - of nnkEmpty: - discard - else: - error( - "EventBroker object definition only supports simple field declarations", - field, - ) - let exportedObjectType = newTree( - nnkObjectTy, copyNimTree(obj[0]), copyNimTree(obj[1]), exportedRecList - ) - objectDef = newTree(nnkRefTy, exportedObjectType) - hasInlineFields = true - else: - # Native type / alias / externally-defined type. - # Ensure we create a unique event type by wrapping in `distinct` unless - # the user already did. - objectDef = ensureDistinctType(rhs) - if typeIdent.isNil(): - error("EventBroker body must declare exactly one type", body) + let parsed = parseSingleTypeDef(body, "EventBroker", collectFieldInfo = true) + let typeIdent = parsed.typeIdent + let objectDef = parsed.objectDef + let fieldNames = parsed.fieldNames + let fieldTypes = parsed.fieldTypes + let hasInlineFields = parsed.hasInlineFields let exportedTypeIdent = postfix(copyNimTree(typeIdent), "*") let sanitized = sanitizeIdentName(typeIdent) diff --git a/waku/common/broker/helper/broker_utils.nim b/waku/common/broker/helper/broker_utils.nim index ea9f85750..90f2055d3 100644 --- a/waku/common/broker/helper/broker_utils.nim +++ b/waku/common/broker/helper/broker_utils.nim @@ -1,5 +1,21 @@ import std/macros +type ParsedBrokerType* = object + ## Result of parsing the single `type` definition inside a broker macro body. + ## + ## - `typeIdent`: base identifier for the declared type name + ## - `objectDef`: exported type definition RHS (inline object fields exported; + ## non-object types wrapped in `distinct` unless already distinct) + ## - `isRefObject`: true only for inline `ref object` definitions + ## - `hasInlineFields`: true for inline `object` / `ref object` + ## - `fieldNames`/`fieldTypes`: populated only when `collectFieldInfo = true` + typeIdent*: NimNode + objectDef*: NimNode + isRefObject*: bool + hasInlineFields*: bool + fieldNames*: seq[NimNode] + fieldTypes*: seq[NimNode] + proc sanitizeIdentName*(node: NimNode): string = var raw = $node var sanitizedName = newStringOfCap(raw.len) @@ -41,3 +57,150 @@ proc baseTypeIdent*(defName: NimNode): NimNode = baseTypeIdent(defName[0]) else: error("Unsupported type name in broker definition", defName) + +proc ensureDistinctType*(rhs: NimNode): NimNode = + ## For PODs / aliases / externally-defined types, wrap in `distinct` unless + ## it's already distinct. + if rhs.kind == nnkDistinctTy: + return copyNimTree(rhs) + newTree(nnkDistinctTy, copyNimTree(rhs)) + +proc cloneParams*(params: seq[NimNode]): seq[NimNode] = + ## Deep copy parameter definitions so they can be inserted in multiple places. + result = @[] + for param in params: + result.add(copyNimTree(param)) + +proc collectParamNames*(params: seq[NimNode]): seq[NimNode] = + ## Extract all identifier symbols declared across IdentDefs nodes. + result = @[] + for param in params: + assert param.kind == nnkIdentDefs + for i in 0 ..< param.len - 2: + let nameNode = param[i] + if nameNode.kind == nnkEmpty: + continue + result.add(ident($nameNode)) + +proc parseSingleTypeDef*( + body: NimNode, + macroName: string, + allowRefToNonObject = false, + collectFieldInfo = false, +): ParsedBrokerType = + ## Parses exactly one `type` definition from a broker macro body. + ## + ## Supported RHS: + ## - inline `object` / `ref object` (fields are auto-exported) + ## - non-object types / aliases / externally-defined types (wrapped in `distinct`) + ## - optionally: `ref SomeType` when `allowRefToNonObject = true` + var typeIdent: NimNode = nil + var objectDef: NimNode = nil + var isRefObject = false + var hasInlineFields = false + var fieldNames: seq[NimNode] = @[] + var fieldTypes: seq[NimNode] = @[] + + for stmt in body: + if stmt.kind != nnkTypeSection: + continue + for def in stmt: + if def.kind != nnkTypeDef: + continue + if not typeIdent.isNil(): + error("Only one type may be declared inside " & macroName, def) + typeIdent = baseTypeIdent(def[0]) + let rhs = def[2] + + case rhs.kind + of nnkObjectTy: + let recList = rhs[2] + if recList.kind != nnkRecList: + error(macroName & " object must declare a standard field list", rhs) + var exportedRecList = newTree(nnkRecList) + for field in recList: + case field.kind + of nnkIdentDefs: + ensureFieldDef(field) + if collectFieldInfo: + let fieldTypeNode = field[field.len - 2] + for i in 0 ..< field.len - 2: + let baseFieldIdent = baseTypeIdent(field[i]) + fieldNames.add(copyNimTree(baseFieldIdent)) + fieldTypes.add(copyNimTree(fieldTypeNode)) + var cloned = copyNimTree(field) + for i in 0 ..< cloned.len - 2: + cloned[i] = exportIdentNode(cloned[i]) + exportedRecList.add(cloned) + of nnkEmpty: + discard + else: + error( + macroName & " object definition only supports simple field declarations", + field, + ) + objectDef = newTree( + nnkObjectTy, copyNimTree(rhs[0]), copyNimTree(rhs[1]), exportedRecList + ) + isRefObject = false + hasInlineFields = true + of nnkRefTy: + if rhs.len != 1: + error(macroName & " ref type must have a single base", rhs) + if rhs[0].kind == nnkObjectTy: + let obj = rhs[0] + let recList = obj[2] + if recList.kind != nnkRecList: + error(macroName & " object must declare a standard field list", obj) + var exportedRecList = newTree(nnkRecList) + for field in recList: + case field.kind + of nnkIdentDefs: + ensureFieldDef(field) + if collectFieldInfo: + let fieldTypeNode = field[field.len - 2] + for i in 0 ..< field.len - 2: + let baseFieldIdent = baseTypeIdent(field[i]) + fieldNames.add(copyNimTree(baseFieldIdent)) + fieldTypes.add(copyNimTree(fieldTypeNode)) + var cloned = copyNimTree(field) + for i in 0 ..< cloned.len - 2: + cloned[i] = exportIdentNode(cloned[i]) + exportedRecList.add(cloned) + of nnkEmpty: + discard + else: + error( + macroName & " object definition only supports simple field declarations", + field, + ) + let exportedObjectType = newTree( + nnkObjectTy, copyNimTree(obj[0]), copyNimTree(obj[1]), exportedRecList + ) + objectDef = newTree(nnkRefTy, exportedObjectType) + isRefObject = true + hasInlineFields = true + elif allowRefToNonObject: + ## `ref SomeType` (SomeType can be defined elsewhere) + objectDef = ensureDistinctType(rhs) + isRefObject = false + hasInlineFields = false + else: + error(macroName & " ref object must wrap a concrete object definition", rhs) + else: + ## Non-object type / alias. + objectDef = ensureDistinctType(rhs) + isRefObject = false + hasInlineFields = false + + if typeIdent.isNil(): + error(macroName & " body must declare exactly one type", body) + + result = ParsedBrokerType( + typeIdent: typeIdent, + objectDef: objectDef, + isRefObject: isRefObject, + hasInlineFields: hasInlineFields, + fieldNames: fieldNames, + fieldTypes: fieldTypes, + ) diff --git a/waku/common/broker/multi_request_broker.nim b/waku/common/broker/multi_request_broker.nim index c2b9cf66f..2baa19940 100644 --- a/waku/common/broker/multi_request_broker.nim +++ b/waku/common/broker/multi_request_broker.nim @@ -122,23 +122,6 @@ proc isReturnTypeValid(returnType, typeIdent: NimNode): bool = return false inner[2].kind == nnkIdent and inner[2].eqIdent("string") -proc cloneParams(params: seq[NimNode]): seq[NimNode] = - ## Deep copy parameter definitions so they can be reused in generated nodes. - result = @[] - for param in params: - result.add(copyNimTree(param)) - -proc collectParamNames(params: seq[NimNode]): seq[NimNode] = - ## Extract identifiers declared in parameter definitions. - result = @[] - for param in params: - assert param.kind == nnkIdentDefs - for i in 0 ..< param.len - 2: - let nameNode = param[i] - if nameNode.kind == nnkEmpty: - continue - result.add(ident($nameNode)) - proc makeProcType(returnType: NimNode, params: seq[NimNode]): NimNode = var formal = newTree(nnkFormalParams) formal.add(returnType) @@ -150,105 +133,13 @@ proc makeProcType(returnType: NimNode, params: seq[NimNode]): NimNode = newTree(nnkProcTy, formal, pragmas) -proc ensureDistinctType(rhs: NimNode): NimNode = - ## For PODs / aliases / externally-defined types, wrap in `distinct` unless - ## it's already distinct. - if rhs.kind == nnkDistinctTy: - return copyNimTree(rhs) - newTree(nnkDistinctTy, copyNimTree(rhs)) - macro MultiRequestBroker*(body: untyped): untyped = when defined(requestBrokerDebug): echo body.treeRepr - var typeIdent: NimNode = nil - var objectDef: NimNode = nil - var isRefObject = false - for stmt in body: - if stmt.kind == nnkTypeSection: - for def in stmt: - if def.kind != nnkTypeDef: - continue - if not typeIdent.isNil(): - error("Only one type may be declared inside MultiRequestBroker", def) - - typeIdent = baseTypeIdent(def[0]) - let rhs = def[2] - - case rhs.kind - of nnkObjectTy: - let objectType = rhs - let recList = objectType[2] - if recList.kind != nnkRecList: - error( - "MultiRequestBroker object must declare a standard field list", objectType - ) - var exportedRecList = newTree(nnkRecList) - for field in recList: - case field.kind - of nnkIdentDefs: - ensureFieldDef(field) - var cloned = copyNimTree(field) - for i in 0 ..< cloned.len - 2: - cloned[i] = exportIdentNode(cloned[i]) - exportedRecList.add(cloned) - of nnkEmpty: - discard - else: - error( - "MultiRequestBroker object definition only supports simple field declarations", - field, - ) - objectDef = newTree( - nnkObjectTy, - copyNimTree(objectType[0]), - copyNimTree(objectType[1]), - exportedRecList, - ) - of nnkRefTy: - isRefObject = true - if rhs.len != 1 or rhs[0].kind != nnkObjectTy: - error( - "MultiRequestBroker ref object must wrap a concrete object definition", - rhs, - ) - let objectType = rhs[0] - let recList = objectType[2] - if recList.kind != nnkRecList: - error( - "MultiRequestBroker object must declare a standard field list", objectType - ) - var exportedRecList = newTree(nnkRecList) - for field in recList: - case field.kind - of nnkIdentDefs: - ensureFieldDef(field) - var cloned = copyNimTree(field) - for i in 0 ..< cloned.len - 2: - cloned[i] = exportIdentNode(cloned[i]) - exportedRecList.add(cloned) - of nnkEmpty: - discard - else: - error( - "MultiRequestBroker object definition only supports simple field declarations", - field, - ) - let exportedObjectType = newTree( - nnkObjectTy, - copyNimTree(objectType[0]), - copyNimTree(objectType[1]), - exportedRecList, - ) - objectDef = newTree(nnkRefTy, exportedObjectType) - else: - # Native type / alias / externally-defined type. - # Ensure we create a unique request type by wrapping in `distinct` unless - # the user already did. - objectDef = ensureDistinctType(rhs) - isRefObject = false - - if typeIdent.isNil(): - error("MultiRequestBroker body must declare exactly one type", body) + let parsed = parseSingleTypeDef(body, "MultiRequestBroker") + let typeIdent = parsed.typeIdent + let objectDef = parsed.objectDef + let isRefObject = parsed.isRefObject when defined(requestBrokerDebug): echo "MultiRequestBroker generating type: ", $typeIdent diff --git a/waku/common/broker/request_broker.nim b/waku/common/broker/request_broker.nim index c71f90229..46f7d7d16 100644 --- a/waku/common/broker/request_broker.nim +++ b/waku/common/broker/request_broker.nim @@ -206,23 +206,6 @@ proc isReturnTypeValid(returnType, typeIdent: NimNode, mode: RequestBrokerMode): of rbSync: isSyncReturnTypeValid(returnType, typeIdent) -proc cloneParams(params: seq[NimNode]): seq[NimNode] = - ## Deep copy parameter definitions so they can be inserted in multiple places. - result = @[] - for param in params: - result.add(copyNimTree(param)) - -proc collectParamNames(params: seq[NimNode]): seq[NimNode] = - ## Extract all identifier symbols declared across IdentDefs nodes. - result = @[] - for param in params: - assert param.kind == nnkIdentDefs - for i in 0 ..< param.len - 2: - let nameNode = param[i] - if nameNode.kind == nnkEmpty: - continue - result.add(ident($nameNode)) - proc makeProcType( returnType: NimNode, params: seq[NimNode], mode: RequestBrokerMode ): NimNode = @@ -253,92 +236,13 @@ proc parseMode(modeNode: NimNode): RequestBrokerMode = else: error("RequestBroker mode must be `sync` or `async` (default is async)", modeNode) -proc ensureDistinctType(rhs: NimNode): NimNode = - ## For PODs / aliases / externally-defined types, wrap in `distinct` unless - ## it's already distinct. - if rhs.kind == nnkDistinctTy: - return copyNimTree(rhs) - newTree(nnkDistinctTy, copyNimTree(rhs)) - proc generateRequestBroker(body: NimNode, mode: RequestBrokerMode): NimNode = when defined(requestBrokerDebug): echo body.treeRepr echo "RequestBroker mode: ", $mode - var typeIdent: NimNode = nil - var objectDef: NimNode = nil - for stmt in body: - if stmt.kind == nnkTypeSection: - for def in stmt: - if def.kind != nnkTypeDef: - continue - if not typeIdent.isNil(): - error("Only one type may be declared inside RequestBroker", def) - - typeIdent = baseTypeIdent(def[0]) - let rhs = def[2] - - ## Support inline object types (fields are auto-exported) - ## AND non-object types / aliases (e.g. `string`, `int`, `OtherType`). - case rhs.kind - of nnkObjectTy: - let recList = rhs[2] - if recList.kind != nnkRecList: - error("RequestBroker object must declare a standard field list", rhs) - var exportedRecList = newTree(nnkRecList) - for field in recList: - case field.kind - of nnkIdentDefs: - ensureFieldDef(field) - var cloned = copyNimTree(field) - for i in 0 ..< cloned.len - 2: - cloned[i] = exportIdentNode(cloned[i]) - exportedRecList.add(cloned) - of nnkEmpty: - discard - else: - error( - "RequestBroker object definition only supports simple field declarations", - field, - ) - objectDef = newTree( - nnkObjectTy, copyNimTree(rhs[0]), copyNimTree(rhs[1]), exportedRecList - ) - of nnkRefTy: - if rhs.len != 1: - error("RequestBroker ref type must have a single base", rhs) - if rhs[0].kind == nnkObjectTy: - let obj = rhs[0] - let recList = obj[2] - if recList.kind != nnkRecList: - error("RequestBroker object must declare a standard field list", obj) - var exportedRecList = newTree(nnkRecList) - for field in recList: - case field.kind - of nnkIdentDefs: - ensureFieldDef(field) - var cloned = copyNimTree(field) - for i in 0 ..< cloned.len - 2: - cloned[i] = exportIdentNode(cloned[i]) - exportedRecList.add(cloned) - of nnkEmpty: - discard - else: - error( - "RequestBroker object definition only supports simple field declarations", - field, - ) - let exportedObjectType = newTree( - nnkObjectTy, copyNimTree(obj[0]), copyNimTree(obj[1]), exportedRecList - ) - objectDef = newTree(nnkRefTy, exportedObjectType) - else: - ## `ref SomeType` (SomeType can be defined elsewhere) - objectDef = ensureDistinctType(rhs) - else: - ## Non-object type / alias (e.g. `string`, `int`, `SomeExternalType`). - objectDef = ensureDistinctType(rhs) - if typeIdent.isNil(): - error("RequestBroker body must declare exactly one type", body) + let parsed = parseSingleTypeDef(body, "RequestBroker", allowRefToNonObject = true) + let typeIdent = parsed.typeIdent + let objectDef = parsed.objectDef when defined(requestBrokerDebug): echo "RequestBroker generating type: ", $typeIdent