mirror of
https://github.com/protocolbuffers/protobuf-go.git
synced 2025-03-09 22:13:27 +00:00
cmd/protoc-gen-go: generate oneofs
Generate everything related to oneofs: Message struct fields, wrapper types, XXX_OneofFuncs. Change-Id: I409040e0deb5716afabf59186eeaae21757d29f1 Reviewed-on: https://go-review.googlesource.com/135535 Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
This commit is contained in:
parent
1ec3315873
commit
1fa78d8a35
@ -270,8 +270,14 @@ func genMessage(gen *protogen.Plugin, g *protogen.GeneratedFile, f *File, messag
|
||||
// TODO: deprecation
|
||||
g.P("type ", message.GoIdent, " struct {")
|
||||
for _, field := range message.Fields {
|
||||
if field.Desc.OneofType() != nil {
|
||||
// TODO oneofs
|
||||
if field.OneofType != nil {
|
||||
// It would be a bit simpler to iterate over the oneofs below,
|
||||
// but generating the field here keeps the contents of the Go
|
||||
// struct in the same order as the contents of the source
|
||||
// .proto file.
|
||||
if field == field.OneofType.Fields[0] {
|
||||
genOneofField(gen, g, f, message, field.OneofType)
|
||||
}
|
||||
continue
|
||||
}
|
||||
genComment(g, f, field.Path)
|
||||
@ -291,7 +297,7 @@ func genMessage(gen *protogen.Plugin, g *protogen.GeneratedFile, f *File, messag
|
||||
fmt.Sprintf("protobuf_val:%q", fieldProtobufTag(val)),
|
||||
)
|
||||
}
|
||||
g.P(field.GoIdent, " ", goType, " `", strings.Join(tags, " "), "`")
|
||||
g.P(field.GoName, " ", goType, " `", strings.Join(tags, " "), "`")
|
||||
}
|
||||
g.P("XXX_NoUnkeyedLiteral struct{} `json:\"-\"`")
|
||||
// TODO XXX_InternalExtensions
|
||||
@ -359,7 +365,7 @@ func genMessage(gen *protogen.Plugin, g *protogen.GeneratedFile, f *File, messag
|
||||
if !field.Desc.HasDefault() {
|
||||
continue
|
||||
}
|
||||
defVarName := "Default_" + message.GoIdent.GoName + "_" + field.GoIdent.GoName
|
||||
defVarName := "Default_" + message.GoIdent.GoName + "_" + field.GoName
|
||||
def := field.Desc.Default()
|
||||
switch field.Desc.Kind() {
|
||||
case protoreflect.StringKind:
|
||||
@ -408,26 +414,41 @@ func genMessage(gen *protogen.Plugin, g *protogen.GeneratedFile, f *File, messag
|
||||
|
||||
// Getters.
|
||||
for _, field := range message.Fields {
|
||||
if field.OneofType != nil {
|
||||
if field == field.OneofType.Fields[0] {
|
||||
genOneofTypes(gen, g, f, message, field.OneofType)
|
||||
}
|
||||
}
|
||||
goType, pointer := fieldGoType(g, field)
|
||||
defaultValue := fieldDefaultValue(g, message, field)
|
||||
g.P("func (m *", message.GoIdent, ") Get", field.GoIdent, "() ", goType, " {")
|
||||
if field.Desc.Syntax() == protoreflect.Proto3 || defaultValue == "nil" {
|
||||
g.P("if m != nil {")
|
||||
g.P("func (m *", message.GoIdent, ") Get", field.GoName, "() ", goType, " {")
|
||||
if field.OneofType != nil {
|
||||
g.P("if x, ok := m.Get", field.OneofType.GoName, "().(*", message.GoIdent.GoName, "_", field.GoName, "); ok {")
|
||||
g.P("return x.", field.GoName)
|
||||
g.P("}")
|
||||
} else {
|
||||
g.P("if m != nil && m.", field.GoIdent, " != nil {")
|
||||
if field.Desc.Syntax() == protoreflect.Proto3 || defaultValue == "nil" {
|
||||
g.P("if m != nil {")
|
||||
} else {
|
||||
g.P("if m != nil && m.", field.GoName, " != nil {")
|
||||
}
|
||||
star := ""
|
||||
if pointer {
|
||||
star = "*"
|
||||
}
|
||||
g.P("return ", star, " m.", field.GoName)
|
||||
g.P("}")
|
||||
}
|
||||
star := ""
|
||||
if pointer {
|
||||
star = "*"
|
||||
}
|
||||
g.P("return ", star, " m.", field.GoIdent)
|
||||
g.P("}")
|
||||
g.P("return ", defaultValue)
|
||||
g.P("}")
|
||||
g.P()
|
||||
}
|
||||
|
||||
genWellKnownType(g, message.GoIdent, message.Desc)
|
||||
|
||||
if len(message.Oneofs) > 0 {
|
||||
genOneofFuncs(gen, g, f, message)
|
||||
}
|
||||
}
|
||||
|
||||
// fieldGoType returns the Go type used for a field.
|
||||
@ -555,7 +576,7 @@ func fieldDefaultValue(g *protogen.GeneratedFile, message *protogen.Message, fie
|
||||
return "nil"
|
||||
}
|
||||
if field.Desc.HasDefault() {
|
||||
defVarName := "Default_" + message.GoIdent.GoName + "_" + field.GoIdent.GoName
|
||||
defVarName := "Default_" + message.GoIdent.GoName + "_" + field.GoName
|
||||
if field.Desc.Kind() == protoreflect.BytesKind {
|
||||
return "append([]byte(nil), " + defVarName + "...)"
|
||||
}
|
||||
@ -651,16 +672,18 @@ func genInitFunction(gen *protogen.Plugin, g *protogen.GeneratedFile, f *File) {
|
||||
g.P()
|
||||
}
|
||||
|
||||
func genComment(g *protogen.GeneratedFile, f *File, path []int32) {
|
||||
func genComment(g *protogen.GeneratedFile, f *File, path []int32) (hasComment bool) {
|
||||
for _, loc := range f.locationMap[pathKey(path)] {
|
||||
if loc.LeadingComments == nil {
|
||||
continue
|
||||
}
|
||||
for _, line := range strings.Split(strings.TrimSuffix(loc.GetLeadingComments(), "\n"), "\n") {
|
||||
hasComment = true
|
||||
g.P("//", line)
|
||||
}
|
||||
return
|
||||
break
|
||||
}
|
||||
return hasComment
|
||||
}
|
||||
|
||||
// pathKey converts a location path to a string suitable for use as a map key.
|
||||
|
346
cmd/protoc-gen-go/oneof.go
Normal file
346
cmd/protoc-gen-go/oneof.go
Normal file
@ -0,0 +1,346 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"google.golang.org/proto/protogen"
|
||||
"google.golang.org/proto/reflect/protoreflect"
|
||||
)
|
||||
|
||||
// genOneofField generates the struct field for a oneof.
|
||||
func genOneofField(gen *protogen.Plugin, g *protogen.GeneratedFile, f *File, message *protogen.Message, oneof *protogen.Oneof) {
|
||||
if genComment(g, f, oneof.Path) {
|
||||
g.P("//")
|
||||
}
|
||||
g.P("// Types that are valid to be assigned to ", oneof.GoName, ":")
|
||||
for _, field := range oneof.Fields {
|
||||
g.P("//\t*", fieldOneofType(field))
|
||||
}
|
||||
g.P(oneof.GoName, " ", oneofInterfaceName(message, oneof), " `protobuf_oneof:\"", oneof.Desc.Name(), "\"`")
|
||||
}
|
||||
|
||||
// genOneofTypes generates the interface type used for a oneof field,
|
||||
// and the wrapper types that satisfy that interface.
|
||||
//
|
||||
// It also generates the getter method for the parent oneof field
|
||||
// (but not the member fields).
|
||||
func genOneofTypes(gen *protogen.Plugin, g *protogen.GeneratedFile, f *File, message *protogen.Message, oneof *protogen.Oneof) {
|
||||
ifName := oneofInterfaceName(message, oneof)
|
||||
g.P("type ", ifName, " interface {")
|
||||
g.P(ifName, "()")
|
||||
g.P("}")
|
||||
g.P()
|
||||
for _, field := range oneof.Fields {
|
||||
g.P("type ", fieldOneofType(field), " struct {")
|
||||
goType, _ := fieldGoType(g, field)
|
||||
tags := []string{
|
||||
fmt.Sprintf("protobuf:%q", fieldProtobufTag(field)),
|
||||
}
|
||||
g.P(field.GoName, " ", goType, " `", strings.Join(tags, " "), "`")
|
||||
g.P("}")
|
||||
g.P()
|
||||
}
|
||||
for _, field := range oneof.Fields {
|
||||
g.P("func (* ", fieldOneofType(field), ") ", ifName, "() {}")
|
||||
g.P()
|
||||
}
|
||||
g.P("func (m *", message.GoIdent.GoName, ") Get", oneof.GoName, "() ", ifName, " {")
|
||||
g.P("if m != nil {")
|
||||
g.P("return m.", oneof.GoName)
|
||||
g.P("}")
|
||||
g.P("return nil")
|
||||
g.P("}")
|
||||
g.P()
|
||||
}
|
||||
|
||||
func oneofInterfaceName(message *protogen.Message, oneof *protogen.Oneof) string {
|
||||
return fmt.Sprintf("is%s_%s", message.GoIdent.GoName, oneof.GoName)
|
||||
}
|
||||
|
||||
// genOneofFuncs generates the XXX_OneofFuncs method for a message.
|
||||
func genOneofFuncs(gen *protogen.Plugin, g *protogen.GeneratedFile, f *File, message *protogen.Message) {
|
||||
protoMessage := g.QualifiedGoIdent(protogen.GoIdent{
|
||||
GoImportPath: protoPackage,
|
||||
GoName: "Message",
|
||||
})
|
||||
protoBuffer := g.QualifiedGoIdent(protogen.GoIdent{
|
||||
GoImportPath: protoPackage,
|
||||
GoName: "Buffer",
|
||||
})
|
||||
encFunc := "_" + message.GoIdent.GoName + "_OneofMarshaler"
|
||||
decFunc := "_" + message.GoIdent.GoName + "_OneofUnmarshaler"
|
||||
sizeFunc := "_" + message.GoIdent.GoName + "_OneofSizer"
|
||||
encSig := "(msg " + protoMessage + ", b *" + protoBuffer + ") error"
|
||||
decSig := "(msg " + protoMessage + ", tag, wire int, b *" + protoBuffer + ") (bool, error)"
|
||||
sizeSig := "(msg " + protoMessage + ") (n int)"
|
||||
|
||||
// XXX_OneofFuncs
|
||||
g.P("// XXX_OneofFuncs is for the internal use of the proto package.")
|
||||
g.P("func (*", message.GoIdent.GoName, ") XXX_OneofFuncs() (func ", encSig, ", func ", decSig, ", func ", sizeSig, ", []interface{}) {")
|
||||
g.P("return ", encFunc, ", ", decFunc, ", ", sizeFunc, ", []interface{}{")
|
||||
for _, oneof := range message.Oneofs {
|
||||
for _, field := range oneof.Fields {
|
||||
g.P("(*", fieldOneofType(field), ")(nil),")
|
||||
}
|
||||
}
|
||||
g.P("}")
|
||||
g.P("}")
|
||||
g.P()
|
||||
|
||||
// Marshaler
|
||||
g.P("func ", encFunc, encSig, " {")
|
||||
g.P("m := msg.(*", message.GoIdent, ")")
|
||||
for _, oneof := range message.Oneofs {
|
||||
g.P("// ", oneof.Desc.Name())
|
||||
g.P("switch x := m.", oneof.GoName, ".(type) {")
|
||||
for _, field := range oneof.Fields {
|
||||
genOneofFieldMarshal(g, field)
|
||||
}
|
||||
g.P("case nil:")
|
||||
g.P("default:")
|
||||
g.P("return ", protogen.GoIdent{
|
||||
GoImportPath: "fmt",
|
||||
GoName: "Errorf",
|
||||
}, `("`, message.GoIdent.GoName, ".", oneof.GoName, ` has unexpected type %T", x)`)
|
||||
g.P("}")
|
||||
}
|
||||
g.P("return nil")
|
||||
g.P("}")
|
||||
g.P()
|
||||
|
||||
// Unmarshaler
|
||||
g.P("func ", decFunc, decSig, " {")
|
||||
g.P("m := msg.(*", message.GoIdent, ")")
|
||||
g.P("switch tag {")
|
||||
for _, oneof := range message.Oneofs {
|
||||
for _, field := range oneof.Fields {
|
||||
genOneofFieldUnmarshal(g, field)
|
||||
}
|
||||
}
|
||||
g.P("default:")
|
||||
g.P("return false, nil")
|
||||
g.P("}")
|
||||
g.P("}")
|
||||
g.P()
|
||||
|
||||
// Sizer
|
||||
g.P("func ", sizeFunc, sizeSig, " {")
|
||||
g.P("m := msg.(*", message.GoIdent, ")")
|
||||
for _, oneof := range message.Oneofs {
|
||||
g.P("// ", oneof.Desc.Name())
|
||||
g.P("switch x := m.", oneof.GoName, ".(type) {")
|
||||
for _, field := range oneof.Fields {
|
||||
genOneofFieldSizer(g, field)
|
||||
}
|
||||
g.P("case nil:")
|
||||
g.P("default:")
|
||||
g.P("panic(", protogen.GoIdent{
|
||||
GoImportPath: "fmt",
|
||||
GoName: "Sprintf",
|
||||
}, `("proto: unexpected type %T in oneof", x))`)
|
||||
g.P("}")
|
||||
}
|
||||
g.P("return n")
|
||||
g.P("}")
|
||||
g.P()
|
||||
}
|
||||
|
||||
// genOneofFieldMarshal generates the marshal case for a oneof subfield.
|
||||
func genOneofFieldMarshal(g *protogen.GeneratedFile, field *protogen.Field) {
|
||||
g.P("case *", fieldOneofType(field), ":")
|
||||
encodeTag := func(wireType string) {
|
||||
g.P("b.EncodeVarint(", field.Desc.Number(), "<<3|", protogen.GoIdent{
|
||||
GoImportPath: protoPackage,
|
||||
GoName: wireType,
|
||||
}, ")")
|
||||
}
|
||||
switch field.Desc.Kind() {
|
||||
case protoreflect.BoolKind:
|
||||
g.P("t := uint64(0)")
|
||||
g.P("if x.", field.GoName, " { t = 1 }")
|
||||
encodeTag("WireVarint")
|
||||
g.P("b.EncodeVarint(t)")
|
||||
case protoreflect.EnumKind, protoreflect.Int32Kind, protoreflect.Uint32Kind, protoreflect.Int64Kind, protoreflect.Uint64Kind:
|
||||
encodeTag("WireVarint")
|
||||
g.P("b.EncodeVarint(uint64(x.", field.GoName, "))")
|
||||
case protoreflect.Sint32Kind:
|
||||
encodeTag("WireVarint")
|
||||
g.P("b.EncodeZigzag32(uint64(x.", field.GoName, "))")
|
||||
case protoreflect.Sint64Kind:
|
||||
encodeTag("WireVarint")
|
||||
g.P("b.EncodeZigzag64(uint64(x.", field.GoName, "))")
|
||||
case protoreflect.Sfixed32Kind, protoreflect.Fixed32Kind:
|
||||
encodeTag("WireFixed32")
|
||||
g.P("b.EncodeFixed32(uint64(x.", field.GoName, "))")
|
||||
case protoreflect.FloatKind:
|
||||
encodeTag("WireFixed32")
|
||||
g.P("b.EncodeFixed32(uint64(", protogen.GoIdent{
|
||||
GoImportPath: "math",
|
||||
GoName: "Float32bits",
|
||||
}, "(x.", field.GoName, ")))")
|
||||
case protoreflect.Sfixed64Kind, protoreflect.Fixed64Kind:
|
||||
encodeTag("WireFixed64")
|
||||
g.P("b.EncodeFixed64(uint64(x.", field.GoName, "))")
|
||||
case protoreflect.DoubleKind:
|
||||
encodeTag("WireFixed64")
|
||||
g.P("b.EncodeFixed64(", protogen.GoIdent{
|
||||
GoImportPath: "math",
|
||||
GoName: "Float64bits",
|
||||
}, "(x.", field.GoName, "))")
|
||||
case protoreflect.StringKind:
|
||||
encodeTag("WireBytes")
|
||||
g.P("b.EncodeStringBytes(x.", field.GoName, ")")
|
||||
case protoreflect.BytesKind:
|
||||
encodeTag("WireBytes")
|
||||
g.P("b.EncodeRawBytes(x.", field.GoName, ")")
|
||||
case protoreflect.MessageKind:
|
||||
encodeTag("WireBytes")
|
||||
g.P("if err := b.EncodeMessage(x.", field.GoName, "); err != nil {")
|
||||
g.P("return err")
|
||||
g.P("}")
|
||||
case protoreflect.GroupKind:
|
||||
encodeTag("WireStartGroup")
|
||||
g.P("if err := b.Marshal(x.", field.GoName, "); err != nil {")
|
||||
g.P("return err")
|
||||
g.P("}")
|
||||
encodeTag("WireEndGroup")
|
||||
}
|
||||
}
|
||||
|
||||
// genOneofFieldUnmarshal generates the unmarshal case for a oneof subfield.
|
||||
func genOneofFieldUnmarshal(g *protogen.GeneratedFile, field *protogen.Field) {
|
||||
oneof := field.OneofType
|
||||
g.P("case ", field.Desc.Number(), ": // ", oneof.Desc.Name(), ".", field.Desc.Name())
|
||||
checkTag := func(wireType string) {
|
||||
g.P("if wire != ", protogen.GoIdent{
|
||||
GoImportPath: protoPackage,
|
||||
GoName: wireType,
|
||||
}, " {")
|
||||
g.P("return true, ", protogen.GoIdent{
|
||||
GoImportPath: protoPackage,
|
||||
GoName: "ErrInternalBadWireType",
|
||||
})
|
||||
g.P("}")
|
||||
}
|
||||
switch field.Desc.Kind() {
|
||||
case protoreflect.BoolKind:
|
||||
checkTag("WireVarint")
|
||||
g.P("x, err := b.DecodeVarint()")
|
||||
g.P("m.", oneof.GoName, " = &", fieldOneofType(field), "{x != 0}")
|
||||
case protoreflect.EnumKind:
|
||||
checkTag("WireVarint")
|
||||
g.P("x, err := b.DecodeVarint()")
|
||||
g.P("m.", oneof.GoName, " = &", fieldOneofType(field), "{", field.EnumType.GoIdent, "(x)}")
|
||||
case protoreflect.Int32Kind, protoreflect.Uint32Kind, protoreflect.Int64Kind, protoreflect.Uint64Kind:
|
||||
checkTag("WireVarint")
|
||||
g.P("x, err := b.DecodeVarint()")
|
||||
x := "x"
|
||||
if goType, _ := fieldGoType(g, field); goType != "uint64" {
|
||||
x = goType + "(x)"
|
||||
}
|
||||
g.P("m.", oneof.GoName, " = &", fieldOneofType(field), "{", x, "}")
|
||||
case protoreflect.Sint32Kind:
|
||||
checkTag("WireVarint")
|
||||
g.P("x, err := b.DecodeZigzag32()")
|
||||
g.P("m.", oneof.GoName, " = &", fieldOneofType(field), "{int32(x)}")
|
||||
case protoreflect.Sint64Kind:
|
||||
checkTag("WireVarint")
|
||||
g.P("x, err := b.DecodeZigzag64()")
|
||||
g.P("m.", oneof.GoName, " = &", fieldOneofType(field), "{int64(x)}")
|
||||
case protoreflect.Sfixed32Kind:
|
||||
checkTag("WireFixed32")
|
||||
g.P("x, err := b.DecodeFixed32()")
|
||||
g.P("m.", oneof.GoName, " = &", fieldOneofType(field), "{int32(x)}")
|
||||
case protoreflect.Fixed32Kind:
|
||||
checkTag("WireFixed32")
|
||||
g.P("x, err := b.DecodeFixed32()")
|
||||
g.P("m.", oneof.GoName, " = &", fieldOneofType(field), "{uint32(x)}")
|
||||
case protoreflect.FloatKind:
|
||||
checkTag("WireFixed32")
|
||||
g.P("x, err := b.DecodeFixed32()")
|
||||
g.P("m.", oneof.GoName, " = &", fieldOneofType(field), "{", protogen.GoIdent{
|
||||
GoImportPath: "math",
|
||||
GoName: "Float32frombits",
|
||||
}, "(uint32(x))}")
|
||||
case protoreflect.Sfixed64Kind:
|
||||
checkTag("WireFixed64")
|
||||
g.P("x, err := b.DecodeFixed64()")
|
||||
g.P("m.", oneof.GoName, " = &", fieldOneofType(field), "{int64(x)}")
|
||||
case protoreflect.Fixed64Kind:
|
||||
checkTag("WireFixed64")
|
||||
g.P("x, err := b.DecodeFixed64()")
|
||||
g.P("m.", oneof.GoName, " = &", fieldOneofType(field), "{x}")
|
||||
case protoreflect.DoubleKind:
|
||||
checkTag("WireFixed64")
|
||||
g.P("x, err := b.DecodeFixed64()")
|
||||
g.P("m.", oneof.GoName, " = &", fieldOneofType(field), "{", protogen.GoIdent{
|
||||
GoImportPath: "math",
|
||||
GoName: "Float64frombits",
|
||||
}, "(x)}")
|
||||
case protoreflect.StringKind:
|
||||
checkTag("WireBytes")
|
||||
g.P("x, err := b.DecodeStringBytes()")
|
||||
g.P("m.", oneof.GoName, " = &", fieldOneofType(field), "{x}")
|
||||
case protoreflect.BytesKind:
|
||||
checkTag("WireBytes")
|
||||
g.P("x, err := b.DecodeRawBytes(true)")
|
||||
g.P("m.", oneof.GoName, " = &", fieldOneofType(field), "{x}")
|
||||
case protoreflect.MessageKind:
|
||||
checkTag("WireBytes")
|
||||
g.P("msg := new(", field.MessageType.GoIdent, ")")
|
||||
g.P("err := b.DecodeMessage(msg)")
|
||||
g.P("m.", oneof.GoName, " = &", fieldOneofType(field), "{msg}")
|
||||
case protoreflect.GroupKind:
|
||||
checkTag("WireStartGroup")
|
||||
g.P("msg := new(", field.MessageType.GoIdent, ")")
|
||||
g.P("err := b.DecodeGroup(msg)")
|
||||
g.P("m.", oneof.GoName, " = &", fieldOneofType(field), "{msg}")
|
||||
}
|
||||
g.P("return true, err")
|
||||
}
|
||||
|
||||
// genOneofFieldSizer generates the sizer case for a oneof subfield.
|
||||
func genOneofFieldSizer(g *protogen.GeneratedFile, field *protogen.Field) {
|
||||
sizeProto := protogen.GoIdent{GoImportPath: protoPackage, GoName: "Size"}
|
||||
sizeVarint := protogen.GoIdent{GoImportPath: protoPackage, GoName: "SizeVarint"}
|
||||
g.P("case *", fieldOneofType(field), ":")
|
||||
if field.Desc.Kind() == protoreflect.MessageKind {
|
||||
g.P("s := ", sizeProto, "(x.", field.GoName, ")")
|
||||
}
|
||||
// Tag and wire varint is known statically.
|
||||
tagAndWireSize := proto.SizeVarint(uint64(field.Desc.Number() << 3)) // wire doesn't affect arint size
|
||||
g.P("n += ", tagAndWireSize, " // tag and wire")
|
||||
switch field.Desc.Kind() {
|
||||
case protoreflect.BoolKind:
|
||||
g.P("n += 1")
|
||||
case protoreflect.EnumKind, protoreflect.Int32Kind, protoreflect.Uint32Kind, protoreflect.Int64Kind, protoreflect.Uint64Kind:
|
||||
g.P("n += ", sizeVarint, "(uint64(x.", field.GoName, "))")
|
||||
case protoreflect.Sint32Kind:
|
||||
g.P("n += ", sizeVarint, "(uint64((uint32(x.", field.GoName, ") << 1) ^ uint32((int32(x.", field.GoName, ") >> 31))))")
|
||||
case protoreflect.Sint64Kind:
|
||||
g.P("n += ", sizeVarint, "(uint64(uint64(x.", field.GoName, "<<1) ^ uint64((int64(x.", field.GoName, ") >> 63))))")
|
||||
case protoreflect.Sfixed32Kind, protoreflect.Fixed32Kind, protoreflect.FloatKind:
|
||||
g.P("n += 4")
|
||||
case protoreflect.Sfixed64Kind, protoreflect.Fixed64Kind, protoreflect.DoubleKind:
|
||||
g.P("n += 8")
|
||||
case protoreflect.StringKind, protoreflect.BytesKind:
|
||||
g.P("n += ", sizeVarint, "(uint64(len(x.", field.GoName, ")))")
|
||||
g.P("n += len(x.", field.GoName, ")")
|
||||
case protoreflect.MessageKind:
|
||||
g.P("n += ", sizeVarint, "(uint64(s))")
|
||||
g.P("n += s")
|
||||
case protoreflect.GroupKind:
|
||||
g.P("n += ", sizeProto, "(x.", field.GoName, ")")
|
||||
g.P("n += ", tagAndWireSize, " // tag and wire")
|
||||
}
|
||||
}
|
||||
|
||||
// fieldOneofType returns the wrapper type used to represent a field in a oneof.
|
||||
func fieldOneofType(field *protogen.Field) protogen.GoIdent {
|
||||
return protogen.GoIdent{
|
||||
GoImportPath: field.ContainingType.GoIdent.GoImportPath,
|
||||
GoName: field.ContainingType.GoIdent.GoName + "_" + field.GoName,
|
||||
}
|
||||
}
|
@ -42,11 +42,22 @@ type Message struct {
|
||||
CamelCase__ *string `protobuf:"bytes,22,opt,name=camel_case,json=camelCase" json:"camel_case,omitempty"`
|
||||
CamelCase___ *string `protobuf:"bytes,23,opt,name=CamelCase__,json=CamelCase" json:"CamelCase__,omitempty"`
|
||||
// Field with a getter that conflicts with another field.
|
||||
GetName *string `protobuf:"bytes,30,opt,name=get_name,json=getName" json:"get_name,omitempty"`
|
||||
Name_ *string `protobuf:"bytes,31,opt,name=name" json:"name,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
GetName *string `protobuf:"bytes,30,opt,name=get_name,json=getName" json:"get_name,omitempty"`
|
||||
Name_ *string `protobuf:"bytes,31,opt,name=name" json:"name,omitempty"`
|
||||
// Oneof that conflicts with its first field: The oneof is renamed.
|
||||
//
|
||||
// Types that are valid to be assigned to OneofConflictA_:
|
||||
// *Message_OneofConflictA
|
||||
OneofConflictA_ isMessage_OneofConflictA_ `protobuf_oneof:"oneof_conflict_a"`
|
||||
// Oneof that conflicts with its second field: The field is renamed.
|
||||
//
|
||||
// Types that are valid to be assigned to OneofConflictB:
|
||||
// *Message_OneofNoConflict
|
||||
// *Message_OneofConflictB_
|
||||
OneofConflictB isMessage_OneofConflictB `protobuf_oneof:"oneof_conflict_b"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Message) Reset() { *m = Message{} }
|
||||
@ -171,27 +182,160 @@ func (m *Message) GetName_() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
type isMessage_OneofConflictA_ interface {
|
||||
isMessage_OneofConflictA_()
|
||||
}
|
||||
|
||||
type Message_OneofConflictA struct {
|
||||
OneofConflictA string `protobuf:"bytes,40,opt,name=OneofConflictA,oneof"`
|
||||
}
|
||||
|
||||
func (*Message_OneofConflictA) isMessage_OneofConflictA_() {}
|
||||
|
||||
func (m *Message) GetOneofConflictA_() isMessage_OneofConflictA_ {
|
||||
if m != nil {
|
||||
return m.OneofConflictA_
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Message) GetOneofConflictA() string {
|
||||
if m != nil && m.OneofConflictA != nil {
|
||||
return *m.OneofConflictA
|
||||
if x, ok := m.GetOneofConflictA_().(*Message_OneofConflictA); ok {
|
||||
return x.OneofConflictA
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type isMessage_OneofConflictB interface {
|
||||
isMessage_OneofConflictB()
|
||||
}
|
||||
|
||||
type Message_OneofNoConflict struct {
|
||||
OneofNoConflict string `protobuf:"bytes,50,opt,name=oneof_no_conflict,json=oneofNoConflict,oneof"`
|
||||
}
|
||||
|
||||
type Message_OneofConflictB_ struct {
|
||||
OneofConflictB_ string `protobuf:"bytes,51,opt,name=OneofConflictB,oneof"`
|
||||
}
|
||||
|
||||
func (*Message_OneofNoConflict) isMessage_OneofConflictB() {}
|
||||
|
||||
func (*Message_OneofConflictB_) isMessage_OneofConflictB() {}
|
||||
|
||||
func (m *Message) GetOneofConflictB() isMessage_OneofConflictB {
|
||||
if m != nil {
|
||||
return m.OneofConflictB
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Message) GetOneofNoConflict() string {
|
||||
if m != nil && m.OneofNoConflict != nil {
|
||||
return *m.OneofNoConflict
|
||||
if x, ok := m.GetOneofConflictB().(*Message_OneofNoConflict); ok {
|
||||
return x.OneofNoConflict
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Message) GetOneofConflictB() string {
|
||||
if m != nil && m.OneofConflictB != nil {
|
||||
return *m.OneofConflictB
|
||||
func (m *Message) GetOneofConflictB_() string {
|
||||
if x, ok := m.GetOneofConflictB().(*Message_OneofConflictB_); ok {
|
||||
return x.OneofConflictB_
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// XXX_OneofFuncs is for the internal use of the proto package.
|
||||
func (*Message) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) {
|
||||
return _Message_OneofMarshaler, _Message_OneofUnmarshaler, _Message_OneofSizer, []interface{}{
|
||||
(*Message_OneofConflictA)(nil),
|
||||
(*Message_OneofNoConflict)(nil),
|
||||
(*Message_OneofConflictB_)(nil),
|
||||
}
|
||||
}
|
||||
|
||||
func _Message_OneofMarshaler(msg proto.Message, b *proto.Buffer) error {
|
||||
m := msg.(*Message)
|
||||
// oneof_conflict_a
|
||||
switch x := m.OneofConflictA_.(type) {
|
||||
case *Message_OneofConflictA:
|
||||
b.EncodeVarint(40<<3 | proto.WireBytes)
|
||||
b.EncodeStringBytes(x.OneofConflictA)
|
||||
case nil:
|
||||
default:
|
||||
return fmt.Errorf("Message.OneofConflictA_ has unexpected type %T", x)
|
||||
}
|
||||
// oneof_conflict_b
|
||||
switch x := m.OneofConflictB.(type) {
|
||||
case *Message_OneofNoConflict:
|
||||
b.EncodeVarint(50<<3 | proto.WireBytes)
|
||||
b.EncodeStringBytes(x.OneofNoConflict)
|
||||
case *Message_OneofConflictB_:
|
||||
b.EncodeVarint(51<<3 | proto.WireBytes)
|
||||
b.EncodeStringBytes(x.OneofConflictB_)
|
||||
case nil:
|
||||
default:
|
||||
return fmt.Errorf("Message.OneofConflictB has unexpected type %T", x)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func _Message_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) {
|
||||
m := msg.(*Message)
|
||||
switch tag {
|
||||
case 40: // oneof_conflict_a.OneofConflictA
|
||||
if wire != proto.WireBytes {
|
||||
return true, proto.ErrInternalBadWireType
|
||||
}
|
||||
x, err := b.DecodeStringBytes()
|
||||
m.OneofConflictA_ = &Message_OneofConflictA{x}
|
||||
return true, err
|
||||
case 50: // oneof_conflict_b.oneof_no_conflict
|
||||
if wire != proto.WireBytes {
|
||||
return true, proto.ErrInternalBadWireType
|
||||
}
|
||||
x, err := b.DecodeStringBytes()
|
||||
m.OneofConflictB = &Message_OneofNoConflict{x}
|
||||
return true, err
|
||||
case 51: // oneof_conflict_b.OneofConflictB
|
||||
if wire != proto.WireBytes {
|
||||
return true, proto.ErrInternalBadWireType
|
||||
}
|
||||
x, err := b.DecodeStringBytes()
|
||||
m.OneofConflictB = &Message_OneofConflictB_{x}
|
||||
return true, err
|
||||
default:
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
func _Message_OneofSizer(msg proto.Message) (n int) {
|
||||
m := msg.(*Message)
|
||||
// oneof_conflict_a
|
||||
switch x := m.OneofConflictA_.(type) {
|
||||
case *Message_OneofConflictA:
|
||||
n += 2 // tag and wire
|
||||
n += proto.SizeVarint(uint64(len(x.OneofConflictA)))
|
||||
n += len(x.OneofConflictA)
|
||||
case nil:
|
||||
default:
|
||||
panic(fmt.Sprintf("proto: unexpected type %T in oneof", x))
|
||||
}
|
||||
// oneof_conflict_b
|
||||
switch x := m.OneofConflictB.(type) {
|
||||
case *Message_OneofNoConflict:
|
||||
n += 2 // tag and wire
|
||||
n += proto.SizeVarint(uint64(len(x.OneofNoConflict)))
|
||||
n += len(x.OneofNoConflict)
|
||||
case *Message_OneofConflictB_:
|
||||
n += 2 // tag and wire
|
||||
n += proto.SizeVarint(uint64(len(x.OneofConflictB_)))
|
||||
n += len(x.OneofConflictB_)
|
||||
case nil:
|
||||
default:
|
||||
panic(fmt.Sprintf("proto: unexpected type %T in oneof", x))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*Message)(nil), "goproto.protoc.fieldnames.Message")
|
||||
}
|
||||
|
1066
cmd/protoc-gen-go/testdata/proto2/fields.pb.go
vendored
1066
cmd/protoc-gen-go/testdata/proto2/fields.pb.go
vendored
File diff suppressed because it is too large
Load Diff
28
cmd/protoc-gen-go/testdata/proto2/fields.proto
vendored
28
cmd/protoc-gen-go/testdata/proto2/fields.proto
vendored
@ -100,6 +100,34 @@ message FieldTestMessage {
|
||||
map<string,Message> map_string_message = 501;
|
||||
map<fixed64,Enum> map_fixed64_enum = 502;
|
||||
|
||||
oneof oneof_field {
|
||||
bool oneof_bool = 601;
|
||||
Enum oneof_enum = 602;
|
||||
int32 oneof_int32 = 603;
|
||||
sint32 oneof_sint32 = 604;
|
||||
uint32 oneof_uint32 = 605;
|
||||
int64 oneof_int64 = 606;
|
||||
sint64 oneof_sint64 = 607;
|
||||
uint64 oneof_uint64 = 608;
|
||||
sfixed32 oneof_sfixed32 = 609;
|
||||
fixed32 oneof_fixed32 = 610;
|
||||
float oneof_float = 611;
|
||||
sfixed64 oneof_sfixed64 = 612;
|
||||
fixed64 oneof_fixed64 = 613;
|
||||
double oneof_double = 614;
|
||||
string oneof_string = 615;
|
||||
bytes oneof_bytes = 616;
|
||||
Message oneof_Message = 617;
|
||||
group OneofGroup = 618 {
|
||||
optional string oneof_group_field = 619;
|
||||
}
|
||||
}
|
||||
|
||||
oneof oneof_two {
|
||||
int32 oneof_two_1 = 700;
|
||||
int64 oneof_two_2 = 701;
|
||||
}
|
||||
|
||||
enum Enum {
|
||||
ZERO = 0;
|
||||
ONE = 1;
|
||||
|
@ -392,11 +392,7 @@ func newFile(gen *Plugin, p *descpb.FileDescriptorProto, packageName GoPackageNa
|
||||
f.GeneratedFilenamePrefix = prefix
|
||||
|
||||
for i, mdescs := 0, desc.Messages(); i < mdescs.Len(); i++ {
|
||||
message, err := newMessage(gen, f, nil, mdescs.Get(i))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f.Messages = append(f.Messages, message)
|
||||
f.Messages = append(f.Messages, newMessage(gen, f, nil, mdescs.Get(i)))
|
||||
}
|
||||
for i, edescs := 0, desc.Enums(); i < edescs.Len(); i++ {
|
||||
f.Enums = append(f.Enums, newEnum(gen, f, nil, edescs.Get(i)))
|
||||
@ -433,12 +429,13 @@ type Message struct {
|
||||
|
||||
GoIdent GoIdent // name of the generated Go type
|
||||
Fields []*Field // message field declarations
|
||||
Oneofs []*Oneof // oneof declarations
|
||||
Messages []*Message // nested message declarations
|
||||
Enums []*Enum // nested enum declarations
|
||||
Path []int32 // location path of this message
|
||||
}
|
||||
|
||||
func newMessage(gen *Plugin, f *File, parent *Message, desc protoreflect.MessageDescriptor) (*Message, error) {
|
||||
func newMessage(gen *Plugin, f *File, parent *Message, desc protoreflect.MessageDescriptor) *Message {
|
||||
var path []int32
|
||||
if parent != nil {
|
||||
path = pathAppend(parent.Path, messageMessageField, int32(desc.Index()))
|
||||
@ -452,21 +449,16 @@ func newMessage(gen *Plugin, f *File, parent *Message, desc protoreflect.Message
|
||||
}
|
||||
gen.messagesByName[desc.FullName()] = message
|
||||
for i, mdescs := 0, desc.Messages(); i < mdescs.Len(); i++ {
|
||||
m, err := newMessage(gen, f, message, mdescs.Get(i))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
message.Messages = append(message.Messages, m)
|
||||
message.Messages = append(message.Messages, newMessage(gen, f, message, mdescs.Get(i)))
|
||||
}
|
||||
for i, edescs := 0, desc.Enums(); i < edescs.Len(); i++ {
|
||||
message.Enums = append(message.Enums, newEnum(gen, f, message, edescs.Get(i)))
|
||||
}
|
||||
for i, odescs := 0, desc.Oneofs(); i < odescs.Len(); i++ {
|
||||
message.Oneofs = append(message.Oneofs, newOneof(gen, f, message, odescs.Get(i)))
|
||||
}
|
||||
for i, fdescs := 0, desc.Fields(); i < fdescs.Len(); i++ {
|
||||
field, err := newField(gen, f, message, fdescs.Get(i))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
message.Fields = append(message.Fields, field)
|
||||
message.Fields = append(message.Fields, newField(gen, f, message, fdescs.Get(i)))
|
||||
}
|
||||
|
||||
// Field name conflict resolution.
|
||||
@ -502,13 +494,20 @@ func newMessage(gen *Plugin, f *File, parent *Message, desc protoreflect.Message
|
||||
usedNames["Get"+name] = true
|
||||
return name
|
||||
}
|
||||
seenOneofs := make(map[int]bool)
|
||||
for _, field := range message.Fields {
|
||||
field.GoIdent.GoName = makeNameUnique(field.GoIdent.GoName)
|
||||
// TODO: If this is the first field of a oneof that we haven't seen
|
||||
// before, generate the name for the oneof.
|
||||
field.GoName = makeNameUnique(field.GoName)
|
||||
if field.OneofType != nil {
|
||||
if !seenOneofs[field.OneofType.Desc.Index()] {
|
||||
// If this is a field in a oneof that we haven't seen before,
|
||||
// make the name for that oneof unique as well.
|
||||
field.OneofType.GoName = makeNameUnique(field.OneofType.GoName)
|
||||
seenOneofs[field.OneofType.Desc.Index()] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return message, nil
|
||||
return message
|
||||
}
|
||||
|
||||
func (message *Message) init(gen *Plugin) error {
|
||||
@ -522,6 +521,9 @@ func (message *Message) init(gen *Plugin) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, oneof := range message.Oneofs {
|
||||
oneof.init(gen, message)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -529,26 +531,29 @@ func (message *Message) init(gen *Plugin) error {
|
||||
type Field struct {
|
||||
Desc protoreflect.FieldDescriptor
|
||||
|
||||
// GoIdent is the base name of this field's Go fields and methods.
|
||||
// GoName is the base name of this field's Go field and methods.
|
||||
// For code generated by protoc-gen-go, this means a field named
|
||||
// '{{GoIdent}}' and a getter method named 'Get{{GoIdent}}'.
|
||||
GoIdent GoIdent
|
||||
// '{{GoName}}' and a getter method named 'Get{{GoName}}'.
|
||||
GoName string
|
||||
|
||||
MessageType *Message // type for message or group fields; nil otherwise
|
||||
EnumType *Enum // type for enum fields; nil otherwise
|
||||
Path []int32 // location path of this field
|
||||
ContainingType *Message // message in which this field occurs
|
||||
MessageType *Message // type for message or group fields; nil otherwise
|
||||
EnumType *Enum // type for enum fields; nil otherwise
|
||||
OneofType *Oneof // containing oneof; nil if not part of a oneof
|
||||
Path []int32 // location path of this field
|
||||
}
|
||||
|
||||
func newField(gen *Plugin, f *File, message *Message, desc protoreflect.FieldDescriptor) (*Field, error) {
|
||||
func newField(gen *Plugin, f *File, message *Message, desc protoreflect.FieldDescriptor) *Field {
|
||||
field := &Field{
|
||||
Desc: desc,
|
||||
GoIdent: GoIdent{
|
||||
GoName: camelCase(string(desc.Name())),
|
||||
GoImportPath: f.GoImportPath,
|
||||
},
|
||||
Path: pathAppend(message.Path, messageFieldField, int32(desc.Index())),
|
||||
Desc: desc,
|
||||
GoName: camelCase(string(desc.Name())),
|
||||
ContainingType: message,
|
||||
Path: pathAppend(message.Path, messageFieldField, int32(desc.Index())),
|
||||
}
|
||||
return field, nil
|
||||
if desc.OneofType() != nil {
|
||||
field.OneofType = message.Oneofs[desc.OneofType().Index()]
|
||||
}
|
||||
return field
|
||||
}
|
||||
|
||||
func (field *Field) init(gen *Plugin) error {
|
||||
@ -572,6 +577,31 @@ func (field *Field) init(gen *Plugin) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// A Oneof describes a oneof field.
|
||||
type Oneof struct {
|
||||
Desc protoreflect.OneofDescriptor
|
||||
|
||||
GoName string // Go field name of this oneof
|
||||
ContainingType *Message // message in which this oneof occurs
|
||||
Fields []*Field // fields that are part of this oneof
|
||||
Path []int32 // location path of this oneof
|
||||
}
|
||||
|
||||
func newOneof(gen *Plugin, f *File, message *Message, desc protoreflect.OneofDescriptor) *Oneof {
|
||||
return &Oneof{
|
||||
Desc: desc,
|
||||
ContainingType: message,
|
||||
GoName: camelCase(string(desc.Name())),
|
||||
Path: pathAppend(message.Path, messageOneofField, int32(desc.Index())),
|
||||
}
|
||||
}
|
||||
|
||||
func (oneof *Oneof) init(gen *Plugin, parent *Message) {
|
||||
for i, fdescs := 0, oneof.Desc.Fields(); i < fdescs.Len(); i++ {
|
||||
oneof.Fields = append(oneof.Fields, parent.Fields[fdescs.Get(i).Index()])
|
||||
}
|
||||
}
|
||||
|
||||
// An Enum describes an enum.
|
||||
type Enum struct {
|
||||
Desc protoreflect.EnumDescriptor
|
||||
|
Loading…
x
Reference in New Issue
Block a user