aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPřemysl Eric Janouch <p@janouch.name>2022-09-14 04:29:31 +0200
committerPřemysl Eric Janouch <p@janouch.name>2022-09-14 06:56:36 +0200
commitc1d2e38840c0596efd10e97ff5a9edaa20d5457e (patch)
treef1d56b745e9a8f1d649c442f52a3f0ddcf5d795b
parentf89f21a47fd2764ab48d908dd93dd78f8ff8b471 (diff)
downloadxK-c1d2e38840c0596efd10e97ff5a9edaa20d5457e.tar.gz
xK-c1d2e38840c0596efd10e97ff5a9edaa20d5457e.tar.xz
xK-c1d2e38840c0596efd10e97ff5a9edaa20d5457e.zip
xP: generate our own JSON marshallers
For non-trivial types, which are expensive to serialize with encoding/json's struct reflection.
-rw-r--r--xC-gen-proto-go.awk67
-rw-r--r--xP/xP.go6
2 files changed, 65 insertions, 8 deletions
diff --git a/xC-gen-proto-go.awk b/xC-gen-proto-go.awk
index 4220ccc..eb08477 100644
--- a/xC-gen-proto-go.awk
+++ b/xC-gen-proto-go.awk
@@ -206,13 +206,14 @@ function codegen_enum(name, cg, gotype, fields) {
print "}"
print ""
+ CodegenIsMarshaler[name] = 1
fields = cg["marshal"]
sub(/,\n$/, ":", fields)
gsub(/\n/, "\n\t", fields)
print "func (v " gotype ") MarshalJSON() ([]byte, error) {"
print "\tswitch v {"
print indent("case " fields)
- print "\t\treturn json.Marshal(v.String())"
+ print "\t\treturn []byte(`\"` + v.String() + `\"`), nil"
print "\t}"
print "\treturn json.Marshal(int(v))"
print "}"
@@ -252,7 +253,50 @@ function codegen_enum(name, cg, gotype, fields) {
delete cg[i]
}
+function codegen_struct_field_marshal(d, cg, camel, f, marshal) {
+ camel = snaketocamel(d["name"])
+ f = "s." camel
+
+ # Complex types are json.Marshalers, there's no need to json.Marshal(&f).
+ if (!d["isarray"]) {
+ if (CodegenIsMarshaler[d["type"]])
+ marshal = f ".MarshalJSON()"
+ else
+ marshal = "json.Marshal(" f ")"
+
+ append(cg, "marshal",
+ "\tb = append(b, `,\"" decapitalize(camel) "\":`...)\n" \
+ "\tif j, err := " marshal "; err != nil {\n" \
+ "\t\treturn nil, err\n" \
+ "\t} else {\n" \
+ "\t\tb = append(b, j...)\n" \
+ "\t}\n")
+ return
+ }
+
+ if (CodegenIsMarshaler[d["type"]])
+ marshal = f "[i].MarshalJSON()"
+ else
+ marshal = "json.Marshal(" f "[i])"
+
+ append(cg, "marshal",
+ "\tb = append(b, `,\"" decapitalize(camel) "\":[`...)\n" \
+ "\tfor i := 0; i < len(" f "); i++ {\n" \
+ "\t\tif i > 0 {\n" \
+ "\t\t\tb = append(b, ',')\n" \
+ "\t\t}\n" \
+ "\t\tif j, err := " marshal "; err != nil {\n" \
+ "\t\t\treturn nil, err\n" \
+ "\t\t} else {\n" \
+ "\t\t\tb = append(b, j...)\n" \
+ "\t\t}\n" \
+ "\t}\n" \
+ "\tb = append(b, ']')\n")
+}
+
function codegen_struct_field(d, cg, camel, f, serialize, deserialize) {
+ codegen_struct_field_marshal(d, cg)
+
camel = snaketocamel(d["name"])
f = "s." camel
serialize = CodegenSerialize[d["type"]]
@@ -303,6 +347,8 @@ function codegen_struct_field(d, cg, camel, f, serialize, deserialize) {
}
function codegen_struct_tag(d, cg, camel, f) {
+ codegen_struct_field_marshal(d, cg)
+
camel = snaketocamel(d["name"])
f = "s." camel
append(cg, "fields", "\t" camel " " CodegenGoType[d["type"]] \
@@ -315,6 +361,16 @@ function codegen_struct(name, cg, gotype) {
gotype = PrefixCamel name
print "type " gotype " struct {\n" cg["fields"] "}\n"
+ if (cg["marshal"]) {
+ CodegenIsMarshaler[name] = 1
+ print "func (s *" gotype ") MarshalJSON() ([]byte, error) {"
+ print "\tb := []byte{}"
+ print cg["marshal"] "\tb[0] = '{'"
+ print "\treturn append(b, '}'), nil"
+ print "}"
+ print ""
+ }
+
if (cg["serialize"]) {
print "func (s *" gotype ") AppendTo(data []byte) ([]byte, bool) {"
print "\tok := true"
@@ -362,15 +418,15 @@ function codegen_union_struct(name, casename, cg, scg, structname, init) {
"\tcase " CodegenGoType[cg["tagtype"]] snaketocamel(casename) ":\n" \
"\t\ts := " init "\n" \
"\t\terr = json.Unmarshal(data, &s)\n" \
- "\t\tu.Interface = s\n")
+ "\t\tu.Interface = &s\n")
append(cg, "serialize",
- "\tcase " CodegenGoType[structname] ":\n" \
+ "\tcase *" CodegenGoType[structname] ":\n" \
indent(sprintf(CodegenSerialize[structname], "union")))
append(cg, "deserialize",
"\tcase " CodegenGoType[cg["tagtype"]] snaketocamel(casename) ":\n" \
"\t\ts := " init "\n" \
indent(sprintf(CodegenDeserialize[structname], "s")) \
- "\t\tu.Interface = s\n")
+ "\t\tu.Interface = &s\n")
}
function codegen_union(name, cg, gotype, tagfield, tagvar) {
@@ -381,8 +437,9 @@ function codegen_union(name, cg, gotype, tagfield, tagvar) {
print ""
# This cannot be a pointer method, it wouldn't work recursively.
+ CodegenIsMarshaler[name] = 1
print "func (u " gotype ") MarshalJSON() ([]byte, error) {"
- print "\treturn json.Marshal(u.Interface)"
+ print "\treturn u.Interface.(json.Marshaler).MarshalJSON()"
print "}"
print ""
diff --git a/xP/xP.go b/xP/xP.go
index dc5aa5e..2d6e096 100644
--- a/xP/xP.go
+++ b/xP/xP.go
@@ -50,7 +50,7 @@ func relayReadJSON(conn net.Conn) []byte {
return nil
}
- j, err := json.Marshal(&m)
+ j, err := m.MarshalJSON()
if err != nil {
log.Println("Event marshalling failed: " + err.Error())
return nil
@@ -126,7 +126,7 @@ func clientWriteJSON(ctx context.Context, ws *websocket.Conn, j []byte) bool {
}
func clientWriteError(ctx context.Context, ws *websocket.Conn, err error) bool {
- j, err := json.Marshal(&RelayEventMessage{
+ j, err := (&RelayEventMessage{
EventSeq: 0,
Data: RelayEventData{
Interface: RelayEventDataError{
@@ -135,7 +135,7 @@ func clientWriteError(ctx context.Context, ws *websocket.Conn, err error) bool {
Error: err.Error(),
},
},
- })
+ }).MarshalJSON()
if err != nil {
log.Println("Event marshalling failed: " + err.Error())
return false