From 1a51820dff91ebf04a0838dab20d5d546d486de7 Mon Sep 17 00:00:00 2001 From: Vitalii Levitskii Date: Mon, 24 Jul 2023 19:49:22 +0200 Subject: [PATCH] Implemented optional (presented) fields for proto3 --- .gitignore | 4 +- gogoproto/helper.go | 17 +- plugin/compare/compare.go | 41 +- plugin/defaultcheck/defaultcheck.go | 15 +- plugin/embedcheck/embedcheck.go | 9 +- plugin/equal/equal.go | 53 +- plugin/face/face.go | 37 +- plugin/gostring/gostring.go | 69 +-- plugin/marshalto/marshalto.go | 178 +++--- plugin/oneofcheck/oneofcheck.go | 8 +- plugin/populate/populate.go | 119 ++-- plugin/size/size.go | 119 ++-- plugin/stringer/stringer.go | 77 +-- plugin/union/union.go | 57 +- plugin/unmarshal/unmarshal.go | 296 +++++----- proto3optional/resolver.go | 70 +++ .../google/protobuf/compiler/plugin.proto | 15 + protobuf/google/protobuf/descriptor.proto | 23 + protoc-gen-gogo/descriptor/descriptor.pb.go | 528 ++++++++++-------- .../descriptor/descriptor_gostring.gen.go | 5 +- protoc-gen-gogo/generator/generator.go | 111 ++-- protoc-gen-gogo/generator/helper.go | 23 +- protoc-gen-gogo/plugin/plugin.pb.go | 138 +++-- 23 files changed, 1149 insertions(+), 863 deletions(-) create mode 100644 proto3optional/resolver.go diff --git a/.gitignore b/.gitignore index 82f4de4a51..9b274d6ca4 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,6 @@ *.js.map # Conformance test output and transient files. -conformance/failing_tests.txt \ No newline at end of file +conformance/failing_tests.txt + +.idea diff --git a/gogoproto/helper.go b/gogoproto/helper.go index 390d4e4be6..3e08fe43ab 100644 --- a/gogoproto/helper.go +++ b/gogoproto/helper.go @@ -28,15 +28,18 @@ package gogoproto -import google_protobuf "github.com/gogo/protobuf/protoc-gen-gogo/descriptor" -import proto "github.com/gogo/protobuf/proto" +import ( + proto "github.com/gogo/protobuf/proto" + "github.com/gogo/protobuf/proto3optional" + google_protobuf "github.com/gogo/protobuf/protoc-gen-gogo/descriptor" +) func IsEmbed(field *google_protobuf.FieldDescriptorProto) bool { return proto.GetBoolExtension(field.Options, E_Embed, false) } -func IsNullable(field *google_protobuf.FieldDescriptorProto) bool { - return proto.GetBoolExtension(field.Options, E_Nullable, true) +func IsNullable(field *google_protobuf.FieldDescriptorProto, proto3Resolver *proto3optional.Resolver) bool { + return proto.GetBoolExtension(field.Options, E_Nullable, true) || proto3Resolver.IsFakeOneOf(field) } func IsStdTime(field *google_protobuf.FieldDescriptorProto) bool { @@ -96,12 +99,12 @@ func IsWktPtr(field *google_protobuf.FieldDescriptorProto) bool { return proto.GetBoolExtension(field.Options, E_Wktpointer, false) } -func NeedsNilCheck(proto3 bool, field *google_protobuf.FieldDescriptorProto) bool { - nullable := IsNullable(field) +func NeedsNilCheck(field *google_protobuf.FieldDescriptorProto, proto3Resolver *proto3optional.Resolver) bool { + nullable := IsNullable(field, proto3Resolver) if field.IsMessage() || IsCustomType(field) { return nullable } - if proto3 { + if proto3Resolver.IsProto3WithoutOptional(field) { return false } return nullable || *field.Type == google_protobuf.FieldDescriptorProto_TYPE_BYTES diff --git a/plugin/compare/compare.go b/plugin/compare/compare.go index 9ab40ef150..2a7f4d80d1 100644 --- a/plugin/compare/compare.go +++ b/plugin/compare/compare.go @@ -31,6 +31,7 @@ package compare import ( "github.com/gogo/protobuf/gogoproto" "github.com/gogo/protobuf/proto" + "github.com/gogo/protobuf/proto3optional" descriptor "github.com/gogo/protobuf/protoc-gen-gogo/descriptor" "github.com/gogo/protobuf/protoc-gen-gogo/generator" "github.com/gogo/protobuf/vanity" @@ -142,12 +143,11 @@ func (p *plugin) generateMsgNullAndTypeCheck(ccTypeName string) { p.P(`}`) } -func (p *plugin) generateField(file *generator.FileDescriptor, message *generator.Descriptor, field *descriptor.FieldDescriptorProto) { - proto3 := gogoproto.IsProto3(file.FileDescriptorProto) - fieldname := p.GetOneOfFieldName(message, field) +func (p *plugin) generateField(file *generator.FileDescriptor, message *generator.Descriptor, field *descriptor.FieldDescriptorProto, proto3Resolver *proto3optional.Resolver) { + fieldname := p.GetOneOfFieldName(message, field, proto3Resolver) repeated := field.IsRepeated() ctype := gogoproto.IsCustomType(field) - nullable := gogoproto.IsNullable(field) + nullable := gogoproto.IsNullable(field, proto3Resolver) // oneof := field.OneofIndex != nil if !repeated { if ctype { @@ -190,7 +190,7 @@ func (p *plugin) generateField(file *generator.FileDescriptor, message *generato p.Out() p.P(`}`) } else if field.IsString() { - if nullable && !proto3 { + if nullable && !proto3Resolver.IsProto3WithoutOptional(field) { p.generateNullableField(fieldname) } else { p.P(`if this.`, fieldname, ` != that1.`, fieldname, `{`) @@ -205,7 +205,7 @@ func (p *plugin) generateField(file *generator.FileDescriptor, message *generato p.P(`}`) } } else if field.IsBool() { - if nullable && !proto3 { + if nullable && !proto3Resolver.IsProto3WithoutOptional(field) { p.P(`if this.`, fieldname, ` != nil && that1.`, fieldname, ` != nil {`) p.In() p.P(`if *this.`, fieldname, ` != *that1.`, fieldname, `{`) @@ -241,7 +241,7 @@ func (p *plugin) generateField(file *generator.FileDescriptor, message *generato p.P(`}`) } } else { - if nullable && !proto3 { + if nullable && !proto3Resolver.IsProto3WithoutOptional(field) { p.generateNullableField(fieldname) } else { p.P(`if this.`, fieldname, ` != that1.`, fieldname, `{`) @@ -278,10 +278,10 @@ func (p *plugin) generateField(file *generator.FileDescriptor, message *generato p.P(`}`) } else { if p.IsMap(field) { - m := p.GoMapType(nil, field) - valuegoTyp, _ := p.GoType(nil, m.ValueField) - valuegoAliasTyp, _ := p.GoType(nil, m.ValueAliasField) - nullable, valuegoTyp, valuegoAliasTyp = generator.GoMapValueTypes(field, m.ValueField, valuegoTyp, valuegoAliasTyp) + m := p.GoMapType(nil, field, proto3Resolver) + valuegoTyp, _ := p.GoType(nil, m.ValueField, proto3Resolver) + valuegoAliasTyp, _ := p.GoType(nil, m.ValueAliasField, proto3Resolver) + nullable, valuegoTyp, valuegoAliasTyp = generator.GoMapValueTypes(field, m.ValueField, valuegoTyp, valuegoAliasTyp, proto3Resolver) mapValue := m.ValueAliasField if mapValue.IsMessage() || p.IsGroup(mapValue) { @@ -402,12 +402,15 @@ func (p *plugin) generateMessage(file *generator.FileDescriptor, message *genera p.P(`func (this *`, ccTypeName, `) Compare(that interface{}) int {`) p.In() p.generateMsgNullAndTypeCheck(ccTypeName) + + proto3Resolver := proto3optional.NewResolver(gogoproto.IsProto3(file.FileDescriptorProto), message.Field) + oneofs := make(map[string]struct{}) for _, field := range message.Field { - oneof := field.OneofIndex != nil + oneof := proto3Resolver.IsRealOneOf(field) if oneof { - fieldname := p.GetFieldName(message, field) + fieldname := p.GetFieldName(message, field, proto3Resolver) if _, ok := oneofs[fieldname]; ok { continue } else { @@ -435,7 +438,7 @@ func (p *plugin) generateMessage(file *generator.FileDescriptor, message *genera p.P(`switch this.`, fieldname, `.(type) {`) for i, subfield := range message.Field { if *subfield.OneofIndex == *field.OneofIndex { - ccTypeName := p.OneOfTypeName(message, subfield) + ccTypeName := p.OneOfTypeName(message, subfield, proto3Resolver) p.P(`case *`, ccTypeName, `:`) p.In() p.P(`thisType = `, i) @@ -452,7 +455,7 @@ func (p *plugin) generateMessage(file *generator.FileDescriptor, message *genera p.P(`switch that1.`, fieldname, `.(type) {`) for i, subfield := range message.Field { if *subfield.OneofIndex == *field.OneofIndex { - ccTypeName := p.OneOfTypeName(message, subfield) + ccTypeName := p.OneOfTypeName(message, subfield, proto3Resolver) p.P(`case *`, ccTypeName, `:`) p.In() p.P(`that1Type = `, i) @@ -485,7 +488,7 @@ func (p *plugin) generateMessage(file *generator.FileDescriptor, message *genera p.Out() p.P(`}`) } else { - p.generateField(file, message, field) + p.generateField(file, message, field, proto3Resolver) } } if message.DescriptorProto.HasExtension() { @@ -557,17 +560,17 @@ func (p *plugin) generateMessage(file *generator.FileDescriptor, message *genera //Generate Compare methods for oneof fields m := proto.Clone(message.DescriptorProto).(*descriptor.DescriptorProto) for _, field := range m.Field { - oneof := field.OneofIndex != nil + oneof := proto3Resolver.IsRealOneOf(field) if !oneof { continue } - ccTypeName := p.OneOfTypeName(message, field) + ccTypeName := p.OneOfTypeName(message, field, proto3Resolver) p.P(`func (this *`, ccTypeName, `) Compare(that interface{}) int {`) p.In() p.generateMsgNullAndTypeCheck(ccTypeName) vanity.TurnOffNullableForNativeTypes(field) - p.generateField(file, message, field) + p.generateField(file, message, field, proto3Resolver) p.P(`return 0`) p.Out() diff --git a/plugin/defaultcheck/defaultcheck.go b/plugin/defaultcheck/defaultcheck.go index 486f287719..f2633acd40 100644 --- a/plugin/defaultcheck/defaultcheck.go +++ b/plugin/defaultcheck/defaultcheck.go @@ -46,14 +46,14 @@ It is enabled by the following extensions: For incorrect usage of nullable with tests see: - github.com/gogo/protobuf/test/nullableconflict - + github.com/gogo/protobuf/test/nullableconflict */ package defaultcheck import ( "fmt" "github.com/gogo/protobuf/gogoproto" + "github.com/gogo/protobuf/proto3optional" "github.com/gogo/protobuf/protoc-gen-gogo/generator" "os" ) @@ -75,10 +75,11 @@ func (p *plugin) Init(g *generator.Generator) { } func (p *plugin) Generate(file *generator.FileDescriptor) { - proto3 := gogoproto.IsProto3(file.FileDescriptorProto) for _, msg := range file.Messages() { getters := gogoproto.HasGoGetters(file.FileDescriptorProto, msg.DescriptorProto) face := gogoproto.IsFace(file.FileDescriptorProto, msg.DescriptorProto) + proto3Resolver := proto3optional.NewResolver(gogoproto.IsProto3(file.FileDescriptorProto), msg.Field) + for _, field := range msg.GetField() { if len(field.GetDefaultValue()) > 0 { if !getters { @@ -90,7 +91,7 @@ func (p *plugin) Generate(file *generator.FileDescriptor) { os.Exit(1) } } - if gogoproto.IsNullable(field) { + if gogoproto.IsNullable(field, proto3Resolver) { continue } if len(field.GetDefaultValue()) > 0 { @@ -100,7 +101,7 @@ func (p *plugin) Generate(file *generator.FileDescriptor) { if !field.IsMessage() && !gogoproto.IsCustomType(field) { if field.IsRepeated() { fmt.Fprintf(os.Stderr, "WARNING: field %v.%v is a repeated non-nullable native type, nullable=false has no effect\n", generator.CamelCase(*msg.Name), generator.CamelCase(*field.Name)) - } else if proto3 { + } else if proto3Resolver.IsProto3WithoutOptional(field) { fmt.Fprintf(os.Stderr, "ERROR: field %v.%v is a native type and in proto3 syntax with nullable=false there exists conflicting implementations when encoding zero values", generator.CamelCase(*msg.Name), generator.CamelCase(*field.Name)) os.Exit(1) } @@ -118,8 +119,10 @@ func (p *plugin) Generate(file *generator.FileDescriptor) { } } } + + proto3Resolver := proto3optional.NewResolver(gogoproto.IsProto3(file.FileDescriptorProto), file.GetExtension()) for _, e := range file.GetExtension() { - if !gogoproto.IsNullable(e) { + if !gogoproto.IsNullable(e, proto3Resolver) { fmt.Fprintf(os.Stderr, "ERROR: extended field %v cannot be nullable %v", generator.CamelCase(e.GetName()), generator.CamelCase(*e.Name)) os.Exit(1) } diff --git a/plugin/embedcheck/embedcheck.go b/plugin/embedcheck/embedcheck.go index bc68efe12c..4513fd83ac 100644 --- a/plugin/embedcheck/embedcheck.go +++ b/plugin/embedcheck/embedcheck.go @@ -40,8 +40,7 @@ It is enabled by the following extensions: For incorrect usage of embed with tests see: - github.com/gogo/protobuf/test/embedconflict - + github.com/gogo/protobuf/test/embedconflict */ package embedcheck @@ -109,7 +108,7 @@ func (p *plugin) Generate(file *generator.FileDescriptor) { p.checkOverwrite(msg, os) } } - p.checkNameSpace(msg) + p.checkNameSpace(msg, gogoproto.IsProto3(file.FileDescriptorProto)) for _, field := range msg.GetField() { if gogoproto.IsEmbed(field) && gogoproto.IsCustomName(field) { fmt.Fprintf(os.Stderr, "ERROR: field %v with custom name %v cannot be embedded", *field.Name, gogoproto.GetCustomName(field)) @@ -126,14 +125,14 @@ func (p *plugin) Generate(file *generator.FileDescriptor) { } } -func (p *plugin) checkNameSpace(message *generator.Descriptor) map[string]bool { +func (p *plugin) checkNameSpace(message *generator.Descriptor, proto3 bool) map[string]bool { ccTypeName := generator.CamelCaseSlice(message.TypeName()) names := make(map[string]bool) for _, field := range message.Field { fieldname := generator.CamelCase(*field.Name) if field.IsMessage() && gogoproto.IsEmbed(field) { desc := p.ObjectNamed(field.GetTypeName()) - moreNames := p.checkNameSpace(desc.(*generator.Descriptor)) + moreNames := p.checkNameSpace(desc.(*generator.Descriptor), proto3) for another := range moreNames { if names[another] { fmt.Fprintf(os.Stderr, "ERROR: duplicate embedded fieldname %v in type %v\n", fieldname, ccTypeName) diff --git a/plugin/equal/equal.go b/plugin/equal/equal.go index 6358fc99ad..5c2d723bc1 100644 --- a/plugin/equal/equal.go +++ b/plugin/equal/equal.go @@ -50,21 +50,21 @@ The equal plugin also generates a test given it is enabled using one of the foll Let us look at: - github.com/gogo/protobuf/test/example/example.proto + github.com/gogo/protobuf/test/example/example.proto Btw all the output can be seen at: - github.com/gogo/protobuf/test/example/* + github.com/gogo/protobuf/test/example/* The following message: - option (gogoproto.equal_all) = true; - option (gogoproto.verbose_equal_all) = true; + option (gogoproto.equal_all) = true; + option (gogoproto.verbose_equal_all) = true; - message B { - optional A A = 1 [(gogoproto.nullable) = false, (gogoproto.embed) = true]; - repeated bytes G = 2 [(gogoproto.customtype) = "github.com/gogo/protobuf/test/custom.Uint128", (gogoproto.nullable) = false]; - } + message B { + optional A A = 1 [(gogoproto.nullable) = false, (gogoproto.embed) = true]; + repeated bytes G = 2 [(gogoproto.customtype) = "github.com/gogo/protobuf/test/custom.Uint128", (gogoproto.nullable) = false]; + } given to the equal plugin, will generate the following code: @@ -152,13 +152,13 @@ and the following test code: if err := p.VerboseEqual(msg); err != nil { t.Fatalf("%#v !VerboseEqual %#v, since %v", msg, p, err) } - */ package equal import ( "github.com/gogo/protobuf/gogoproto" "github.com/gogo/protobuf/proto" + "github.com/gogo/protobuf/proto3optional" descriptor "github.com/gogo/protobuf/protoc-gen-gogo/descriptor" "github.com/gogo/protobuf/protoc-gen-gogo/generator" "github.com/gogo/protobuf/vanity" @@ -286,12 +286,12 @@ func (p *plugin) generateMsgNullAndTypeCheck(ccTypeName string, verbose bool) { p.P(`}`) } -func (p *plugin) generateField(file *generator.FileDescriptor, message *generator.Descriptor, field *descriptor.FieldDescriptorProto, verbose bool) { - proto3 := gogoproto.IsProto3(file.FileDescriptorProto) - fieldname := p.GetOneOfFieldName(message, field) +func (p *plugin) generateField(file *generator.FileDescriptor, message *generator.Descriptor, field *descriptor.FieldDescriptorProto, verbose bool, proto3Resolver *proto3optional.Resolver) { + fieldname := p.GetOneOfFieldName(message, field, proto3Resolver) repeated := field.IsRepeated() ctype := gogoproto.IsCustomType(field) - nullable := gogoproto.IsNullable(field) + nullable := gogoproto.IsNullable(field, proto3Resolver) + isNormal := (gogoproto.IsStdDuration(field) || gogoproto.IsStdDouble(field) || gogoproto.IsStdFloat(field) || @@ -381,13 +381,13 @@ func (p *plugin) generateField(file *generator.FileDescriptor, message *generato } else if field.IsBytes() { p.P(`if !`, p.bytesPkg.Use(), `.Equal(this.`, fieldname, `, that1.`, fieldname, `) {`) } else if field.IsString() { - if nullable && !proto3 { + if nullable && !proto3Resolver.IsProto3WithoutOptional(field) { p.generateNullableField(fieldname, verbose) } else { p.P(`if this.`, fieldname, ` != that1.`, fieldname, `{`) } } else { - if nullable && !proto3 { + if nullable && !proto3Resolver.IsProto3WithoutOptional(field) { p.generateNullableField(fieldname, verbose) } else { p.P(`if this.`, fieldname, ` != that1.`, fieldname, `{`) @@ -436,10 +436,10 @@ func (p *plugin) generateField(file *generator.FileDescriptor, message *generato } } else { if p.IsMap(field) { - m := p.GoMapType(nil, field) - valuegoTyp, _ := p.GoType(nil, m.ValueField) - valuegoAliasTyp, _ := p.GoType(nil, m.ValueAliasField) - nullable, valuegoTyp, valuegoAliasTyp = generator.GoMapValueTypes(field, m.ValueField, valuegoTyp, valuegoAliasTyp) + m := p.GoMapType(nil, field, proto3Resolver) + valuegoTyp, _ := p.GoType(nil, m.ValueField, proto3Resolver) + valuegoAliasTyp, _ := p.GoType(nil, m.ValueAliasField, proto3Resolver) + nullable, valuegoTyp, valuegoAliasTyp = generator.GoMapValueTypes(field, m.ValueField, valuegoTyp, valuegoAliasTyp, proto3Resolver) mapValue := m.ValueAliasField mapValueNormal := (gogoproto.IsStdDuration(mapValue) || @@ -537,10 +537,13 @@ func (p *plugin) generateMessage(file *generator.FileDescriptor, message *genera p.generateMsgNullAndTypeCheck(ccTypeName, verbose) oneofs := make(map[string]struct{}) + proto3Resolver := proto3optional.NewResolver(gogoproto.IsProto3(file.FileDescriptorProto), message.Field) + for _, field := range message.Field { - oneof := field.OneofIndex != nil + oneof := proto3Resolver.IsRealOneOf(field) + if oneof { - fieldname := p.GetFieldName(message, field) + fieldname := p.GetFieldName(message, field, proto3Resolver) if _, ok := oneofs[fieldname]; ok { continue } else { @@ -580,7 +583,7 @@ func (p *plugin) generateMessage(file *generator.FileDescriptor, message *genera p.Out() p.P(`}`) } else { - p.generateField(file, message, field, verbose) + p.generateField(file, message, field, verbose, proto3Resolver) } } if message.DescriptorProto.HasExtension() { @@ -663,11 +666,11 @@ func (p *plugin) generateMessage(file *generator.FileDescriptor, message *genera //Generate Equal methods for oneof fields m := proto.Clone(message.DescriptorProto).(*descriptor.DescriptorProto) for _, field := range m.Field { - oneof := field.OneofIndex != nil + oneof := proto3Resolver.IsRealOneOf(field) if !oneof { continue } - ccTypeName := p.OneOfTypeName(message, field) + ccTypeName := p.OneOfTypeName(message, field, proto3Resolver) if verbose { p.P(`func (this *`, ccTypeName, `) VerboseEqual(that interface{}) error {`) } else { @@ -677,7 +680,7 @@ func (p *plugin) generateMessage(file *generator.FileDescriptor, message *genera p.generateMsgNullAndTypeCheck(ccTypeName, verbose) vanity.TurnOffNullableForNativeTypes(field) - p.generateField(file, message, field, verbose) + p.generateField(file, message, field, verbose, proto3Resolver) if verbose { p.P(`return nil`) diff --git a/plugin/face/face.go b/plugin/face/face.go index a029345265..1c79c57089 100644 --- a/plugin/face/face.go +++ b/plugin/face/face.go @@ -50,21 +50,21 @@ The face plugin also generates a test given it is enabled using one of the follo Let us look at: - github.com/gogo/protobuf/test/example/example.proto + github.com/gogo/protobuf/test/example/example.proto Btw all the output can be seen at: - github.com/gogo/protobuf/test/example/* + github.com/gogo/protobuf/test/example/* The following message: - message A { - option (gogoproto.face) = true; - option (gogoproto.goproto_getters) = false; - optional string Description = 1 [(gogoproto.nullable) = false]; - optional int64 Number = 2 [(gogoproto.nullable) = false]; - optional bytes Id = 3 [(gogoproto.customtype) = "github.com/gogo/protobuf/test/custom.Uuid", (gogoproto.nullable) = false]; - } + message A { + option (gogoproto.face) = true; + option (gogoproto.goproto_getters) = false; + optional string Description = 1 [(gogoproto.nullable) = false]; + optional int64 Number = 2 [(gogoproto.nullable) = false]; + optional bytes Id = 3 [(gogoproto.customtype) = "github.com/gogo/protobuf/test/custom.Uuid", (gogoproto.nullable) = false]; + } given to the face plugin, will generate the following code: @@ -126,12 +126,12 @@ Implementing The Proto method is done with the helper function NewAFromFace: } just the like TestProto method which is used to test the NewAFromFace function. - */ package face import ( "github.com/gogo/protobuf/gogoproto" + "github.com/gogo/protobuf/proto3optional" "github.com/gogo/protobuf/protoc-gen-gogo/generator" ) @@ -175,11 +175,14 @@ func (p *plugin) Generate(file *generator.FileDescriptor) { p.P(`type `, ccTypeName, `Face interface{`) p.In() p.P(`Proto() `, protoPkg.Use(), `.Message`) + + proto3Resolver := proto3optional.NewResolver(gogoproto.IsProto3(file.FileDescriptorProto), message.Field) + for _, field := range message.Field { - fieldname := p.GetFieldName(message, field) - goTyp, _ := p.GoType(message, field) + fieldname := p.GetFieldName(message, field, proto3Resolver) + goTyp, _ := p.GoType(message, field, proto3Resolver) if p.IsMap(field) { - m := p.GoMapType(nil, field) + m := p.GoMapType(nil, field, proto3Resolver) goTyp = m.GoType } p.P(`Get`, fieldname, `() `, goTyp) @@ -200,10 +203,10 @@ func (p *plugin) Generate(file *generator.FileDescriptor) { p.P(`}`) p.P(``) for _, field := range message.Field { - fieldname := p.GetFieldName(message, field) - goTyp, _ := p.GoType(message, field) + fieldname := p.GetFieldName(message, field, proto3Resolver) + goTyp, _ := p.GoType(message, field, proto3Resolver) if p.IsMap(field) { - m := p.GoMapType(nil, field) + m := p.GoMapType(nil, field, proto3Resolver) goTyp = m.GoType } p.P(`func (this *`, ccTypeName, `) Get`, fieldname, `() `, goTyp, `{`) @@ -218,7 +221,7 @@ func (p *plugin) Generate(file *generator.FileDescriptor) { p.In() p.P(`this := &`, ccTypeName, `{}`) for _, field := range message.Field { - fieldname := p.GetFieldName(message, field) + fieldname := p.GetFieldName(message, field, proto3Resolver) p.P(`this.`, fieldname, ` = that.Get`, fieldname, `()`) } p.P(`return this`) diff --git a/plugin/gostring/gostring.go b/plugin/gostring/gostring.go index bc89a7b871..c01e5cbe13 100644 --- a/plugin/gostring/gostring.go +++ b/plugin/gostring/gostring.go @@ -30,7 +30,7 @@ The gostring plugin generates a GoString method for each message. The GoString method is called whenever you use a fmt.Printf as such: - fmt.Printf("%#v", mymessage) + fmt.Printf("%#v", mymessage) or whenever you actually call GoString() The output produced by the GoString method can be copied from the output into code and used to set a variable. @@ -48,31 +48,31 @@ The gostring plugin also generates a test given it is enabled using one of the f Let us look at: - github.com/gogo/protobuf/test/example/example.proto + github.com/gogo/protobuf/test/example/example.proto Btw all the output can be seen at: - github.com/gogo/protobuf/test/example/* + github.com/gogo/protobuf/test/example/* The following message: - option (gogoproto.gostring_all) = true; + option (gogoproto.gostring_all) = true; - message A { - optional string Description = 1 [(gogoproto.nullable) = false]; - optional int64 Number = 2 [(gogoproto.nullable) = false]; - optional bytes Id = 3 [(gogoproto.customtype) = "github.com/gogo/protobuf/test/custom.Uuid", (gogoproto.nullable) = false]; - } + message A { + optional string Description = 1 [(gogoproto.nullable) = false]; + optional int64 Number = 2 [(gogoproto.nullable) = false]; + optional bytes Id = 3 [(gogoproto.customtype) = "github.com/gogo/protobuf/test/custom.Uuid", (gogoproto.nullable) = false]; + } given to the gostring plugin, will generate the following code: - func (this *A) GoString() string { - if this == nil { - return "nil" - } - s := strings1.Join([]string{`&test.A{` + `Description:` + fmt1.Sprintf("%#v", this.Description), `Number:` + fmt1.Sprintf("%#v", this.Number), `Id:` + fmt1.Sprintf("%#v", this.Id), `XXX_unrecognized:` + fmt1.Sprintf("%#v", this.XXX_unrecognized) + `}`}, ", ") - return s - } + func (this *A) GoString() string { + if this == nil { + return "nil" + } + s := strings1.Join([]string{`&test.A{` + `Description:` + fmt1.Sprintf("%#v", this.Description), `Number:` + fmt1.Sprintf("%#v", this.Number), `Id:` + fmt1.Sprintf("%#v", this.Id), `XXX_unrecognized:` + fmt1.Sprintf("%#v", this.XXX_unrecognized) + `}`}, ", ") + return s + } and the following test code: @@ -92,7 +92,6 @@ and the following test code: Typically fmt.Printf("%#v") will stop to print when it reaches a pointer and not print their values, while the generated GoString method will always print all values, recursively. - */ package gostring @@ -103,6 +102,7 @@ import ( "strings" "github.com/gogo/protobuf/gogoproto" + "github.com/gogo/protobuf/proto3optional" "github.com/gogo/protobuf/protoc-gen-gogo/generator" ) @@ -131,7 +131,6 @@ func (p *gostring) Init(g *generator.Generator) { } func (p *gostring) Generate(file *generator.FileDescriptor) { - proto3 := gogoproto.IsProto3(file.FileDescriptorProto) p.PluginImports = generator.NewPluginImports(p.Generator) p.atleastOne = false @@ -171,12 +170,14 @@ func (p *gostring) Generate(file *generator.FileDescriptor) { p.P(`s := make([]string, 0, `, strconv.Itoa(len(message.Field)+4), `)`) p.P(`s = append(s, "&`, packageName, ".", ccTypeName, `{")`) + proto3Resolver := proto3optional.NewResolver(gogoproto.IsProto3(file.FileDescriptorProto), message.Field) + oneofs := make(map[string]struct{}) for _, field := range message.Field { - nullable := gogoproto.IsNullable(field) + nullable := gogoproto.IsNullable(field, proto3Resolver) repeated := field.IsRepeated() - fieldname := p.GetFieldName(message, field) - oneof := field.OneofIndex != nil + fieldname := p.GetFieldName(message, field, proto3Resolver) + oneof := proto3Resolver.IsRealOneOf(field) if oneof { if _, ok := oneofs[fieldname]; ok { continue @@ -189,12 +190,12 @@ func (p *gostring) Generate(file *generator.FileDescriptor) { p.Out() p.P(`}`) } else if p.IsMap(field) { - m := p.GoMapType(nil, field) + m := p.GoMapType(nil, field, proto3Resolver) mapgoTyp, keyField, keyAliasField := m.GoType, m.KeyField, m.KeyAliasField keysName := `keysFor` + fieldname - keygoTyp, _ := p.GoType(nil, keyField) + keygoTyp, _ := p.GoType(nil, keyField, proto3Resolver) keygoTyp = strings.Replace(keygoTyp, "*", "", 1) - keygoAliasTyp, _ := p.GoType(nil, keyAliasField) + keygoAliasTyp, _ := p.GoType(nil, keyAliasField, proto3Resolver) keygoAliasTyp = strings.Replace(keygoAliasTyp, "*", "", 1) keyCapTyp := generator.CamelCase(keygoTyp) p.P(keysName, ` := make([]`, keygoTyp, `, 0, len(this.`, fieldname, `))`) @@ -236,7 +237,7 @@ func (p *gostring) Generate(file *generator.FileDescriptor) { if nullable { p.P(`s = append(s, "`, fieldname, `: " + `, fmtPkg.Use(), `.Sprintf("%#v", this.`, fieldname, `) + ",\n")`) } else { - goTyp, _ := p.GoType(message, field) + goTyp, _ := p.GoType(message, field, proto3Resolver) goTyp = strings.Replace(goTyp, "[]", "", 1) p.P("vs := make([]", goTyp, ", len(this.", fieldname, "))") p.P("for i := range vs {") @@ -254,26 +255,26 @@ func (p *gostring) Generate(file *generator.FileDescriptor) { p.P(`}`) } } else { - if !proto3 && (nullable || repeated) { + if !proto3Resolver.IsProto3WithoutOptional(field) && (nullable || repeated) { p.P(`if this.`, fieldname, ` != nil {`) p.In() } if field.IsEnum() { - if nullable && !repeated && !proto3 { - goTyp, _ := p.GoType(message, field) + if nullable && !repeated && !proto3Resolver.IsProto3WithoutOptional(field) { + goTyp, _ := p.GoType(message, field, proto3Resolver) p.P(`s = append(s, "`, fieldname, `: " + valueToGoString`, p.localName, `(this.`, fieldname, `,"`, generator.GoTypeToName(goTyp), `"`, `) + ",\n")`) } else { p.P(`s = append(s, "`, fieldname, `: " + `, fmtPkg.Use(), `.Sprintf("%#v", this.`, fieldname, `) + ",\n")`) } } else { - if nullable && !repeated && !proto3 { - goTyp, _ := p.GoType(message, field) + if nullable && !repeated && !proto3Resolver.IsProto3WithoutOptional(field) { + goTyp, _ := p.GoType(message, field, proto3Resolver) p.P(`s = append(s, "`, fieldname, `: " + valueToGoString`, p.localName, `(this.`, fieldname, `,"`, generator.GoTypeToName(goTyp), `"`, `) + ",\n")`) } else { p.P(`s = append(s, "`, fieldname, `: " + `, fmtPkg.Use(), `.Sprintf("%#v", this.`, fieldname, `) + ",\n")`) } } - if !proto3 && (nullable || repeated) { + if !proto3Resolver.IsProto3WithoutOptional(field) && (nullable || repeated) { p.Out() p.P(`}`) } @@ -306,11 +307,11 @@ func (p *gostring) Generate(file *generator.FileDescriptor) { //Generate GoString methods for oneof fields for _, field := range message.Field { - oneof := field.OneofIndex != nil + oneof := proto3Resolver.IsRealOneOf(field) if !oneof { continue } - ccTypeName := p.OneOfTypeName(message, field) + ccTypeName := p.OneOfTypeName(message, field, proto3Resolver) p.P(`func (this *`, ccTypeName, `) GoString() string {`) p.In() p.P(`if this == nil {`) @@ -318,7 +319,7 @@ func (p *gostring) Generate(file *generator.FileDescriptor) { p.P(`return "nil"`) p.Out() p.P(`}`) - fieldname := p.GetOneOfFieldName(message, field) + fieldname := p.GetOneOfFieldName(message, field, proto3Resolver) outStr := strings.Join([]string{ "s := ", stringsPkg.Use(), ".Join([]string{`&", packageName, ".", ccTypeName, "{` + \n", diff --git a/plugin/marshalto/marshalto.go b/plugin/marshalto/marshalto.go index f82c28c281..3662dd7100 100644 --- a/plugin/marshalto/marshalto.go +++ b/plugin/marshalto/marshalto.go @@ -57,74 +57,74 @@ And benchmarks given it is enabled using one of the following extensions: Let us look at: - github.com/gogo/protobuf/test/example/example.proto + github.com/gogo/protobuf/test/example/example.proto Btw all the output can be seen at: - github.com/gogo/protobuf/test/example/* + github.com/gogo/protobuf/test/example/* The following message: option (gogoproto.marshaler_all) = true; -message B { - option (gogoproto.description) = true; - optional A A = 1 [(gogoproto.nullable) = false, (gogoproto.embed) = true]; - repeated bytes G = 2 [(gogoproto.customtype) = "github.com/gogo/protobuf/test/custom.Uint128", (gogoproto.nullable) = false]; -} + message B { + option (gogoproto.description) = true; + optional A A = 1 [(gogoproto.nullable) = false, (gogoproto.embed) = true]; + repeated bytes G = 2 [(gogoproto.customtype) = "github.com/gogo/protobuf/test/custom.Uint128", (gogoproto.nullable) = false]; + } given to the marshalto plugin, will generate the following code: - func (m *B) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil - } - - func (m *B) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) - } - - func (m *B) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.XXX_unrecognized != nil { - i -= len(m.XXX_unrecognized) - copy(dAtA[i:], m.XXX_unrecognized) - } - if len(m.G) > 0 { - for iNdEx := len(m.G) - 1; iNdEx >= 0; iNdEx-- { - { - size := m.G[iNdEx].Size() - i -= size - if _, err := m.G[iNdEx].MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintExample(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - } - } - { - size, err := m.A.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintExample(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil - } + func (m *B) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil + } + + func (m *B) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) + } + + func (m *B) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.G) > 0 { + for iNdEx := len(m.G) - 1; iNdEx >= 0; iNdEx-- { + { + size := m.G[iNdEx].Size() + i -= size + if _, err := m.G[iNdEx].MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintExample(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + { + size, err := m.A.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintExample(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil + } As shown above Marshal calculates the size of the not yet marshalled message and allocates the appropriate buffer. @@ -151,6 +151,7 @@ import ( "github.com/gogo/protobuf/gogoproto" "github.com/gogo/protobuf/proto" + "github.com/gogo/protobuf/proto3optional" descriptor "github.com/gogo/protobuf/protoc-gen-gogo/descriptor" "github.com/gogo/protobuf/protoc-gen-gogo/generator" "github.com/gogo/protobuf/vanity" @@ -330,14 +331,14 @@ func (this orderFields) Swap(i, j int) { this[i], this[j] = this[j], this[i] } -func (p *marshalto) generateField(proto3 bool, numGen NumGen, file *generator.FileDescriptor, message *generator.Descriptor, field *descriptor.FieldDescriptorProto) { - fieldname := p.GetOneOfFieldName(message, field) - nullable := gogoproto.IsNullable(field) +func (p *marshalto) generateField(proto3 bool, numGen NumGen, file *generator.FileDescriptor, message *generator.Descriptor, field *descriptor.FieldDescriptorProto, proto3Resolver *proto3optional.Resolver) { + fieldname := p.GetOneOfFieldName(message, field, proto3Resolver) + nullable := gogoproto.IsNullable(field, proto3Resolver) repeated := field.IsRepeated() required := field.IsRequired() protoSizer := gogoproto.IsProtoSizer(file.FileDescriptorProto, message.DescriptorProto) - doNilCheck := gogoproto.NeedsNilCheck(proto3, field) + doNilCheck := gogoproto.NeedsNilCheck(field, proto3Resolver) if required && nullable { p.P(`if m.`, fieldname, `== nil {`) p.In() @@ -378,7 +379,7 @@ func (p *marshalto) generateField(proto3 bool, numGen NumGen, file *generator.Fi p.encodeKey(fieldNumber, wireType) p.Out() p.P(`}`) - } else if proto3 { + } else if proto3Resolver.IsProto3WithoutOptional(field) { p.P(`if m.`, fieldname, ` != 0 {`) p.In() p.callFixed64(p.mathPkg.Use(), `.Float64bits(float64(m.`+fieldname, `))`) @@ -408,7 +409,7 @@ func (p *marshalto) generateField(proto3 bool, numGen NumGen, file *generator.Fi p.encodeKey(fieldNumber, wireType) p.Out() p.P(`}`) - } else if proto3 { + } else if proto3Resolver.IsProto3WithoutOptional(field) { p.P(`if m.`, fieldname, ` != 0 {`) p.In() p.callFixed32(p.mathPkg.Use(), `.Float32bits(float32(m.`+fieldname, `))`) @@ -461,7 +462,7 @@ func (p *marshalto) generateField(proto3 bool, numGen NumGen, file *generator.Fi p.encodeKey(fieldNumber, wireType) p.Out() p.P(`}`) - } else if proto3 { + } else if proto3Resolver.IsProto3WithoutOptional(field) { p.P(`if m.`, fieldname, ` != 0 {`) p.In() p.callVarint(`m.`, fieldname) @@ -490,7 +491,7 @@ func (p *marshalto) generateField(proto3 bool, numGen NumGen, file *generator.Fi p.encodeKey(fieldNumber, wireType) p.Out() p.P(`}`) - } else if proto3 { + } else if proto3Resolver.IsProto3WithoutOptional(field) { p.P(`if m.`, fieldname, ` != 0 {`) p.In() p.callFixed64("m." + fieldname) @@ -519,7 +520,7 @@ func (p *marshalto) generateField(proto3 bool, numGen NumGen, file *generator.Fi p.encodeKey(fieldNumber, wireType) p.Out() p.P(`}`) - } else if proto3 { + } else if proto3Resolver.IsProto3WithoutOptional(field) { p.P(`if m.`, fieldname, ` != 0 {`) p.In() p.callFixed32("m." + fieldname) @@ -565,7 +566,7 @@ func (p *marshalto) generateField(proto3 bool, numGen NumGen, file *generator.Fi p.encodeKey(fieldNumber, wireType) p.Out() p.P(`}`) - } else if proto3 { + } else if proto3Resolver.IsProto3WithoutOptional(field) { p.P(`if m.`, fieldname, ` {`) p.In() p.P(`i--`) @@ -615,7 +616,7 @@ func (p *marshalto) generateField(proto3 bool, numGen NumGen, file *generator.Fi p.encodeKey(fieldNumber, wireType) p.Out() p.P(`}`) - } else if proto3 { + } else if proto3Resolver.IsProto3WithoutOptional(field) { p.P(`if len(m.`, fieldname, `) > 0 {`) p.In() p.P(`i -= len(m.`, fieldname, `)`) @@ -639,16 +640,16 @@ func (p *marshalto) generateField(proto3 bool, numGen NumGen, file *generator.Fi panic(fmt.Errorf("marshaler does not support group %v", fieldname)) case descriptor.FieldDescriptorProto_TYPE_MESSAGE: if p.IsMap(field) { - m := p.GoMapType(nil, field) - keygoTyp, keywire := p.GoType(nil, m.KeyField) - keygoAliasTyp, _ := p.GoType(nil, m.KeyAliasField) + m := p.GoMapType(nil, field, proto3Resolver) + keygoTyp, keywire := p.GoType(nil, m.KeyField, proto3Resolver) + keygoAliasTyp, _ := p.GoType(nil, m.KeyAliasField, proto3Resolver) // keys may not be pointers keygoTyp = strings.Replace(keygoTyp, "*", "", 1) keygoAliasTyp = strings.Replace(keygoAliasTyp, "*", "", 1) keyCapTyp := generator.CamelCase(keygoTyp) - valuegoTyp, valuewire := p.GoType(nil, m.ValueField) - valuegoAliasTyp, _ := p.GoType(nil, m.ValueAliasField) - nullable, valuegoTyp, valuegoAliasTyp = generator.GoMapValueTypes(field, m.ValueField, valuegoTyp, valuegoAliasTyp) + valuegoTyp, valuewire := p.GoType(nil, m.ValueField, proto3Resolver) + valuegoAliasTyp, _ := p.GoType(nil, m.ValueAliasField, proto3Resolver) + nullable, valuegoTyp, valuegoAliasTyp = generator.GoMapValueTypes(field, m.ValueField, valuegoTyp, valuegoAliasTyp, proto3Resolver) var val string if gogoproto.IsStableMarshaler(file.FileDescriptorProto, message.DescriptorProto) { keysName := `keysFor` + fieldname @@ -693,7 +694,7 @@ func (p *marshalto) generateField(proto3 bool, numGen NumGen, file *generator.Fi p.P(`if `, accessor, ` != nil { `) p.In() } else if plainBytes { - if proto3 { + if proto3Resolver.IsProto3WithoutOptional(field) { p.P(`if len(`, accessor, `) > 0 {`) } else { p.P(`if `, accessor, ` != nil {`) @@ -718,7 +719,7 @@ func (p *marshalto) generateField(proto3 bool, numGen NumGen, file *generator.Fi } else if repeated { val := p.reverseListRange(`m.`, fieldname) sizeOfVarName := val - if gogoproto.IsNullable(field) { + if gogoproto.IsNullable(field, proto3Resolver) { sizeOfVarName = `*` + val } if !p.marshalAllSizeOf(field, sizeOfVarName, ``) { @@ -733,7 +734,7 @@ func (p *marshalto) generateField(proto3 bool, numGen NumGen, file *generator.Fi p.P(`}`) } else { sizeOfVarName := `m.` + fieldname - if gogoproto.IsNullable(field) { + if gogoproto.IsNullable(field, proto3Resolver) { sizeOfVarName = `*` + sizeOfVarName } if !p.marshalAllSizeOf(field, sizeOfVarName, numGen.Next()) { @@ -755,7 +756,7 @@ func (p *marshalto) generateField(proto3 bool, numGen NumGen, file *generator.Fi p.encodeKey(fieldNumber, wireType) p.Out() p.P(`}`) - } else if proto3 { + } else if proto3Resolver.IsProto3WithoutOptional(field) { p.P(`if len(m.`, fieldname, `) > 0 {`) p.In() p.P(`i -= len(m.`, fieldname, `)`) @@ -814,7 +815,7 @@ func (p *marshalto) generateField(proto3 bool, numGen NumGen, file *generator.Fi p.encodeKey(fieldNumber, wireType) p.Out() p.P(`}`) - } else if proto3 { + } else if proto3Resolver.IsProto3WithoutOptional(field) { p.P(`if m.`, fieldname, ` != 0 {`) p.In() p.callVarint(`(uint32(m.`, fieldname, `) << 1) ^ uint32((m.`, fieldname, ` >> 31))`) @@ -860,7 +861,7 @@ func (p *marshalto) generateField(proto3 bool, numGen NumGen, file *generator.Fi p.encodeKey(fieldNumber, wireType) p.Out() p.P(`}`) - } else if proto3 { + } else if proto3Resolver.IsProto3WithoutOptional(field) { p.P(`if m.`, fieldname, ` != 0 {`) p.In() p.callVarint(`(uint64(m.`, fieldname, `) << 1) ^ uint64((m.`, fieldname, ` >> 63))`) @@ -976,15 +977,18 @@ func (p *marshalto) Generate(file *generator.FileDescriptor) { } fields := orderFields(message.GetField()) sort.Sort(fields) + + proto3 := gogoproto.IsProto3(file.FileDescriptorProto) + proto3Resolver := proto3optional.NewResolver(proto3, message.Field) + oneofs := make(map[string]struct{}) for i := len(message.Field) - 1; i >= 0; i-- { field := message.Field[i] - oneof := field.OneofIndex != nil + oneof := proto3Resolver.IsRealOneOf(field) if !oneof { - proto3 := gogoproto.IsProto3(file.FileDescriptorProto) - p.generateField(proto3, numGen, file, message, field) + p.generateField(proto3, numGen, file, message, field, proto3Resolver) } else { - fieldname := p.GetFieldName(message, field) + fieldname := p.GetFieldName(message, field, proto3Resolver) if _, ok := oneofs[fieldname]; !ok { oneofs[fieldname] = struct{}{} p.P(`if m.`, fieldname, ` != nil {`) @@ -1003,11 +1007,11 @@ func (p *marshalto) Generate(file *generator.FileDescriptor) { //Generate MarshalTo methods for oneof fields m := proto.Clone(message.DescriptorProto).(*descriptor.DescriptorProto) for _, field := range m.Field { - oneof := field.OneofIndex != nil + oneof := proto3Resolver.IsRealOneOf(field) if !oneof { continue } - ccTypeName := p.OneOfTypeName(message, field) + ccTypeName := p.OneOfTypeName(message, field, proto3Resolver) p.P(`func (m *`, ccTypeName, `) MarshalTo(dAtA []byte) (int, error) {`) p.In() if gogoproto.IsProtoSizer(file.FileDescriptorProto, message.DescriptorProto) { @@ -1023,7 +1027,7 @@ func (p *marshalto) Generate(file *generator.FileDescriptor) { p.In() p.P(`i := len(dAtA)`) vanity.TurnOffNullableForNativeTypes(field) - p.generateField(false, numGen, file, message, field) + p.generateField(false, numGen, file, message, field, proto3Resolver) p.P(`return len(dAtA) - i, nil`) p.Out() p.P(`}`) diff --git a/plugin/oneofcheck/oneofcheck.go b/plugin/oneofcheck/oneofcheck.go index 0f822e8a8a..cc9aae0721 100644 --- a/plugin/oneofcheck/oneofcheck.go +++ b/plugin/oneofcheck/oneofcheck.go @@ -32,13 +32,13 @@ For instance: An error is caused if a oneof field: - is used in a face - is an embedded field - */ package oneofcheck import ( "fmt" "github.com/gogo/protobuf/gogoproto" + "github.com/gogo/protobuf/proto3optional" "github.com/gogo/protobuf/protoc-gen-gogo/generator" "os" ) @@ -61,9 +61,11 @@ func (p *plugin) Init(g *generator.Generator) { func (p *plugin) Generate(file *generator.FileDescriptor) { for _, msg := range file.Messages() { + proto3Resolver := proto3optional.NewResolver(gogoproto.IsProto3(file.FileDescriptorProto), msg.Field) + face := gogoproto.IsFace(file.FileDescriptorProto, msg.DescriptorProto) for _, field := range msg.GetField() { - if field.OneofIndex == nil { + if !proto3Resolver.IsRealOneOf(field) { continue } if face { @@ -74,7 +76,7 @@ func (p *plugin) Generate(file *generator.FileDescriptor) { fmt.Fprintf(os.Stderr, "ERROR: field %v.%v cannot be in an oneof and an embedded field\n", generator.CamelCase(*msg.Name), generator.CamelCase(*field.Name)) os.Exit(1) } - if !gogoproto.IsNullable(field) { + if !gogoproto.IsNullable(field, proto3Resolver) { fmt.Fprintf(os.Stderr, "ERROR: field %v.%v cannot be in an oneof and a non-nullable field\n", generator.CamelCase(*msg.Name), generator.CamelCase(*field.Name)) os.Exit(1) } diff --git a/plugin/populate/populate.go b/plugin/populate/populate.go index da705945c3..d750be3566 100644 --- a/plugin/populate/populate.go +++ b/plugin/populate/populate.go @@ -37,40 +37,40 @@ It is enabled by the following extensions: Let us look at: - github.com/gogo/protobuf/test/example/example.proto + github.com/gogo/protobuf/test/example/example.proto Btw all the output can be seen at: - github.com/gogo/protobuf/test/example/* + github.com/gogo/protobuf/test/example/* The following message: - option (gogoproto.populate_all) = true; + option (gogoproto.populate_all) = true; - message B { - optional A A = 1 [(gogoproto.nullable) = false, (gogoproto.embed) = true]; - repeated bytes G = 2 [(gogoproto.customtype) = "github.com/gogo/protobuf/test/custom.Uint128", (gogoproto.nullable) = false]; - } + message B { + optional A A = 1 [(gogoproto.nullable) = false, (gogoproto.embed) = true]; + repeated bytes G = 2 [(gogoproto.customtype) = "github.com/gogo/protobuf/test/custom.Uint128", (gogoproto.nullable) = false]; + } given to the populate plugin, will generate code the following code: - func NewPopulatedB(r randyExample, easy bool) *B { - this := &B{} - v2 := NewPopulatedA(r, easy) - this.A = *v2 - if r.Intn(10) != 0 { - v3 := r.Intn(10) - this.G = make([]github_com_gogo_protobuf_test_custom.Uint128, v3) - for i := 0; i < v3; i++ { - v4 := github_com_gogo_protobuf_test_custom.NewPopulatedUint128(r) - this.G[i] = *v4 + func NewPopulatedB(r randyExample, easy bool) *B { + this := &B{} + v2 := NewPopulatedA(r, easy) + this.A = *v2 + if r.Intn(10) != 0 { + v3 := r.Intn(10) + this.G = make([]github_com_gogo_protobuf_test_custom.Uint128, v3) + for i := 0; i < v3; i++ { + v4 := github_com_gogo_protobuf_test_custom.NewPopulatedUint128(r) + this.G[i] = *v4 + } } - } - if !easy && r.Intn(10) != 0 { - this.XXX_unrecognized = randUnrecognizedExample(r, 3) - } - return this - } + if !easy && r.Intn(10) != 0 { + this.XXX_unrecognized = randUnrecognizedExample(r, 3) + } + return this + } The idea that is useful for testing. Most of the other plugins' generated test code uses it. @@ -79,7 +79,6 @@ if you turn off the popluate plugin and write your own custom NewPopulated funct If the easy flag is not set the XXX_unrecognized and XXX_extensions fields are also populated. These have caused problems with JSON marshalling and unmarshalling tests. - */ package populate @@ -91,6 +90,7 @@ import ( "github.com/gogo/protobuf/gogoproto" "github.com/gogo/protobuf/proto" + "github.com/gogo/protobuf/proto3optional" descriptor "github.com/gogo/protobuf/protoc-gen-gogo/descriptor" "github.com/gogo/protobuf/protoc-gen-gogo/generator" "github.com/gogo/protobuf/vanity" @@ -243,25 +243,24 @@ func (p *plugin) getEnumVal(field *descriptor.FieldDescriptorProto, goTyp string return val } -func (p *plugin) GenerateField(file *generator.FileDescriptor, message *generator.Descriptor, field *descriptor.FieldDescriptorProto) { - proto3 := gogoproto.IsProto3(file.FileDescriptorProto) - goTyp, _ := p.GoType(message, field) - fieldname := p.GetOneOfFieldName(message, field) +func (p *plugin) GenerateField(file *generator.FileDescriptor, message *generator.Descriptor, field *descriptor.FieldDescriptorProto, proto3Resolver *proto3optional.Resolver) { + goTyp, _ := p.GoType(message, field, proto3Resolver) + fieldname := p.GetOneOfFieldName(message, field, proto3Resolver) goTypName := generator.GoTypeToName(goTyp) if p.IsMap(field) { - m := p.GoMapType(nil, field) - keygoTyp, _ := p.GoType(nil, m.KeyField) + m := p.GoMapType(nil, field, proto3Resolver) + keygoTyp, _ := p.GoType(nil, m.KeyField, proto3Resolver) keygoTyp = strings.Replace(keygoTyp, "*", "", 1) - keygoAliasTyp, _ := p.GoType(nil, m.KeyAliasField) + keygoAliasTyp, _ := p.GoType(nil, m.KeyAliasField, proto3Resolver) keygoAliasTyp = strings.Replace(keygoAliasTyp, "*", "", 1) - valuegoTyp, _ := p.GoType(nil, m.ValueField) - valuegoAliasTyp, _ := p.GoType(nil, m.ValueAliasField) + valuegoTyp, _ := p.GoType(nil, m.ValueField, proto3Resolver) + valuegoAliasTyp, _ := p.GoType(nil, m.ValueAliasField, proto3Resolver) keytypName := generator.GoTypeToName(keygoTyp) keygoAliasTyp = generator.GoTypeToName(keygoAliasTyp) valuetypAliasName := generator.GoTypeToName(valuegoAliasTyp) - nullable, valuegoTyp, valuegoAliasTyp := generator.GoMapValueTypes(field, m.ValueField, valuegoTyp, valuegoAliasTyp) + nullable, valuegoTyp, valuegoAliasTyp := generator.GoMapValueTypes(field, m.ValueField, valuegoTyp, valuegoAliasTyp, proto3Resolver) p.P(p.varGen.Next(), ` := r.Intn(10)`) p.P(`this.`, fieldname, ` = make(`, m.GoType, `)`) @@ -335,7 +334,7 @@ func (p *plugin) GenerateField(file *generator.FileDescriptor, message *generato p.P(`this.`, fieldname, `[i] = *`, p.varGen.Current()) p.Out() p.P(`}`) - } else if gogoproto.IsNullable(field) { + } else if gogoproto.IsNullable(field, proto3Resolver) { p.P(`this.`, fieldname, ` = `, funcCall) } else { p.P(p.varGen.Next(), `:= `, funcCall) @@ -348,7 +347,7 @@ func (p *plugin) GenerateField(file *generator.FileDescriptor, message *generato p.P(`this.`, fieldname, ` = make(`, goTyp, `, `, p.varGen.Current(), `)`) p.P(`for i := 0; i < `, p.varGen.Current(), `; i++ {`) p.In() - if gogoproto.IsNullable(field) { + if gogoproto.IsNullable(field, proto3Resolver) { p.P(`this.`, fieldname, `[i] = `, funcCall) } else { p.P(p.varGen.Next(), `:= `, funcCall) @@ -357,7 +356,7 @@ func (p *plugin) GenerateField(file *generator.FileDescriptor, message *generato p.Out() p.P(`}`) } else { - if gogoproto.IsNullable(field) { + if gogoproto.IsNullable(field, proto3Resolver) { p.P(`this.`, fieldname, ` = `, funcCall) } else { p.P(p.varGen.Next(), `:= `, funcCall) @@ -375,7 +374,7 @@ func (p *plugin) GenerateField(file *generator.FileDescriptor, message *generato p.P(`this.`, fieldname, `[i] = `, val) p.Out() p.P(`}`) - } else if !gogoproto.IsNullable(field) || proto3 { + } else if !gogoproto.IsNullable(field, proto3Resolver) || proto3Resolver.IsProto3WithoutOptional(field) { p.P(`this.`, fieldname, ` = `, val) } else { p.P(p.varGen.Next(), ` := `, val) @@ -416,7 +415,7 @@ func (p *plugin) GenerateField(file *generator.FileDescriptor, message *generato p.P(`this.`, fieldname, `[i] = `, val) p.Out() p.P(`}`) - } else if !gogoproto.IsNullable(field) || proto3 { + } else if !gogoproto.IsNullable(field, proto3Resolver) || proto3Resolver.IsProto3WithoutOptional(field) { p.P(`this.`, fieldname, ` = `, val) } else { p.P(p.varGen.Next(), `:= `, val) @@ -439,7 +438,7 @@ func (p *plugin) GenerateField(file *generator.FileDescriptor, message *generato } p.Out() p.P(`}`) - } else if !gogoproto.IsNullable(field) || proto3 { + } else if !gogoproto.IsNullable(field, proto3Resolver) || proto3Resolver.IsProto3WithoutOptional(field) { p.P(`this.`, fieldname, ` = `, value(typName, field.GetType())) if negative(field.GetType()) { p.P(`if r.Intn(2) == 0 {`) @@ -463,11 +462,11 @@ func (p *plugin) GenerateField(file *generator.FileDescriptor, message *generato } } -func (p *plugin) hasLoop(pkg string, field *descriptor.FieldDescriptorProto, visited []*generator.Descriptor, excludes []*generator.Descriptor) *generator.Descriptor { +func (p *plugin) hasLoop(pkg string, field *descriptor.FieldDescriptorProto, visited []*generator.Descriptor, excludes []*generator.Descriptor, proto3Resolver *proto3optional.Resolver) *generator.Descriptor { if field.IsMessage() || p.IsGroup(field) || p.IsMap(field) { var fieldMessage *generator.Descriptor if p.IsMap(field) { - m := p.GoMapType(nil, field) + m := p.GoMapType(nil, field, proto3Resolver) if !m.ValueField.IsMessage() { return nil } @@ -491,7 +490,7 @@ func (p *plugin) hasLoop(pkg string, field *descriptor.FieldDescriptorProto, vis for _, f := range fieldMessage.Field { if strings.HasPrefix(f.GetTypeName(), "."+pkg) { visited = append(visited, fieldMessage) - loopTo := p.hasLoop(pkg, f, visited, excludes) + loopTo := p.hasLoop(pkg, f, visited, excludes, proto3Resolver) if loopTo != nil { return loopTo } @@ -501,13 +500,13 @@ func (p *plugin) hasLoop(pkg string, field *descriptor.FieldDescriptorProto, vis return nil } -func (p *plugin) loops(pkg string, field *descriptor.FieldDescriptorProto, message *generator.Descriptor) int { +func (p *plugin) loops(pkg string, field *descriptor.FieldDescriptorProto, message *generator.Descriptor, proto3Resolver *proto3optional.Resolver) int { //fmt.Fprintf(os.Stderr, "loops %v %v\n", field.GetTypeName(), generator.CamelCaseSlice(message.TypeName())) excludes := []*generator.Descriptor{} loops := 0 for { visited := []*generator.Descriptor{} - loopTo := p.hasLoop(pkg, field, visited, excludes) + loopTo := p.hasLoop(pkg, field, visited, excludes, proto3Resolver) if loopTo == nil { break } @@ -522,7 +521,6 @@ func (p *plugin) Generate(file *generator.FileDescriptor) { p.atleastOne = false p.PluginImports = generator.NewPluginImports(p.Generator) p.varGen = NewVarGen() - proto3 := gogoproto.IsProto3(file.FileDescriptorProto) p.typesPkg = p.NewImport("github.com/gogo/protobuf/types") p.localName = generator.FileName(file) protoPkg := p.NewImport("github.com/gogo/protobuf/proto") @@ -541,8 +539,11 @@ func (p *plugin) Generate(file *generator.FileDescriptor) { ccTypeName := generator.CamelCaseSlice(message.TypeName()) loopLevels := make([]int, len(message.Field)) maxLoopLevel := 0 + + proto3Resolver := proto3optional.NewResolver(gogoproto.IsProto3(file.FileDescriptorProto), message.Field) + for i, field := range message.Field { - loopLevels[i] = p.loops(file.GetPackage(), field, message) + loopLevels[i] = p.loops(file.GetPackage(), field, message, proto3Resolver) if loopLevels[i] > maxLoopLevel { maxLoopLevel = loopLevels[i] } @@ -567,7 +568,7 @@ func (p *plugin) Generate(file *generator.FileDescriptor) { k += ran p.P(`case `, strings.Join(is, ","), `:`) p.In() - p.GenerateField(file, message, field) + p.GenerateField(file, message, field, proto3Resolver) p.Out() } p.P(`}`) @@ -578,10 +579,10 @@ func (p *plugin) Generate(file *generator.FileDescriptor) { if field.GetNumber() > maxFieldNumber { maxFieldNumber = field.GetNumber() } - oneof := field.OneofIndex != nil + oneof := proto3Resolver.IsRealOneOf(field) if !oneof { - if field.IsRequired() || (!gogoproto.IsNullable(field) && !field.IsRepeated()) || (proto3 && !field.IsMessage()) { - p.GenerateField(file, message, field) + if field.IsRequired() || (!gogoproto.IsNullable(field, proto3Resolver) && !field.IsRepeated()) || (proto3Resolver.IsProto3WithoutOptional(field) && !field.IsMessage()) { + p.GenerateField(file, message, field, proto3Resolver) } else { if loopLevels[fieldIndex] > 0 { p.P(`if r.Intn(5) == 0 {`) @@ -589,12 +590,12 @@ func (p *plugin) Generate(file *generator.FileDescriptor) { p.P(`if r.Intn(5) != 0 {`) } p.In() - p.GenerateField(file, message, field) + p.GenerateField(file, message, field, proto3Resolver) p.Out() p.P(`}`) } } else { - fieldname := p.GetFieldName(message, field) + fieldname := p.GetFieldName(message, field, proto3Resolver) if _, ok := oneofs[fieldname]; ok { continue } else { @@ -602,7 +603,7 @@ func (p *plugin) Generate(file *generator.FileDescriptor) { } fieldNumbers := []int32{} for _, f := range message.Field { - fname := p.GetFieldName(message, f) + fname := p.GetFieldName(message, f, proto3Resolver) if fname == fieldname { fieldNumbers = append(fieldNumbers, f.GetNumber()) } @@ -611,13 +612,13 @@ func (p *plugin) Generate(file *generator.FileDescriptor) { p.P(`oneofNumber_`, fieldname, ` := `, fmt.Sprintf("%#v", fieldNumbers), `[r.Intn(`, strconv.Itoa(len(fieldNumbers)), `)]`) p.P(`switch oneofNumber_`, fieldname, ` {`) for _, f := range message.Field { - fname := p.GetFieldName(message, f) + fname := p.GetFieldName(message, f, proto3Resolver) if fname != fieldname { continue } p.P(`case `, strconv.Itoa(int(f.GetNumber())), `:`) p.In() - ccTypeName := p.OneOfTypeName(message, f) + ccTypeName := p.OneOfTypeName(message, f, proto3Resolver) p.P(`this.`, fname, ` = NewPopulated`, ccTypeName, `(r, easy)`) p.Out() } @@ -679,16 +680,16 @@ func (p *plugin) Generate(file *generator.FileDescriptor) { //Generate NewPopulated functions for oneof fields m := proto.Clone(message.DescriptorProto).(*descriptor.DescriptorProto) for _, f := range m.Field { - oneof := f.OneofIndex != nil + oneof := proto3Resolver.IsRealOneOf(f) if !oneof { continue } - ccTypeName := p.OneOfTypeName(message, f) + ccTypeName := p.OneOfTypeName(message, f, proto3Resolver) p.P(`func NewPopulated`, ccTypeName, `(r randy`, p.localName, `, easy bool) *`, ccTypeName, ` {`) p.In() p.P(`this := &`, ccTypeName, `{}`) vanity.TurnOffNullableForNativeTypes(f) - p.GenerateField(file, message, f) + p.GenerateField(file, message, f, proto3Resolver) p.P(`return this`) p.Out() p.P(`}`) diff --git a/plugin/size/size.go b/plugin/size/size.go index 1650b43875..01120c8289 100644 --- a/plugin/size/size.go +++ b/plugin/size/size.go @@ -50,43 +50,43 @@ And a benchmark given it is enabled using one of the following extensions: Let us look at: - github.com/gogo/protobuf/test/example/example.proto + github.com/gogo/protobuf/test/example/example.proto Btw all the output can be seen at: - github.com/gogo/protobuf/test/example/* + github.com/gogo/protobuf/test/example/* The following message: - option (gogoproto.sizer_all) = true; + option (gogoproto.sizer_all) = true; - message B { - option (gogoproto.description) = true; - optional A A = 1 [(gogoproto.nullable) = false, (gogoproto.embed) = true]; - repeated bytes G = 2 [(gogoproto.customtype) = "github.com/gogo/protobuf/test/custom.Uint128", (gogoproto.nullable) = false]; - } + message B { + option (gogoproto.description) = true; + optional A A = 1 [(gogoproto.nullable) = false, (gogoproto.embed) = true]; + repeated bytes G = 2 [(gogoproto.customtype) = "github.com/gogo/protobuf/test/custom.Uint128", (gogoproto.nullable) = false]; + } given to the size plugin, will generate the following code: - func (m *B) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = m.A.Size() - n += 1 + l + sovExample(uint64(l)) - if len(m.G) > 0 { - for _, e := range m.G { - l = e.Size() - n += 1 + l + sovExample(uint64(l)) + func (m *B) Size() (n int) { + if m == nil { + return 0 } - } - if m.XXX_unrecognized != nil { - n += len(m.XXX_unrecognized) - } - return n - } + var l int + _ = l + l = m.A.Size() + n += 1 + l + sovExample(uint64(l)) + if len(m.G) > 0 { + for _, e := range m.G { + l = e.Size() + n += 1 + l + sovExample(uint64(l)) + } + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n + } and the following test code: @@ -118,7 +118,6 @@ and the following test code: } The sovExample function is a size of varint function for the example.pb.go file. - */ package size @@ -130,6 +129,7 @@ import ( "github.com/gogo/protobuf/gogoproto" "github.com/gogo/protobuf/proto" + "github.com/gogo/protobuf/proto3optional" descriptor "github.com/gogo/protobuf/protoc-gen-gogo/descriptor" "github.com/gogo/protobuf/protoc-gen-gogo/generator" "github.com/gogo/protobuf/vanity" @@ -199,9 +199,9 @@ func (p *size) sizeZigZag() { }`) } -func (p *size) std(field *descriptor.FieldDescriptorProto, name string) (string, bool) { +func (p *size) std(field *descriptor.FieldDescriptorProto, name string, proto3Resolver *proto3optional.Resolver) (string, bool) { ptr := "" - if gogoproto.IsNullable(field) { + if gogoproto.IsNullable(field, proto3Resolver) { ptr = "*" } if gogoproto.IsStdTime(field) { @@ -230,11 +230,11 @@ func (p *size) std(field *descriptor.FieldDescriptorProto, name string) (string, return "", false } -func (p *size) generateField(proto3 bool, file *generator.FileDescriptor, message *generator.Descriptor, field *descriptor.FieldDescriptorProto, sizeName string) { - fieldname := p.GetOneOfFieldName(message, field) - nullable := gogoproto.IsNullable(field) +func (p *size) generateField(proto3 bool, file *generator.FileDescriptor, message *generator.Descriptor, field *descriptor.FieldDescriptorProto, sizeName string, proto3Resolver *proto3optional.Resolver) { + fieldname := p.GetOneOfFieldName(message, field, proto3Resolver) + nullable := gogoproto.IsNullable(field, proto3Resolver) repeated := field.IsRepeated() - doNilCheck := gogoproto.NeedsNilCheck(proto3, field) + doNilCheck := gogoproto.NeedsNilCheck(field, proto3Resolver) if repeated { p.P(`if len(m.`, fieldname, `) > 0 {`) p.In() @@ -243,7 +243,7 @@ func (p *size) generateField(proto3 bool, file *generator.FileDescriptor, messag p.In() } packed := field.IsPacked() || (proto3 && field.IsPacked3()) - _, wire := p.GoType(message, field) + _, wire := p.GoType(message, field, proto3Resolver) wireType := wireToType(wire) fieldNumber := field.GetNumber() if packed { @@ -258,7 +258,7 @@ func (p *size) generateField(proto3 bool, file *generator.FileDescriptor, messag p.P(`n+=`, strconv.Itoa(key), `+sov`, p.localName, `(uint64(len(m.`, fieldname, `)*8))`, `+len(m.`, fieldname, `)*8`) } else if repeated { p.P(`n+=`, strconv.Itoa(key+8), `*len(m.`, fieldname, `)`) - } else if proto3 { + } else if proto3Resolver.IsProto3WithoutOptional(field) { p.P(`if m.`, fieldname, ` != 0 {`) p.In() p.P(`n+=`, strconv.Itoa(key+8)) @@ -276,7 +276,7 @@ func (p *size) generateField(proto3 bool, file *generator.FileDescriptor, messag p.P(`n+=`, strconv.Itoa(key), `+sov`, p.localName, `(uint64(len(m.`, fieldname, `)*4))`, `+len(m.`, fieldname, `)*4`) } else if repeated { p.P(`n+=`, strconv.Itoa(key+4), `*len(m.`, fieldname, `)`) - } else if proto3 { + } else if proto3Resolver.IsProto3WithoutOptional(field) { p.P(`if m.`, fieldname, ` != 0 {`) p.In() p.P(`n+=`, strconv.Itoa(key+4)) @@ -306,7 +306,7 @@ func (p *size) generateField(proto3 bool, file *generator.FileDescriptor, messag p.P(`n+=`, strconv.Itoa(key), `+sov`, p.localName, `(uint64(e))`) p.Out() p.P(`}`) - } else if proto3 { + } else if proto3Resolver.IsProto3WithoutOptional(field) { p.P(`if m.`, fieldname, ` != 0 {`) p.In() p.P(`n+=`, strconv.Itoa(key), `+sov`, p.localName, `(uint64(m.`, fieldname, `))`) @@ -322,7 +322,7 @@ func (p *size) generateField(proto3 bool, file *generator.FileDescriptor, messag p.P(`n+=`, strconv.Itoa(key), `+sov`, p.localName, `(uint64(len(m.`, fieldname, `)))`, `+len(m.`, fieldname, `)*1`) } else if repeated { p.P(`n+=`, strconv.Itoa(key+1), `*len(m.`, fieldname, `)`) - } else if proto3 { + } else if proto3Resolver.IsProto3WithoutOptional(field) { p.P(`if m.`, fieldname, ` {`) p.In() p.P(`n+=`, strconv.Itoa(key+1)) @@ -341,7 +341,7 @@ func (p *size) generateField(proto3 bool, file *generator.FileDescriptor, messag p.P(`n+=`, strconv.Itoa(key), `+l+sov`, p.localName, `(uint64(l))`) p.Out() p.P(`}`) - } else if proto3 { + } else if proto3Resolver.IsProto3WithoutOptional(field) { p.P(`l=len(m.`, fieldname, `)`) p.P(`if l > 0 {`) p.In() @@ -359,13 +359,13 @@ func (p *size) generateField(proto3 bool, file *generator.FileDescriptor, messag panic(fmt.Errorf("size does not support group %v", fieldname)) case descriptor.FieldDescriptorProto_TYPE_MESSAGE: if p.IsMap(field) { - m := p.GoMapType(nil, field) - _, keywire := p.GoType(nil, m.KeyAliasField) - valuegoTyp, _ := p.GoType(nil, m.ValueField) - valuegoAliasTyp, valuewire := p.GoType(nil, m.ValueAliasField) - _, fieldwire := p.GoType(nil, field) + m := p.GoMapType(nil, field, proto3Resolver) + _, keywire := p.GoType(nil, m.KeyAliasField, proto3Resolver) + valuegoTyp, _ := p.GoType(nil, m.ValueField, proto3Resolver) + valuegoAliasTyp, valuewire := p.GoType(nil, m.ValueAliasField, proto3Resolver) + _, fieldwire := p.GoType(nil, field, proto3Resolver) - nullable, valuegoTyp, valuegoAliasTyp = generator.GoMapValueTypes(field, m.ValueField, valuegoTyp, valuegoAliasTyp) + nullable, valuegoTyp, valuegoAliasTyp = generator.GoMapValueTypes(field, m.ValueField, valuegoTyp, valuegoAliasTyp, proto3Resolver) fieldKeySize := keySize(field.GetNumber(), wireToType(fieldwire)) keyKeySize := keySize(1, wireToType(keywire)) @@ -439,7 +439,7 @@ func (p *size) generateField(proto3 bool, file *generator.FileDescriptor, messag sum = append(sum, `l`) } else { p.P(`l = 0`) - if proto3 { + if proto3Resolver.IsProto3WithoutOptional(field) { p.P(`if len(v) > 0 {`) } else { p.P(`if v != nil {`) @@ -455,7 +455,7 @@ func (p *size) generateField(proto3 bool, file *generator.FileDescriptor, messag sum = append(sum, strconv.Itoa(valueKeySize)) sum = append(sum, `soz`+p.localName+`(uint64(v))`) case descriptor.FieldDescriptorProto_TYPE_MESSAGE: - stdSizeCall, stdOk := p.std(m.ValueAliasField, "v") + stdSizeCall, stdOk := p.std(m.ValueAliasField, "v", proto3Resolver) if nullable { p.P(`l = 0`) p.P(`if v != nil {`) @@ -490,7 +490,7 @@ func (p *size) generateField(proto3 bool, file *generator.FileDescriptor, messag } else if repeated { p.P(`for _, e := range m.`, fieldname, ` { `) p.In() - stdSizeCall, stdOk := p.std(field, "e") + stdSizeCall, stdOk := p.std(field, "e", proto3Resolver) if stdOk { p.P(`l=`, stdSizeCall) } else { @@ -500,7 +500,7 @@ func (p *size) generateField(proto3 bool, file *generator.FileDescriptor, messag p.Out() p.P(`}`) } else { - stdSizeCall, stdOk := p.std(field, "m."+fieldname) + stdSizeCall, stdOk := p.std(field, "m."+fieldname, proto3Resolver) if stdOk { p.P(`l=`, stdSizeCall) } else { @@ -517,7 +517,7 @@ func (p *size) generateField(proto3 bool, file *generator.FileDescriptor, messag p.P(`n+=`, strconv.Itoa(key), `+l+sov`, p.localName, `(uint64(l))`) p.Out() p.P(`}`) - } else if proto3 { + } else if proto3Resolver.IsProto3WithoutOptional(field) { p.P(`l=len(m.`, fieldname, `)`) p.P(`if l > 0 {`) p.In() @@ -557,7 +557,7 @@ func (p *size) generateField(proto3 bool, file *generator.FileDescriptor, messag p.P(`n+=`, strconv.Itoa(key), `+soz`, p.localName, `(uint64(e))`) p.Out() p.P(`}`) - } else if proto3 { + } else if proto3Resolver.IsProto3WithoutOptional(field) { p.P(`if m.`, fieldname, ` != 0 {`) p.In() p.P(`n+=`, strconv.Itoa(key), `+soz`, p.localName, `(uint64(m.`, fieldname, `))`) @@ -614,14 +614,17 @@ func (p *size) Generate(file *generator.FileDescriptor) { p.P(`}`) p.P(`var l int`) p.P(`_ = l`) + + proto3 := gogoproto.IsProto3(file.FileDescriptorProto) + proto3Resolver := proto3optional.NewResolver(proto3, message.Field) + oneofs := make(map[string]struct{}) for _, field := range message.Field { - oneof := field.OneofIndex != nil + oneof := proto3Resolver.IsRealOneOf(field) if !oneof { - proto3 := gogoproto.IsProto3(file.FileDescriptorProto) - p.generateField(proto3, file, message, field, sizeName) + p.generateField(proto3, file, message, field, sizeName, proto3Resolver) } else { - fieldname := p.GetFieldName(message, field) + fieldname := p.GetFieldName(message, field, proto3Resolver) if _, ok := oneofs[fieldname]; ok { continue } else { @@ -660,11 +663,11 @@ func (p *size) Generate(file *generator.FileDescriptor) { //Generate Size methods for oneof fields m := proto.Clone(message.DescriptorProto).(*descriptor.DescriptorProto) for _, f := range m.Field { - oneof := f.OneofIndex != nil + oneof := proto3Resolver.IsRealOneOf(f) if !oneof { continue } - ccTypeName := p.OneOfTypeName(message, f) + ccTypeName := p.OneOfTypeName(message, f, proto3Resolver) p.P(`func (m *`, ccTypeName, `) `, sizeName, `() (n int) {`) p.In() p.P(`if m == nil {`) @@ -675,7 +678,7 @@ func (p *size) Generate(file *generator.FileDescriptor) { p.P(`var l int`) p.P(`_ = l`) vanity.TurnOffNullableForNativeTypes(f) - p.generateField(false, file, message, f, sizeName) + p.generateField(false, file, message, f, sizeName, proto3Resolver) p.P(`return n`) p.Out() p.P(`}`) diff --git a/plugin/stringer/stringer.go b/plugin/stringer/stringer.go index df9792c7c4..b6c26e66d5 100644 --- a/plugin/stringer/stringer.go +++ b/plugin/stringer/stringer.go @@ -41,38 +41,38 @@ The stringer plugin also generates a test given it is enabled using one of the f Let us look at: - github.com/gogo/protobuf/test/example/example.proto + github.com/gogo/protobuf/test/example/example.proto Btw all the output can be seen at: - github.com/gogo/protobuf/test/example/* + github.com/gogo/protobuf/test/example/* The following message: - option (gogoproto.goproto_stringer_all) = false; - option (gogoproto.stringer_all) = true; + option (gogoproto.goproto_stringer_all) = false; + option (gogoproto.stringer_all) = true; - message A { - optional string Description = 1 [(gogoproto.nullable) = false]; - optional int64 Number = 2 [(gogoproto.nullable) = false]; - optional bytes Id = 3 [(gogoproto.customtype) = "github.com/gogo/protobuf/test/custom.Uuid", (gogoproto.nullable) = false]; - } + message A { + optional string Description = 1 [(gogoproto.nullable) = false]; + optional int64 Number = 2 [(gogoproto.nullable) = false]; + optional bytes Id = 3 [(gogoproto.customtype) = "github.com/gogo/protobuf/test/custom.Uuid", (gogoproto.nullable) = false]; + } given to the stringer stringer, will generate the following code: - func (this *A) String() string { - if this == nil { - return "nil" - } - s := strings.Join([]string{`&A{`, - `Description:` + fmt.Sprintf("%v", this.Description) + `,`, - `Number:` + fmt.Sprintf("%v", this.Number) + `,`, - `Id:` + fmt.Sprintf("%v", this.Id) + `,`, - `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, - `}`, - }, "") - return s - } + func (this *A) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&A{`, + `Description:` + fmt.Sprintf("%v", this.Description) + `,`, + `Number:` + fmt.Sprintf("%v", this.Number) + `,`, + `Id:` + fmt.Sprintf("%v", this.Id) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s + } and the following test code: @@ -88,12 +88,12 @@ and the following test code: Typically fmt.Printf("%v") will stop to print when it reaches a pointer and not print their values, while the generated String method will always print all values, recursively. - */ package stringer import ( "github.com/gogo/protobuf/gogoproto" + "github.com/gogo/protobuf/proto3optional" "github.com/gogo/protobuf/protoc-gen-gogo/generator" "strings" ) @@ -118,7 +118,6 @@ func (p *stringer) Init(g *generator.Generator) { } func (p *stringer) Generate(file *generator.FileDescriptor) { - proto3 := gogoproto.IsProto3(file.FileDescriptorProto) p.PluginImports = generator.NewPluginImports(p.Generator) p.atleastOne = false @@ -148,12 +147,15 @@ func (p *stringer) Generate(file *generator.FileDescriptor) { p.P(`return "nil"`) p.Out() p.P(`}`) + + proto3Resolver := proto3optional.NewResolver(gogoproto.IsProto3(file.FileDescriptorProto), message.Field) + for _, field := range message.Field { if p.IsMap(field) || !field.IsRepeated() { continue } if (field.IsMessage() && !gogoproto.IsCustomType(field)) || p.IsGroup(field) { - nullable := gogoproto.IsNullable(field) + nullable := gogoproto.IsNullable(field, proto3Resolver) desc := p.ObjectNamed(field.GetTypeName()) msgname := p.TypeName(desc) msgnames := strings.Split(msgname, ".") @@ -163,7 +165,7 @@ func (p *stringer) Generate(file *generator.FileDescriptor) { if fieldMessageDesc != nil { gogoStringer = gogoproto.IsStringer(file.FileDescriptorProto, fieldMessageDesc) } - fieldname := p.GetFieldName(message, field) + fieldname := p.GetFieldName(message, field, proto3Resolver) stringfunc := fmtPkg.Use() + `.Sprintf("%v", f)` if gogoStringer { stringfunc = `f.String()` @@ -193,14 +195,14 @@ func (p *stringer) Generate(file *generator.FileDescriptor) { if !p.IsMap(field) { continue } - fieldname := p.GetFieldName(message, field) + fieldname := p.GetFieldName(message, field, proto3Resolver) - m := p.GoMapType(nil, field) + m := p.GoMapType(nil, field, proto3Resolver) mapgoTyp, keyField, keyAliasField := m.GoType, m.KeyField, m.KeyAliasField keysName := `keysFor` + fieldname - keygoTyp, _ := p.GoType(nil, keyField) + keygoTyp, _ := p.GoType(nil, keyField, proto3Resolver) keygoTyp = strings.Replace(keygoTyp, "*", "", 1) - keygoAliasTyp, _ := p.GoType(nil, keyAliasField) + keygoAliasTyp, _ := p.GoType(nil, keyAliasField, proto3Resolver) keygoAliasTyp = strings.Replace(keygoAliasTyp, "*", "", 1) keyCapTyp := generator.CamelCase(keygoTyp) p.P(keysName, ` := make([]`, keygoTyp, `, 0, len(this.`, fieldname, `))`) @@ -228,12 +230,13 @@ func (p *stringer) Generate(file *generator.FileDescriptor) { p.P(mapName, ` += "}"`) } p.P("s := ", stringsPkg.Use(), ".Join([]string{`&", ccTypeName, "{`,") + oneofs := make(map[string]struct{}) for _, field := range message.Field { - nullable := gogoproto.IsNullable(field) + nullable := gogoproto.IsNullable(field, proto3Resolver) repeated := field.IsRepeated() - fieldname := p.GetFieldName(message, field) - oneof := field.OneofIndex != nil + fieldname := p.GetFieldName(message, field, proto3Resolver) + oneof := proto3Resolver.IsRealOneOf(field) if oneof { if _, ok := oneofs[fieldname]; ok { continue @@ -267,7 +270,7 @@ func (p *stringer) Generate(file *generator.FileDescriptor) { p.P("`", fieldname, ":`", ` + `, stringsPkg.Use(), `.Replace(`, stringsPkg.Use(), `.Replace(`, stringfunc, `, "`, typeName, `","`, msgname, `"`, ", 1),`&`,``,1) + `,", "`,") } } else { - if nullable && !repeated && !proto3 { + if nullable && !repeated && !proto3Resolver.IsProto3WithoutOptional(field) { p.P("`", fieldname, ":`", ` + valueToString`, p.localName, `(this.`, fieldname, ") + `,", "`,") } else { p.P("`", fieldname, ":`", ` + `, fmtPkg.Use(), `.Sprintf("%v", this.`, fieldname, ") + `,", "`,") @@ -292,11 +295,11 @@ func (p *stringer) Generate(file *generator.FileDescriptor) { //Generate String methods for oneof fields for _, field := range message.Field { - oneof := field.OneofIndex != nil + oneof := proto3Resolver.IsRealOneOf(field) if !oneof { continue } - ccTypeName := p.OneOfTypeName(message, field) + ccTypeName := p.OneOfTypeName(message, field, proto3Resolver) p.P(`func (this *`, ccTypeName, `) String() string {`) p.In() p.P(`if this == nil {`) @@ -305,7 +308,7 @@ func (p *stringer) Generate(file *generator.FileDescriptor) { p.Out() p.P(`}`) p.P("s := ", stringsPkg.Use(), ".Join([]string{`&", ccTypeName, "{`,") - fieldname := p.GetOneOfFieldName(message, field) + fieldname := p.GetOneOfFieldName(message, field, proto3Resolver) if field.IsMessage() || p.IsGroup(field) { desc := p.ObjectNamed(field.GetTypeName()) msgname := p.TypeName(desc) diff --git a/plugin/union/union.go b/plugin/union/union.go index 90def721c9..63bec53984 100644 --- a/plugin/union/union.go +++ b/plugin/union/union.go @@ -31,11 +31,11 @@ The onlyone plugin generates code for the onlyone extension. All fields must be nullable and only one of the fields may be set, like a union. Two methods are generated - GetValue() interface{} + GetValue() interface{} and - SetValue(v interface{}) (set bool) + SetValue(v interface{}) (set bool) These provide easier interaction with a onlyone. @@ -54,19 +54,19 @@ The onlyone plugin also generates a test given it is enabled using one of the fo Lets look at: - github.com/gogo/protobuf/test/example/example.proto + github.com/gogo/protobuf/test/example/example.proto Btw all the output can be seen at: - github.com/gogo/protobuf/test/example/* + github.com/gogo/protobuf/test/example/* The following message: - message U { - option (gogoproto.onlyone) = true; - optional A A = 1; - optional B B = 2; - } + message U { + option (gogoproto.onlyone) = true; + optional A A = 1; + optional B B = 2; + } given to the onlyone plugin, will generate code which looks a lot like this: @@ -94,24 +94,24 @@ given to the onlyone plugin, will generate code which looks a lot like this: and the following test code: - func TestUUnion(t *testing.T) { - popr := math_rand.New(math_rand.NewSource(time.Now().UnixNano())) - p := NewPopulatedU(popr) - v := p.GetValue() - msg := &U{} - if !msg.SetValue(v) { - t.Fatalf("Union: Could not set Value") - } - if !p.Equal(msg) { - t.Fatalf("%#v !Union Equal %#v", msg, p) - } - } - + func TestUUnion(t *testing.T) { + popr := math_rand.New(math_rand.NewSource(time.Now().UnixNano())) + p := NewPopulatedU(popr) + v := p.GetValue() + msg := &U{} + if !msg.SetValue(v) { + t.Fatalf("Union: Could not set Value") + } + if !p.Equal(msg) { + t.Fatalf("%#v !Union Equal %#v", msg, p) + } + } */ package union import ( "github.com/gogo/protobuf/gogoproto" + "github.com/gogo/protobuf/proto3optional" "github.com/gogo/protobuf/protoc-gen-gogo/generator" ) @@ -149,8 +149,11 @@ func (p *union) Generate(file *generator.FileDescriptor) { ccTypeName := generator.CamelCaseSlice(message.TypeName()) p.P(`func (this *`, ccTypeName, `) GetValue() interface{} {`) p.In() + + proto3Resolver := proto3optional.NewResolver(gogoproto.IsProto3(file.FileDescriptorProto), message.Field) + for _, field := range message.Field { - fieldname := p.GetFieldName(message, field) + fieldname := p.GetFieldName(message, field, proto3Resolver) if fieldname == "Value" { panic("cannot have a onlyone message " + ccTypeName + " with a field named Value") } @@ -169,8 +172,8 @@ func (p *union) Generate(file *generator.FileDescriptor) { p.P(`switch vt := value.(type) {`) p.In() for _, field := range message.Field { - fieldname := p.GetFieldName(message, field) - goTyp, _ := p.GoType(message, field) + fieldname := p.GetFieldName(message, field, proto3Resolver) + goTyp, _ := p.GoType(message, field, proto3Resolver) p.P(`case `, goTyp, `:`) p.In() p.P(`this.`, fieldname, ` = vt`) @@ -179,9 +182,9 @@ func (p *union) Generate(file *generator.FileDescriptor) { p.P(`default:`) p.In() for _, field := range message.Field { - fieldname := p.GetFieldName(message, field) + fieldname := p.GetFieldName(message, field, proto3Resolver) if field.IsMessage() { - goTyp, _ := p.GoType(message, field) + goTyp, _ := p.GoType(message, field, proto3Resolver) obj := p.ObjectNamed(field.GetTypeName()).(*generator.Descriptor) if gogoproto.IsUnion(obj.File().FileDescriptorProto, obj.DescriptorProto) { diff --git a/plugin/unmarshal/unmarshal.go b/plugin/unmarshal/unmarshal.go index fae67de4fd..ce95c545d2 100644 --- a/plugin/unmarshal/unmarshal.go +++ b/plugin/unmarshal/unmarshal.go @@ -57,120 +57,119 @@ And benchmarks given it is enabled using one of the following extensions: Let us look at: - github.com/gogo/protobuf/test/example/example.proto + github.com/gogo/protobuf/test/example/example.proto Btw all the output can be seen at: - github.com/gogo/protobuf/test/example/* + github.com/gogo/protobuf/test/example/* The following message: - option (gogoproto.unmarshaler_all) = true; + option (gogoproto.unmarshaler_all) = true; - message B { - option (gogoproto.description) = true; - optional A A = 1 [(gogoproto.nullable) = false, (gogoproto.embed) = true]; - repeated bytes G = 2 [(gogoproto.customtype) = "github.com/gogo/protobuf/test/custom.Uint128", (gogoproto.nullable) = false]; - } + message B { + option (gogoproto.description) = true; + optional A A = 1 [(gogoproto.nullable) = false, (gogoproto.embed) = true]; + repeated bytes G = 2 [(gogoproto.customtype) = "github.com/gogo/protobuf/test/custom.Uint128", (gogoproto.nullable) = false]; + } given to the unmarshal plugin, will generate the following code: - func (m *B) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - var wire uint64 - for shift := uint(0); ; shift += 7 { - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - switch fieldNum { - case 1: - if wireType != 2 { - return proto.ErrWrongType - } - var msglen int + func (m *B) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + var wire uint64 for shift := uint(0); ; shift += 7 { if iNdEx >= l { return io.ErrUnexpectedEOF } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } } - postIndex := iNdEx + msglen - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.A.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return proto.ErrWrongType - } - var byteLen int - for shift := uint(0); ; shift += 7 { - if iNdEx >= l { + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + switch fieldNum { + case 1: + if wireType != 2 { + return proto.ErrWrongType + } + var msglen int + for shift := uint(0); ; shift += 7 { + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + postIndex := iNdEx + msglen + if postIndex > l { return io.ErrUnexpectedEOF } - b := dAtA[iNdEx] - iNdEx++ - byteLen |= (int(b) & 0x7F) << shift - if b < 0x80 { - break + if err := m.A.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err } - } - postIndex := iNdEx + byteLen - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.G = append(m.G, github_com_gogo_protobuf_test_custom.Uint128{}) - if err := m.G[len(m.G)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - var sizeOfWire int - for { - sizeOfWire++ - wire >>= 7 - if wire == 0 { - break + iNdEx = postIndex + case 2: + if wireType != 2 { + return proto.ErrWrongType } + var byteLen int + for shift := uint(0); ; shift += 7 { + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + postIndex := iNdEx + byteLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.G = append(m.G, github_com_gogo_protobuf_test_custom.Uint128{}) + if err := m.G[len(m.G)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + var sizeOfWire int + for { + sizeOfWire++ + wire >>= 7 + if wire == 0 { + break + } + } + iNdEx -= sizeOfWire + skippy, err := skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy } - iNdEx -= sizeOfWire - skippy, err := skip(dAtA[iNdEx:]) - if err != nil { - return err - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) - iNdEx += skippy } - } - return nil - } + return nil + } Remember when using this code to call proto.Unmarshal. This will call m.Reset and invoke the generated Unmarshal method for you. If you call m.Unmarshal without m.Reset you could be merging protocol buffers. - */ package unmarshal @@ -181,6 +180,7 @@ import ( "github.com/gogo/protobuf/gogoproto" "github.com/gogo/protobuf/proto" + "github.com/gogo/protobuf/proto3optional" descriptor "github.com/gogo/protobuf/protoc-gen-gogo/descriptor" "github.com/gogo/protobuf/protoc-gen-gogo/generator" ) @@ -253,7 +253,7 @@ func (p *unmarshal) decodeFixed64(varName string, typeName string) { p.P(`iNdEx += 8`) } -func (p *unmarshal) declareMapField(varName string, nullable bool, customType bool, field *descriptor.FieldDescriptorProto) { +func (p *unmarshal) declareMapField(varName string, nullable bool, customType bool, field *descriptor.FieldDescriptorProto, proto3Resolver *proto3optional.Resolver) { switch field.GetType() { case descriptor.FieldDescriptorProto_TYPE_DOUBLE: p.P(`var `, varName, ` float64`) @@ -272,7 +272,7 @@ func (p *unmarshal) declareMapField(varName string, nullable bool, customType bo case descriptor.FieldDescriptorProto_TYPE_BOOL: p.P(`var `, varName, ` bool`) case descriptor.FieldDescriptorProto_TYPE_STRING: - cast, _ := p.GoType(nil, field) + cast, _ := p.GoType(nil, field, proto3Resolver) cast = strings.Replace(cast, "*", "", 1) p.P(`var `, varName, ` `, cast) case descriptor.FieldDescriptorProto_TYPE_MESSAGE: @@ -334,7 +334,7 @@ func (p *unmarshal) declareMapField(varName string, nullable bool, customType bo } } -func (p *unmarshal) mapField(varName string, customType bool, field *descriptor.FieldDescriptorProto) { +func (p *unmarshal) mapField(varName string, customType bool, field *descriptor.FieldDescriptorProto, proto3Resolver *proto3optional.Resolver) { switch field.GetType() { case descriptor.FieldDescriptorProto_TYPE_DOUBLE: p.P(`var `, varName, `temp uint64`) @@ -378,7 +378,7 @@ func (p *unmarshal) mapField(varName string, customType bool, field *descriptor. p.P(`return `, p.ioPkg.Use(), `.ErrUnexpectedEOF`) p.Out() p.P(`}`) - cast, _ := p.GoType(nil, field) + cast, _ := p.GoType(nil, field, proto3Resolver) cast = strings.Replace(cast, "*", "", 1) p.P(varName, ` = `, cast, `(dAtA[iNdEx:postStringIndex`, varName, `])`) p.P(`iNdEx = postStringIndex`, varName) @@ -488,8 +488,8 @@ func (p *unmarshal) mapField(varName string, customType bool, field *descriptor. } } -func (p *unmarshal) noStarOrSliceType(msg *generator.Descriptor, field *descriptor.FieldDescriptorProto) string { - typ, _ := p.GoType(msg, field) +func (p *unmarshal) noStarOrSliceType(msg *generator.Descriptor, field *descriptor.FieldDescriptorProto, proto3Resolver *proto3optional.Resolver) string { + typ, _ := p.GoType(msg, field, proto3Resolver) if typ[0] == '*' { return typ[1:] } @@ -499,21 +499,21 @@ func (p *unmarshal) noStarOrSliceType(msg *generator.Descriptor, field *descript return typ } -func (p *unmarshal) field(file *generator.FileDescriptor, msg *generator.Descriptor, field *descriptor.FieldDescriptorProto, fieldname string, proto3 bool) { +func (p *unmarshal) field(file *generator.FileDescriptor, msg *generator.Descriptor, field *descriptor.FieldDescriptorProto, fieldname string, proto3Resolver *proto3optional.Resolver) { repeated := field.IsRepeated() - nullable := gogoproto.IsNullable(field) - typ := p.noStarOrSliceType(msg, field) - oneof := field.OneofIndex != nil + nullable := gogoproto.IsNullable(field, proto3Resolver) + typ := p.noStarOrSliceType(msg, field, proto3Resolver) + oneof := proto3Resolver.IsRealOneOf(field) switch *field.Type { case descriptor.FieldDescriptorProto_TYPE_DOUBLE: p.P(`var v uint64`) p.decodeFixed64("v", "uint64") if oneof { - p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field), `{`, typ, "(", p.mathPkg.Use(), `.Float64frombits(v))}`) + p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field, proto3Resolver), `{`, typ, "(", p.mathPkg.Use(), `.Float64frombits(v))}`) } else if repeated { p.P(`v2 := `, typ, "(", p.mathPkg.Use(), `.Float64frombits(v))`) p.P(`m.`, fieldname, ` = append(m.`, fieldname, `, v2)`) - } else if proto3 || !nullable { + } else if proto3Resolver.IsProto3WithoutOptional(field) || !nullable { p.P(`m.`, fieldname, ` = `, typ, "(", p.mathPkg.Use(), `.Float64frombits(v))`) } else { p.P(`v2 := `, typ, "(", p.mathPkg.Use(), `.Float64frombits(v))`) @@ -523,11 +523,11 @@ func (p *unmarshal) field(file *generator.FileDescriptor, msg *generator.Descrip p.P(`var v uint32`) p.decodeFixed32("v", "uint32") if oneof { - p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field), `{`, typ, "(", p.mathPkg.Use(), `.Float32frombits(v))}`) + p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field, proto3Resolver), `{`, typ, "(", p.mathPkg.Use(), `.Float32frombits(v))}`) } else if repeated { p.P(`v2 := `, typ, "(", p.mathPkg.Use(), `.Float32frombits(v))`) p.P(`m.`, fieldname, ` = append(m.`, fieldname, `, v2)`) - } else if proto3 || !nullable { + } else if proto3Resolver.IsProto3WithoutOptional(field) || !nullable { p.P(`m.`, fieldname, ` = `, typ, "(", p.mathPkg.Use(), `.Float32frombits(v))`) } else { p.P(`v2 := `, typ, "(", p.mathPkg.Use(), `.Float32frombits(v))`) @@ -537,12 +537,12 @@ func (p *unmarshal) field(file *generator.FileDescriptor, msg *generator.Descrip if oneof { p.P(`var v `, typ) p.decodeVarint("v", typ) - p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field), `{v}`) + p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field, proto3Resolver), `{v}`) } else if repeated { p.P(`var v `, typ) p.decodeVarint("v", typ) p.P(`m.`, fieldname, ` = append(m.`, fieldname, `, v)`) - } else if proto3 || !nullable { + } else if proto3Resolver.IsProto3WithoutOptional(field) || !nullable { p.P(`m.`, fieldname, ` = 0`) p.decodeVarint("m."+fieldname, typ) } else { @@ -554,12 +554,12 @@ func (p *unmarshal) field(file *generator.FileDescriptor, msg *generator.Descrip if oneof { p.P(`var v `, typ) p.decodeVarint("v", typ) - p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field), `{v}`) + p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field, proto3Resolver), `{v}`) } else if repeated { p.P(`var v `, typ) p.decodeVarint("v", typ) p.P(`m.`, fieldname, ` = append(m.`, fieldname, `, v)`) - } else if proto3 || !nullable { + } else if proto3Resolver.IsProto3WithoutOptional(field) || !nullable { p.P(`m.`, fieldname, ` = 0`) p.decodeVarint("m."+fieldname, typ) } else { @@ -571,12 +571,12 @@ func (p *unmarshal) field(file *generator.FileDescriptor, msg *generator.Descrip if oneof { p.P(`var v `, typ) p.decodeVarint("v", typ) - p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field), `{v}`) + p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field, proto3Resolver), `{v}`) } else if repeated { p.P(`var v `, typ) p.decodeVarint("v", typ) p.P(`m.`, fieldname, ` = append(m.`, fieldname, `, v)`) - } else if proto3 || !nullable { + } else if proto3Resolver.IsProto3WithoutOptional(field) || !nullable { p.P(`m.`, fieldname, ` = 0`) p.decodeVarint("m."+fieldname, typ) } else { @@ -588,12 +588,12 @@ func (p *unmarshal) field(file *generator.FileDescriptor, msg *generator.Descrip if oneof { p.P(`var v `, typ) p.decodeFixed64("v", typ) - p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field), `{v}`) + p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field, proto3Resolver), `{v}`) } else if repeated { p.P(`var v `, typ) p.decodeFixed64("v", typ) p.P(`m.`, fieldname, ` = append(m.`, fieldname, `, v)`) - } else if proto3 || !nullable { + } else if proto3Resolver.IsProto3WithoutOptional(field) || !nullable { p.P(`m.`, fieldname, ` = 0`) p.decodeFixed64("m."+fieldname, typ) } else { @@ -605,12 +605,12 @@ func (p *unmarshal) field(file *generator.FileDescriptor, msg *generator.Descrip if oneof { p.P(`var v `, typ) p.decodeFixed32("v", typ) - p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field), `{v}`) + p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field, proto3Resolver), `{v}`) } else if repeated { p.P(`var v `, typ) p.decodeFixed32("v", typ) p.P(`m.`, fieldname, ` = append(m.`, fieldname, `, v)`) - } else if proto3 || !nullable { + } else if proto3Resolver.IsProto3WithoutOptional(field) || !nullable { p.P(`m.`, fieldname, ` = 0`) p.decodeFixed32("m."+fieldname, typ) } else { @@ -623,10 +623,10 @@ func (p *unmarshal) field(file *generator.FileDescriptor, msg *generator.Descrip p.decodeVarint("v", "int") if oneof { p.P(`b := `, typ, `(v != 0)`) - p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field), `{b}`) + p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field, proto3Resolver), `{b}`) } else if repeated { p.P(`m.`, fieldname, ` = append(m.`, fieldname, `, `, typ, `(v != 0))`) - } else if proto3 || !nullable { + } else if proto3Resolver.IsProto3WithoutOptional(field) || !nullable { p.P(`m.`, fieldname, ` = `, typ, `(v != 0)`) } else { p.P(`b := `, typ, `(v != 0)`) @@ -653,10 +653,10 @@ func (p *unmarshal) field(file *generator.FileDescriptor, msg *generator.Descrip p.Out() p.P(`}`) if oneof { - p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field), `{`, typ, `(dAtA[iNdEx:postIndex])}`) + p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field, proto3Resolver), `{`, typ, `(dAtA[iNdEx:postIndex])}`) } else if repeated { p.P(`m.`, fieldname, ` = append(m.`, fieldname, `, `, typ, `(dAtA[iNdEx:postIndex]))`) - } else if proto3 || !nullable { + } else if proto3Resolver.IsProto3WithoutOptional(field) || !nullable { p.P(`m.`, fieldname, ` = `, typ, `(dAtA[iNdEx:postIndex])`) } else { p.P(`s := `, typ, `(dAtA[iNdEx:postIndex])`) @@ -784,18 +784,18 @@ func (p *unmarshal) field(file *generator.FileDescriptor, msg *generator.Descrip p.P(`return err`) p.Out() p.P(`}`) - p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field), `{v}`) + p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field, proto3Resolver), `{v}`) } else if p.IsMap(field) { - m := p.GoMapType(nil, field) + m := p.GoMapType(nil, field, proto3Resolver) - keygoTyp, _ := p.GoType(nil, m.KeyField) - keygoAliasTyp, _ := p.GoType(nil, m.KeyAliasField) + keygoTyp, _ := p.GoType(nil, m.KeyField, proto3Resolver) + keygoAliasTyp, _ := p.GoType(nil, m.KeyAliasField, proto3Resolver) // keys may not be pointers keygoTyp = strings.Replace(keygoTyp, "*", "", 1) keygoAliasTyp = strings.Replace(keygoAliasTyp, "*", "", 1) - valuegoTyp, _ := p.GoType(nil, m.ValueField) - valuegoAliasTyp, _ := p.GoType(nil, m.ValueAliasField) + valuegoTyp, _ := p.GoType(nil, m.ValueField, proto3Resolver) + valuegoAliasTyp, _ := p.GoType(nil, m.ValueAliasField, proto3Resolver) // if the map type is an alias and key or values are aliases (type Foo map[Bar]Baz), // we need to explicitly record their use here. @@ -806,7 +806,7 @@ func (p *unmarshal) field(file *generator.FileDescriptor, msg *generator.Descrip p.RecordTypeUse(m.ValueAliasField.GetTypeName()) } - nullable, valuegoTyp, valuegoAliasTyp = generator.GoMapValueTypes(field, m.ValueField, valuegoTyp, valuegoAliasTyp) + nullable, valuegoTyp, valuegoAliasTyp = generator.GoMapValueTypes(field, m.ValueField, valuegoTyp, valuegoAliasTyp, proto3Resolver) if gogoproto.IsStdType(field) { valuegoTyp = valuegoAliasTyp } @@ -817,8 +817,8 @@ func (p *unmarshal) field(file *generator.FileDescriptor, msg *generator.Descrip p.Out() p.P(`}`) - p.declareMapField("mapkey", false, false, m.KeyAliasField) - p.declareMapField("mapvalue", nullable, gogoproto.IsCustomType(field), m.ValueAliasField) + p.declareMapField("mapkey", false, false, m.KeyAliasField, proto3Resolver) + p.declareMapField("mapvalue", nullable, gogoproto.IsCustomType(field), m.ValueAliasField, proto3Resolver) p.P(`for iNdEx < postIndex {`) p.In() @@ -829,11 +829,11 @@ func (p *unmarshal) field(file *generator.FileDescriptor, msg *generator.Descrip p.P(`if fieldNum == 1 {`) p.In() - p.mapField("mapkey", false, m.KeyAliasField) + p.mapField("mapkey", false, m.KeyAliasField, proto3Resolver) p.Out() p.P(`} else if fieldNum == 2 {`) p.In() - p.mapField("mapvalue", gogoproto.IsCustomType(field), m.ValueAliasField) + p.mapField("mapvalue", gogoproto.IsCustomType(field), m.ValueAliasField, proto3Resolver) p.Out() p.P(`} else {`) p.In() @@ -947,7 +947,7 @@ func (p *unmarshal) field(file *generator.FileDescriptor, msg *generator.Descrip } else if nullable && !gogoproto.IsCustomType(field) { p.P(`m.`, fieldname, ` = append(m.`, fieldname, `, &`, msgname, `{})`) } else { - goType, _ := p.GoType(nil, field) + goType, _ := p.GoType(nil, field, proto3Resolver) // remove the slice from the type, i.e. []*T -> *T goType = goType[2:] p.P(`m.`, fieldname, ` = append(m.`, fieldname, `, `, goType, `{})`) @@ -1053,7 +1053,7 @@ func (p *unmarshal) field(file *generator.FileDescriptor, msg *generator.Descrip } else if gogoproto.IsStdBytes(field) { p.P(`m.`, fieldname, ` = new([]byte)`) } else { - goType, _ := p.GoType(nil, field) + goType, _ := p.GoType(nil, field, proto3Resolver) // remove the star from the type p.P(`m.`, fieldname, ` = &`, goType[1:], `{}`) } @@ -1144,7 +1144,7 @@ func (p *unmarshal) field(file *generator.FileDescriptor, msg *generator.Descrip if oneof { p.P(`v := make([]byte, postIndex-iNdEx)`) p.P(`copy(v, dAtA[iNdEx:postIndex])`) - p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field), `{v}`) + p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field, proto3Resolver), `{v}`) } else if repeated { p.P(`m.`, fieldname, ` = append(m.`, fieldname, `, make([]byte, postIndex-iNdEx))`) p.P(`copy(m.`, fieldname, `[len(m.`, fieldname, `)-1], dAtA[iNdEx:postIndex])`) @@ -1169,7 +1169,7 @@ func (p *unmarshal) field(file *generator.FileDescriptor, msg *generator.Descrip p.P(`return err`) p.Out() p.P(`}`) - p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field), `{*v}`) + p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field, proto3Resolver), `{*v}`) } else if repeated { p.P(`var v `, ctyp) p.P(`m.`, fieldname, ` = append(m.`, fieldname, `, v)`) @@ -1199,12 +1199,12 @@ func (p *unmarshal) field(file *generator.FileDescriptor, msg *generator.Descrip if oneof { p.P(`var v `, typ) p.decodeVarint("v", typ) - p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field), `{v}`) + p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field, proto3Resolver), `{v}`) } else if repeated { p.P(`var v `, typ) p.decodeVarint("v", typ) p.P(`m.`, fieldname, ` = append(m.`, fieldname, `, v)`) - } else if proto3 || !nullable { + } else if proto3Resolver.IsProto3WithoutOptional(field) || !nullable { p.P(`m.`, fieldname, ` = 0`) p.decodeVarint("m."+fieldname, typ) } else { @@ -1217,12 +1217,12 @@ func (p *unmarshal) field(file *generator.FileDescriptor, msg *generator.Descrip if oneof { p.P(`var v `, typName) p.decodeVarint("v", typName) - p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field), `{v}`) + p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field, proto3Resolver), `{v}`) } else if repeated { p.P(`var v `, typName) p.decodeVarint("v", typName) p.P(`m.`, fieldname, ` = append(m.`, fieldname, `, v)`) - } else if proto3 || !nullable { + } else if proto3Resolver.IsProto3WithoutOptional(field) || !nullable { p.P(`m.`, fieldname, ` = 0`) p.decodeVarint("m."+fieldname, typName) } else { @@ -1234,12 +1234,12 @@ func (p *unmarshal) field(file *generator.FileDescriptor, msg *generator.Descrip if oneof { p.P(`var v `, typ) p.decodeFixed32("v", typ) - p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field), `{v}`) + p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field, proto3Resolver), `{v}`) } else if repeated { p.P(`var v `, typ) p.decodeFixed32("v", typ) p.P(`m.`, fieldname, ` = append(m.`, fieldname, `, v)`) - } else if proto3 || !nullable { + } else if proto3Resolver.IsProto3WithoutOptional(field) || !nullable { p.P(`m.`, fieldname, ` = 0`) p.decodeFixed32("m."+fieldname, typ) } else { @@ -1251,12 +1251,12 @@ func (p *unmarshal) field(file *generator.FileDescriptor, msg *generator.Descrip if oneof { p.P(`var v `, typ) p.decodeFixed64("v", typ) - p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field), `{v}`) + p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field, proto3Resolver), `{v}`) } else if repeated { p.P(`var v `, typ) p.decodeFixed64("v", typ) p.P(`m.`, fieldname, ` = append(m.`, fieldname, `, v)`) - } else if proto3 || !nullable { + } else if proto3Resolver.IsProto3WithoutOptional(field) || !nullable { p.P(`m.`, fieldname, ` = 0`) p.decodeFixed64("m."+fieldname, typ) } else { @@ -1269,10 +1269,10 @@ func (p *unmarshal) field(file *generator.FileDescriptor, msg *generator.Descrip p.decodeVarint("v", typ) p.P(`v = `, typ, `((uint32(v) >> 1) ^ uint32(((v&1)<<31)>>31))`) if oneof { - p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field), `{v}`) + p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field, proto3Resolver), `{v}`) } else if repeated { p.P(`m.`, fieldname, ` = append(m.`, fieldname, `, v)`) - } else if proto3 || !nullable { + } else if proto3Resolver.IsProto3WithoutOptional(field) || !nullable { p.P(`m.`, fieldname, ` = v`) } else { p.P(`m.`, fieldname, ` = &v`) @@ -1282,10 +1282,10 @@ func (p *unmarshal) field(file *generator.FileDescriptor, msg *generator.Descrip p.decodeVarint("v", "uint64") p.P(`v = (v >> 1) ^ uint64((int64(v&1)<<63)>>63)`) if oneof { - p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field), `{`, typ, `(v)}`) + p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field, proto3Resolver), `{`, typ, `(v)}`) } else if repeated { p.P(`m.`, fieldname, ` = append(m.`, fieldname, `, `, typ, `(v))`) - } else if proto3 || !nullable { + } else if proto3Resolver.IsProto3WithoutOptional(field) || !nullable { p.P(`m.`, fieldname, ` = `, typ, `(v)`) } else { p.P(`v2 := `, typ, `(v)`) @@ -1297,7 +1297,6 @@ func (p *unmarshal) field(file *generator.FileDescriptor, msg *generator.Descrip } func (p *unmarshal) Generate(file *generator.FileDescriptor) { - proto3 := gogoproto.IsProto3(file.FileDescriptorProto) p.PluginImports = generator.NewPluginImports(p.Generator) p.atleastOne = false p.localName = generator.FileName(file) @@ -1364,11 +1363,14 @@ func (p *unmarshal) Generate(file *generator.FileDescriptor) { p.P(`}`) p.P(`switch fieldNum {`) p.In() + + proto3Resolver := proto3optional.NewResolver(gogoproto.IsProto3(file.FileDescriptorProto), message.Field) + for _, field := range message.Field { - fieldname := p.GetFieldName(message, field) + fieldname := p.GetFieldName(message, field, proto3Resolver) errFieldname := fieldname - if field.OneofIndex != nil { - errFieldname = p.GetOneOfFieldName(message, field) + if proto3Resolver.IsRealOneOf(field) { + errFieldname = p.GetOneOfFieldName(message, field, proto3Resolver) } possiblyPacked := field.IsScalar() && field.IsRepeated() p.P(`case `, strconv.Itoa(int(field.GetNumber())), `:`) @@ -1377,7 +1379,7 @@ func (p *unmarshal) Generate(file *generator.FileDescriptor) { if possiblyPacked { p.P(`if wireType == `, strconv.Itoa(wireType), `{`) p.In() - p.field(file, message, field, fieldname, false) + p.field(file, message, field, fieldname, proto3Resolver) p.Out() p.P(`} else if wireType == `, strconv.Itoa(proto.WireBytes), `{`) p.In() @@ -1423,13 +1425,13 @@ func (p *unmarshal) Generate(file *generator.FileDescriptor) { } p.P(`if elementCount != 0 && len(m.`, fieldname, `) == 0 {`) p.In() - p.P(`m.`, fieldname, ` = make([]`, p.noStarOrSliceType(message, field), `, 0, elementCount)`) + p.P(`m.`, fieldname, ` = make([]`, p.noStarOrSliceType(message, field, proto3Resolver), `, 0, elementCount)`) p.Out() p.P(`}`) p.P(`for iNdEx < postIndex {`) p.In() - p.field(file, message, field, fieldname, false) + p.field(file, message, field, fieldname, proto3Resolver) p.Out() p.P(`}`) p.Out() @@ -1444,7 +1446,7 @@ func (p *unmarshal) Generate(file *generator.FileDescriptor) { p.P(`return ` + fmtPkg.Use() + `.Errorf("proto: wrong wireType = %d for field ` + errFieldname + `", wireType)`) p.Out() p.P(`}`) - p.field(file, message, field, fieldname, proto3) + p.field(file, message, field, fieldname, proto3Resolver) } if field.IsRequired() { diff --git a/proto3optional/resolver.go b/proto3optional/resolver.go new file mode 100644 index 0000000000..0763e7ca77 --- /dev/null +++ b/proto3optional/resolver.go @@ -0,0 +1,70 @@ +package proto3optional + +import ( + "fmt" + "strconv" + + "github.com/gogo/protobuf/protoc-gen-gogo/descriptor" +) + +type Resolver struct { + proto3 bool + fakeOneOfs map[string]struct{} + allOneOfs map[string]*int32 +} + +func NewResolver(proto3 bool, fields []*descriptor.FieldDescriptorProto) *Resolver { + if !proto3 { + return &Resolver{ + proto3: false, + } + } + + r := &Resolver{ + proto3: true, + fakeOneOfs: make(map[string]struct{}), + allOneOfs: make(map[string]*int32), + } + + tmp := make(map[int32][]*descriptor.FieldDescriptorProto) + for _, f := range fields { + r.allOneOfs[getMapKey(f)] = f.OneofIndex + + if f.OneofIndex != nil { + tmp[*f.OneofIndex] = append(tmp[*f.OneofIndex], f) + } + } + + for _, v := range tmp { + if len(v) == 1 && v[0].GetProto3Optional() { + r.fakeOneOfs[getMapKey(v[0])] = struct{}{} + } + } + + return r +} + +func (r *Resolver) IsFakeOneOf(f *descriptor.FieldDescriptorProto) bool { + if !r.proto3 { + return false + } + + _, ok := r.fakeOneOfs[getMapKey(f)] + return ok +} + +func (r *Resolver) IsRealOneOf(f *descriptor.FieldDescriptorProto) bool { + return !r.IsFakeOneOf(f) && r.allOneOfs[getMapKey(f)] != nil +} + +func (r *Resolver) IsProto3WithoutOptional(f *descriptor.FieldDescriptorProto) bool { + return r.proto3 && !r.IsFakeOneOf(f) +} + +func getMapKey(f *descriptor.FieldDescriptorProto) string { + if f.GetNumber() == 0 { + panic(fmt.Sprintf("field %s has no number", f.GetName())) + } + + return strconv.Itoa(int(f.GetNumber())) + f.GetType().String() + f.GetName() +} diff --git a/protobuf/google/protobuf/compiler/plugin.proto b/protobuf/google/protobuf/compiler/plugin.proto index 4a88adf148..94a3575f23 100644 --- a/protobuf/google/protobuf/compiler/plugin.proto +++ b/protobuf/google/protobuf/compiler/plugin.proto @@ -107,6 +107,16 @@ message CodeGeneratorResponse { // exiting with a non-zero status code. optional string error = 1; + // A bitmask of supported features that the code generator supports. + // This is a bitwise "or" of values from the Feature enum. + optional uint64 supported_features = 2; + + // Sync with code_generator.h. + enum Feature { + FEATURE_NONE = 0; + FEATURE_PROTO3_OPTIONAL = 1; + } + // Represents a single generated file. message File { // The file name, relative to the output directory. The name must not @@ -163,6 +173,11 @@ message CodeGeneratorResponse { // The file contents. optional string content = 15; + + // Information describing the file content being inserted. If an insertion + // point is used, this information will be appropriately offset and inserted + // into the code generation metadata for the generated files. + optional GeneratedCodeInfo generated_code_info = 16; } repeated File file = 15; } diff --git a/protobuf/google/protobuf/descriptor.proto b/protobuf/google/protobuf/descriptor.proto index 4a08905a56..f97b703d8d 100644 --- a/protobuf/google/protobuf/descriptor.proto +++ b/protobuf/google/protobuf/descriptor.proto @@ -212,6 +212,29 @@ message FieldDescriptorProto { optional string json_name = 10; optional FieldOptions options = 8; + + // If true, this is a proto3 "optional". When a proto3 field is optional, it + // tracks presence regardless of field type. + // + // When proto3_optional is true, this field must be belong to a oneof to + // signal to old proto3 clients that presence is tracked for this field. This + // oneof is known as a "synthetic" oneof, and this field must be its sole + // member (each proto3 optional field gets its own synthetic oneof). Synthetic + // oneofs exist in the descriptor only, and do not generate any API. Synthetic + // oneofs must be ordered after all "real" oneofs. + // + // For message fields, proto3_optional doesn't create any semantic change, + // since non-repeated message fields always track presence. However it still + // indicates the semantic detail of whether the user wrote "optional" or not. + // This can be useful for round-tripping the .proto file. For consistency we + // give message fields a synthetic oneof also, even though it is not required + // to track presence. This is especially important because the parser can't + // tell if a field is a message or an enum, so it must always create a + // synthetic oneof. + // + // Proto2 optional fields do not set this flag, because they already indicate + // optional with `LABEL_OPTIONAL`. + optional bool proto3_optional = 17; } // Describes a oneof. diff --git a/protoc-gen-gogo/descriptor/descriptor.pb.go b/protoc-gen-gogo/descriptor/descriptor.pb.go index 18b2a3318a..26983940b5 100644 --- a/protoc-gen-gogo/descriptor/descriptor.pb.go +++ b/protoc-gen-gogo/descriptor/descriptor.pb.go @@ -817,11 +817,33 @@ type FieldDescriptorProto struct { // user has set a "json_name" option on this field, that option's value // will be used. Otherwise, it's deduced from the field's name by converting // it to camelCase. - JsonName *string `protobuf:"bytes,10,opt,name=json_name,json=jsonName" json:"json_name,omitempty"` - Options *FieldOptions `protobuf:"bytes,8,opt,name=options" json:"options,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + JsonName *string `protobuf:"bytes,10,opt,name=json_name,json=jsonName" json:"json_name,omitempty"` + Options *FieldOptions `protobuf:"bytes,8,opt,name=options" json:"options,omitempty"` + // If true, this is a proto3 "optional". When a proto3 field is optional, it + // tracks presence regardless of field type. + // + // When proto3_optional is true, this field must be belong to a oneof to + // signal to old proto3 clients that presence is tracked for this field. This + // oneof is known as a "synthetic" oneof, and this field must be its sole + // member (each proto3 optional field gets its own synthetic oneof). Synthetic + // oneofs exist in the descriptor only, and do not generate any API. Synthetic + // oneofs must be ordered after all "real" oneofs. + // + // For message fields, proto3_optional doesn't create any semantic change, + // since non-repeated message fields always track presence. However it still + // indicates the semantic detail of whether the user wrote "optional" or not. + // This can be useful for round-tripping the .proto file. For consistency we + // give message fields a synthetic oneof also, even though it is not required + // to track presence. This is especially important because the parser can't + // tell if a field is a message or an enum, so it must always create a + // synthetic oneof. + // + // Proto2 optional fields do not set this flag, because they already indicate + // optional with `LABEL_OPTIONAL`. + Proto3Optional *bool `protobuf:"varint,17,opt,name=proto3_optional,json=proto3Optional" json:"proto3_optional,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *FieldDescriptorProto) Reset() { *m = FieldDescriptorProto{} } @@ -918,6 +940,13 @@ func (m *FieldDescriptorProto) GetOptions() *FieldOptions { return nil } +func (m *FieldDescriptorProto) GetProto3Optional() bool { + if m != nil && m.Proto3Optional != nil { + return *m.Proto3Optional + } + return false +} + // Describes a oneof. type OneofDescriptorProto struct { Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` @@ -1578,10 +1607,12 @@ type MessageOptions struct { // efficient, has fewer features, and is more complicated. // // The message must be defined exactly as follows: - // message Foo { - // option message_set_wire_format = true; - // extensions 4 to max; - // } + // + // message Foo { + // option message_set_wire_format = true; + // extensions 4 to max; + // } + // // Note that the message cannot have any defined fields; MessageSets only // have extensions. // @@ -1604,14 +1635,17 @@ type MessageOptions struct { // maps field. // // For maps fields: - // map map_field = 1; + // + // map map_field = 1; + // // The parsed descriptor looks like: - // message MapFieldEntry { - // option map_entry = true; - // optional KeyType key = 1; - // optional ValueType value = 2; - // } - // repeated MapFieldEntry map_field = 1; + // + // message MapFieldEntry { + // option map_entry = true; + // optional KeyType key = 1; + // optional ValueType value = 2; + // } + // repeated MapFieldEntry map_field = 1; // // Implementations may choose not to generate the map_entry=true message, but // use a native map in the target language to hold the keys and values. @@ -1743,7 +1777,6 @@ type FieldOptions struct { // call from multiple threads concurrently, while non-const methods continue // to require exclusive access. // - // // Note that implementations may choose not to check required fields within // a lazy sub-message. That is, calling IsInitialized() on the outer message // may return true even if the inner message has missing required fields. @@ -2332,43 +2365,48 @@ type SourceCodeInfo struct { // tools. // // For example, say we have a file like: - // message Foo { - // optional string foo = 1; - // } + // + // message Foo { + // optional string foo = 1; + // } + // // Let's look at just the field definition: - // optional string foo = 1; - // ^ ^^ ^^ ^ ^^^ - // a bc de f ghi + // + // optional string foo = 1; + // ^ ^^ ^^ ^ ^^^ + // a bc de f ghi + // // We have the following locations: - // span path represents - // [a,i) [ 4, 0, 2, 0 ] The whole field definition. - // [a,b) [ 4, 0, 2, 0, 4 ] The label (optional). - // [c,d) [ 4, 0, 2, 0, 5 ] The type (string). - // [e,f) [ 4, 0, 2, 0, 1 ] The name (foo). - // [g,h) [ 4, 0, 2, 0, 3 ] The number (1). + // + // span path represents + // [a,i) [ 4, 0, 2, 0 ] The whole field definition. + // [a,b) [ 4, 0, 2, 0, 4 ] The label (optional). + // [c,d) [ 4, 0, 2, 0, 5 ] The type (string). + // [e,f) [ 4, 0, 2, 0, 1 ] The name (foo). + // [g,h) [ 4, 0, 2, 0, 3 ] The number (1). // // Notes: - // - A location may refer to a repeated field itself (i.e. not to any - // particular index within it). This is used whenever a set of elements are - // logically enclosed in a single code segment. For example, an entire - // extend block (possibly containing multiple extension definitions) will - // have an outer location whose path refers to the "extensions" repeated - // field without an index. - // - Multiple locations may have the same path. This happens when a single - // logical declaration is spread out across multiple places. The most - // obvious example is the "extend" block again -- there may be multiple - // extend blocks in the same scope, each of which will have the same path. - // - A location's span is not always a subset of its parent's span. For - // example, the "extendee" of an extension declaration appears at the - // beginning of the "extend" block and is shared by all extensions within - // the block. - // - Just because a location's span is a subset of some other location's span - // does not mean that it is a descendant. For example, a "group" defines - // both a type and a field in a single declaration. Thus, the locations - // corresponding to the type and field and their components will overlap. - // - Code which tries to interpret locations should probably be designed to - // ignore those that it doesn't understand, as more types of locations could - // be recorded in the future. + // - A location may refer to a repeated field itself (i.e. not to any + // particular index within it). This is used whenever a set of elements are + // logically enclosed in a single code segment. For example, an entire + // extend block (possibly containing multiple extension definitions) will + // have an outer location whose path refers to the "extensions" repeated + // field without an index. + // - Multiple locations may have the same path. This happens when a single + // logical declaration is spread out across multiple places. The most + // obvious example is the "extend" block again -- there may be multiple + // extend blocks in the same scope, each of which will have the same path. + // - A location's span is not always a subset of its parent's span. For + // example, the "extendee" of an extension declaration appears at the + // beginning of the "extend" block and is shared by all extensions within + // the block. + // - Just because a location's span is a subset of some other location's span + // does not mean that it is a descendant. For example, a "group" defines + // both a type and a field in a single declaration. Thus, the locations + // corresponding to the type and field and their components will overlap. + // - Code which tries to interpret locations should probably be designed to + // ignore those that it doesn't understand, as more types of locations could + // be recorded in the future. Location []*SourceCodeInfo_Location `protobuf:"bytes,1,rep,name=location" json:"location,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` @@ -2413,21 +2451,32 @@ type SourceCodeInfo_Location struct { // Each element is a field number or an index. They form a path from // the root FileDescriptorProto to the place where the definition. For // example, this path: - // [ 4, 3, 2, 7, 1 ] + // + // [ 4, 3, 2, 7, 1 ] + // // refers to: - // file.message_type(3) // 4, 3 - // .field(7) // 2, 7 - // .name() // 1 + // + // file.message_type(3) // 4, 3 + // .field(7) // 2, 7 + // .name() // 1 + // // This is because FileDescriptorProto.message_type has field number 4: - // repeated DescriptorProto message_type = 4; + // + // repeated DescriptorProto message_type = 4; + // // and DescriptorProto.field has field number 2: - // repeated FieldDescriptorProto field = 2; + // + // repeated FieldDescriptorProto field = 2; + // // and FieldDescriptorProto.name has field number 1: - // optional string name = 1; + // + // optional string name = 1; // // Thus, the above path gives the location of a field name. If we removed // the last element: - // [ 4, 3, 2, 7 ] + // + // [ 4, 3, 2, 7 ] + // // this path refers to the whole field declaration (from the beginning // of the label to the terminating semicolon). Path []int32 `protobuf:"varint,1,rep,packed,name=path" json:"path,omitempty"` @@ -2456,34 +2505,34 @@ type SourceCodeInfo_Location struct { // // Examples: // - // optional int32 foo = 1; // Comment attached to foo. - // // Comment attached to bar. - // optional int32 bar = 2; + // optional int32 foo = 1; // Comment attached to foo. + // // Comment attached to bar. + // optional int32 bar = 2; // - // optional string baz = 3; - // // Comment attached to baz. - // // Another line attached to baz. + // optional string baz = 3; + // // Comment attached to baz. + // // Another line attached to baz. // - // // Comment attached to qux. - // // - // // Another line attached to qux. - // optional double qux = 4; + // // Comment attached to qux. + // // + // // Another line attached to qux. + // optional double qux = 4; // - // // Detached comment for corge. This is not leading or trailing comments - // // to qux or corge because there are blank lines separating it from - // // both. + // // Detached comment for corge. This is not leading or trailing comments + // // to qux or corge because there are blank lines separating it from + // // both. // - // // Detached comment for corge paragraph 2. + // // Detached comment for corge paragraph 2. // - // optional string corge = 5; - // /* Block comment attached - // * to corge. Leading asterisks - // * will be removed. */ - // /* Block comment attached to - // * grault. */ - // optional int32 grault = 6; + // optional string corge = 5; + // /* Block comment attached + // * to corge. Leading asterisks + // * will be removed. */ + // /* Block comment attached to + // * grault. */ + // optional int32 grault = 6; // - // // ignored detached comments. + // // ignored detached comments. LeadingComments *string `protobuf:"bytes,3,opt,name=leading_comments,json=leadingComments" json:"leading_comments,omitempty"` TrailingComments *string `protobuf:"bytes,4,opt,name=trailing_comments,json=trailingComments" json:"trailing_comments,omitempty"` LeadingDetachedComments []string `protobuf:"bytes,6,rep,name=leading_detached_comments,json=leadingDetachedComments" json:"leading_detached_comments,omitempty"` @@ -2703,163 +2752,164 @@ func init() { func init() { proto.RegisterFile("descriptor.proto", fileDescriptor_308767df5ffe18af) } var fileDescriptor_308767df5ffe18af = []byte{ - // 2522 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x59, 0xcd, 0x6f, 0xdb, 0xc8, - 0x15, 0x5f, 0x7d, 0x5a, 0x7a, 0x92, 0x65, 0x7a, 0xec, 0x75, 0x18, 0xef, 0x47, 0x1c, 0xed, 0x66, - 0xe3, 0x24, 0xbb, 0xca, 0xc2, 0x49, 0x9c, 0xac, 0x53, 0x6c, 0x2b, 0x4b, 0x8c, 0x57, 0xa9, 0xbe, - 0x4a, 0xc9, 0xdd, 0x64, 0x8b, 0x82, 0x18, 0x93, 0x23, 0x89, 0x09, 0x45, 0x72, 0x49, 0x2a, 0x89, - 0x83, 0x1e, 0x02, 0xf4, 0x54, 0xa0, 0x7f, 0x40, 0x51, 0x14, 0x3d, 0xf4, 0xb2, 0x40, 0xff, 0x80, - 0x02, 0xed, 0xbd, 0xd7, 0x02, 0xbd, 0xf7, 0x50, 0xa0, 0x05, 0xda, 0x3f, 0xa1, 0xc7, 0x62, 0x66, - 0x48, 0x8a, 0xd4, 0x47, 0xe2, 0x5d, 0x20, 0xd9, 0x93, 0x3d, 0xef, 0xfd, 0xde, 0x9b, 0x37, 0x8f, - 0xbf, 0x79, 0xf3, 0x66, 0x04, 0x82, 0x46, 0x5c, 0xd5, 0xd1, 0x6d, 0xcf, 0x72, 0x2a, 0xb6, 0x63, - 0x79, 0x16, 0x5a, 0x1b, 0x5a, 0xd6, 0xd0, 0x20, 0x7c, 0x74, 0x32, 0x19, 0x94, 0x5b, 0xb0, 0x7e, - 0x4f, 0x37, 0x48, 0x3d, 0x04, 0xf6, 0x88, 0x87, 0xee, 0x40, 0x7a, 0xa0, 0x1b, 0x44, 0x4c, 0xec, - 0xa4, 0x76, 0x0b, 0x7b, 0x1f, 0x56, 0x66, 0x8c, 0x2a, 0x71, 0x8b, 0x2e, 0x15, 0xcb, 0xcc, 0xa2, - 0xfc, 0xef, 0x34, 0x6c, 0x2c, 0xd0, 0x22, 0x04, 0x69, 0x13, 0x8f, 0xa9, 0xc7, 0xc4, 0x6e, 0x5e, - 0x66, 0xff, 0x23, 0x11, 0x56, 0x6c, 0xac, 0x3e, 0xc6, 0x43, 0x22, 0x26, 0x99, 0x38, 0x18, 0xa2, - 0xf7, 0x01, 0x34, 0x62, 0x13, 0x53, 0x23, 0xa6, 0x7a, 0x2a, 0xa6, 0x76, 0x52, 0xbb, 0x79, 0x39, - 0x22, 0x41, 0xd7, 0x60, 0xdd, 0x9e, 0x9c, 0x18, 0xba, 0xaa, 0x44, 0x60, 0xb0, 0x93, 0xda, 0xcd, - 0xc8, 0x02, 0x57, 0xd4, 0xa7, 0xe0, 0xcb, 0xb0, 0xf6, 0x94, 0xe0, 0xc7, 0x51, 0x68, 0x81, 0x41, - 0x4b, 0x54, 0x1c, 0x01, 0xd6, 0xa0, 0x38, 0x26, 0xae, 0x8b, 0x87, 0x44, 0xf1, 0x4e, 0x6d, 0x22, - 0xa6, 0xd9, 0xea, 0x77, 0xe6, 0x56, 0x3f, 0xbb, 0xf2, 0x82, 0x6f, 0xd5, 0x3f, 0xb5, 0x09, 0xaa, - 0x42, 0x9e, 0x98, 0x93, 0x31, 0xf7, 0x90, 0x59, 0x92, 0x3f, 0xc9, 0x9c, 0x8c, 0x67, 0xbd, 0xe4, - 0xa8, 0x99, 0xef, 0x62, 0xc5, 0x25, 0xce, 0x13, 0x5d, 0x25, 0x62, 0x96, 0x39, 0xb8, 0x3c, 0xe7, - 0xa0, 0xc7, 0xf5, 0xb3, 0x3e, 0x02, 0x3b, 0x54, 0x83, 0x3c, 0x79, 0xe6, 0x11, 0xd3, 0xd5, 0x2d, - 0x53, 0x5c, 0x61, 0x4e, 0x2e, 0x2d, 0xf8, 0x8a, 0xc4, 0xd0, 0x66, 0x5d, 0x4c, 0xed, 0xd0, 0x3e, - 0xac, 0x58, 0xb6, 0xa7, 0x5b, 0xa6, 0x2b, 0xe6, 0x76, 0x12, 0xbb, 0x85, 0xbd, 0x77, 0x17, 0x12, - 0xa1, 0xc3, 0x31, 0x72, 0x00, 0x46, 0x0d, 0x10, 0x5c, 0x6b, 0xe2, 0xa8, 0x44, 0x51, 0x2d, 0x8d, - 0x28, 0xba, 0x39, 0xb0, 0xc4, 0x3c, 0x73, 0x70, 0x61, 0x7e, 0x21, 0x0c, 0x58, 0xb3, 0x34, 0xd2, - 0x30, 0x07, 0x96, 0x5c, 0x72, 0x63, 0x63, 0xb4, 0x05, 0x59, 0xf7, 0xd4, 0xf4, 0xf0, 0x33, 0xb1, - 0xc8, 0x18, 0xe2, 0x8f, 0xca, 0x7f, 0xce, 0xc2, 0xda, 0x59, 0x28, 0x76, 0x17, 0x32, 0x03, 0xba, - 0x4a, 0x31, 0xf9, 0x6d, 0x72, 0xc0, 0x6d, 0xe2, 0x49, 0xcc, 0x7e, 0xc7, 0x24, 0x56, 0xa1, 0x60, - 0x12, 0xd7, 0x23, 0x1a, 0x67, 0x44, 0xea, 0x8c, 0x9c, 0x02, 0x6e, 0x34, 0x4f, 0xa9, 0xf4, 0x77, - 0xa2, 0xd4, 0x03, 0x58, 0x0b, 0x43, 0x52, 0x1c, 0x6c, 0x0e, 0x03, 0x6e, 0x5e, 0x7f, 0x55, 0x24, - 0x15, 0x29, 0xb0, 0x93, 0xa9, 0x99, 0x5c, 0x22, 0xb1, 0x31, 0xaa, 0x03, 0x58, 0x26, 0xb1, 0x06, - 0x8a, 0x46, 0x54, 0x43, 0xcc, 0x2d, 0xc9, 0x52, 0x87, 0x42, 0xe6, 0xb2, 0x64, 0x71, 0xa9, 0x6a, - 0xa0, 0xcf, 0xa6, 0x54, 0x5b, 0x59, 0xc2, 0x94, 0x16, 0xdf, 0x64, 0x73, 0x6c, 0x3b, 0x86, 0x92, - 0x43, 0x28, 0xef, 0x89, 0xe6, 0xaf, 0x2c, 0xcf, 0x82, 0xa8, 0xbc, 0x72, 0x65, 0xb2, 0x6f, 0xc6, - 0x17, 0xb6, 0xea, 0x44, 0x87, 0xe8, 0x03, 0x08, 0x05, 0x0a, 0xa3, 0x15, 0xb0, 0x2a, 0x54, 0x0c, - 0x84, 0x6d, 0x3c, 0x26, 0xdb, 0xcf, 0xa1, 0x14, 0x4f, 0x0f, 0xda, 0x84, 0x8c, 0xeb, 0x61, 0xc7, - 0x63, 0x2c, 0xcc, 0xc8, 0x7c, 0x80, 0x04, 0x48, 0x11, 0x53, 0x63, 0x55, 0x2e, 0x23, 0xd3, 0x7f, - 0xd1, 0x8f, 0xa6, 0x0b, 0x4e, 0xb1, 0x05, 0x7f, 0x34, 0xff, 0x45, 0x63, 0x9e, 0x67, 0xd7, 0xbd, - 0x7d, 0x1b, 0x56, 0x63, 0x0b, 0x38, 0xeb, 0xd4, 0xe5, 0x5f, 0xc0, 0xdb, 0x0b, 0x5d, 0xa3, 0x07, - 0xb0, 0x39, 0x31, 0x75, 0xd3, 0x23, 0x8e, 0xed, 0x10, 0xca, 0x58, 0x3e, 0x95, 0xf8, 0x9f, 0x95, - 0x25, 0x9c, 0x3b, 0x8e, 0xa2, 0xb9, 0x17, 0x79, 0x63, 0x32, 0x2f, 0xbc, 0x9a, 0xcf, 0xfd, 0x77, - 0x45, 0x78, 0xf1, 0xe2, 0xc5, 0x8b, 0x64, 0xf9, 0x37, 0x59, 0xd8, 0x5c, 0xb4, 0x67, 0x16, 0x6e, - 0xdf, 0x2d, 0xc8, 0x9a, 0x93, 0xf1, 0x09, 0x71, 0x58, 0x92, 0x32, 0xb2, 0x3f, 0x42, 0x55, 0xc8, - 0x18, 0xf8, 0x84, 0x18, 0x62, 0x7a, 0x27, 0xb1, 0x5b, 0xda, 0xbb, 0x76, 0xa6, 0x5d, 0x59, 0x69, - 0x52, 0x13, 0x99, 0x5b, 0xa2, 0xcf, 0x21, 0xed, 0x97, 0x68, 0xea, 0xe1, 0xea, 0xd9, 0x3c, 0xd0, - 0xbd, 0x24, 0x33, 0x3b, 0xf4, 0x0e, 0xe4, 0xe9, 0x5f, 0xce, 0x8d, 0x2c, 0x8b, 0x39, 0x47, 0x05, - 0x94, 0x17, 0x68, 0x1b, 0x72, 0x6c, 0x9b, 0x68, 0x24, 0x38, 0xda, 0xc2, 0x31, 0x25, 0x96, 0x46, - 0x06, 0x78, 0x62, 0x78, 0xca, 0x13, 0x6c, 0x4c, 0x08, 0x23, 0x7c, 0x5e, 0x2e, 0xfa, 0xc2, 0x9f, - 0x52, 0x19, 0xba, 0x00, 0x05, 0xbe, 0xab, 0x74, 0x53, 0x23, 0xcf, 0x58, 0xf5, 0xcc, 0xc8, 0x7c, - 0xa3, 0x35, 0xa8, 0x84, 0x4e, 0xff, 0xc8, 0xb5, 0xcc, 0x80, 0x9a, 0x6c, 0x0a, 0x2a, 0x60, 0xd3, - 0xdf, 0x9e, 0x2d, 0xdc, 0xef, 0x2d, 0x5e, 0xde, 0x2c, 0xa7, 0xca, 0x7f, 0x4a, 0x42, 0x9a, 0xd5, - 0x8b, 0x35, 0x28, 0xf4, 0x1f, 0x76, 0x25, 0xa5, 0xde, 0x39, 0x3e, 0x6c, 0x4a, 0x42, 0x02, 0x95, - 0x00, 0x98, 0xe0, 0x5e, 0xb3, 0x53, 0xed, 0x0b, 0xc9, 0x70, 0xdc, 0x68, 0xf7, 0xf7, 0x6f, 0x0a, - 0xa9, 0xd0, 0xe0, 0x98, 0x0b, 0xd2, 0x51, 0xc0, 0x8d, 0x3d, 0x21, 0x83, 0x04, 0x28, 0x72, 0x07, - 0x8d, 0x07, 0x52, 0x7d, 0xff, 0xa6, 0x90, 0x8d, 0x4b, 0x6e, 0xec, 0x09, 0x2b, 0x68, 0x15, 0xf2, - 0x4c, 0x72, 0xd8, 0xe9, 0x34, 0x85, 0x5c, 0xe8, 0xb3, 0xd7, 0x97, 0x1b, 0xed, 0x23, 0x21, 0x1f, - 0xfa, 0x3c, 0x92, 0x3b, 0xc7, 0x5d, 0x01, 0x42, 0x0f, 0x2d, 0xa9, 0xd7, 0xab, 0x1e, 0x49, 0x42, - 0x21, 0x44, 0x1c, 0x3e, 0xec, 0x4b, 0x3d, 0xa1, 0x18, 0x0b, 0xeb, 0xc6, 0x9e, 0xb0, 0x1a, 0x4e, - 0x21, 0xb5, 0x8f, 0x5b, 0x42, 0x09, 0xad, 0xc3, 0x2a, 0x9f, 0x22, 0x08, 0x62, 0x6d, 0x46, 0xb4, - 0x7f, 0x53, 0x10, 0xa6, 0x81, 0x70, 0x2f, 0xeb, 0x31, 0xc1, 0xfe, 0x4d, 0x01, 0x95, 0x6b, 0x90, - 0x61, 0xec, 0x42, 0x08, 0x4a, 0xcd, 0xea, 0xa1, 0xd4, 0x54, 0x3a, 0xdd, 0x7e, 0xa3, 0xd3, 0xae, - 0x36, 0x85, 0xc4, 0x54, 0x26, 0x4b, 0x3f, 0x39, 0x6e, 0xc8, 0x52, 0x5d, 0x48, 0x46, 0x65, 0x5d, - 0xa9, 0xda, 0x97, 0xea, 0x42, 0xaa, 0xac, 0xc2, 0xe6, 0xa2, 0x3a, 0xb9, 0x70, 0x67, 0x44, 0x3e, - 0x71, 0x72, 0xc9, 0x27, 0x66, 0xbe, 0xe6, 0x3e, 0xf1, 0xbf, 0x92, 0xb0, 0xb1, 0xe0, 0xac, 0x58, - 0x38, 0xc9, 0x0f, 0x21, 0xc3, 0x29, 0xca, 0x4f, 0xcf, 0x2b, 0x0b, 0x0f, 0x1d, 0x46, 0xd8, 0xb9, - 0x13, 0x94, 0xd9, 0x45, 0x3b, 0x88, 0xd4, 0x92, 0x0e, 0x82, 0xba, 0x98, 0xab, 0xe9, 0x3f, 0x9f, - 0xab, 0xe9, 0xfc, 0xd8, 0xdb, 0x3f, 0xcb, 0xb1, 0xc7, 0x64, 0xdf, 0xae, 0xb6, 0x67, 0x16, 0xd4, - 0xf6, 0xbb, 0xb0, 0x3e, 0xe7, 0xe8, 0xcc, 0x35, 0xf6, 0x97, 0x09, 0x10, 0x97, 0x25, 0xe7, 0x15, - 0x95, 0x2e, 0x19, 0xab, 0x74, 0x77, 0x67, 0x33, 0x78, 0x71, 0xf9, 0x47, 0x98, 0xfb, 0xd6, 0xdf, - 0x24, 0x60, 0x6b, 0x71, 0xa7, 0xb8, 0x30, 0x86, 0xcf, 0x21, 0x3b, 0x26, 0xde, 0xc8, 0x0a, 0xba, - 0xa5, 0x8f, 0x16, 0x9c, 0xc1, 0x54, 0x3d, 0xfb, 0xb1, 0x7d, 0xab, 0xe8, 0x21, 0x9e, 0x5a, 0xd6, - 0xee, 0xf1, 0x68, 0xe6, 0x22, 0xfd, 0x55, 0x12, 0xde, 0x5e, 0xe8, 0x7c, 0x61, 0xa0, 0xef, 0x01, - 0xe8, 0xa6, 0x3d, 0xf1, 0x78, 0x47, 0xc4, 0x0b, 0x6c, 0x9e, 0x49, 0x58, 0xf1, 0xa2, 0xc5, 0x73, - 0xe2, 0x85, 0xfa, 0x14, 0xd3, 0x03, 0x17, 0x31, 0xc0, 0x9d, 0x69, 0xa0, 0x69, 0x16, 0xe8, 0xfb, - 0x4b, 0x56, 0x3a, 0x47, 0xcc, 0x4f, 0x41, 0x50, 0x0d, 0x9d, 0x98, 0x9e, 0xe2, 0x7a, 0x0e, 0xc1, - 0x63, 0xdd, 0x1c, 0xb2, 0x13, 0x24, 0x77, 0x90, 0x19, 0x60, 0xc3, 0x25, 0xf2, 0x1a, 0x57, 0xf7, - 0x02, 0x2d, 0xb5, 0x60, 0x04, 0x72, 0x22, 0x16, 0xd9, 0x98, 0x05, 0x57, 0x87, 0x16, 0xe5, 0x5f, - 0xe7, 0xa1, 0x10, 0xe9, 0xab, 0xd1, 0x45, 0x28, 0x3e, 0xc2, 0x4f, 0xb0, 0x12, 0xdc, 0x95, 0x78, - 0x26, 0x0a, 0x54, 0xd6, 0xf5, 0xef, 0x4b, 0x9f, 0xc2, 0x26, 0x83, 0x58, 0x13, 0x8f, 0x38, 0x8a, - 0x6a, 0x60, 0xd7, 0x65, 0x49, 0xcb, 0x31, 0x28, 0xa2, 0xba, 0x0e, 0x55, 0xd5, 0x02, 0x0d, 0xba, - 0x05, 0x1b, 0xcc, 0x62, 0x3c, 0x31, 0x3c, 0xdd, 0x36, 0x88, 0x42, 0x6f, 0x6f, 0x2e, 0x3b, 0x49, - 0xc2, 0xc8, 0xd6, 0x29, 0xa2, 0xe5, 0x03, 0x68, 0x44, 0x2e, 0xaa, 0xc3, 0x7b, 0xcc, 0x6c, 0x48, - 0x4c, 0xe2, 0x60, 0x8f, 0x28, 0xe4, 0xeb, 0x09, 0x36, 0x5c, 0x05, 0x9b, 0x9a, 0x32, 0xc2, 0xee, - 0x48, 0xdc, 0xa4, 0x0e, 0x0e, 0x93, 0x62, 0x42, 0x3e, 0x4f, 0x81, 0x47, 0x3e, 0x4e, 0x62, 0xb0, - 0xaa, 0xa9, 0x7d, 0x81, 0xdd, 0x11, 0x3a, 0x80, 0x2d, 0xe6, 0xc5, 0xf5, 0x1c, 0xdd, 0x1c, 0x2a, - 0xea, 0x88, 0xa8, 0x8f, 0x95, 0x89, 0x37, 0xb8, 0x23, 0xbe, 0x13, 0x9d, 0x9f, 0x45, 0xd8, 0x63, - 0x98, 0x1a, 0x85, 0x1c, 0x7b, 0x83, 0x3b, 0xa8, 0x07, 0x45, 0xfa, 0x31, 0xc6, 0xfa, 0x73, 0xa2, - 0x0c, 0x2c, 0x87, 0x1d, 0x8d, 0xa5, 0x05, 0xa5, 0x29, 0x92, 0xc1, 0x4a, 0xc7, 0x37, 0x68, 0x59, - 0x1a, 0x39, 0xc8, 0xf4, 0xba, 0x92, 0x54, 0x97, 0x0b, 0x81, 0x97, 0x7b, 0x96, 0x43, 0x09, 0x35, - 0xb4, 0xc2, 0x04, 0x17, 0x38, 0xa1, 0x86, 0x56, 0x90, 0xde, 0x5b, 0xb0, 0xa1, 0xaa, 0x7c, 0xcd, - 0xba, 0xaa, 0xf8, 0x77, 0x2c, 0x57, 0x14, 0x62, 0xc9, 0x52, 0xd5, 0x23, 0x0e, 0xf0, 0x39, 0xee, - 0xa2, 0xcf, 0xe0, 0xed, 0x69, 0xb2, 0xa2, 0x86, 0xeb, 0x73, 0xab, 0x9c, 0x35, 0xbd, 0x05, 0x1b, - 0xf6, 0xe9, 0xbc, 0x21, 0x8a, 0xcd, 0x68, 0x9f, 0xce, 0x9a, 0xdd, 0x86, 0x4d, 0x7b, 0x64, 0xcf, - 0xdb, 0x5d, 0x8d, 0xda, 0x21, 0x7b, 0x64, 0xcf, 0x1a, 0x5e, 0x62, 0x17, 0x6e, 0x87, 0xa8, 0xd8, - 0x23, 0x9a, 0x78, 0x2e, 0x0a, 0x8f, 0x28, 0xd0, 0x75, 0x10, 0x54, 0x55, 0x21, 0x26, 0x3e, 0x31, - 0x88, 0x82, 0x1d, 0x62, 0x62, 0x57, 0xbc, 0x10, 0x05, 0x97, 0x54, 0x55, 0x62, 0xda, 0x2a, 0x53, - 0xa2, 0xab, 0xb0, 0x6e, 0x9d, 0x3c, 0x52, 0x39, 0x25, 0x15, 0xdb, 0x21, 0x03, 0xfd, 0x99, 0xf8, - 0x21, 0xcb, 0xef, 0x1a, 0x55, 0x30, 0x42, 0x76, 0x99, 0x18, 0x5d, 0x01, 0x41, 0x75, 0x47, 0xd8, - 0xb1, 0x59, 0x4d, 0x76, 0x6d, 0xac, 0x12, 0xf1, 0x12, 0x87, 0x72, 0x79, 0x3b, 0x10, 0xd3, 0x2d, - 0xe1, 0x3e, 0xd5, 0x07, 0x5e, 0xe0, 0xf1, 0x32, 0xdf, 0x12, 0x4c, 0xe6, 0x7b, 0xdb, 0x05, 0x81, - 0xa6, 0x22, 0x36, 0xf1, 0x2e, 0x83, 0x95, 0xec, 0x91, 0x1d, 0x9d, 0xf7, 0x03, 0x58, 0xa5, 0xc8, - 0xe9, 0xa4, 0x57, 0x78, 0x43, 0x66, 0x8f, 0x22, 0x33, 0xde, 0x84, 0x2d, 0x0a, 0x1a, 0x13, 0x0f, - 0x6b, 0xd8, 0xc3, 0x11, 0xf4, 0xc7, 0x0c, 0x4d, 0xf3, 0xde, 0xf2, 0x95, 0xb1, 0x38, 0x9d, 0xc9, - 0xc9, 0x69, 0xc8, 0xac, 0x4f, 0x78, 0x9c, 0x54, 0x16, 0x70, 0xeb, 0xb5, 0x35, 0xdd, 0xe5, 0x03, - 0x28, 0x46, 0x89, 0x8f, 0xf2, 0xc0, 0xa9, 0x2f, 0x24, 0x68, 0x17, 0x54, 0xeb, 0xd4, 0x69, 0xff, - 0xf2, 0x95, 0x24, 0x24, 0x69, 0x1f, 0xd5, 0x6c, 0xf4, 0x25, 0x45, 0x3e, 0x6e, 0xf7, 0x1b, 0x2d, - 0x49, 0x48, 0x45, 0x1b, 0xf6, 0xbf, 0x26, 0xa1, 0x14, 0xbf, 0x7b, 0xa1, 0x1f, 0xc0, 0xb9, 0xe0, - 0xa1, 0xc4, 0x25, 0x9e, 0xf2, 0x54, 0x77, 0xd8, 0x5e, 0x1c, 0x63, 0x7e, 0x2e, 0x86, 0x6c, 0xd8, - 0xf4, 0x51, 0x3d, 0xe2, 0x7d, 0xa9, 0x3b, 0x74, 0xa7, 0x8d, 0xb1, 0x87, 0x9a, 0x70, 0xc1, 0xb4, - 0x14, 0xd7, 0xc3, 0xa6, 0x86, 0x1d, 0x4d, 0x99, 0x3e, 0x51, 0x29, 0x58, 0x55, 0x89, 0xeb, 0x5a, - 0xfc, 0x0c, 0x0c, 0xbd, 0xbc, 0x6b, 0x5a, 0x3d, 0x1f, 0x3c, 0x3d, 0x1c, 0xaa, 0x3e, 0x74, 0x86, - 0xb9, 0xa9, 0x65, 0xcc, 0x7d, 0x07, 0xf2, 0x63, 0x6c, 0x2b, 0xc4, 0xf4, 0x9c, 0x53, 0xd6, 0x71, - 0xe7, 0xe4, 0xdc, 0x18, 0xdb, 0x12, 0x1d, 0xbf, 0x99, 0x8b, 0xcf, 0x3f, 0x52, 0x50, 0x8c, 0x76, - 0xdd, 0xf4, 0x12, 0xa3, 0xb2, 0x03, 0x2a, 0xc1, 0x4a, 0xd8, 0x07, 0x2f, 0xed, 0xd1, 0x2b, 0x35, - 0x7a, 0x72, 0x1d, 0x64, 0x79, 0x2f, 0x2c, 0x73, 0x4b, 0xda, 0x35, 0x50, 0x6a, 0x11, 0xde, 0x7b, - 0xe4, 0x64, 0x7f, 0x84, 0x8e, 0x20, 0xfb, 0xc8, 0x65, 0xbe, 0xb3, 0xcc, 0xf7, 0x87, 0x2f, 0xf7, - 0x7d, 0xbf, 0xc7, 0x9c, 0xe7, 0xef, 0xf7, 0x94, 0x76, 0x47, 0x6e, 0x55, 0x9b, 0xb2, 0x6f, 0x8e, - 0xce, 0x43, 0xda, 0xc0, 0xcf, 0x4f, 0xe3, 0x67, 0x1c, 0x13, 0x9d, 0x35, 0xf1, 0xe7, 0x21, 0xfd, - 0x94, 0xe0, 0xc7, 0xf1, 0x93, 0x85, 0x89, 0x5e, 0x23, 0xf5, 0xaf, 0x43, 0x86, 0xe5, 0x0b, 0x01, - 0xf8, 0x19, 0x13, 0xde, 0x42, 0x39, 0x48, 0xd7, 0x3a, 0x32, 0xa5, 0xbf, 0x00, 0x45, 0x2e, 0x55, - 0xba, 0x0d, 0xa9, 0x26, 0x09, 0xc9, 0xf2, 0x2d, 0xc8, 0xf2, 0x24, 0xd0, 0xad, 0x11, 0xa6, 0x41, - 0x78, 0xcb, 0x1f, 0xfa, 0x3e, 0x12, 0x81, 0xf6, 0xb8, 0x75, 0x28, 0xc9, 0x42, 0x32, 0xfa, 0x79, - 0x5d, 0x28, 0x46, 0x1b, 0xee, 0x37, 0xc3, 0xa9, 0xbf, 0x24, 0xa0, 0x10, 0x69, 0xa0, 0x69, 0xe7, - 0x83, 0x0d, 0xc3, 0x7a, 0xaa, 0x60, 0x43, 0xc7, 0xae, 0x4f, 0x0a, 0x60, 0xa2, 0x2a, 0x95, 0x9c, - 0xf5, 0xa3, 0xbd, 0x91, 0xe0, 0x7f, 0x9f, 0x00, 0x61, 0xb6, 0x77, 0x9d, 0x09, 0x30, 0xf1, 0xbd, - 0x06, 0xf8, 0xbb, 0x04, 0x94, 0xe2, 0x0d, 0xeb, 0x4c, 0x78, 0x17, 0xbf, 0xd7, 0xf0, 0xfe, 0x99, - 0x84, 0xd5, 0x58, 0x9b, 0x7a, 0xd6, 0xe8, 0xbe, 0x86, 0x75, 0x5d, 0x23, 0x63, 0xdb, 0xf2, 0x88, - 0xa9, 0x9e, 0x2a, 0x06, 0x79, 0x42, 0x0c, 0xb1, 0xcc, 0x0a, 0xc5, 0xf5, 0x97, 0x37, 0xc2, 0x95, - 0xc6, 0xd4, 0xae, 0x49, 0xcd, 0x0e, 0x36, 0x1a, 0x75, 0xa9, 0xd5, 0xed, 0xf4, 0xa5, 0x76, 0xed, - 0xa1, 0x72, 0xdc, 0xfe, 0x71, 0xbb, 0xf3, 0x65, 0x5b, 0x16, 0xf4, 0x19, 0xd8, 0x6b, 0xdc, 0xea, - 0x5d, 0x10, 0x66, 0x83, 0x42, 0xe7, 0x60, 0x51, 0x58, 0xc2, 0x5b, 0x68, 0x03, 0xd6, 0xda, 0x1d, - 0xa5, 0xd7, 0xa8, 0x4b, 0x8a, 0x74, 0xef, 0x9e, 0x54, 0xeb, 0xf7, 0xf8, 0xd3, 0x46, 0x88, 0xee, - 0xc7, 0x37, 0xf5, 0x6f, 0x53, 0xb0, 0xb1, 0x20, 0x12, 0x54, 0xf5, 0x2f, 0x25, 0xfc, 0x9e, 0xf4, - 0xc9, 0x59, 0xa2, 0xaf, 0xd0, 0xae, 0xa0, 0x8b, 0x1d, 0xcf, 0xbf, 0xc3, 0x5c, 0x01, 0x9a, 0x25, - 0xd3, 0xd3, 0x07, 0x3a, 0x71, 0xfc, 0x97, 0x20, 0x7e, 0x53, 0x59, 0x9b, 0xca, 0xf9, 0x63, 0xd0, - 0xc7, 0x80, 0x6c, 0xcb, 0xd5, 0x3d, 0xfd, 0x09, 0x51, 0x74, 0x33, 0x78, 0x36, 0xa2, 0x37, 0x97, - 0xb4, 0x2c, 0x04, 0x9a, 0x86, 0xe9, 0x85, 0x68, 0x93, 0x0c, 0xf1, 0x0c, 0x9a, 0x16, 0xf0, 0x94, - 0x2c, 0x04, 0x9a, 0x10, 0x7d, 0x11, 0x8a, 0x9a, 0x35, 0xa1, 0xed, 0x1c, 0xc7, 0xd1, 0xf3, 0x22, - 0x21, 0x17, 0xb8, 0x2c, 0x84, 0xf8, 0x8d, 0xfa, 0xf4, 0xbd, 0xaa, 0x28, 0x17, 0xb8, 0x8c, 0x43, - 0x2e, 0xc3, 0x1a, 0x1e, 0x0e, 0x1d, 0xea, 0x3c, 0x70, 0xc4, 0xaf, 0x1e, 0xa5, 0x50, 0xcc, 0x80, - 0xdb, 0xf7, 0x21, 0x17, 0xe4, 0x81, 0x1e, 0xc9, 0x34, 0x13, 0x8a, 0xcd, 0xef, 0xd3, 0xc9, 0xdd, - 0xbc, 0x9c, 0x33, 0x03, 0xe5, 0x45, 0x28, 0xea, 0xae, 0x32, 0x7d, 0x7e, 0x4f, 0xee, 0x24, 0x77, - 0x73, 0x72, 0x41, 0x77, 0xc3, 0xa7, 0xcb, 0xf2, 0x37, 0x49, 0x28, 0xc5, 0x7f, 0x3e, 0x40, 0x75, - 0xc8, 0x19, 0x96, 0x8a, 0x19, 0xb5, 0xf8, 0x6f, 0x57, 0xbb, 0xaf, 0xf8, 0xc5, 0xa1, 0xd2, 0xf4, - 0xf1, 0x72, 0x68, 0xb9, 0xfd, 0xb7, 0x04, 0xe4, 0x02, 0x31, 0xda, 0x82, 0xb4, 0x8d, 0xbd, 0x11, - 0x73, 0x97, 0x39, 0x4c, 0x0a, 0x09, 0x99, 0x8d, 0xa9, 0xdc, 0xb5, 0xb1, 0xc9, 0x28, 0xe0, 0xcb, - 0xe9, 0x98, 0x7e, 0x57, 0x83, 0x60, 0x8d, 0xdd, 0x6b, 0xac, 0xf1, 0x98, 0x98, 0x9e, 0x1b, 0x7c, - 0x57, 0x5f, 0x5e, 0xf3, 0xc5, 0xe8, 0x1a, 0xac, 0x7b, 0x0e, 0xd6, 0x8d, 0x18, 0x36, 0xcd, 0xb0, - 0x42, 0xa0, 0x08, 0xc1, 0x07, 0x70, 0x3e, 0xf0, 0xab, 0x11, 0x0f, 0xab, 0x23, 0xa2, 0x4d, 0x8d, - 0xb2, 0xec, 0xfd, 0xe2, 0x9c, 0x0f, 0xa8, 0xfb, 0xfa, 0xc0, 0xb6, 0xfc, 0xf7, 0x04, 0xac, 0x07, - 0x37, 0x31, 0x2d, 0x4c, 0x56, 0x0b, 0x00, 0x9b, 0xa6, 0xe5, 0x45, 0xd3, 0x35, 0x4f, 0xe5, 0x39, - 0xbb, 0x4a, 0x35, 0x34, 0x92, 0x23, 0x0e, 0xb6, 0xc7, 0x00, 0x53, 0xcd, 0xd2, 0xb4, 0x5d, 0x80, - 0x82, 0xff, 0xdb, 0x10, 0xfb, 0x81, 0x91, 0xdf, 0xdd, 0x81, 0x8b, 0xe8, 0x95, 0x0d, 0x6d, 0x42, - 0xe6, 0x84, 0x0c, 0x75, 0xd3, 0x7f, 0xf1, 0xe5, 0x83, 0xe0, 0x85, 0x25, 0x1d, 0xbe, 0xb0, 0x1c, - 0xfe, 0x0c, 0x36, 0x54, 0x6b, 0x3c, 0x1b, 0xee, 0xa1, 0x30, 0xf3, 0x7e, 0xe0, 0x7e, 0x91, 0xf8, - 0x0a, 0xa6, 0x2d, 0xe6, 0xff, 0x12, 0x89, 0x3f, 0x24, 0x53, 0x47, 0xdd, 0xc3, 0x3f, 0x26, 0xb7, - 0x8f, 0xb8, 0x69, 0x37, 0x58, 0xa9, 0x4c, 0x06, 0x06, 0x51, 0x69, 0xf4, 0xff, 0x0f, 0x00, 0x00, - 0xff, 0xff, 0x88, 0x17, 0xc1, 0xbe, 0x38, 0x1d, 0x00, 0x00, + // 2542 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x59, 0x5b, 0x8f, 0xdb, 0xc6, + 0x15, 0x0e, 0x75, 0x5b, 0xe9, 0x48, 0xab, 0xa5, 0x66, 0x37, 0x36, 0xbd, 0xb9, 0x78, 0xad, 0x5c, + 0x2c, 0x3b, 0x89, 0x1c, 0xf8, 0x16, 0x67, 0x53, 0xa4, 0xd5, 0x4a, 0xf4, 0x46, 0xa9, 0x6e, 0xa5, + 0xb4, 0xcd, 0xa5, 0x28, 0x88, 0x59, 0x72, 0x24, 0xd1, 0xa6, 0x48, 0x86, 0xa4, 0x6c, 0x6f, 0xd0, + 0x07, 0x03, 0x7d, 0x2a, 0xd0, 0x5f, 0x50, 0x14, 0x7d, 0xe8, 0x4b, 0x80, 0xfe, 0x80, 0x02, 0xed, + 0x5b, 0x1f, 0xfa, 0x5a, 0xa0, 0xef, 0x7d, 0x28, 0xd0, 0x02, 0xed, 0x4f, 0xe8, 0x63, 0x31, 0x33, + 0x24, 0x45, 0xea, 0x12, 0x6f, 0x02, 0xc4, 0x79, 0xda, 0x9d, 0x6f, 0xbe, 0x73, 0xe6, 0xcc, 0xe1, + 0x37, 0x33, 0x67, 0x46, 0x20, 0xea, 0xc4, 0xd3, 0x5c, 0xc3, 0xf1, 0x6d, 0xb7, 0xee, 0xb8, 0xb6, + 0x6f, 0xa3, 0x9d, 0x89, 0x6d, 0x4f, 0x4c, 0xc2, 0x5b, 0xa7, 0xf3, 0x71, 0xb5, 0x0b, 0x95, 0xfb, + 0x86, 0x49, 0x5a, 0x11, 0x71, 0x48, 0x7c, 0x74, 0x0f, 0x32, 0x63, 0xc3, 0x24, 0x92, 0x70, 0x90, + 0xae, 0x15, 0x6f, 0xbe, 0x5e, 0x5f, 0x32, 0xaa, 0x27, 0x2d, 0x06, 0x14, 0x56, 0x98, 0x45, 0xf5, + 0xdf, 0x19, 0xd8, 0x5d, 0xd3, 0x8b, 0x10, 0x64, 0x2c, 0x3c, 0xa3, 0x1e, 0x85, 0x5a, 0x41, 0x61, + 0xff, 0x23, 0x09, 0xb6, 0x1c, 0xac, 0x3d, 0xc4, 0x13, 0x22, 0xa5, 0x18, 0x1c, 0x36, 0xd1, 0xab, + 0x00, 0x3a, 0x71, 0x88, 0xa5, 0x13, 0x4b, 0x3b, 0x93, 0xd2, 0x07, 0xe9, 0x5a, 0x41, 0x89, 0x21, + 0xe8, 0x2d, 0xa8, 0x38, 0xf3, 0x53, 0xd3, 0xd0, 0xd4, 0x18, 0x0d, 0x0e, 0xd2, 0xb5, 0xac, 0x22, + 0xf2, 0x8e, 0xd6, 0x82, 0x7c, 0x15, 0x76, 0x1e, 0x13, 0xfc, 0x30, 0x4e, 0x2d, 0x32, 0x6a, 0x99, + 0xc2, 0x31, 0x62, 0x13, 0x4a, 0x33, 0xe2, 0x79, 0x78, 0x42, 0x54, 0xff, 0xcc, 0x21, 0x52, 0x86, + 0xcd, 0xfe, 0x60, 0x65, 0xf6, 0xcb, 0x33, 0x2f, 0x06, 0x56, 0xa3, 0x33, 0x87, 0xa0, 0x06, 0x14, + 0x88, 0x35, 0x9f, 0x71, 0x0f, 0xd9, 0x0d, 0xf9, 0x93, 0xad, 0xf9, 0x6c, 0xd9, 0x4b, 0x9e, 0x9a, + 0x05, 0x2e, 0xb6, 0x3c, 0xe2, 0x3e, 0x32, 0x34, 0x22, 0xe5, 0x98, 0x83, 0xab, 0x2b, 0x0e, 0x86, + 0xbc, 0x7f, 0xd9, 0x47, 0x68, 0x87, 0x9a, 0x50, 0x20, 0x4f, 0x7c, 0x62, 0x79, 0x86, 0x6d, 0x49, + 0x5b, 0xcc, 0xc9, 0x1b, 0x6b, 0xbe, 0x22, 0x31, 0xf5, 0x65, 0x17, 0x0b, 0x3b, 0x74, 0x17, 0xb6, + 0x6c, 0xc7, 0x37, 0x6c, 0xcb, 0x93, 0xf2, 0x07, 0x42, 0xad, 0x78, 0xf3, 0xe5, 0xb5, 0x42, 0xe8, + 0x73, 0x8e, 0x12, 0x92, 0x51, 0x1b, 0x44, 0xcf, 0x9e, 0xbb, 0x1a, 0x51, 0x35, 0x5b, 0x27, 0xaa, + 0x61, 0x8d, 0x6d, 0xa9, 0xc0, 0x1c, 0x5c, 0x5e, 0x9d, 0x08, 0x23, 0x36, 0x6d, 0x9d, 0xb4, 0xad, + 0xb1, 0xad, 0x94, 0xbd, 0x44, 0x1b, 0x5d, 0x80, 0x9c, 0x77, 0x66, 0xf9, 0xf8, 0x89, 0x54, 0x62, + 0x0a, 0x09, 0x5a, 0xd5, 0x3f, 0xe5, 0x60, 0xe7, 0x3c, 0x12, 0xfb, 0x00, 0xb2, 0x63, 0x3a, 0x4b, + 0x29, 0xf5, 0x4d, 0x72, 0xc0, 0x6d, 0x92, 0x49, 0xcc, 0x7d, 0xcb, 0x24, 0x36, 0xa0, 0x68, 0x11, + 0xcf, 0x27, 0x3a, 0x57, 0x44, 0xfa, 0x9c, 0x9a, 0x02, 0x6e, 0xb4, 0x2a, 0xa9, 0xcc, 0xb7, 0x92, + 0xd4, 0xa7, 0xb0, 0x13, 0x85, 0xa4, 0xba, 0xd8, 0x9a, 0x84, 0xda, 0xbc, 0xf1, 0xac, 0x48, 0xea, + 0x72, 0x68, 0xa7, 0x50, 0x33, 0xa5, 0x4c, 0x12, 0x6d, 0xd4, 0x02, 0xb0, 0x2d, 0x62, 0x8f, 0x55, + 0x9d, 0x68, 0xa6, 0x94, 0xdf, 0x90, 0xa5, 0x3e, 0xa5, 0xac, 0x64, 0xc9, 0xe6, 0xa8, 0x66, 0xa2, + 0xf7, 0x17, 0x52, 0xdb, 0xda, 0xa0, 0x94, 0x2e, 0x5f, 0x64, 0x2b, 0x6a, 0x3b, 0x81, 0xb2, 0x4b, + 0xa8, 0xee, 0x89, 0x1e, 0xcc, 0xac, 0xc0, 0x82, 0xa8, 0x3f, 0x73, 0x66, 0x4a, 0x60, 0xc6, 0x27, + 0xb6, 0xed, 0xc6, 0x9b, 0xe8, 0x35, 0x88, 0x00, 0x95, 0xc9, 0x0a, 0xd8, 0x2e, 0x54, 0x0a, 0xc1, + 0x1e, 0x9e, 0x91, 0xfd, 0x2f, 0xa1, 0x9c, 0x4c, 0x0f, 0xda, 0x83, 0xac, 0xe7, 0x63, 0xd7, 0x67, + 0x2a, 0xcc, 0x2a, 0xbc, 0x81, 0x44, 0x48, 0x13, 0x4b, 0x67, 0xbb, 0x5c, 0x56, 0xa1, 0xff, 0xa2, + 0x1f, 0x2d, 0x26, 0x9c, 0x66, 0x13, 0x7e, 0x73, 0xf5, 0x8b, 0x26, 0x3c, 0x2f, 0xcf, 0x7b, 0xff, + 0x3d, 0xd8, 0x4e, 0x4c, 0xe0, 0xbc, 0x43, 0x57, 0x7f, 0x01, 0x2f, 0xae, 0x75, 0x8d, 0x3e, 0x85, + 0xbd, 0xb9, 0x65, 0x58, 0x3e, 0x71, 0x1d, 0x97, 0x50, 0xc5, 0xf2, 0xa1, 0xa4, 0xff, 0x6c, 0x6d, + 0xd0, 0xdc, 0x49, 0x9c, 0xcd, 0xbd, 0x28, 0xbb, 0xf3, 0x55, 0xf0, 0x7a, 0x21, 0xff, 0xdf, 0x2d, + 0xf1, 0xe9, 0xd3, 0xa7, 0x4f, 0x53, 0xd5, 0xbf, 0xe4, 0x60, 0x6f, 0xdd, 0x9a, 0x59, 0xbb, 0x7c, + 0x2f, 0x40, 0xce, 0x9a, 0xcf, 0x4e, 0x89, 0xcb, 0x92, 0x94, 0x55, 0x82, 0x16, 0x6a, 0x40, 0xd6, + 0xc4, 0xa7, 0xc4, 0x94, 0x32, 0x07, 0x42, 0xad, 0x7c, 0xf3, 0xad, 0x73, 0xad, 0xca, 0x7a, 0x87, + 0x9a, 0x28, 0xdc, 0x12, 0x7d, 0x08, 0x99, 0x60, 0x8b, 0xa6, 0x1e, 0xae, 0x9f, 0xcf, 0x03, 0x5d, + 0x4b, 0x0a, 0xb3, 0x43, 0x2f, 0x41, 0x81, 0xfe, 0xe5, 0xda, 0xc8, 0xb1, 0x98, 0xf3, 0x14, 0xa0, + 0xba, 0x40, 0xfb, 0x90, 0x67, 0xcb, 0x44, 0x27, 0xe1, 0xd1, 0x16, 0xb5, 0xa9, 0xb0, 0x74, 0x32, + 0xc6, 0x73, 0xd3, 0x57, 0x1f, 0x61, 0x73, 0x4e, 0x98, 0xe0, 0x0b, 0x4a, 0x29, 0x00, 0x7f, 0x4a, + 0x31, 0x74, 0x19, 0x8a, 0x7c, 0x55, 0x19, 0x96, 0x4e, 0x9e, 0xb0, 0xdd, 0x33, 0xab, 0xf0, 0x85, + 0xd6, 0xa6, 0x08, 0x1d, 0xfe, 0x81, 0x67, 0x5b, 0xa1, 0x34, 0xd9, 0x10, 0x14, 0x60, 0xc3, 0xbf, + 0xb7, 0xbc, 0x71, 0xbf, 0xb2, 0x7e, 0x7a, 0x2b, 0x6b, 0xe9, 0x2a, 0xec, 0x30, 0xc6, 0xad, 0xe0, + 0xd3, 0x63, 0x53, 0xaa, 0x1c, 0x08, 0xb5, 0xbc, 0x52, 0xe6, 0x70, 0x3f, 0x40, 0xab, 0x7f, 0x4c, + 0x41, 0x86, 0x6d, 0x2c, 0x3b, 0x50, 0x1c, 0x7d, 0x36, 0x90, 0xd5, 0x56, 0xff, 0xe4, 0xa8, 0x23, + 0x8b, 0x02, 0x2a, 0x03, 0x30, 0xe0, 0x7e, 0xa7, 0xdf, 0x18, 0x89, 0xa9, 0xa8, 0xdd, 0xee, 0x8d, + 0xee, 0xde, 0x16, 0xd3, 0x91, 0xc1, 0x09, 0x07, 0x32, 0x71, 0xc2, 0xad, 0x9b, 0x62, 0x16, 0x89, + 0x50, 0xe2, 0x0e, 0xda, 0x9f, 0xca, 0xad, 0xbb, 0xb7, 0xc5, 0x5c, 0x12, 0xb9, 0x75, 0x53, 0xdc, + 0x42, 0xdb, 0x50, 0x60, 0xc8, 0x51, 0xbf, 0xdf, 0x11, 0xf3, 0x91, 0xcf, 0xe1, 0x48, 0x69, 0xf7, + 0x8e, 0xc5, 0x42, 0xe4, 0xf3, 0x58, 0xe9, 0x9f, 0x0c, 0x44, 0x88, 0x3c, 0x74, 0xe5, 0xe1, 0xb0, + 0x71, 0x2c, 0x8b, 0xc5, 0x88, 0x71, 0xf4, 0xd9, 0x48, 0x1e, 0x8a, 0xa5, 0x44, 0x58, 0xb7, 0x6e, + 0x8a, 0xdb, 0xd1, 0x10, 0x72, 0xef, 0xa4, 0x2b, 0x96, 0x51, 0x05, 0xb6, 0xf9, 0x10, 0x61, 0x10, + 0x3b, 0x4b, 0xd0, 0xdd, 0xdb, 0xa2, 0xb8, 0x08, 0x84, 0x7b, 0xa9, 0x24, 0x80, 0xbb, 0xb7, 0x45, + 0x54, 0x6d, 0x42, 0x96, 0xc9, 0x10, 0x21, 0x28, 0x77, 0x1a, 0x47, 0x72, 0x47, 0xed, 0x0f, 0x46, + 0xed, 0x7e, 0xaf, 0xd1, 0x11, 0x85, 0x05, 0xa6, 0xc8, 0x3f, 0x39, 0x69, 0x2b, 0x72, 0x4b, 0x4c, + 0xc5, 0xb1, 0x81, 0xdc, 0x18, 0xc9, 0x2d, 0x31, 0x5d, 0xd5, 0x60, 0x6f, 0xdd, 0x86, 0xba, 0x76, + 0x09, 0xc5, 0xb4, 0x90, 0xda, 0xa0, 0x05, 0xe6, 0x6b, 0x59, 0x0b, 0xd5, 0x7f, 0xa5, 0x60, 0x77, + 0xcd, 0xa1, 0xb2, 0x76, 0x90, 0x1f, 0x42, 0x96, 0x6b, 0x99, 0x1f, 0xb3, 0xd7, 0xd6, 0x9e, 0x4e, + 0x4c, 0xd9, 0x2b, 0x47, 0x2d, 0xb3, 0x8b, 0x97, 0x1a, 0xe9, 0x0d, 0xa5, 0x06, 0x75, 0xb1, 0x22, + 0xd8, 0x9f, 0xaf, 0x6c, 0xfe, 0xfc, 0x7c, 0xbc, 0x7b, 0x9e, 0xf3, 0x91, 0x61, 0xdf, 0xec, 0x10, + 0xc8, 0xae, 0x39, 0x04, 0x3e, 0x80, 0xca, 0x8a, 0xa3, 0x73, 0x6f, 0xc6, 0xbf, 0x14, 0x40, 0xda, + 0x94, 0x9c, 0x67, 0x6c, 0x89, 0xa9, 0xc4, 0x96, 0xf8, 0xc1, 0x72, 0x06, 0xaf, 0x6c, 0xfe, 0x08, + 0x2b, 0xdf, 0xfa, 0x2b, 0x01, 0x2e, 0xac, 0x2f, 0x29, 0xd7, 0xc6, 0xf0, 0x21, 0xe4, 0x66, 0xc4, + 0x9f, 0xda, 0x61, 0x59, 0xf5, 0xe6, 0x9a, 0xc3, 0x9a, 0x76, 0x2f, 0x7f, 0xec, 0xc0, 0x2a, 0x7e, + 0xda, 0xa7, 0x37, 0xd5, 0x85, 0x3c, 0x9a, 0x95, 0x48, 0x7f, 0x95, 0x82, 0x17, 0xd7, 0x3a, 0x5f, + 0x1b, 0xe8, 0x2b, 0x00, 0x86, 0xe5, 0xcc, 0x7d, 0x5e, 0x3a, 0xf1, 0x9d, 0xb8, 0xc0, 0x10, 0xb6, + 0x79, 0xd1, 0x5d, 0x76, 0xee, 0x47, 0xfd, 0x69, 0xd6, 0x0f, 0x1c, 0x62, 0x84, 0x7b, 0x8b, 0x40, + 0x33, 0x2c, 0xd0, 0x57, 0x37, 0xcc, 0x74, 0x45, 0x98, 0xef, 0x82, 0xa8, 0x99, 0x06, 0xb1, 0x7c, + 0xd5, 0xf3, 0x5d, 0x82, 0x67, 0x86, 0x35, 0x61, 0x47, 0x4d, 0xfe, 0x30, 0x3b, 0xc6, 0xa6, 0x47, + 0x94, 0x1d, 0xde, 0x3d, 0x0c, 0x7b, 0xa9, 0x05, 0x13, 0x90, 0x1b, 0xb3, 0xc8, 0x25, 0x2c, 0x78, + 0x77, 0x64, 0x51, 0xfd, 0x75, 0x01, 0x8a, 0xb1, 0x02, 0x1c, 0x5d, 0x81, 0xd2, 0x03, 0xfc, 0x08, + 0xab, 0xe1, 0xa5, 0x8a, 0x67, 0xa2, 0x48, 0xb1, 0x41, 0x70, 0xb1, 0x7a, 0x17, 0xf6, 0x18, 0xc5, + 0x9e, 0xfb, 0xc4, 0x55, 0x35, 0x13, 0x7b, 0x1e, 0x4b, 0x5a, 0x9e, 0x51, 0x11, 0xed, 0xeb, 0xd3, + 0xae, 0x66, 0xd8, 0x83, 0xee, 0xc0, 0x2e, 0xb3, 0x98, 0xcd, 0x4d, 0xdf, 0x70, 0x4c, 0xa2, 0xd2, + 0x6b, 0x9e, 0xc7, 0x8e, 0x9c, 0x28, 0xb2, 0x0a, 0x65, 0x74, 0x03, 0x02, 0x8d, 0xc8, 0x43, 0x2d, + 0x78, 0x85, 0x99, 0x4d, 0x88, 0x45, 0x5c, 0xec, 0x13, 0x95, 0x7c, 0x31, 0xc7, 0xa6, 0xa7, 0x62, + 0x4b, 0x57, 0xa7, 0xd8, 0x9b, 0x4a, 0x7b, 0xd4, 0xc1, 0x51, 0x4a, 0x12, 0x94, 0x4b, 0x94, 0x78, + 0x1c, 0xf0, 0x64, 0x46, 0x6b, 0x58, 0xfa, 0x47, 0xd8, 0x9b, 0xa2, 0x43, 0xb8, 0xc0, 0xbc, 0x78, + 0xbe, 0x6b, 0x58, 0x13, 0x55, 0x9b, 0x12, 0xed, 0xa1, 0x3a, 0xf7, 0xc7, 0xf7, 0xa4, 0x97, 0xe2, + 0xe3, 0xb3, 0x08, 0x87, 0x8c, 0xd3, 0xa4, 0x94, 0x13, 0x7f, 0x7c, 0x0f, 0x0d, 0xa1, 0x44, 0x3f, + 0xc6, 0xcc, 0xf8, 0x92, 0xa8, 0x63, 0xdb, 0x65, 0x67, 0x68, 0x79, 0xcd, 0xd6, 0x14, 0xcb, 0x60, + 0xbd, 0x1f, 0x18, 0x74, 0x6d, 0x9d, 0x1c, 0x66, 0x87, 0x03, 0x59, 0x6e, 0x29, 0xc5, 0xd0, 0xcb, + 0x7d, 0xdb, 0xa5, 0x82, 0x9a, 0xd8, 0x51, 0x82, 0x8b, 0x5c, 0x50, 0x13, 0x3b, 0x4c, 0xef, 0x1d, + 0xd8, 0xd5, 0x34, 0x3e, 0x67, 0x43, 0x53, 0x83, 0xcb, 0x98, 0x27, 0x89, 0x89, 0x64, 0x69, 0xda, + 0x31, 0x27, 0x04, 0x1a, 0xf7, 0xd0, 0xfb, 0xf0, 0xe2, 0x22, 0x59, 0x71, 0xc3, 0xca, 0xca, 0x2c, + 0x97, 0x4d, 0xef, 0xc0, 0xae, 0x73, 0xb6, 0x6a, 0x88, 0x12, 0x23, 0x3a, 0x67, 0xcb, 0x66, 0xef, + 0xc1, 0x9e, 0x33, 0x75, 0x56, 0xed, 0xae, 0xc7, 0xed, 0x90, 0x33, 0x75, 0x96, 0x0d, 0xdf, 0x60, + 0x37, 0x73, 0x97, 0x68, 0xd8, 0x27, 0xba, 0x74, 0x31, 0x4e, 0x8f, 0x75, 0xa0, 0x1b, 0x20, 0x6a, + 0x9a, 0x4a, 0x2c, 0x7c, 0x6a, 0x12, 0x15, 0xbb, 0xc4, 0xc2, 0x9e, 0x74, 0x39, 0x4e, 0x2e, 0x6b, + 0x9a, 0xcc, 0x7a, 0x1b, 0xac, 0x13, 0x5d, 0x87, 0x8a, 0x7d, 0xfa, 0x40, 0xe3, 0x92, 0x54, 0x1d, + 0x97, 0x8c, 0x8d, 0x27, 0xd2, 0xeb, 0x2c, 0xbf, 0x3b, 0xb4, 0x83, 0x09, 0x72, 0xc0, 0x60, 0x74, + 0x0d, 0x44, 0xcd, 0x9b, 0x62, 0xd7, 0x61, 0x7b, 0xb2, 0xe7, 0x60, 0x8d, 0x48, 0x6f, 0x70, 0x2a, + 0xc7, 0x7b, 0x21, 0x4c, 0x97, 0x84, 0xf7, 0xd8, 0x18, 0xfb, 0xa1, 0xc7, 0xab, 0x7c, 0x49, 0x30, + 0x2c, 0xf0, 0x56, 0x03, 0x91, 0xa6, 0x22, 0x31, 0x70, 0x8d, 0xd1, 0xca, 0xce, 0xd4, 0x89, 0x8f, + 0xfb, 0x1a, 0x6c, 0x53, 0xe6, 0x62, 0xd0, 0x6b, 0xbc, 0x72, 0x73, 0xa6, 0xb1, 0x11, 0x6f, 0xc3, + 0x05, 0x4a, 0x9a, 0x11, 0x1f, 0xeb, 0xd8, 0xc7, 0x31, 0xf6, 0xdb, 0x8c, 0x4d, 0xf3, 0xde, 0x0d, + 0x3a, 0x13, 0x71, 0xba, 0xf3, 0xd3, 0xb3, 0x48, 0x59, 0xef, 0xf0, 0x38, 0x29, 0x16, 0x6a, 0xeb, + 0x3b, 0xab, 0xce, 0xab, 0x87, 0x50, 0x8a, 0x0b, 0x1f, 0x15, 0x80, 0x4b, 0x5f, 0x14, 0x68, 0x15, + 0xd4, 0xec, 0xb7, 0x68, 0xfd, 0xf2, 0xb9, 0x2c, 0xa6, 0x68, 0x1d, 0xd5, 0x69, 0x8f, 0x64, 0x55, + 0x39, 0xe9, 0x8d, 0xda, 0x5d, 0x59, 0x4c, 0xc7, 0x2b, 0xfb, 0xbf, 0xa6, 0xa0, 0x9c, 0xbc, 0xa4, + 0xa1, 0x1f, 0xc0, 0xc5, 0xf0, 0x45, 0xc5, 0x23, 0xbe, 0xfa, 0xd8, 0x70, 0xd9, 0x5a, 0x9c, 0x61, + 0x7e, 0x2e, 0x46, 0x6a, 0xd8, 0x0b, 0x58, 0x43, 0xe2, 0x7f, 0x62, 0xb8, 0x74, 0xa5, 0xcd, 0xb0, + 0x8f, 0x3a, 0x70, 0xd9, 0xb2, 0x55, 0xcf, 0xc7, 0x96, 0x8e, 0x5d, 0x5d, 0x5d, 0xbc, 0x65, 0xa9, + 0x58, 0xd3, 0x88, 0xe7, 0xd9, 0xfc, 0x0c, 0x8c, 0xbc, 0xbc, 0x6c, 0xd9, 0xc3, 0x80, 0xbc, 0x38, + 0x1c, 0x1a, 0x01, 0x75, 0x49, 0xb9, 0xe9, 0x4d, 0xca, 0x7d, 0x09, 0x0a, 0x33, 0xec, 0xa8, 0xc4, + 0xf2, 0xdd, 0x33, 0x56, 0x9a, 0xe7, 0x95, 0xfc, 0x0c, 0x3b, 0x32, 0x6d, 0x3f, 0x9f, 0x1b, 0xd2, + 0x3f, 0xd2, 0x50, 0x8a, 0x97, 0xe7, 0xf4, 0xb6, 0xa3, 0xb1, 0x03, 0x4a, 0x60, 0x5b, 0xd8, 0x6b, + 0x5f, 0x5b, 0xcc, 0xd7, 0x9b, 0xf4, 0xe4, 0x3a, 0xcc, 0xf1, 0x5a, 0x58, 0xe1, 0x96, 0xb4, 0x6a, + 0xa0, 0xd2, 0x22, 0xbc, 0xf6, 0xc8, 0x2b, 0x41, 0x0b, 0x1d, 0x43, 0xee, 0x81, 0xc7, 0x7c, 0xe7, + 0x98, 0xef, 0xd7, 0xbf, 0xde, 0xf7, 0xc7, 0x43, 0xe6, 0xbc, 0xf0, 0xf1, 0x50, 0xed, 0xf5, 0x95, + 0x6e, 0xa3, 0xa3, 0x04, 0xe6, 0xe8, 0x12, 0x64, 0x4c, 0xfc, 0xe5, 0x59, 0xf2, 0x8c, 0x63, 0xd0, + 0x79, 0x13, 0x7f, 0x09, 0x32, 0x8f, 0x09, 0x7e, 0x98, 0x3c, 0x59, 0x18, 0xf4, 0x1d, 0x4a, 0xff, + 0x06, 0x64, 0x59, 0xbe, 0x10, 0x40, 0x90, 0x31, 0xf1, 0x05, 0x94, 0x87, 0x4c, 0xb3, 0xaf, 0x50, + 0xf9, 0x8b, 0x50, 0xe2, 0xa8, 0x3a, 0x68, 0xcb, 0x4d, 0x59, 0x4c, 0x55, 0xef, 0x40, 0x8e, 0x27, + 0x81, 0x2e, 0x8d, 0x28, 0x0d, 0xe2, 0x0b, 0x41, 0x33, 0xf0, 0x21, 0x84, 0xbd, 0x27, 0xdd, 0x23, + 0x59, 0x11, 0x53, 0xf1, 0xcf, 0xeb, 0x41, 0x29, 0x5e, 0x70, 0x3f, 0x1f, 0x4d, 0xfd, 0x59, 0x80, + 0x62, 0xac, 0x80, 0xa6, 0x95, 0x0f, 0x36, 0x4d, 0xfb, 0xb1, 0x8a, 0x4d, 0x03, 0x7b, 0x81, 0x28, + 0x80, 0x41, 0x0d, 0x8a, 0x9c, 0xf7, 0xa3, 0x3d, 0x97, 0xe0, 0x7f, 0x27, 0x80, 0xb8, 0x5c, 0xbb, + 0x2e, 0x05, 0x28, 0x7c, 0xaf, 0x01, 0xfe, 0x56, 0x80, 0x72, 0xb2, 0x60, 0x5d, 0x0a, 0xef, 0xca, + 0xf7, 0x1a, 0xde, 0x3f, 0x53, 0xb0, 0x9d, 0x28, 0x53, 0xcf, 0x1b, 0xdd, 0x17, 0x50, 0x31, 0x74, + 0x32, 0x73, 0x6c, 0x9f, 0x58, 0xda, 0x99, 0x6a, 0x92, 0x47, 0xc4, 0x94, 0xaa, 0x6c, 0xa3, 0xb8, + 0xf1, 0xf5, 0x85, 0x70, 0xbd, 0xbd, 0xb0, 0xeb, 0x50, 0xb3, 0xc3, 0xdd, 0x76, 0x4b, 0xee, 0x0e, + 0xfa, 0x23, 0xb9, 0xd7, 0xfc, 0x4c, 0x3d, 0xe9, 0xfd, 0xb8, 0xd7, 0xff, 0xa4, 0xa7, 0x88, 0xc6, + 0x12, 0xed, 0x3b, 0x5c, 0xea, 0x03, 0x10, 0x97, 0x83, 0x42, 0x17, 0x61, 0x5d, 0x58, 0xe2, 0x0b, + 0x68, 0x17, 0x76, 0x7a, 0x7d, 0x75, 0xd8, 0x6e, 0xc9, 0xaa, 0x7c, 0xff, 0xbe, 0xdc, 0x1c, 0x0d, + 0xf9, 0xd3, 0x46, 0xc4, 0x1e, 0x25, 0x17, 0xf5, 0x6f, 0xd2, 0xb0, 0xbb, 0x26, 0x12, 0xd4, 0x08, + 0x2e, 0x25, 0xfc, 0x9e, 0xf4, 0xce, 0x79, 0xa2, 0xaf, 0xd3, 0xaa, 0x60, 0x80, 0x5d, 0x3f, 0xb8, + 0xc3, 0x5c, 0x03, 0x9a, 0x25, 0xcb, 0x37, 0xc6, 0x06, 0x71, 0x83, 0x27, 0x23, 0x7e, 0x53, 0xd9, + 0x59, 0xe0, 0xfc, 0xd5, 0xe8, 0x6d, 0x40, 0x8e, 0xed, 0x19, 0xbe, 0xf1, 0x88, 0xa8, 0x86, 0x15, + 0xbe, 0x2f, 0xd1, 0x9b, 0x4b, 0x46, 0x11, 0xc3, 0x9e, 0xb6, 0xe5, 0x47, 0x6c, 0x8b, 0x4c, 0xf0, + 0x12, 0x9b, 0x6e, 0xe0, 0x69, 0x45, 0x0c, 0x7b, 0x22, 0xf6, 0x15, 0x28, 0xe9, 0xf6, 0x9c, 0x96, + 0x73, 0x9c, 0x47, 0xcf, 0x0b, 0x41, 0x29, 0x72, 0x2c, 0xa2, 0x04, 0x85, 0xfa, 0xe2, 0x61, 0xab, + 0xa4, 0x14, 0x39, 0xc6, 0x29, 0x57, 0x61, 0x07, 0x4f, 0x26, 0x2e, 0x75, 0x1e, 0x3a, 0xe2, 0x57, + 0x8f, 0x72, 0x04, 0x33, 0xe2, 0xfe, 0xc7, 0x90, 0x0f, 0xf3, 0x40, 0x8f, 0x64, 0x9a, 0x09, 0xd5, + 0xe1, 0xf7, 0xe9, 0x54, 0xad, 0xa0, 0xe4, 0xad, 0xb0, 0xf3, 0x0a, 0x94, 0x0c, 0x4f, 0x5d, 0xbc, + 0xd3, 0xa7, 0x0e, 0x52, 0xb5, 0xbc, 0x52, 0x34, 0xbc, 0xe8, 0x8d, 0xb3, 0xfa, 0x55, 0x0a, 0xca, + 0xc9, 0xdf, 0x19, 0x50, 0x0b, 0xf2, 0xa6, 0xad, 0x61, 0x26, 0x2d, 0xfe, 0x23, 0x57, 0xed, 0x19, + 0x3f, 0x4d, 0xd4, 0x3b, 0x01, 0x5f, 0x89, 0x2c, 0xf7, 0xff, 0x26, 0x40, 0x3e, 0x84, 0xd1, 0x05, + 0xc8, 0x38, 0xd8, 0x9f, 0x32, 0x77, 0xd9, 0xa3, 0x94, 0x28, 0x28, 0xac, 0x4d, 0x71, 0xcf, 0xc1, + 0x16, 0x93, 0x40, 0x80, 0xd3, 0x36, 0xfd, 0xae, 0x26, 0xc1, 0x3a, 0xbb, 0xd7, 0xd8, 0xb3, 0x19, + 0xb1, 0x7c, 0x2f, 0xfc, 0xae, 0x01, 0xde, 0x0c, 0x60, 0xf4, 0x16, 0x54, 0x7c, 0x17, 0x1b, 0x66, + 0x82, 0x9b, 0x61, 0x5c, 0x31, 0xec, 0x88, 0xc8, 0x87, 0x70, 0x29, 0xf4, 0xab, 0x13, 0x1f, 0x6b, + 0x53, 0xa2, 0x2f, 0x8c, 0x72, 0xec, 0xfd, 0xe2, 0x62, 0x40, 0x68, 0x05, 0xfd, 0xa1, 0x6d, 0xf5, + 0xef, 0x02, 0x54, 0xc2, 0x9b, 0x98, 0x1e, 0x25, 0xab, 0x0b, 0x80, 0x2d, 0xcb, 0xf6, 0xe3, 0xe9, + 0x5a, 0x95, 0xf2, 0x8a, 0x5d, 0xbd, 0x11, 0x19, 0x29, 0x31, 0x07, 0xfb, 0x33, 0x80, 0x45, 0xcf, + 0xc6, 0xb4, 0x5d, 0x86, 0x62, 0xf0, 0x23, 0x12, 0xfb, 0x25, 0x92, 0xdf, 0xdd, 0x81, 0x43, 0xf4, + 0xca, 0x86, 0xf6, 0x20, 0x7b, 0x4a, 0x26, 0x86, 0x15, 0x3c, 0x0d, 0xf3, 0x46, 0xf8, 0xc2, 0x92, + 0x89, 0x5e, 0x58, 0x8e, 0x7e, 0x06, 0xbb, 0x9a, 0x3d, 0x5b, 0x0e, 0xf7, 0x48, 0x5c, 0x7a, 0x3f, + 0xf0, 0x3e, 0x12, 0x3e, 0x87, 0x45, 0x89, 0xf9, 0x3f, 0x41, 0xf8, 0x7d, 0x2a, 0x7d, 0x3c, 0x38, + 0xfa, 0x43, 0x6a, 0xff, 0x98, 0x9b, 0x0e, 0xc2, 0x99, 0x2a, 0x64, 0x6c, 0x12, 0x8d, 0x46, 0xff, + 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf4, 0xa9, 0x35, 0x77, 0x61, 0x1d, 0x00, 0x00, } diff --git a/protoc-gen-gogo/descriptor/descriptor_gostring.gen.go b/protoc-gen-gogo/descriptor/descriptor_gostring.gen.go index 165b2110df..b41921e16b 100644 --- a/protoc-gen-gogo/descriptor/descriptor_gostring.gen.go +++ b/protoc-gen-gogo/descriptor/descriptor_gostring.gen.go @@ -183,7 +183,7 @@ func (this *FieldDescriptorProto) GoString() string { if this == nil { return "nil" } - s := make([]string, 0, 14) + s := make([]string, 0, 15) s = append(s, "&descriptor.FieldDescriptorProto{") if this.Name != nil { s = append(s, "Name: "+valueToGoStringDescriptor(this.Name, "string")+",\n") @@ -215,6 +215,9 @@ func (this *FieldDescriptorProto) GoString() string { if this.Options != nil { s = append(s, "Options: "+fmt.Sprintf("%#v", this.Options)+",\n") } + if this.Proto3Optional != nil { + s = append(s, "Proto3Optional: "+valueToGoStringDescriptor(this.Proto3Optional, "bool")+",\n") + } if this.XXX_unrecognized != nil { s = append(s, "XXX_unrecognized:"+fmt.Sprintf("%#v", this.XXX_unrecognized)+",\n") } diff --git a/protoc-gen-gogo/generator/generator.go b/protoc-gen-gogo/generator/generator.go index 879939ea48..03786508eb 100644 --- a/protoc-gen-gogo/generator/generator.go +++ b/protoc-gen-gogo/generator/generator.go @@ -35,9 +35,9 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /* - The code generator for the plugin for the Google protocol buffer compiler. - It generates Go code from the protocol buffer description files read by the - main routine. +The code generator for the plugin for the Google protocol buffer compiler. +It generates Go code from the protocol buffer description files read by the +main routine. */ package generator @@ -64,6 +64,7 @@ import ( "github.com/gogo/protobuf/gogoproto" "github.com/gogo/protobuf/proto" + "github.com/gogo/protobuf/proto3optional" descriptor "github.com/gogo/protobuf/protoc-gen-gogo/descriptor" "github.com/gogo/protobuf/protoc-gen-gogo/generator/internal/remap" plugin "github.com/gogo/protobuf/protoc-gen-gogo/plugin" @@ -481,6 +482,7 @@ func New() *Generator { g.Buffer = new(bytes.Buffer) g.Request = new(plugin.CodeGeneratorRequest) g.Response = new(plugin.CodeGeneratorResponse) + g.Response.SupportedFeatures = proto.Uint64(uint64(plugin.CodeGeneratorResponse_FEATURE_PROTO3_OPTIONAL)) g.writtenImports = make(map[string]bool) g.addedImports = make(map[GoImportPath]bool) return g @@ -1222,8 +1224,9 @@ func (g *Generator) generate(file *FileDescriptor) { } g.generateMessage(desc) } + proto3Resolver := proto3optional.NewResolver(g.file.proto3, nil) for _, ext := range g.file.ext { - g.generateExtension(ext) + g.generateExtension(ext, proto3Resolver) } g.generateInitFunction() g.generateFileDescriptor(file) @@ -1605,6 +1608,7 @@ func (g *Generator) generateEnum(enum *EnumDescriptor) { // The tag is a string like "varint,2,opt,name=fieldname,def=7" that // identifies details of the field for the protocol buffer marshaling and unmarshaling // code. The fields are: +// // wire encoding // protocol tag number // opt,req,rep for optional, required, or repeated @@ -1613,6 +1617,7 @@ func (g *Generator) generateEnum(enum *EnumDescriptor) { // enum= the name of the enum type if it is an enum-typed field. // proto3 if this field is in a proto3 message // def= string representation of the default value, if any. +// // The default value must be in a representation that can be used at run-time // to generate the default value. Thus bools become 0 and 1, for instance. func (g *Generator) goTag(message *Descriptor, field *descriptor.FieldDescriptorProto, wiretype string) string { @@ -1749,7 +1754,7 @@ func (g *Generator) goTag(message *Descriptor, field *descriptor.FieldDescriptor name += ",proto3" } oneof := "" - if field.OneofIndex != nil { + if field.OneofIndex != nil { // todo create task for google-protobuf oneof = ",oneof" } stdtime := "" @@ -1783,7 +1788,7 @@ func (g *Generator) goTag(message *Descriptor, field *descriptor.FieldDescriptor wktptr)) } -func needsStar(field *descriptor.FieldDescriptorProto, proto3 bool, allowOneOf bool) bool { +func needsStar(field *descriptor.FieldDescriptorProto, fieldExtendee bool, allowOneOf bool, proto3Resolver *proto3optional.Resolver) bool { if isRepeated(field) && (*field.Type != descriptor.FieldDescriptorProto_TYPE_MESSAGE || gogoproto.IsCustomType(field)) && (*field.Type != descriptor.FieldDescriptorProto_TYPE_GROUP) { @@ -1792,15 +1797,15 @@ func needsStar(field *descriptor.FieldDescriptorProto, proto3 bool, allowOneOf b if *field.Type == descriptor.FieldDescriptorProto_TYPE_BYTES && !gogoproto.IsCustomType(field) { return false } - if !gogoproto.IsNullable(field) { + if !gogoproto.IsNullable(field, proto3Resolver) { return false } - if field.OneofIndex != nil && allowOneOf && + if proto3Resolver.IsRealOneOf(field) && allowOneOf && (*field.Type != descriptor.FieldDescriptorProto_TYPE_MESSAGE) && (*field.Type != descriptor.FieldDescriptorProto_TYPE_GROUP) { return false } - if proto3 && + if proto3Resolver.IsProto3WithoutOptional(field) && fieldExtendee && (*field.Type != descriptor.FieldDescriptorProto_TYPE_MESSAGE) && (*field.Type != descriptor.FieldDescriptorProto_TYPE_GROUP) && !gogoproto.IsCustomType(field) { @@ -1819,7 +1824,7 @@ func (g *Generator) TypeName(obj Object) string { } // GoType returns a string representing the type name, and the wire type -func (g *Generator) GoType(message *Descriptor, field *descriptor.FieldDescriptorProto) (typ string, wire string) { +func (g *Generator) GoType(message *Descriptor, field *descriptor.FieldDescriptorProto, proto3Resolver *proto3optional.Resolver) (typ string, wire string) { // TODO: Options. switch *field.Type { case descriptor.FieldDescriptorProto_TYPE_DOUBLE: @@ -1912,7 +1917,7 @@ func (g *Generator) GoType(message *Descriptor, field *descriptor.FieldDescripto case gogoproto.IsStdBytes(field): typ = "[]byte" } - if needsStar(field, g.file.proto3 && field.Extendee == nil, message != nil && message.allowOneof()) { + if needsStar(field, field.Extendee == nil, message != nil && message.allowOneof(), proto3Resolver) { typ = "*" + typ } if isRepeated(field) { @@ -1934,7 +1939,7 @@ type GoMapDescriptor struct { ValueTag string } -func (g *Generator) GoMapType(d *Descriptor, field *descriptor.FieldDescriptorProto) *GoMapDescriptor { +func (g *Generator) GoMapType(d *Descriptor, field *descriptor.FieldDescriptorProto, proto3Resolver *proto3optional.Resolver) *GoMapDescriptor { if d == nil { byName := g.ObjectNamed(field.GetTypeName()) desc, ok := byName.(*Descriptor) @@ -1951,9 +1956,9 @@ func (g *Generator) GoMapType(d *Descriptor, field *descriptor.FieldDescriptorPr } // Figure out the Go types and tags for the key and value types. - m.KeyAliasField, m.ValueAliasField = g.GetMapKeyField(field, m.KeyField), g.GetMapValueField(field, m.ValueField) - keyType, keyWire := g.GoType(d, m.KeyAliasField) - valType, valWire := g.GoType(d, m.ValueAliasField) + m.KeyAliasField, m.ValueAliasField = g.GetMapKeyField(field, m.KeyField), g.GetMapValueField(field, m.ValueField, proto3Resolver) + keyType, keyWire := g.GoType(d, m.KeyAliasField, proto3Resolver) + valType, valWire := g.GoType(d, m.ValueAliasField, proto3Resolver) m.KeyTag, m.ValueTag = g.goTag(d, m.KeyField, keyWire), g.goTag(d, m.ValueField, valWire) @@ -1980,7 +1985,7 @@ func (g *Generator) GoMapType(d *Descriptor, field *descriptor.FieldDescriptorPr valType = strings.TrimPrefix(valType, "*") g.RecordTypeUse(m.ValueAliasField.GetTypeName()) case descriptor.FieldDescriptorProto_TYPE_MESSAGE: - if !gogoproto.IsNullable(m.ValueAliasField) { + if !gogoproto.IsNullable(m.ValueAliasField, proto3Resolver) { valType = strings.TrimPrefix(valType, "*") } if !gogoproto.IsStdType(m.ValueAliasField) && !gogoproto.IsCustomType(field) && !gogoproto.IsCastType(field) { @@ -1988,7 +1993,7 @@ func (g *Generator) GoMapType(d *Descriptor, field *descriptor.FieldDescriptorPr } default: if gogoproto.IsCustomType(m.ValueAliasField) { - if !gogoproto.IsNullable(m.ValueAliasField) { + if !gogoproto.IsNullable(m.ValueAliasField, proto3Resolver) { valType = strings.TrimPrefix(valType, "*") } if !gogoproto.IsStdType(field) { @@ -2059,7 +2064,7 @@ var wellKnownTypes = map[string]bool{ // getterDefault finds the default value for the field to return from a getter, // regardless of if it's a built in default or explicit from the source. Returns e.g. "nil", `""`, "Default_MessageType_FieldName" -func (g *Generator) getterDefault(field *descriptor.FieldDescriptorProto, goMessageType, goTypeName string) string { +func (g *Generator) getterDefault(field *descriptor.FieldDescriptorProto, goMessageType, goTypeName string, proto3Resolver *proto3optional.Resolver) string { if isRepeated(field) { return "nil" } @@ -2073,19 +2078,19 @@ func (g *Generator) getterDefault(field *descriptor.FieldDescriptorProto, goMess switch *field.Type { case descriptor.FieldDescriptorProto_TYPE_GROUP, descriptor.FieldDescriptorProto_TYPE_MESSAGE: - if field.OneofIndex != nil { + if proto3Resolver.IsRealOneOf(field) { return "nil" } else { - if !gogoproto.IsNullable(field) && (gogoproto.IsStdDuration(field) || + if !gogoproto.IsNullable(field, proto3Resolver) && (gogoproto.IsStdDuration(field) || gogoproto.IsStdDouble(field) || gogoproto.IsStdFloat(field) || gogoproto.IsStdInt64(field) || gogoproto.IsStdUInt64(field) || gogoproto.IsStdInt32(field) || gogoproto.IsStdUInt32(field)) { return "0" - } else if !gogoproto.IsNullable(field) && gogoproto.IsStdBool(field) { + } else if !gogoproto.IsNullable(field, proto3Resolver) && gogoproto.IsStdBool(field) { return "false" - } else if !gogoproto.IsNullable(field) && gogoproto.IsStdString(field) { + } else if !gogoproto.IsNullable(field, proto3Resolver) && gogoproto.IsStdString(field) { return "\"\"" - } else if !gogoproto.IsNullable(field) && gogoproto.IsStdBytes(field) { + } else if !gogoproto.IsNullable(field, proto3Resolver) && gogoproto.IsStdBytes(field) { return "[]byte{}" } else { return goTypeName + "{}" @@ -2193,7 +2198,7 @@ func (f *simpleField) decl(g *Generator, mc *msgCtx) { } // getter prints the getter for the field. -func (f *simpleField) getter(g *Generator, mc *msgCtx) { +func (f *simpleField) getter(g *Generator, mc *msgCtx, proto3Resolver *proto3optional.Resolver) { oneof := false if !oneof && !gogoproto.HasGoGetters(g.file.FileDescriptorProto, mc.message.DescriptorProto) { return @@ -2204,7 +2209,7 @@ func (f *simpleField) getter(g *Generator, mc *msgCtx) { if f.deprecated != "" { g.P(f.deprecated) } - g.generateGet(mc, f.protoField, f.protoType, false, f.goName, f.goType, "", "", f.fullPath, f.getterName, f.getterDef) + g.generateGet(mc, f.protoField, f.protoType, false, f.goName, f.goType, "", "", f.fullPath, f.getterName, f.getterDef, proto3Resolver) } // setter prints the setter method of the field. @@ -2287,7 +2292,7 @@ func (f *oneofField) decl(g *Generator, mc *msgCtx) { // getter for a oneof field will print additional discriminators and interfaces for the oneof, // also it prints all the getters for the sub fields. -func (f *oneofField) getter(g *Generator, mc *msgCtx) { +func (f *oneofField) getter(g *Generator, mc *msgCtx, proto3Resolver *proto3optional.Resolver) { oneof := true if !oneof && !gogoproto.HasGoGetters(g.file.FileDescriptorProto, mc.message.DescriptorProto) { return @@ -2300,7 +2305,7 @@ func (f *oneofField) getter(g *Generator, mc *msgCtx) { if sf.deprecated != "" { g.P(sf.deprecated) } - g.generateGet(mc, sf.protoField, sf.protoType, true, sf.goName, sf.goType, f.goName, sf.oneofTypeName, sf.fullPath, sf.getterName, sf.getterDef) + g.generateGet(mc, sf.protoField, sf.protoType, true, sf.goName, sf.goType, f.goName, sf.oneofTypeName, sf.fullPath, sf.getterName, sf.getterDef, proto3Resolver) } } @@ -2311,9 +2316,9 @@ func (f *oneofField) setter(g *Generator, mc *msgCtx) { // topLevelField interface implemented by all types of fields on the top level (not oneofSubField). type topLevelField interface { - decl(g *Generator, mc *msgCtx) // print declaration within the struct - getter(g *Generator, mc *msgCtx) // print getter - setter(g *Generator, mc *msgCtx) // print setter if applicable + decl(g *Generator, mc *msgCtx) // print declaration within the struct + getter(g *Generator, mc *msgCtx, proto3Resolver *proto3optional.Resolver) // print getter + setter(g *Generator, mc *msgCtx) // print setter if applicable } // defField interface implemented by all types of fields that can have defaults (not oneofField, but instead oneofSubField). @@ -2332,6 +2337,7 @@ func (g *Generator) generateDefaultConstants(mc *msgCtx, topLevelFields []topLev // Collect fields that can have defaults dFields := []defField{} for _, pf := range topLevelFields { + // No check for "real" needed, because it was made in the previous step if f, ok := pf.(*oneofField); ok { for _, osf := range f.subFields { dFields = append(dFields, osf) @@ -2340,12 +2346,19 @@ func (g *Generator) generateDefaultConstants(mc *msgCtx, topLevelFields []topLev } dFields = append(dFields, pf.(defField)) } + + protoFields := make([]*descriptor.FieldDescriptorProto, 0, len(dFields)) + for _, f := range dFields { + protoFields = append(protoFields, f.getProto()) + } + proto3Resolver := proto3optional.NewResolver(g.file.proto3, protoFields) + for _, df := range dFields { def := df.getProtoDef() if def == "" { continue } - if !gogoproto.IsNullable(df.getProto()) { + if !gogoproto.IsNullable(df.getProto(), proto3Resolver) { g.Fail("illegal default value: ", df.getProtoName(), " in ", mc.message.GetName(), " is not nullable and is thus not allowed to have a default value") } fieldname := g.defaultConstantName(mc.goName, df.getProtoName()) @@ -2430,11 +2443,11 @@ func (g *Generator) generateDefaultConstants(mc *msgCtx, topLevelFields []topLev // We did not want to duplicate the code since it is quite intricate so we came // up with this ugly method. At least the logic is in one place. This can be reworked. func (g *Generator) generateGet(mc *msgCtx, protoField *descriptor.FieldDescriptorProto, protoType descriptor.FieldDescriptorProto_Type, - oneof bool, fname, tname, uname, oneoftname, fullpath, gname, def string) { + oneof bool, fname, tname, uname, oneoftname, fullpath, gname, def string, proto3Resolver *proto3optional.Resolver) { star := "" if (protoType != descriptor.FieldDescriptorProto_TYPE_MESSAGE) && (protoType != descriptor.FieldDescriptorProto_TYPE_GROUP) && - needsStar(protoField, g.file.proto3, mc.message != nil && mc.message.allowOneof()) && tname[0] == '*' { + needsStar(protoField, true, mc.message != nil && mc.message.allowOneof(), proto3Resolver) && tname[0] == '*' { tname = tname[1:] star = "*" } @@ -2443,7 +2456,7 @@ func (g *Generator) generateGet(mc *msgCtx, protoField *descriptor.FieldDescript case descriptor.FieldDescriptorProto_TYPE_BYTES: typeDefaultIsNil = def == "nil" case descriptor.FieldDescriptorProto_TYPE_GROUP, descriptor.FieldDescriptorProto_TYPE_MESSAGE: - typeDefaultIsNil = gogoproto.IsNullable(protoField) + typeDefaultIsNil = gogoproto.IsNullable(protoField, proto3Resolver) } if isRepeated(protoField) { typeDefaultIsNil = true @@ -2463,7 +2476,7 @@ func (g *Generator) generateGet(mc *msgCtx, protoField *descriptor.FieldDescript g.P() return } - if !gogoproto.IsNullable(protoField) { + if !gogoproto.IsNullable(protoField, proto3Resolver) { g.P("if m != nil {") g.In() g.P("return m." + fname) @@ -2635,10 +2648,9 @@ func (g *Generator) generateMessageStruct(mc *msgCtx, topLevelFields []topLevelF } // generateGetters adds getters for all fields, including oneofs and weak fields when applicable. -func (g *Generator) generateGetters(mc *msgCtx, topLevelFields []topLevelField) { +func (g *Generator) generateGetters(mc *msgCtx, topLevelFields []topLevelField, proto3Resolver *proto3optional.Resolver) { for _, pf := range topLevelFields { - pf.getter(g, mc) - + pf.getter(g, mc, proto3Resolver) } } @@ -2826,6 +2838,8 @@ func (g *Generator) generateMessage(message *Descriptor) { mapFieldTypes := make(map[*descriptor.FieldDescriptorProto]string) // keep track of the map fields to be added later + proto3Resolver := proto3optional.NewResolver(g.file.proto3, message.Field) + for i, field := range message.Field { // Allocate the getter and the field at the same time so name // collisions create field/method consistent names. @@ -2839,11 +2853,11 @@ func (g *Generator) generateMessage(message *Descriptor) { ns := allocNames(base, "Get"+base) fieldName, fieldGetterName := ns[0], ns[1] - typename, wiretype := g.GoType(message, field) + typename, wiretype := g.GoType(message, field, proto3Resolver) jsonName := *field.Name jsonTag := jsonName + ",omitempty" repeatedNativeType := (!field.IsMessage() && !gogoproto.IsCustomType(field) && field.IsRepeated()) - if !gogoproto.IsNullable(field) && !repeatedNativeType { + if !gogoproto.IsNullable(field, proto3Resolver) && !repeatedNativeType { jsonTag = jsonName } gogoJsonTag := gogoproto.GetJsonTag(field) @@ -2860,7 +2874,8 @@ func (g *Generator) generateMessage(message *Descriptor) { fieldName = "" } - oneof := field.OneofIndex != nil && message.allowOneof() + oneof := message.allowOneof() && proto3Resolver.IsRealOneOf(field) + if oneof && oFields[*field.OneofIndex] == nil { odp := message.OneofDecl[int(*field.OneofIndex)] base := CamelCase(odp.GetName()) @@ -2899,19 +2914,19 @@ func (g *Generator) generateMessage(message *Descriptor) { if *field.Type == descriptor.FieldDescriptorProto_TYPE_MESSAGE { desc := g.ObjectNamed(field.GetTypeName()) if d, ok := desc.(*Descriptor); ok && d.GetOptions().GetMapEntry() { - m := g.GoMapType(d, field) + m := g.GoMapType(d, field, proto3Resolver) typename = m.GoType mapFieldTypes[field] = typename // record for the getter generation tag += fmt.Sprintf(" protobuf_key:%s protobuf_val:%s", m.KeyTag, m.ValueTag) } } - goTyp, _ := g.GoType(message, field) + goTyp, _ := g.GoType(message, field, proto3Resolver) fieldDeprecated := "" if field.GetOptions().GetDeprecated() { fieldDeprecated = deprecationComment } - dvalue := g.getterDefault(field, goTypeName, GoTypeToName(goTyp)) + dvalue := g.getterDefault(field, goTypeName, GoTypeToName(goTyp), proto3Resolver) if oneof { tname := goTypeName + "_" + fieldName // It is possible for this to collide with a message or enum @@ -3021,7 +3036,7 @@ func (g *Generator) generateMessage(message *Descriptor) { g.P() g.generateOneofDecls(mc, topLevelFields) g.P() - g.generateGetters(mc, topLevelFields) + g.generateGetters(mc, topLevelFields, proto3Resolver) g.P() g.generateSetters(mc, topLevelFields) g.P() @@ -3047,7 +3062,7 @@ func (g *Generator) generateMessage(message *Descriptor) { g.file.addExport(message, ms) for _, ext := range message.ext { - g.generateExtension(ext) + g.generateExtension(ext, proto3Resolver) } fullName := strings.Join(message.TypeName(), ".") @@ -3153,7 +3168,7 @@ func unescape(s string) string { return string(out) } -func (g *Generator) generateExtension(ext *ExtensionDescriptor) { +func (g *Generator) generateExtension(ext *ExtensionDescriptor, proto3Resolver *proto3optional.Resolver) { ccTypeName := ext.DescName() extObj := g.ObjectNamed(*ext.Extendee) @@ -3167,7 +3182,7 @@ func (g *Generator) generateExtension(ext *ExtensionDescriptor) { } extendedType := "*" + g.TypeName(extObj) // always use the original field := ext.FieldDescriptorProto - fieldType, wireType := g.GoType(ext.parent, field) + fieldType, wireType := g.GoType(ext.parent, field, proto3Resolver) tag := g.goTag(extDesc, field, wireType) g.RecordTypeUse(*ext.Extendee) if n := ext.FieldDescriptorProto.TypeName; n != nil { diff --git a/protoc-gen-gogo/generator/helper.go b/protoc-gen-gogo/generator/helper.go index 7091e281cb..2fa46c0ae1 100644 --- a/protoc-gen-gogo/generator/helper.go +++ b/protoc-gen-gogo/generator/helper.go @@ -38,6 +38,7 @@ import ( "github.com/gogo/protobuf/gogoproto" "github.com/gogo/protobuf/proto" + "github.com/gogo/protobuf/proto3optional" descriptor "github.com/gogo/protobuf/protoc-gen-gogo/descriptor" plugin "github.com/gogo/protobuf/protoc-gen-gogo/plugin" ) @@ -69,10 +70,10 @@ func (g *Generator) TypeNameByObject(typeName string) Object { return o } -func (g *Generator) OneOfTypeName(message *Descriptor, field *descriptor.FieldDescriptorProto) string { +func (g *Generator) OneOfTypeName(message *Descriptor, field *descriptor.FieldDescriptorProto, proto3Resolver *proto3optional.Resolver) string { typeName := message.TypeName() ccTypeName := CamelCaseSlice(typeName) - fieldName := g.GetOneOfFieldName(message, field) + fieldName := g.GetOneOfFieldName(message, field, proto3Resolver) tname := ccTypeName + "_" + fieldName // It is possible for this to collide with a message or enum // nested in this message. Check for collisions. @@ -164,8 +165,8 @@ func (this *importedPackage) Location() string { return this.importPrefix + this.pkg } -func (g *Generator) GetFieldName(message *Descriptor, field *descriptor.FieldDescriptorProto) string { - goTyp, _ := g.GoType(message, field) +func (g *Generator) GetFieldName(message *Descriptor, field *descriptor.FieldDescriptorProto, proto3Resolver *proto3optional.Resolver) string { + goTyp, _ := g.GoType(message, field, proto3Resolver) fieldname := CamelCase(*field.Name) if gogoproto.IsCustomName(field) { fieldname = gogoproto.GetCustomName(field) @@ -173,7 +174,7 @@ func (g *Generator) GetFieldName(message *Descriptor, field *descriptor.FieldDes if gogoproto.IsEmbed(field) { fieldname = EmbedFieldName(goTyp) } - if field.OneofIndex != nil { + if proto3Resolver.IsRealOneOf(field) { fieldname = message.OneofDecl[int(*field.OneofIndex)].GetName() fieldname = CamelCase(fieldname) } @@ -190,8 +191,8 @@ func (g *Generator) GetFieldName(message *Descriptor, field *descriptor.FieldDes return fieldname } -func (g *Generator) GetOneOfFieldName(message *Descriptor, field *descriptor.FieldDescriptorProto) string { - goTyp, _ := g.GoType(message, field) +func (g *Generator) GetOneOfFieldName(message *Descriptor, field *descriptor.FieldDescriptorProto, proto3Resolver *proto3optional.Resolver) string { + goTyp, _ := g.GoType(message, field, proto3Resolver) fieldname := CamelCase(*field.Name) if gogoproto.IsCustomName(field) { fieldname = gogoproto.GetCustomName(field) @@ -239,7 +240,7 @@ func (g *Generator) GetMapKeyField(field, keyField *descriptor.FieldDescriptorPr return keyField } -func (g *Generator) GetMapValueField(field, valField *descriptor.FieldDescriptorProto) *descriptor.FieldDescriptorProto { +func (g *Generator) GetMapValueField(field, valField *descriptor.FieldDescriptorProto, proto3Resolver *proto3optional.Resolver) *descriptor.FieldDescriptorProto { if gogoproto.IsCustomType(field) && gogoproto.IsCastValue(field) { g.Fail("cannot have a customtype and casttype: ", field.String()) } @@ -280,7 +281,7 @@ func (g *Generator) GetMapValueField(field, valField *descriptor.FieldDescriptor } } - nullable := gogoproto.IsNullable(field) + nullable := gogoproto.IsNullable(field, proto3Resolver) if err := proto.SetExtension(valField.Options, gogoproto.E_Nullable, &nullable); err != nil { g.Fail(err.Error()) } @@ -289,8 +290,8 @@ 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() || gogoproto.IsCustomType(mapField)) +func GoMapValueTypes(mapField, valueField *descriptor.FieldDescriptorProto, goValueType, goValueAliasType string, proto3Resolver *proto3optional.Resolver) (nullable bool, outGoType string, outGoAliasType string) { + nullable = gogoproto.IsNullable(mapField, proto3Resolver) && (valueField.IsMessage() || gogoproto.IsCustomType(mapField)) if nullable { // ensure the non-aliased Go value type is a pointer for consistency if strings.HasPrefix(goValueType, "*") { diff --git a/protoc-gen-gogo/plugin/plugin.pb.go b/protoc-gen-gogo/plugin/plugin.pb.go index 8c9cb58b0d..a87087a7a5 100644 --- a/protoc-gen-gogo/plugin/plugin.pb.go +++ b/protoc-gen-gogo/plugin/plugin.pb.go @@ -21,6 +21,47 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package +// Sync with code_generator.h. +type CodeGeneratorResponse_Feature int32 + +const ( + CodeGeneratorResponse_FEATURE_NONE CodeGeneratorResponse_Feature = 0 + CodeGeneratorResponse_FEATURE_PROTO3_OPTIONAL CodeGeneratorResponse_Feature = 1 +) + +var CodeGeneratorResponse_Feature_name = map[int32]string{ + 0: "FEATURE_NONE", + 1: "FEATURE_PROTO3_OPTIONAL", +} + +var CodeGeneratorResponse_Feature_value = map[string]int32{ + "FEATURE_NONE": 0, + "FEATURE_PROTO3_OPTIONAL": 1, +} + +func (x CodeGeneratorResponse_Feature) Enum() *CodeGeneratorResponse_Feature { + p := new(CodeGeneratorResponse_Feature) + *p = x + return p +} + +func (x CodeGeneratorResponse_Feature) String() string { + return proto.EnumName(CodeGeneratorResponse_Feature_name, int32(x)) +} + +func (x *CodeGeneratorResponse_Feature) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(CodeGeneratorResponse_Feature_value, data, "CodeGeneratorResponse_Feature") + if err != nil { + return err + } + *x = CodeGeneratorResponse_Feature(value) + return nil +} + +func (CodeGeneratorResponse_Feature) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_22a625af4bc1cc87, []int{2, 0} +} + // The version number of protocol compiler. type Version struct { Major *int32 `protobuf:"varint,1,opt,name=major" json:"major,omitempty"` @@ -178,7 +219,10 @@ type CodeGeneratorResponse struct { // problem in protoc itself -- such as the input CodeGeneratorRequest being // unparseable -- should be reported by writing a message to stderr and // exiting with a non-zero status code. - Error *string `protobuf:"bytes,1,opt,name=error" json:"error,omitempty"` + Error *string `protobuf:"bytes,1,opt,name=error" json:"error,omitempty"` + // A bitmask of supported features that the code generator supports. + // This is a bitwise "or" of values from the Feature enum. + SupportedFeatures *uint64 `protobuf:"varint,2,opt,name=supported_features,json=supportedFeatures" json:"supported_features,omitempty"` File []*CodeGeneratorResponse_File `protobuf:"bytes,15,rep,name=file" json:"file,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` @@ -216,6 +260,13 @@ func (m *CodeGeneratorResponse) GetError() string { return "" } +func (m *CodeGeneratorResponse) GetSupportedFeatures() uint64 { + if m != nil && m.SupportedFeatures != nil { + return *m.SupportedFeatures + } + return 0 +} + func (m *CodeGeneratorResponse) GetFile() []*CodeGeneratorResponse_File { if m != nil { return m.File @@ -243,7 +294,9 @@ type CodeGeneratorResponse_File struct { // produced by another code generator. The original generator may provide // insertion points by placing special annotations in the file that look // like: - // @@protoc_insertion_point(NAME) + // + // @@protoc_insertion_point(NAME) + // // The annotation can have arbitrary text before and after it on the line, // which allows it to be placed in a comment. NAME should be replaced with // an identifier naming the point -- this is what other generators will use @@ -255,7 +308,9 @@ type CodeGeneratorResponse_File struct { // // For example, the C++ code generator places the following line in the // .pb.h files that it generates: - // // @@protoc_insertion_point(namespace_scope) + // + // // @@protoc_insertion_point(namespace_scope) + // // This line appears within the scope of the file's package namespace, but // outside of any particular class. Another plugin can then specify the // insertion_point "namespace_scope" to generate additional classes or @@ -276,10 +331,14 @@ type CodeGeneratorResponse_File struct { // If |insertion_point| is present, |name| must also be present. InsertionPoint *string `protobuf:"bytes,2,opt,name=insertion_point,json=insertionPoint" json:"insertion_point,omitempty"` // The file contents. - Content *string `protobuf:"bytes,15,opt,name=content" json:"content,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + Content *string `protobuf:"bytes,15,opt,name=content" json:"content,omitempty"` + // Information describing the file content being inserted. If an insertion + // point is used, this information will be appropriately offset and inserted + // into the code generation metadata for the generated files. + GeneratedCodeInfo *descriptor.GeneratedCodeInfo `protobuf:"bytes,16,opt,name=generated_code_info,json=generatedCodeInfo" json:"generated_code_info,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *CodeGeneratorResponse_File) Reset() { *m = CodeGeneratorResponse_File{} } @@ -327,7 +386,15 @@ func (m *CodeGeneratorResponse_File) GetContent() string { return "" } +func (m *CodeGeneratorResponse_File) GetGeneratedCodeInfo() *descriptor.GeneratedCodeInfo { + if m != nil { + return m.GeneratedCodeInfo + } + return nil +} + func init() { + proto.RegisterEnum("google.protobuf.compiler.CodeGeneratorResponse_Feature", CodeGeneratorResponse_Feature_name, CodeGeneratorResponse_Feature_value) proto.RegisterType((*Version)(nil), "google.protobuf.compiler.Version") proto.RegisterType((*CodeGeneratorRequest)(nil), "google.protobuf.compiler.CodeGeneratorRequest") proto.RegisterType((*CodeGeneratorResponse)(nil), "google.protobuf.compiler.CodeGeneratorResponse") @@ -337,29 +404,36 @@ func init() { func init() { proto.RegisterFile("plugin.proto", fileDescriptor_22a625af4bc1cc87) } var fileDescriptor_22a625af4bc1cc87 = []byte{ - // 383 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x92, 0xcd, 0x6a, 0xd5, 0x40, - 0x14, 0xc7, 0x89, 0x37, 0xb5, 0xe4, 0xb4, 0x34, 0x65, 0xa8, 0x32, 0x94, 0x2e, 0xe2, 0x45, 0x30, - 0xab, 0x14, 0x8a, 0xe0, 0xbe, 0x15, 0x75, 0xe1, 0xe2, 0x32, 0x88, 0x0b, 0x41, 0x42, 0x4c, 0x4f, - 0xe2, 0x48, 0x32, 0x67, 0x9c, 0x99, 0x88, 0x4f, 0xea, 0x7b, 0xf8, 0x06, 0x32, 0x1f, 0xa9, 0x72, - 0xf1, 0xee, 0xe6, 0xff, 0x3b, 0xf3, 0x71, 0xce, 0x8f, 0x81, 0x53, 0x3d, 0x2d, 0xa3, 0x54, 0x8d, - 0x36, 0xe4, 0x88, 0xf1, 0x91, 0x68, 0x9c, 0x30, 0xa6, 0x2f, 0xcb, 0xd0, 0xf4, 0x34, 0x6b, 0x39, - 0xa1, 0xb9, 0xac, 0x62, 0xe5, 0x7a, 0xad, 0x5c, 0xdf, 0xa3, 0xed, 0x8d, 0xd4, 0x8e, 0x4c, 0xdc, - 0xbd, 0xed, 0xe1, 0xf8, 0x23, 0x1a, 0x2b, 0x49, 0xb1, 0x0b, 0x38, 0x9a, 0xbb, 0x6f, 0x64, 0x78, - 0x56, 0x65, 0xf5, 0x91, 0x88, 0x21, 0x50, 0xa9, 0xc8, 0xf0, 0x47, 0x89, 0xfa, 0xe0, 0xa9, 0xee, - 0x5c, 0xff, 0x95, 0x6f, 0x22, 0x0d, 0x81, 0x3d, 0x85, 0xc7, 0x76, 0x19, 0x06, 0xf9, 0x93, 0xe7, - 0x55, 0x56, 0x17, 0x22, 0xa5, 0xed, 0xef, 0x0c, 0x2e, 0xee, 0xe8, 0x1e, 0xdf, 0xa2, 0x42, 0xd3, - 0x39, 0x32, 0x02, 0xbf, 0x2f, 0x68, 0x1d, 0xab, 0xe1, 0x7c, 0x90, 0x13, 0xb6, 0x8e, 0xda, 0x31, - 0xd6, 0x90, 0x67, 0xd5, 0xa6, 0x2e, 0xc4, 0x99, 0xe7, 0x1f, 0x28, 0x9d, 0x40, 0x76, 0x05, 0x85, - 0xee, 0x4c, 0x37, 0xa3, 0xc3, 0xd8, 0x4a, 0x21, 0xfe, 0x02, 0x76, 0x07, 0x10, 0xc6, 0x69, 0xfd, - 0x29, 0x5e, 0x56, 0x9b, 0xfa, 0xe4, 0xe6, 0x79, 0xb3, 0xaf, 0xe5, 0x8d, 0x9c, 0xf0, 0xf5, 0x83, - 0x80, 0x9d, 0xc7, 0xa2, 0x08, 0x55, 0x5f, 0x61, 0xef, 0xe1, 0x7c, 0x15, 0xd7, 0xfe, 0x88, 0x4e, - 0xc2, 0x78, 0x27, 0x37, 0xcf, 0x9a, 0x43, 0x86, 0x9b, 0x24, 0x4f, 0x94, 0x2b, 0x49, 0x60, 0xfb, - 0x2b, 0x83, 0x27, 0x7b, 0x33, 0x5b, 0x4d, 0xca, 0xa2, 0x77, 0x87, 0xc6, 0x24, 0xcf, 0x85, 0x88, - 0x81, 0xbd, 0x83, 0xfc, 0x9f, 0xe6, 0x5f, 0x1e, 0x7e, 0xf1, 0xbf, 0x97, 0x86, 0xd9, 0x44, 0xb8, - 0xe1, 0xf2, 0x33, 0xe4, 0x61, 0x1e, 0x06, 0xb9, 0xea, 0x66, 0x4c, 0xcf, 0x84, 0x35, 0x7b, 0x01, - 0xa5, 0x54, 0x16, 0x8d, 0x93, 0xa4, 0x5a, 0x4d, 0x52, 0xb9, 0x24, 0xf3, 0xec, 0x01, 0xef, 0x3c, - 0x65, 0x1c, 0x8e, 0x7b, 0x52, 0x0e, 0x95, 0xe3, 0x65, 0xd8, 0xb0, 0xc6, 0xdb, 0x57, 0x70, 0xd5, - 0xd3, 0x7c, 0xb0, 0xbf, 0xdb, 0xd3, 0x5d, 0xf8, 0x9b, 0x41, 0xaf, 0xfd, 0x54, 0xc4, 0x9f, 0xda, - 0x8e, 0xf4, 0x27, 0x00, 0x00, 0xff, 0xff, 0x7a, 0x72, 0x3d, 0x18, 0xb5, 0x02, 0x00, 0x00, + // 488 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x93, 0xd1, 0x6e, 0xd3, 0x30, + 0x14, 0x86, 0x09, 0xed, 0xa8, 0x72, 0x56, 0xad, 0x99, 0x19, 0x10, 0x8d, 0x5d, 0x94, 0x0a, 0x89, + 0xde, 0xd0, 0x49, 0x03, 0x09, 0x6e, 0xb7, 0xd1, 0xc2, 0xa4, 0xa9, 0xad, 0xac, 0xc2, 0x05, 0x37, + 0x56, 0x48, 0x4e, 0x82, 0x51, 0xeb, 0x13, 0x1c, 0x07, 0xf1, 0x20, 0xbc, 0x08, 0x8f, 0xc6, 0x1b, + 0xa0, 0xd8, 0x4e, 0x41, 0x85, 0xde, 0xf5, 0xff, 0xfe, 0xa4, 0x3a, 0xe7, 0x73, 0x0c, 0xfd, 0x72, + 0x5d, 0x17, 0x52, 0x4d, 0x4a, 0x4d, 0x86, 0x58, 0x5c, 0x10, 0x15, 0x6b, 0x74, 0xe9, 0x53, 0x9d, + 0x4f, 0x52, 0xda, 0x94, 0x72, 0x8d, 0xfa, 0x74, 0xe8, 0x9a, 0xf3, 0xb6, 0x39, 0xcf, 0xb0, 0x4a, + 0xb5, 0x2c, 0x0d, 0x69, 0xf7, 0xf4, 0x28, 0x85, 0xde, 0x07, 0xd4, 0x95, 0x24, 0xc5, 0x4e, 0xe0, + 0x60, 0x93, 0x7c, 0x21, 0x1d, 0x07, 0xc3, 0x60, 0x7c, 0xc0, 0x5d, 0xb0, 0x54, 0x2a, 0xd2, 0xf1, + 0x5d, 0x4f, 0x9b, 0xd0, 0xd0, 0x32, 0x31, 0xe9, 0xe7, 0xb8, 0xe3, 0xa8, 0x0d, 0xec, 0x21, 0xdc, + 0xab, 0xea, 0x3c, 0x97, 0xdf, 0xe3, 0xee, 0x30, 0x18, 0x87, 0xdc, 0xa7, 0xd1, 0xaf, 0x00, 0x4e, + 0xae, 0x29, 0xc3, 0xb7, 0xa8, 0x50, 0x27, 0x86, 0x34, 0xc7, 0xaf, 0x35, 0x56, 0x86, 0x8d, 0x21, + 0xca, 0xe5, 0x1a, 0x85, 0x21, 0x51, 0xb8, 0x0e, 0xe3, 0x60, 0xd8, 0x19, 0x87, 0xfc, 0xa8, 0xe1, + 0x2b, 0xf2, 0x6f, 0x20, 0x3b, 0x83, 0xb0, 0x4c, 0x74, 0xb2, 0x41, 0x83, 0x6e, 0x94, 0x90, 0xff, + 0x01, 0xec, 0x1a, 0xc0, 0xae, 0x23, 0x9a, 0xb7, 0xe2, 0xc1, 0xb0, 0x33, 0x3e, 0xbc, 0x78, 0x3a, + 0xd9, 0xd5, 0x32, 0x93, 0x6b, 0x7c, 0xb3, 0x15, 0xb0, 0x6c, 0x30, 0x0f, 0x6d, 0xdb, 0x34, 0xec, + 0x16, 0xa2, 0x56, 0x9c, 0xf8, 0xe6, 0x9c, 0xd8, 0xf5, 0x0e, 0x2f, 0x9e, 0x4c, 0xf6, 0x19, 0x9e, + 0x78, 0x79, 0x7c, 0xd0, 0x12, 0x0f, 0x46, 0x3f, 0x3a, 0xf0, 0x60, 0x67, 0xe7, 0xaa, 0x24, 0x55, + 0x61, 0xe3, 0x0e, 0xb5, 0xf6, 0x9e, 0x43, 0xee, 0x02, 0x7b, 0x0e, 0xac, 0xaa, 0xcb, 0x92, 0xb4, + 0xc1, 0x4c, 0xe4, 0x98, 0x98, 0x5a, 0x63, 0x65, 0x37, 0xed, 0xf2, 0xe3, 0x6d, 0x33, 0xf3, 0x05, + 0x7b, 0x07, 0xdd, 0xbf, 0x76, 0x7d, 0xb9, 0x7f, 0xc0, 0xff, 0xce, 0x60, 0x55, 0x70, 0xfb, 0x0f, + 0xa7, 0x3f, 0x03, 0xe8, 0xda, 0xfd, 0x19, 0x74, 0x55, 0xb2, 0x41, 0x3f, 0x96, 0xfd, 0xcd, 0x9e, + 0xc1, 0x40, 0xaa, 0x0a, 0xb5, 0x91, 0xa4, 0x44, 0x49, 0x52, 0x19, 0x2f, 0xff, 0x68, 0x8b, 0x97, + 0x0d, 0x65, 0x31, 0xf4, 0x52, 0x52, 0x06, 0x95, 0x89, 0x07, 0xf6, 0x81, 0x36, 0x32, 0x0e, 0xf7, + 0xdb, 0xb3, 0xcd, 0x44, 0x4a, 0x19, 0x0a, 0xa9, 0x72, 0x8a, 0x23, 0x6b, 0x76, 0xf4, 0xcf, 0xe0, + 0xed, 0x89, 0x67, 0xcd, 0xe0, 0x37, 0x2a, 0x27, 0x7e, 0x5c, 0xec, 0xa2, 0xd1, 0x6b, 0xe8, 0x79, + 0x13, 0x2c, 0x82, 0xfe, 0x6c, 0x7a, 0xb9, 0x7a, 0xcf, 0xa7, 0x62, 0xbe, 0x98, 0x4f, 0xa3, 0x3b, + 0xec, 0x31, 0x3c, 0x6a, 0xc9, 0x92, 0x2f, 0x56, 0x8b, 0x17, 0x62, 0xb1, 0x5c, 0xdd, 0x2c, 0xe6, + 0x97, 0xb7, 0x51, 0x70, 0xf5, 0x0a, 0xce, 0x52, 0xda, 0xec, 0xd5, 0x75, 0xd5, 0x5f, 0xda, 0x9b, + 0x65, 0x3f, 0x8e, 0xea, 0x63, 0xe8, 0xee, 0x99, 0x28, 0xe8, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x0f, 0x81, 0xd0, 0x5b, 0x73, 0x03, 0x00, 0x00, }