diff options
| author | Oskari Timperi <oskari.timperi@iki.fi> | 2018-04-08 16:07:44 +0300 |
|---|---|---|
| committer | Oskari Timperi <oskari.timperi@iki.fi> | 2018-04-08 16:07:44 +0300 |
| commit | 641e564c7d231b536e9e44c04c95307fef7cfe06 (patch) | |
| tree | fb854dcbb0bda3af1013b2de489f331671d77171 | |
| parent | 2d9ca1dabaabf85f3978242659eca0bed08b3371 (diff) | |
| download | nimpb_protoc-641e564c7d231b536e9e44c04c95307fef7cfe06.tar.gz nimpb_protoc-641e564c7d231b536e9e44c04c95307fef7cfe06.zip | |
Add initial message to JSON serialization support
| -rw-r--r-- | src/nimpb_buildpkg/plugin.nim | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/src/nimpb_buildpkg/plugin.nim b/src/nimpb_buildpkg/plugin.nim index 7354fa8..abdad07 100644 --- a/src/nimpb_buildpkg/plugin.nim +++ b/src/nimpb_buildpkg/plugin.nim @@ -30,6 +30,7 @@ type mapEntry: Message defaultValue: string message: Message + jsonName: string Message = ref object names: Names @@ -149,6 +150,11 @@ proc mapKeyType(field: Field): string = if f.name == "key": return f.nimTypeName +proc mapValueField(field: Field): Field = + for f in field.mapEntry.fields: + if f.name == "value": + return f + proc mapValueType(field: Field): string = for f in field.mapEntry.fields: if f.name == "value": @@ -343,6 +349,9 @@ proc newField(file: ProtoFile, message: Message, desc: google_protobuf_FieldDesc if hasDefaultValue(desc): result.defaultValue = desc.default_value + if hasJsonName(desc): + result.jsonName = desc.jsonName + log(&"newField {result.name} {$result.ftype} {result.typeName} PACKED={result.packed} SYNTAX={file.syntax}") proc newOneof(name: string): Oneof = @@ -847,6 +856,69 @@ iterator genSizeOfMessageProc(msg: Message): string = yield "" +proc shouldGenerateJsonProcs(typeName: string): bool = + const wktsHavingCustomProcs = [ + "google_protobuf_Any", + "google_protobuf_BoolValue", + "google_protobuf_BytesValue", + "google_protobuf_DoubleValue", + "google_protobuf_Duration", + "google_protobuf_FieldMask", + "google_protobuf_FloatValue", + "google_protobuf_Int32Value", + "google_protobuf_Int64Value", + "google_protobuf_ListValue", + "google_protobuf_NullValue", + "google_protobuf_StringValue", + "google_protobuf_Struct", + "google_protobuf_Timestamp", + "google_protobuf_UInt32Value", + "google_protobuf_UInt64Value", + "google_protobuf_Value", + ] + + return typeName notin wktsHavingCustomProcs + +iterator genMessageToJsonProc(msg: Message): string = + yield &"proc toJson*(message: {msg.names}): JsonNode =" + yield indent("result = newJObject()", 4) + + proc fieldToJson(field: Field, v: string): string = + case field.ftype + of google_protobuf_FieldDescriptorProto_Type.TypeMessage, + google_protobuf_FieldDescriptorProto_Type.TypeInt64, + google_protobuf_FieldDescriptorProto_Type.TypeUInt64, + google_protobuf_FieldDescriptorProto_Type.TypeSFixed64, + google_protobuf_FieldDescriptorProto_Type.TypeFixed64, + google_protobuf_FieldDescriptorProto_Type.TypeDouble, + google_protobuf_FieldDescriptorProto_Type.TypeFloat: + result = &"toJson({v})" + of google_protobuf_FieldDescriptorProto_Type.TypeEnum: + result = &"%(${v})" + else: + result = &"%{v}" + + for field in msg.fields: + yield indent(&"if has{field.name}(message):", 4) + if isMapEntry(field): + yield indent("let obj = newJObject()", 8) + yield indent(&"for key, value in message.{field.name}:", 8) + let f = mapValueField(field) + let j = fieldToJson(f, "value") + yield indent(&"obj[$key] = {j}", 12) + yield indent(&"result[\"{field.jsonName}\"] = obj", 8) + elif isRepeated(field): + yield indent(&"let arr = newJArray()", 8) + yield indent(&"for value in message.{field.name}:", 8) + let v = fieldToJson(field, "value") + yield indent(&"add(arr, {v})", 12) + yield indent(&"result[\"{field.jsonName}\"] = arr", 8) + else: + let v = fieldToJson(field, &"message.{field.name}") + yield indent(&"result[\"{field.jsonName}\"] = {v}", 8) + + yield "" + iterator genMessageProcForwards(msg: Message): string = # TODO: can we be more intelligent and only forward declare the minimum set # of procs? @@ -856,6 +928,8 @@ iterator genMessageProcForwards(msg: Message): string = yield &"proc write{msg.names}*(stream: ProtobufStream, message: {msg.names})" yield &"proc read{msg.names}*(stream: ProtobufStream): {msg.names}" yield &"proc sizeOf{msg.names}*(message: {msg.names}): uint64" + if shouldGenerateJsonProcs($msg.names): + yield &"proc toJson*(message: {msg.names}): JsonNode" else: let key = mapKeyField(msg) @@ -887,6 +961,9 @@ iterator genProcs(msg: Message): string = for line in genWriteMessageProc(msg): yield line for line in genReadMessageProc(msg): yield line + if shouldGenerateJsonProcs($msg.names): + for line in genMessageToJsonProc(msg): yield line + yield &"proc serialize*(message: {msg.names}): string =" yield indent("let", 4) yield indent("ss = newStringStream()", 8) @@ -928,12 +1005,15 @@ proc processFile(fdesc: google_protobuf_FileDescriptorProto, addLine(result.data, "# Generated by protoc_gen_nim. Do not edit!") addLine(result.data, "") + addLine(result.data, "import base64") addLine(result.data, "import intsets") + addLine(result.data, "import json") if hasMaps: addLine(result.data, "import tables") addLine(result.data, "export tables") addLine(result.data, "") addLine(result.data, "import nimpb/nimpb") + addLine(result.data, "import nimpb/json as nimpb_json") addLine(result.data, "") for dep in fdesc.dependency: |
