xP: generate our own JSON marshallers
For non-trivial types, which are expensive to serialize with encoding/json's struct reflection.
This commit is contained in:
		@@ -206,13 +206,14 @@ function codegen_enum(name, cg,    gotype, fields) {
 | 
				
			|||||||
	print "}"
 | 
						print "}"
 | 
				
			||||||
	print ""
 | 
						print ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						CodegenIsMarshaler[name] = 1
 | 
				
			||||||
	fields = cg["marshal"]
 | 
						fields = cg["marshal"]
 | 
				
			||||||
	sub(/,\n$/, ":", fields)
 | 
						sub(/,\n$/, ":", fields)
 | 
				
			||||||
	gsub(/\n/, "\n\t", fields)
 | 
						gsub(/\n/, "\n\t", fields)
 | 
				
			||||||
	print "func (v " gotype ") MarshalJSON() ([]byte, error) {"
 | 
						print "func (v " gotype ") MarshalJSON() ([]byte, error) {"
 | 
				
			||||||
	print "\tswitch v {"
 | 
						print "\tswitch v {"
 | 
				
			||||||
	print indent("case " fields)
 | 
						print indent("case " fields)
 | 
				
			||||||
	print "\t\treturn json.Marshal(v.String())"
 | 
						print "\t\treturn []byte(`\"` + v.String() + `\"`), nil"
 | 
				
			||||||
	print "\t}"
 | 
						print "\t}"
 | 
				
			||||||
	print "\treturn json.Marshal(int(v))"
 | 
						print "\treturn json.Marshal(int(v))"
 | 
				
			||||||
	print "}"
 | 
						print "}"
 | 
				
			||||||
@@ -252,7 +253,50 @@ function codegen_enum(name, cg,    gotype, fields) {
 | 
				
			|||||||
		delete cg[i]
 | 
							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) {
 | 
					function codegen_struct_field(d, cg,    camel, f, serialize, deserialize) {
 | 
				
			||||||
 | 
						codegen_struct_field_marshal(d, cg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	camel = snaketocamel(d["name"])
 | 
						camel = snaketocamel(d["name"])
 | 
				
			||||||
	f = "s." camel
 | 
						f = "s." camel
 | 
				
			||||||
	serialize = CodegenSerialize[d["type"]]
 | 
						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) {
 | 
					function codegen_struct_tag(d, cg,    camel, f) {
 | 
				
			||||||
 | 
						codegen_struct_field_marshal(d, cg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	camel = snaketocamel(d["name"])
 | 
						camel = snaketocamel(d["name"])
 | 
				
			||||||
	f = "s." camel
 | 
						f = "s." camel
 | 
				
			||||||
	append(cg, "fields", "\t" camel " " CodegenGoType[d["type"]] \
 | 
						append(cg, "fields", "\t" camel " " CodegenGoType[d["type"]] \
 | 
				
			||||||
@@ -315,6 +361,16 @@ function codegen_struct(name, cg,    gotype) {
 | 
				
			|||||||
	gotype = PrefixCamel name
 | 
						gotype = PrefixCamel name
 | 
				
			||||||
	print "type " gotype " struct {\n" cg["fields"] "}\n"
 | 
						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"]) {
 | 
						if (cg["serialize"]) {
 | 
				
			||||||
		print "func (s *" gotype ") AppendTo(data []byte) ([]byte, bool) {"
 | 
							print "func (s *" gotype ") AppendTo(data []byte) ([]byte, bool) {"
 | 
				
			||||||
		print "\tok := true"
 | 
							print "\tok := true"
 | 
				
			||||||
@@ -362,15 +418,15 @@ function codegen_union_struct(name, casename, cg, scg,     structname, init) {
 | 
				
			|||||||
		"\tcase " CodegenGoType[cg["tagtype"]] snaketocamel(casename) ":\n" \
 | 
							"\tcase " CodegenGoType[cg["tagtype"]] snaketocamel(casename) ":\n" \
 | 
				
			||||||
		"\t\ts := " init "\n" \
 | 
							"\t\ts := " init "\n" \
 | 
				
			||||||
		"\t\terr = json.Unmarshal(data, &s)\n" \
 | 
							"\t\terr = json.Unmarshal(data, &s)\n" \
 | 
				
			||||||
		"\t\tu.Interface = s\n")
 | 
							"\t\tu.Interface = &s\n")
 | 
				
			||||||
	append(cg, "serialize",
 | 
						append(cg, "serialize",
 | 
				
			||||||
		"\tcase " CodegenGoType[structname] ":\n" \
 | 
							"\tcase *" CodegenGoType[structname] ":\n" \
 | 
				
			||||||
		indent(sprintf(CodegenSerialize[structname], "union")))
 | 
							indent(sprintf(CodegenSerialize[structname], "union")))
 | 
				
			||||||
	append(cg, "deserialize",
 | 
						append(cg, "deserialize",
 | 
				
			||||||
		"\tcase " CodegenGoType[cg["tagtype"]] snaketocamel(casename) ":\n" \
 | 
							"\tcase " CodegenGoType[cg["tagtype"]] snaketocamel(casename) ":\n" \
 | 
				
			||||||
		"\t\ts := " init "\n" \
 | 
							"\t\ts := " init "\n" \
 | 
				
			||||||
		indent(sprintf(CodegenDeserialize[structname], "s")) \
 | 
							indent(sprintf(CodegenDeserialize[structname], "s")) \
 | 
				
			||||||
		"\t\tu.Interface = s\n")
 | 
							"\t\tu.Interface = &s\n")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function codegen_union(name, cg,    gotype, tagfield, tagvar) {
 | 
					function codegen_union(name, cg,    gotype, tagfield, tagvar) {
 | 
				
			||||||
@@ -381,8 +437,9 @@ function codegen_union(name, cg,    gotype, tagfield, tagvar) {
 | 
				
			|||||||
	print ""
 | 
						print ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	# This cannot be a pointer method, it wouldn't work recursively.
 | 
						# This cannot be a pointer method, it wouldn't work recursively.
 | 
				
			||||||
 | 
						CodegenIsMarshaler[name] = 1
 | 
				
			||||||
	print "func (u " gotype ") MarshalJSON() ([]byte, error) {"
 | 
						print "func (u " gotype ") MarshalJSON() ([]byte, error) {"
 | 
				
			||||||
	print "\treturn json.Marshal(u.Interface)"
 | 
						print "\treturn u.Interface.(json.Marshaler).MarshalJSON()"
 | 
				
			||||||
	print "}"
 | 
						print "}"
 | 
				
			||||||
	print ""
 | 
						print ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										6
									
								
								xP/xP.go
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								xP/xP.go
									
									
									
									
									
								
							@@ -50,7 +50,7 @@ func relayReadJSON(conn net.Conn) []byte {
 | 
				
			|||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	j, err := json.Marshal(&m)
 | 
						j, err := m.MarshalJSON()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log.Println("Event marshalling failed: " + err.Error())
 | 
							log.Println("Event marshalling failed: " + err.Error())
 | 
				
			||||||
		return nil
 | 
							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 {
 | 
					func clientWriteError(ctx context.Context, ws *websocket.Conn, err error) bool {
 | 
				
			||||||
	j, err := json.Marshal(&RelayEventMessage{
 | 
						j, err := (&RelayEventMessage{
 | 
				
			||||||
		EventSeq: 0,
 | 
							EventSeq: 0,
 | 
				
			||||||
		Data: RelayEventData{
 | 
							Data: RelayEventData{
 | 
				
			||||||
			Interface: RelayEventDataError{
 | 
								Interface: RelayEventDataError{
 | 
				
			||||||
@@ -135,7 +135,7 @@ func clientWriteError(ctx context.Context, ws *websocket.Conn, err error) bool {
 | 
				
			|||||||
				Error:      err.Error(),
 | 
									Error:      err.Error(),
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	})
 | 
						}).MarshalJSON()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log.Println("Event marshalling failed: " + err.Error())
 | 
							log.Println("Event marshalling failed: " + err.Error())
 | 
				
			||||||
		return false
 | 
							return false
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user