import macros, macro_dsl, streams, streams_enh from strutils import format template newLenName(): stmt {.immediate.} = let lenName {.inject.} = ^("len"& $lenNames) inc(lenNames) template defPacketImports*(): stmt {.immediate, dirty.} = import macros, macro_dsl, streams, streams_enh from strutils import format proc `$`*[T](x: seq[T]): string = result = "[seq len=" result.add($x.len) result.add ':' for i in 0.. `(a: string, b: string): NimNode {.compileTime.} = result = newNimNode(nnkIdentDefs).und(^a, ^b, newNimNode(nnkEmpty)) proc `->`(a: string, b: NimNode): NimNode {.compileTime.} = result = newNimNode(nnkIdentDefs).und(^a, b, newNimNode(nnkEmpty)) proc `->`(a, b: NimNode): NimNode {.compileTime.} = a[2] = b result = a proc newProc*(name: string, params: varargs[NimNode], resultType: NimNode): NimNode {.compileTime.} = result = newNimNode(nnkProcDef).und( ^name, emptyNode(), emptyNode(), newNimNode(nnkFormalParams).und(resultType), emptyNode(), emptyNode(), newNimNode(nnkStmtList)) result[3].add(params) macro forwardPacket*(typeName: expr, underlyingType: typedesc): stmt {.immediate.} = result = newNimNode(nnkStmtList).und( newProc( "read"& $typeName.ident, ["s" -> "PStream" -> newNimNode(nnkNilLit)], typeName), newProc( "pack", [ "p" -> newNimNode(nnkVarTy).und(typeName), "s" -> "PStream" -> newNimNode(nnkNilLit)], emptyNode())) result[0][6].add(newNimNode(nnkDiscardStmt).und( newCall( "readData", ^"s", newNimNode(nnkAddr).und(^"result"), newCall("sizeof", ^"result") ))) result[1][6].add( newCall( "writeData", ^"s", newNimNode(nnkAddr).und(^"p"), newCall( "sizeof", ^"p"))) when defined(GenPacketShowOutput): echo(repr(result)) template forwardPacketT*(typeName: expr): stmt {.dirty, immediate.} = proc `read typeName`*(s: PStream): typeName = discard readData(s, addr result, sizeof(result)) proc `pack typeName`*(p: var typeName; s: PStream) = writeData(s, addr p, sizeof(p)) when isMainModule: type SomeEnum = enum A = 0'i8, B, C forwardPacket(SomeEnum, int8) defPacket(Foo, tuple[x: array[0..4, int8]]) var f = newFoo([4'i8, 3'i8, 2'i8, 1'i8, 0'i8]) var s2 = newStringStream("") f.pack(s2) assert s2.data == "\4\3\2\1\0" var s = newStringStream() s.flushImpl = proc(s: PStream) = var z = PStringStream(s) z.setPosition(0) z.data.setLen(0) s.setPosition(0) s.data.setLen(0) var o = B o.pack(s) o = A o.pack(s) o = C o.pack(s) assert s.data == "\1\0\2" s.flush defPacket(Y, tuple[z: int8]) proc `$`(z: Y): string = result = "Y("& $z.z &")" defPacket(TestPkt, tuple[x: seq[Y]]) var test = newTestPkt() test.x.add([newY(5), newY(4), newY(3), newY(2), newY(1)]) for itm in test.x: echo(itm) test.pack(s) echo(repr(s.data))