vendor: Update github.com/gogo/protobuf

Also tweaks the proto definitions:

 - [packed=false] on the block_indexes field to retain compat with
   v0.14.16 and earlier.

 - Uses the vendored protobuf package in include paths.

And, "build.go setup" will install the vendored protoc-gen-gogofast.
This should ensure that a proto rebuild isn't so dependent on whatever
version of the compiler and package the developer has installed...

GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/3864
This commit is contained in:
Jakob Borg
2017-01-03 00:16:21 +00:00
committed by Audrius Butkevicius
parent 4fb9c143ac
commit 987718baf8
603 changed files with 340684 additions and 62506 deletions
+287 -98
View File
@@ -1,7 +1,7 @@
// Extensions for Protocol Buffers to create more go like structures.
// Protocol Buffers for Go with Gadgets
//
// Copyright (c) 2013, Vastech SA (PTY) LTD. All rights reserved.
// http://github.com/gogo/protobuf/gogoproto
// Copyright (c) 2013, The GoGo Authors. All rights reserved.
// http://github.com/gogo/protobuf
//
// Go support for Protocol Buffers - Google's data interchange format
//
@@ -68,7 +68,7 @@ import (
// It is incremented whenever an incompatibility between the generated code and
// proto package is introduced; the generated code references
// a constant, proto.ProtoPackageIsVersionN (where N is generatedCodeVersion).
const generatedCodeVersion = 1
const generatedCodeVersion = 2
// A Plugin provides functionality to add to the output during Go code generation,
// such as to produce RPC stubs.
@@ -300,6 +300,36 @@ type FileDescriptor struct {
// PackageName is the package name we'll use in the generated code to refer to this file.
func (d *FileDescriptor) PackageName() string { return uniquePackageOf(d.FileDescriptorProto) }
// VarName is the variable name we'll use in the generated code to refer
// to the compressed bytes of this descriptor. It is not exported, so
// it is only valid inside the generated package.
func (d *FileDescriptor) VarName() string { return fmt.Sprintf("fileDescriptor%v", FileName(d)) }
// goPackageOption interprets the file's go_package option.
// If there is no go_package, it returns ("", "", false).
// If there's a simple name, it returns ("", pkg, true).
// If the option implies an import path, it returns (impPath, pkg, true).
func (d *FileDescriptor) goPackageOption() (impPath, pkg string, ok bool) {
pkg = d.GetOptions().GetGoPackage()
if pkg == "" {
return
}
ok = true
// The presence of a slash implies there's an import path.
slash := strings.LastIndex(pkg, "/")
if slash < 0 {
return
}
impPath, pkg = pkg, pkg[slash+1:]
// A semicolon-delimited suffix overrides the package name.
sc := strings.IndexByte(impPath, ';')
if sc < 0 {
return
}
impPath, pkg = impPath[:sc], impPath[sc+1:]
return
}
// goPackageName returns the Go package name to use in the
// generated Go file. The result explicit reports whether the name
// came from an option go_package statement. If explicit is false,
@@ -307,10 +337,8 @@ func (d *FileDescriptor) PackageName() string { return uniquePackageOf(d.FileDes
// or the input file name.
func (d *FileDescriptor) goPackageName() (name string, explicit bool) {
// Does the file have a "go_package" option?
if opts := d.Options; opts != nil {
if pkg := opts.GetGoPackage(); pkg != "" {
return pkg, true
}
if _, pkg, ok := d.goPackageOption(); ok {
return pkg, true
}
// Does the file have a package clause?
@@ -321,6 +349,26 @@ func (d *FileDescriptor) goPackageName() (name string, explicit bool) {
return baseName(d.GetName()), false
}
// goFileName returns the output name for the generated Go file.
func (d *FileDescriptor) goFileName() string {
name := *d.Name
if ext := path.Ext(name); ext == ".proto" || ext == ".protodevel" {
name = name[:len(name)-len(ext)]
}
name += ".pb.go"
// Does the file have a "go_package" option?
// If it does, it may override the filename.
if impPath, _, ok := d.goPackageOption(); ok && impPath != "" {
// Replace the existing dirname with the declared import path.
_, name = path.Split(name)
name = path.Join(impPath, name)
return name
}
return name
}
func (d *FileDescriptor) addExport(obj Object, sym symbol) {
d.exported[obj] = append(d.exported[obj], sym)
}
@@ -356,8 +404,6 @@ func (ms *messageSymbol) GenerateAlias(g *Generator, pkg string) {
if ms.hasExtensions {
g.P("func (*", ms.sym, ") ExtensionRangeArray() []", g.Pkg["proto"], ".ExtensionRange ",
"{ return (*", remoteSym, ")(nil).ExtensionRangeArray() }")
g.P("func (m *", ms.sym, ") ExtensionMap() map[int32]", g.Pkg["proto"], ".Extension ",
"{ return (*", remoteSym, ")(m).ExtensionMap() }")
if ms.isMessageSet {
g.P("func (m *", ms.sym, ") Marshal() ([]byte, error) ",
"{ return (*", remoteSym, ")(m).Marshal() }")
@@ -548,7 +594,7 @@ type Generator struct {
Param map[string]string // Command-line parameters.
PackageImportPath string // Go import path of the package we're generating code for
ImportPrefix string // String to prefix to imported package file names.
ImportMap map[string]string // Mapping from import name to generated name
ImportMap map[string]string // Mapping from .proto file name to import path
Pkg map[string]string // The names under which we import support packages
@@ -622,7 +668,6 @@ func (g *Generator) CommandLineParameters(parameter string) {
}
}
}
if pluginList == "" {
return
}
@@ -823,9 +868,9 @@ AllFiles:
// and FileDescriptorProtos into file-referenced objects within the Generator.
// It also creates the list of files to generate and so should be called before GenerateAllFiles.
func (g *Generator) WrapTypes() {
g.allFiles = make([]*FileDescriptor, len(g.Request.ProtoFile))
g.allFiles = make([]*FileDescriptor, 0, len(g.Request.ProtoFile))
g.allFilesByName = make(map[string]*FileDescriptor, len(g.allFiles))
for i, f := range g.Request.ProtoFile {
for _, f := range g.Request.ProtoFile {
// We must wrap the descriptors before we wrap the enums
descs := wrapDescriptors(f)
g.buildNestedDescriptors(descs)
@@ -841,22 +886,22 @@ func (g *Generator) WrapTypes() {
proto3: fileIsProto3(f),
}
extractComments(fd)
g.allFiles[i] = fd
g.allFiles = append(g.allFiles, fd)
g.allFilesByName[f.GetName()] = fd
}
for _, fd := range g.allFiles {
fd.imp = wrapImported(fd.FileDescriptorProto, g)
}
g.genFiles = make([]*FileDescriptor, len(g.Request.FileToGenerate))
for i, fileName := range g.Request.FileToGenerate {
g.genFiles[i] = g.allFilesByName[fileName]
if g.genFiles[i] == nil {
g.genFiles = make([]*FileDescriptor, 0, len(g.Request.FileToGenerate))
for _, fileName := range g.Request.FileToGenerate {
fd := g.allFilesByName[fileName]
if fd == nil {
g.Fail("could not find file named", fileName)
}
g.genFiles[i].index = i
fd.index = len(g.genFiles)
g.genFiles = append(g.genFiles, fd)
}
g.Response.File = make([]*plugin.CodeGeneratorResponse_File, len(g.genFiles))
}
// Scan the descriptors in this file. For each one, build the slice of nested descriptors
@@ -920,9 +965,8 @@ func newDescriptor(desc *descriptor.DescriptorProto, parent *Descriptor, file *d
}
}
d.ext = make([]*ExtensionDescriptor, len(desc.Extension))
for i, field := range desc.Extension {
d.ext[i] = &ExtensionDescriptor{common{file}, field, d}
for _, field := range desc.Extension {
d.ext = append(d.ext, &ExtensionDescriptor{common{file}, field, d})
}
return d
@@ -981,9 +1025,9 @@ func wrapEnumDescriptors(file *descriptor.FileDescriptorProto, descs []*Descript
// Return a slice of all the top-level ExtensionDescriptors defined within this file.
func wrapExtensions(file *descriptor.FileDescriptorProto) []*ExtensionDescriptor {
sl := make([]*ExtensionDescriptor, len(file.Extension))
for i, field := range file.Extension {
sl[i] = &ExtensionDescriptor{common{file}, field, nil}
var sl []*ExtensionDescriptor
for _, field := range file.Extension {
sl = append(sl, &ExtensionDescriptor{common{file}, field, nil})
}
return sl
}
@@ -1161,7 +1205,6 @@ func (g *Generator) GenerateAllFiles() {
for _, file := range g.genFiles {
genFileMap[file] = true
}
i := 0
for _, file := range g.allFiles {
g.Reset()
g.writeOutput = genFileMap[file]
@@ -1169,10 +1212,10 @@ func (g *Generator) GenerateAllFiles() {
if !g.writeOutput {
continue
}
g.Response.File[i] = new(plugin.CodeGeneratorResponse_File)
g.Response.File[i].Name = proto.String(goFileName(*file.Name))
g.Response.File[i].Content = proto.String(g.String())
i++
g.Response.File = append(g.Response.File, &plugin.CodeGeneratorResponse_File{
Name: proto.String(file.goFileName()),
Content: proto.String(g.String()),
})
}
}
@@ -1205,17 +1248,17 @@ func (g *Generator) generate(file *FileDescriptor) {
// For one file in the package, assert version compatibility.
g.P("// This is a compile-time assertion to ensure that this generated file")
g.P("// is compatible with the proto package it is being compiled against.")
g.P("// A compilation error at this line likely means your copy of the")
g.P("// proto package needs to be updated.")
if gogoproto.ImportsGoGoProto(file.FileDescriptorProto) {
g.P("const _ = ", g.Pkg["proto"], ".GoGoProtoPackageIsVersion", generatedCodeVersion)
g.P("const _ = ", g.Pkg["proto"], ".GoGoProtoPackageIsVersion", generatedCodeVersion, " // please upgrade the proto package")
} else {
g.P("const _ = ", g.Pkg["proto"], ".ProtoPackageIsVersion", generatedCodeVersion)
g.P("const _ = ", g.Pkg["proto"], ".ProtoPackageIsVersion", generatedCodeVersion, " // please upgrade the proto package")
}
g.P()
}
// Reset on each file
g.writtenImports = make(map[string]bool)
for _, td := range g.file.imp {
g.generateImported(td)
}
@@ -1386,7 +1429,7 @@ func (g *Generator) generateImports() {
if fd.PackageName() == g.packageName {
continue
}
filename := goFileName(s)
filename := fd.goFileName()
// By default, import path is the dirname of the Go filename.
importPath := path.Dir(filename)
if substitution, ok := g.ImportMap[s]; ok {
@@ -1547,8 +1590,10 @@ func (g *Generator) generateEnum(enum *EnumDescriptor) {
indexes = append([]string{strconv.Itoa(m.index)}, indexes...)
}
indexes = append(indexes, strconv.Itoa(enum.index))
g.P("func (", ccTypeName, ") EnumDescriptor() ([]byte, []int) { return fileDescriptor", FileName(g.file), ", []int{", strings.Join(indexes, ", "), "} }")
g.P("func (", ccTypeName, ") EnumDescriptor() ([]byte, []int) { return ", g.file.VarName(), ", []int{", strings.Join(indexes, ", "), "} }")
if enum.file.GetPackage() == "google.protobuf" && enum.GetName() == "NullValue" {
g.P("func (", ccTypeName, `) XXX_WellKnownType() string { return "`, enum.GetName(), `" }`)
}
g.P()
}
@@ -1624,7 +1669,11 @@ func (g *Generator) goTag(message *Descriptor, field *descriptor.FieldDescriptor
enum += CamelCaseSlice(obj.TypeName())
}
packed := ""
if field.Options != nil && field.Options.GetPacked() {
if (field.Options != nil && field.Options.GetPacked()) ||
// Per https://developers.google.com/protocol-buffers/docs/proto3#simple:
// "In proto3, repeated fields of scalar numeric types use packed encoding by default."
(message.proto3() && (field.Options == nil || field.Options.Packed == nil) &&
isRepeated(field) && IsScalar(field)) {
packed = ",packed"
}
fieldName := field.GetName()
@@ -1692,7 +1741,15 @@ func (g *Generator) goTag(message *Descriptor, field *descriptor.FieldDescriptor
if field.OneofIndex != nil {
oneof = ",oneof"
}
return strconv.Quote(fmt.Sprintf("%s,%d,%s%s%s%s%s%s%s%s%s%s%s",
stdtime := ""
if gogoproto.IsStdTime(field) {
stdtime = ",stdtime"
}
stdduration := ""
if gogoproto.IsStdDuration(field) {
stdduration = ",stdduration"
}
return strconv.Quote(fmt.Sprintf("%s,%d,%s%s%s%s%s%s%s%s%s%s%s%s%s",
wiretype,
field.GetNumber(),
optrepreq,
@@ -1705,7 +1762,9 @@ func (g *Generator) goTag(message *Descriptor, field *descriptor.FieldDescriptor
ctype,
casttype,
castkey,
castvalue))
castvalue,
stdtime,
stdduration))
}
func needsStar(field *descriptor.FieldDescriptorProto, proto3 bool, allowOneOf bool) bool {
@@ -1818,8 +1877,14 @@ func (g *Generator) GoType(message *Descriptor, field *descriptor.FieldDescripto
if len(packageName) > 0 {
g.customImports = append(g.customImports, packageName)
}
case gogoproto.IsStdTime(field):
g.customImports = append(g.customImports, "time")
typ = "time.Time"
case gogoproto.IsStdDuration(field):
g.customImports = append(g.customImports, "time")
typ = "time.Duration"
}
if needsStar(field, g.file.proto3, message != nil && message.allowOneof()) {
if needsStar(field, g.file.proto3 && field.Extendee == nil, message != nil && message.allowOneof()) {
typ = "*" + typ
}
if isRepeated(field) {
@@ -1890,9 +1955,18 @@ func (g *Generator) GoMapType(d *Descriptor, field *descriptor.FieldDescriptorPr
if !gogoproto.IsNullable(m.ValueAliasField) {
valType = strings.TrimPrefix(valType, "*")
}
g.RecordTypeUse(m.ValueAliasField.GetTypeName())
if !gogoproto.IsStdTime(field) && !gogoproto.IsStdDuration(field) {
g.RecordTypeUse(m.ValueAliasField.GetTypeName())
}
default:
valType = strings.TrimPrefix(valType, "*")
if gogoproto.IsCustomType(m.ValueAliasField) {
if !gogoproto.IsNullable(m.ValueAliasField) {
valType = strings.TrimPrefix(valType, "*")
}
g.RecordTypeUse(m.ValueAliasField.GetTypeName())
} else {
valType = strings.TrimPrefix(valType, "*")
}
}
m.GoType = fmt.Sprintf("map[%s]%s", keyType, valType)
@@ -1908,7 +1982,8 @@ func (g *Generator) RecordTypeUse(t string) {
}
// Method names that may be generated. Fields with these names get an
// underscore appended.
// underscore appended. Any change to this set is a potential incompatible
// API change because it changes generated field names.
var methodNames = [...]string{
"Reset",
"String",
@@ -1925,6 +2000,28 @@ var methodNames = [...]string{
"ProtoSize",
}
// Names of messages in the `google.protobuf` package for which
// we will generate XXX_WellKnownType methods.
var wellKnownTypes = map[string]bool{
"Any": true,
"Duration": true,
"Empty": true,
"Struct": true,
"Timestamp": true,
"Value": true,
"ListValue": true,
"DoubleValue": true,
"FloatValue": true,
"Int64Value": true,
"UInt64Value": true,
"Int32Value": true,
"UInt32Value": true,
"BoolValue": true,
"StringValue": true,
"BytesValue": true,
}
// Generate the type and default constant definitions for this Descriptor.
func (g *Generator) generateMessage(message *Descriptor) {
// The full type name
@@ -2076,11 +2173,13 @@ func (g *Generator) generateMessage(message *Descriptor) {
g.PrintComments(fmt.Sprintf("%s,%d,%d", message.path, messageFieldPath, i))
g.P(fieldName, "\t", typename, "\t`", tag, "`")
g.RecordTypeUse(field.GetTypeName())
if !gogoproto.IsStdTime(field) && !gogoproto.IsStdDuration(field) {
g.RecordTypeUse(field.GetTypeName())
}
}
if len(message.ExtensionRange) > 0 {
if gogoproto.HasExtensionsMap(g.file.FileDescriptorProto, message.DescriptorProto) {
g.P("XXX_extensions\t\tmap[int32]", g.Pkg["proto"], ".Extension `json:\"-\"`")
g.P(g.Pkg["proto"], ".XXX_InternalExtensions `json:\"-\"`")
} else {
g.P("XXX_extensions\t\t[]byte `protobuf:\"bytes,0,opt\" json:\"-\"`")
}
@@ -2114,15 +2213,16 @@ func (g *Generator) generateMessage(message *Descriptor) {
g.P("func (m *", ccTypeName, ") String() string { return ", g.Pkg["proto"], ".CompactTextString(m) }")
}
g.P("func (*", ccTypeName, ") ProtoMessage() {}")
if !message.group {
var indexes []string
for m := message; m != nil; m = m.parent {
// XXX: skip groups?
indexes = append([]string{strconv.Itoa(m.index)}, indexes...)
}
g.P("func (*", ccTypeName, ") Descriptor() ([]byte, []int) { return fileDescriptor", FileName(g.file), ", []int{", strings.Join(indexes, ", "), "} }")
var indexes []string
for m := message; m != nil; m = m.parent {
indexes = append([]string{strconv.Itoa(m.index)}, indexes...)
}
g.P("func (*", ccTypeName, ") Descriptor() ([]byte, []int) { return ", g.file.VarName(), ", []int{", strings.Join(indexes, ", "), "} }")
// TODO: Revisit the decision to use a XXX_WellKnownType method
// if we change proto.MessageName to work with multiple equivalents.
if message.file.GetPackage() == "google.protobuf" && wellKnownTypes[message.GetName()] {
g.P("func (*", ccTypeName, `) XXX_WellKnownType() string { return "`, message.GetName(), `" }`)
}
// Extension support methods
var hasExtensions, isMessageSet bool
if len(message.ExtensionRange) > 0 {
@@ -2133,22 +2233,22 @@ func (g *Generator) generateMessage(message *Descriptor) {
g.P()
g.P("func (m *", ccTypeName, ") Marshal() ([]byte, error) {")
g.In()
g.P("return ", g.Pkg["proto"], ".MarshalMessageSet(m.ExtensionMap())")
g.P("return ", g.Pkg["proto"], ".MarshalMessageSet(&m.XXX_InternalExtensions)")
g.Out()
g.P("}")
g.P("func (m *", ccTypeName, ") Unmarshal(buf []byte) error {")
g.In()
g.P("return ", g.Pkg["proto"], ".UnmarshalMessageSet(buf, m.ExtensionMap())")
g.P("return ", g.Pkg["proto"], ".UnmarshalMessageSet(buf, &m.XXX_InternalExtensions)")
g.Out()
g.P("}")
g.P("func (m *", ccTypeName, ") MarshalJSON() ([]byte, error) {")
g.In()
g.P("return ", g.Pkg["proto"], ".MarshalMessageSetJSON(m.XXX_extensions)")
g.P("return ", g.Pkg["proto"], ".MarshalMessageSetJSON(&m.XXX_InternalExtensions)")
g.Out()
g.P("}")
g.P("func (m *", ccTypeName, ") UnmarshalJSON(buf []byte) error {")
g.In()
g.P("return ", g.Pkg["proto"], ".UnmarshalMessageSetJSON(buf, m.XXX_extensions)")
g.P("return ", g.Pkg["proto"], ".UnmarshalMessageSetJSON(buf, &m.XXX_InternalExtensions)")
g.Out()
g.P("}")
g.P("// ensure ", ccTypeName, " satisfies proto.Marshaler and proto.Unmarshaler")
@@ -2161,7 +2261,7 @@ func (g *Generator) generateMessage(message *Descriptor) {
g.In()
for _, r := range message.ExtensionRange {
end := fmt.Sprint(*r.End - 1) // make range inclusive on both ends
g.P("{", r.Start, ", ", end, "},")
g.P("{Start: ", r.Start, ", End: ", end, "},")
}
g.Out()
g.P("}")
@@ -2170,18 +2270,7 @@ func (g *Generator) generateMessage(message *Descriptor) {
g.P("return extRange_", ccTypeName)
g.Out()
g.P("}")
if gogoproto.HasExtensionsMap(g.file.FileDescriptorProto, message.DescriptorProto) {
g.P("func (m *", ccTypeName, ") ExtensionMap() map[int32]", g.Pkg["proto"], ".Extension {")
g.In()
g.P("if m.XXX_extensions == nil {")
g.In()
g.P("m.XXX_extensions = make(map[int32]", g.Pkg["proto"], ".Extension)")
g.Out()
g.P("}")
g.P("return m.XXX_extensions")
g.Out()
g.P("}")
} else {
if !gogoproto.HasExtensionsMap(g.file.FileDescriptorProto, message.DescriptorProto) {
g.P("func (m *", ccTypeName, ") GetExtensions() *[]byte {")
g.In()
g.P("if m.XXX_extensions == nil {")
@@ -2315,7 +2404,9 @@ func (g *Generator) generateMessage(message *Descriptor) {
_, wiretype := g.GoType(message, field)
tag := "protobuf:" + g.goTag(message, field, wiretype)
g.P("type ", oneofTypeName[field], " struct{ ", fieldNames[field], " ", fieldTypes[field], " `", tag, "` }")
g.RecordTypeUse(field.GetTypeName())
if !gogoproto.IsStdTime(field) && !gogoproto.IsStdDuration(field) {
g.RecordTypeUse(field.GetTypeName())
}
}
g.P()
for _, field := range message.Field {
@@ -2359,11 +2450,6 @@ func (g *Generator) generateMessage(message *Descriptor) {
star = "*"
}
// In proto3, only generate getters for message fields and oneof fields.
if message.proto3() && *field.Type != descriptor.FieldDescriptorProto_TYPE_MESSAGE && !oneof {
continue
}
// Only export getter symbols for basic types,
// and for messages and enums in the same package.
// Groups are not exported.
@@ -2428,7 +2514,11 @@ func (g *Generator) generateMessage(message *Descriptor) {
g.Out()
g.P("}")
} else if !oneof {
g.P("if m != nil && m." + fname + " != nil {")
if message.proto3() {
g.P("if m != nil {")
} else {
g.P("if m != nil && m." + fname + " != nil {")
}
g.In()
g.P("return " + star + "m." + fname)
g.Out()
@@ -2457,7 +2547,11 @@ func (g *Generator) generateMessage(message *Descriptor) {
} else {
goTyp, _ := g.GoType(message, field)
goTypName := GoTypeToName(goTyp)
g.P("return ", goTypName, "{}")
if !gogoproto.IsNullable(field) && gogoproto.IsStdDuration(field) {
g.P("return 0")
} else {
g.P("return ", goTypName, "{}")
}
}
case descriptor.FieldDescriptorProto_TYPE_BOOL:
g.P("return false")
@@ -2614,13 +2708,41 @@ func (g *Generator) generateMessage(message *Descriptor) {
fieldWire[field] = wire
g.P("_ = b.EncodeVarint(", field.Number, "<<3|", g.Pkg["proto"], ".", wire, ")")
if *field.Type == descriptor.FieldDescriptorProto_TYPE_BYTES && gogoproto.IsCustomType(field) {
g.P(`data, err := `, val, `.Marshal()`)
g.P(`dAtA, err := `, val, `.Marshal()`)
g.P(`if err != nil {`)
g.In()
g.P(`return err`)
g.Out()
g.P(`}`)
val = "data"
val = "dAtA"
} else if gogoproto.IsStdTime(field) {
pkg := g.useTypes()
if gogoproto.IsNullable(field) {
g.P(`dAtA, err := `, pkg, `.StdTimeMarshal(*`, val, `)`)
} else {
g.P(`dAtA, err := `, pkg, `.StdTimeMarshal(`, val, `)`)
}
g.P(`if err != nil {`)
g.In()
g.P(`return err`)
g.Out()
g.P(`}`)
val = "dAtA"
pre, post = "b.EncodeRawBytes(", ")"
} else if gogoproto.IsStdDuration(field) {
pkg := g.useTypes()
if gogoproto.IsNullable(field) {
g.P(`dAtA, err := `, pkg, `.StdDurationMarshal(*`, val, `)`)
} else {
g.P(`dAtA, err := `, pkg, `.StdDurationMarshal(`, val, `)`)
}
g.P(`if err != nil {`)
g.In()
g.P(`return err`)
g.Out()
g.P(`}`)
val = "dAtA"
pre, post = "b.EncodeRawBytes(", ")"
}
if !canFail {
g.P("_ = ", pre, val, post)
@@ -2684,9 +2806,13 @@ func (g *Generator) generateMessage(message *Descriptor) {
dec = "b.DecodeGroup(msg)"
// handled specially below
case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
g.P("msg := new(", fieldTypes[field][1:], ")") // drop star
lhs = "err"
dec = "b.DecodeMessage(msg)"
if gogoproto.IsStdTime(field) || gogoproto.IsStdDuration(field) {
dec = "b.DecodeRawBytes(true)"
} else {
g.P("msg := new(", fieldTypes[field][1:], ")") // drop star
lhs = "err"
dec = "b.DecodeMessage(msg)"
}
// handled specially below
case descriptor.FieldDescriptorProto_TYPE_BYTES:
dec = "b.DecodeRawBytes(true)"
@@ -2721,6 +2847,34 @@ func (g *Generator) generateMessage(message *Descriptor) {
g.P(`c := &cc`)
g.P(`err = c.Unmarshal(`, val, `)`)
val = "*c"
} else if gogoproto.IsStdTime(field) {
pkg := g.useTypes()
g.P(`if err != nil {`)
g.In()
g.P(`return true, err`)
g.Out()
g.P(`}`)
g.P(`c := new(time.Time)`)
g.P(`if err2 := `, pkg, `.StdTimeUnmarshal(c, `, val, `); err2 != nil {`)
g.In()
g.P(`return true, err`)
g.Out()
g.P(`}`)
val = "c"
} else if gogoproto.IsStdDuration(field) {
pkg := g.useTypes()
g.P(`if err != nil {`)
g.In()
g.P(`return true, err`)
g.Out()
g.P(`}`)
g.P(`c := new(time.Duration)`)
g.P(`if err2 := `, pkg, `.StdDurationUnmarshal(c, `, val, `); err2 != nil {`)
g.In()
g.P(`return true, err`)
g.Out()
g.P(`}`)
val = "c"
}
if cast != "" {
val = cast + "(" + val + ")"
@@ -2733,7 +2887,9 @@ func (g *Generator) generateMessage(message *Descriptor) {
val += " != 0"
case descriptor.FieldDescriptorProto_TYPE_GROUP,
descriptor.FieldDescriptorProto_TYPE_MESSAGE:
val = "msg"
if !gogoproto.IsStdTime(field) && !gogoproto.IsStdDuration(field) {
val = "msg"
}
}
if gogoproto.IsCastType(field) {
_, typ, err := getCastType(field)
@@ -2798,7 +2954,21 @@ func (g *Generator) generateMessage(message *Descriptor) {
fixed = g.Pkg["proto"] + ".Size(" + val + ")"
case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
wire = "WireBytes"
g.P("s := ", g.Pkg["proto"], ".Size(", val, ")")
if gogoproto.IsStdTime(field) {
if gogoproto.IsNullable(field) {
val = "*" + val
}
pkg := g.useTypes()
g.P("s := ", pkg, ".SizeOfStdTime(", val, ")")
} else if gogoproto.IsStdDuration(field) {
if gogoproto.IsNullable(field) {
val = "*" + val
}
pkg := g.useTypes()
g.P("s := ", pkg, ".SizeOfStdDuration(", val, ")")
} else {
g.P("s := ", g.Pkg["proto"], ".Size(", val, ")")
}
fixed = "s"
varint = fixed
case descriptor.FieldDescriptorProto_TYPE_BYTES:
@@ -2898,6 +3068,7 @@ func (g *Generator) generateExtension(ext *ExtensionDescriptor) {
g.P("Field: ", field.Number, ",")
g.P(`Name: "`, extName, `",`)
g.P("Tag: ", tag, ",")
g.P(`Filename: "`, g.file.GetName(), `",`)
g.Out()
g.P("}")
@@ -2953,8 +3124,9 @@ func (g *Generator) generateFileDescriptor(file *FileDescriptor) {
w.Close()
b = buf.Bytes()
v := fmt.Sprintf("fileDescriptor%v", FileName(file))
v := file.VarName()
g.P()
g.P("func init() { ", g.Pkg["proto"], ".RegisterFile(", strconv.Quote(*file.Name), ", ", v, ") }")
g.P("var ", v, " = []byte{")
g.In()
g.P("// ", len(b), " bytes of a gzipped FileDescriptorProto")
@@ -3059,15 +3231,6 @@ func CamelCaseSlice(elem []string) string { return CamelCase(strings.Join(elem,
// dottedSlice turns a sliced name into a dotted name.
func dottedSlice(elem []string) string { return strings.Join(elem, ".") }
// Given a .proto file name, return the output name for the generated Go program.
func goFileName(name string) string {
ext := path.Ext(name)
if ext == ".proto" || ext == ".protodevel" {
name = name[0 : len(name)-len(ext)]
}
return name + ".pb.go"
}
// Is this field optional?
func isOptional(field *descriptor.FieldDescriptorProto) bool {
return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_OPTIONAL
@@ -3083,6 +3246,32 @@ func isRepeated(field *descriptor.FieldDescriptorProto) bool {
return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED
}
// Is this field a scalar numeric type?
func IsScalar(field *descriptor.FieldDescriptorProto) bool {
if field.Type == nil {
return false
}
switch *field.Type {
case descriptor.FieldDescriptorProto_TYPE_DOUBLE,
descriptor.FieldDescriptorProto_TYPE_FLOAT,
descriptor.FieldDescriptorProto_TYPE_INT64,
descriptor.FieldDescriptorProto_TYPE_UINT64,
descriptor.FieldDescriptorProto_TYPE_INT32,
descriptor.FieldDescriptorProto_TYPE_FIXED64,
descriptor.FieldDescriptorProto_TYPE_FIXED32,
descriptor.FieldDescriptorProto_TYPE_BOOL,
descriptor.FieldDescriptorProto_TYPE_UINT32,
descriptor.FieldDescriptorProto_TYPE_ENUM,
descriptor.FieldDescriptorProto_TYPE_SFIXED32,
descriptor.FieldDescriptorProto_TYPE_SFIXED64,
descriptor.FieldDescriptorProto_TYPE_SINT32,
descriptor.FieldDescriptorProto_TYPE_SINT64:
return true
default:
return false
}
}
// badToUnderscore is the mapping function used to generate Go names from package names,
// which can be dotted in the input .proto file. It replaces non-identifier characters such as
// dot or dash with underscore.
+38 -36
View File
@@ -1,5 +1,7 @@
// Copyright (c) 2013, Vastech SA (PTY) LTD. All rights reserved.
// http://github.com/gogo/protobuf/gogoproto
// Protocol Buffers for Go with Gadgets
//
// Copyright (c) 2013, The GoGo Authors. All rights reserved.
// http://github.com/gogo/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -238,18 +240,38 @@ func (g *Generator) GetMapKeyField(field, keyField *descriptor.FieldDescriptorPr
}
func (g *Generator) GetMapValueField(field, valField *descriptor.FieldDescriptorProto) *descriptor.FieldDescriptorProto {
if !gogoproto.IsCastValue(field) && gogoproto.IsNullable(field) {
return valField
if gogoproto.IsCustomType(field) && gogoproto.IsCastValue(field) {
g.Fail("cannot have a customtype and casttype: ", field.String())
}
valField = proto.Clone(valField).(*descriptor.FieldDescriptorProto)
if valField.Options == nil {
valField.Options = &descriptor.FieldOptions{}
}
stdtime := gogoproto.IsStdTime(field)
if stdtime {
if err := proto.SetExtension(valField.Options, gogoproto.E_Stdtime, &stdtime); err != nil {
g.Fail(err.Error())
}
}
stddur := gogoproto.IsStdDuration(field)
if stddur {
if err := proto.SetExtension(valField.Options, gogoproto.E_Stdduration, &stddur); err != nil {
g.Fail(err.Error())
}
}
if valType := gogoproto.GetCastValue(field); len(valType) > 0 {
if err := proto.SetExtension(valField.Options, gogoproto.E_Casttype, &valType); err != nil {
g.Fail(err.Error())
}
}
if valType := gogoproto.GetCustomType(field); len(valType) > 0 {
if err := proto.SetExtension(valField.Options, gogoproto.E_Customtype, &valType); err != nil {
g.Fail(err.Error())
}
}
nullable := gogoproto.IsNullable(field)
if err := proto.SetExtension(valField.Options, gogoproto.E_Nullable, &nullable); err != nil {
@@ -261,7 +283,7 @@ func (g *Generator) GetMapValueField(field, valField *descriptor.FieldDescriptor
// GoMapValueTypes returns the map value Go type and the alias map value Go type (for casting), taking into
// account whether the map is nullable or the value is a message.
func GoMapValueTypes(mapField, valueField *descriptor.FieldDescriptorProto, goValueType, goValueAliasType string) (nullable bool, outGoType string, outGoAliasType string) {
nullable = gogoproto.IsNullable(mapField) && valueField.IsMessage()
nullable = gogoproto.IsNullable(mapField) && (valueField.IsMessage() || gogoproto.IsCustomType(mapField))
if nullable {
// ensure the non-aliased Go value type is a pointer for consistency
if strings.HasPrefix(goValueType, "*") {
@@ -294,6 +316,7 @@ func EmbedFieldName(goTyp string) string {
}
func (g *Generator) GeneratePlugin(p Plugin) {
plugins = []Plugin{p}
p.Init(g)
// Generate the output. The generator runs for every file, even the files
// that we don't generate output for, so that we can collate the full list
@@ -302,7 +325,6 @@ func (g *Generator) GeneratePlugin(p Plugin) {
for _, file := range g.genFiles {
genFileMap[file] = true
}
i := 0
for _, file := range g.allFiles {
g.Reset()
g.writeOutput = genFileMap[file]
@@ -310,10 +332,10 @@ func (g *Generator) GeneratePlugin(p Plugin) {
if !g.writeOutput {
continue
}
g.Response.File[i] = new(plugin.CodeGeneratorResponse_File)
g.Response.File[i].Name = proto.String(goFileName(*file.Name))
g.Response.File[i].Content = proto.String(g.String())
i++
g.Response.File = append(g.Response.File, &plugin.CodeGeneratorResponse_File{
Name: proto.String(file.goFileName()),
Content: proto.String(g.String()),
})
}
}
@@ -397,32 +419,6 @@ func getCastType(field *descriptor.FieldDescriptorProto) (packageName string, ty
return "", "", err
}
func getCastKey(field *descriptor.FieldDescriptorProto) (packageName string, typ string, err error) {
if field.Options != nil {
var v interface{}
v, err = proto.GetExtension(field.Options, gogoproto.E_Castkey)
if err == nil && v.(*string) != nil {
ctype := *(v.(*string))
packageName, typ = splitCPackageType(ctype)
return packageName, typ, nil
}
}
return "", "", err
}
func getCastValue(field *descriptor.FieldDescriptorProto) (packageName string, typ string, err error) {
if field.Options != nil {
var v interface{}
v, err = proto.GetExtension(field.Options, gogoproto.E_Castvalue)
if err == nil && v.(*string) != nil {
ctype := *(v.(*string))
packageName, typ = splitCPackageType(ctype)
return packageName, typ, nil
}
}
return "", "", err
}
func FileName(file *FileDescriptor) string {
fname := path.Base(file.FileDescriptorProto.GetName())
fname = strings.Replace(fname, ".proto", "", -1)
@@ -443,3 +439,9 @@ func (g *Generator) AllFiles() *descriptor.FileDescriptorSet {
func (d *Descriptor) Path() string {
return d.path
}
func (g *Generator) useTypes() string {
pkg := strings.Map(badToUnderscore, "github.com/gogo/protobuf/types")
g.customImports = append(g.customImports, "github.com/gogo/protobuf/types")
return pkg
}
+85
View File
@@ -0,0 +1,85 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2013 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package generator
import (
"testing"
"github.com/gogo/protobuf/protoc-gen-gogo/descriptor"
)
func TestCamelCase(t *testing.T) {
tests := []struct {
in, want string
}{
{"one", "One"},
{"one_two", "OneTwo"},
{"_my_field_name_2", "XMyFieldName_2"},
{"Something_Capped", "Something_Capped"},
{"my_Name", "My_Name"},
{"OneTwo", "OneTwo"},
{"_", "X"},
{"_a_", "XA_"},
}
for _, tc := range tests {
if got := CamelCase(tc.in); got != tc.want {
t.Errorf("CamelCase(%q) = %q, want %q", tc.in, got, tc.want)
}
}
}
func TestGoPackageOption(t *testing.T) {
tests := []struct {
in string
impPath, pkg string
ok bool
}{
{"", "", "", false},
{"foo", "", "foo", true},
{"github.com/golang/bar", "github.com/golang/bar", "bar", true},
{"github.com/golang/bar;baz", "github.com/golang/bar", "baz", true},
}
for _, tc := range tests {
d := &FileDescriptor{
FileDescriptorProto: &descriptor.FileDescriptorProto{
Options: &descriptor.FileOptions{
GoPackage: &tc.in,
},
},
}
impPath, pkg, ok := d.goPackageOption()
if impPath != tc.impPath || pkg != tc.pkg || ok != tc.ok {
t.Errorf("go_package = %q => (%q, %q, %t), want (%q, %q, %t)", tc.in,
impPath, pkg, ok, tc.impPath, tc.pkg, tc.ok)
}
}
}