Kaynağa Gözat

Forward oneof marshal/unmarshal funcs through public imports.

The collision of these two protocol buffer features does not work well in Go;
the best we can easily do is to handle the wire format. It'll operate poorly
when used with the text or JSON formats.
David Symonds 10 yıl önce
ebeveyn
işleme
5baca1b631

+ 34 - 1
protoc-gen-go/generator/generator.go

@@ -292,6 +292,7 @@ type symbol interface {
 type messageSymbol struct {
 	sym                         string
 	hasExtensions, isMessageSet bool
+	hasOneof                    bool
 	getters                     []getterSymbol
 }
 
@@ -321,6 +322,32 @@ func (ms *messageSymbol) GenerateAlias(g *Generator, pkg string) {
 				"{ return (*", remoteSym, ")(m).Unmarshal(buf) }")
 		}
 	}
+	if ms.hasOneof {
+		// Oneofs and public imports do not mix well.
+		// We can make them work okay for the binary format,
+		// but they're going to break weirdly for text/JSON.
+		enc := "_" + ms.sym + "_OneofMarshaler"
+		dec := "_" + ms.sym + "_OneofUnmarshaler"
+		encSig := "(msg " + g.Pkg["proto"] + ".Message, b *" + g.Pkg["proto"] + ".Buffer) error"
+		decSig := "(msg " + g.Pkg["proto"] + ".Message, tag, wire int, b *" + g.Pkg["proto"] + ".Buffer) (bool, error)"
+		g.P("func (m *", ms.sym, ") XXX_OneofFuncs() (func", encSig, ", func", decSig, ", []interface{}) {")
+		g.P("return ", enc, ", ", dec, ", nil")
+		g.P("}")
+
+		g.P("func ", enc, encSig, " {")
+		g.P("m := msg.(*", ms.sym, ")")
+		g.P("m0 := (*", remoteSym, ")(m)")
+		g.P("enc, _, _ := m0.XXX_OneofFuncs()")
+		g.P("return enc(m0, b)")
+		g.P("}")
+
+		g.P("func ", dec, decSig, " {")
+		g.P("m := msg.(*", ms.sym, ")")
+		g.P("m0 := (*", remoteSym, ")(m)")
+		g.P("_, dec, _ := m0.XXX_OneofFuncs()")
+		g.P("return dec(m0, tag, wire, b)")
+		g.P("}")
+	}
 	for _, get := range ms.getters {
 
 		if get.typeName != "" {
@@ -2057,7 +2084,13 @@ func (g *Generator) generateMessage(message *Descriptor) {
 	}
 
 	if !message.group {
-		ms := &messageSymbol{sym: ccTypeName, hasExtensions: hasExtensions, isMessageSet: isMessageSet, getters: getters}
+		ms := &messageSymbol{
+			sym:           ccTypeName,
+			hasExtensions: hasExtensions,
+			isMessageSet:  isMessageSet,
+			hasOneof:      len(message.OneofDecl) > 0,
+			getters:       getters,
+		}
 		g.file.addExport(message, ms)
 	}
 

+ 3 - 0
protoc-gen-go/testdata/imp.proto

@@ -43,6 +43,9 @@ message ImportedMessage {
   optional ImportedMessage2 local_msg = 2;
   optional ForeignImportedMessage foreign_msg = 3;  // in imp3.proto
   optional Owner enum_field = 4;
+  oneof union {
+    int32 state = 9;
+  }
 
   repeated string name = 5;
   repeated Owner boss = 6;