You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
631 lines
18 KiB
631 lines
18 KiB
// Protocol Buffers for Go with Gadgets |
|
// |
|
// Copyright (c) 2013, The GoGo Authors. All rights reserved. |
|
// http://github.com/gogo/protobuf |
|
// |
|
// Redistribution and use in source and binary forms, with or without |
|
// modification, are permitted provided that the following conditions are |
|
// met: |
|
// |
|
// * Redistributions of source code must retain the above copyright |
|
// notice, this list of conditions and the following disclaimer. |
|
// * Redistributions in binary form must reproduce the above |
|
// copyright notice, this list of conditions and the following disclaimer |
|
// in the documentation and/or other materials provided with the |
|
// distribution. |
|
// |
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
|
|
/* |
|
The equal plugin generates an Equal and a VerboseEqual method for each message. |
|
These equal methods are quite obvious. |
|
The only difference is that VerboseEqual returns a non nil error if it is not equal. |
|
This error contains more detail on exactly which part of the message was not equal to the other message. |
|
The idea is that this is useful for debugging. |
|
|
|
Equal is enabled using the following extensions: |
|
|
|
- equal |
|
- equal_all |
|
|
|
While VerboseEqual is enable dusing the following extensions: |
|
|
|
- verbose_equal |
|
- verbose_equal_all |
|
|
|
The equal plugin also generates a test given it is enabled using one of the following extensions: |
|
|
|
- testgen |
|
- testgen_all |
|
|
|
Let us look at: |
|
|
|
github.com/gogo/protobuf/test/example/example.proto |
|
|
|
Btw all the output can be seen at: |
|
|
|
github.com/gogo/protobuf/test/example/* |
|
|
|
The following message: |
|
|
|
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]; |
|
} |
|
|
|
given to the equal plugin, will generate the following code: |
|
|
|
func (this *B) VerboseEqual(that interface{}) error { |
|
if that == nil { |
|
if this == nil { |
|
return nil |
|
} |
|
return fmt2.Errorf("that == nil && this != nil") |
|
} |
|
|
|
that1, ok := that.(*B) |
|
if !ok { |
|
return fmt2.Errorf("that is not of type *B") |
|
} |
|
if that1 == nil { |
|
if this == nil { |
|
return nil |
|
} |
|
return fmt2.Errorf("that is type *B but is nil && this != nil") |
|
} else if this == nil { |
|
return fmt2.Errorf("that is type *B but is not nil && this == nil") |
|
} |
|
if !this.A.Equal(&that1.A) { |
|
return fmt2.Errorf("A this(%v) Not Equal that(%v)", this.A, that1.A) |
|
} |
|
if len(this.G) != len(that1.G) { |
|
return fmt2.Errorf("G this(%v) Not Equal that(%v)", len(this.G), len(that1.G)) |
|
} |
|
for i := range this.G { |
|
if !this.G[i].Equal(that1.G[i]) { |
|
return fmt2.Errorf("G this[%v](%v) Not Equal that[%v](%v)", i, this.G[i], i, that1.G[i]) |
|
} |
|
} |
|
if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) { |
|
return fmt2.Errorf("XXX_unrecognized this(%v) Not Equal that(%v)", this.XXX_unrecognized, that1.XXX_unrecognized) |
|
} |
|
return nil |
|
} |
|
|
|
func (this *B) Equal(that interface{}) bool { |
|
if that == nil { |
|
return this == nil |
|
} |
|
|
|
that1, ok := that.(*B) |
|
if !ok { |
|
return false |
|
} |
|
if that1 == nil { |
|
return this == nil |
|
} else if this == nil { |
|
return false |
|
} |
|
if !this.A.Equal(&that1.A) { |
|
return false |
|
} |
|
if len(this.G) != len(that1.G) { |
|
return false |
|
} |
|
for i := range this.G { |
|
if !this.G[i].Equal(that1.G[i]) { |
|
return false |
|
} |
|
} |
|
if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) { |
|
return false |
|
} |
|
return true |
|
} |
|
|
|
and the following test code: |
|
|
|
func TestBVerboseEqual(t *testing8.T) { |
|
popr := math_rand8.New(math_rand8.NewSource(time8.Now().UnixNano())) |
|
p := NewPopulatedB(popr, false) |
|
dAtA, err := github_com_gogo_protobuf_proto2.Marshal(p) |
|
if err != nil { |
|
panic(err) |
|
} |
|
msg := &B{} |
|
if err := github_com_gogo_protobuf_proto2.Unmarshal(dAtA, msg); err != nil { |
|
panic(err) |
|
} |
|
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" |
|
descriptor "github.com/gogo/protobuf/protoc-gen-gogo/descriptor" |
|
"github.com/gogo/protobuf/protoc-gen-gogo/generator" |
|
"github.com/gogo/protobuf/vanity" |
|
) |
|
|
|
type plugin struct { |
|
*generator.Generator |
|
generator.PluginImports |
|
fmtPkg generator.Single |
|
bytesPkg generator.Single |
|
protoPkg generator.Single |
|
} |
|
|
|
func NewPlugin() *plugin { |
|
return &plugin{} |
|
} |
|
|
|
func (p *plugin) Name() string { |
|
return "equal" |
|
} |
|
|
|
func (p *plugin) Init(g *generator.Generator) { |
|
p.Generator = g |
|
} |
|
|
|
func (p *plugin) Generate(file *generator.FileDescriptor) { |
|
p.PluginImports = generator.NewPluginImports(p.Generator) |
|
p.fmtPkg = p.NewImport("fmt") |
|
p.bytesPkg = p.NewImport("bytes") |
|
p.protoPkg = p.NewImport("github.com/gogo/protobuf/proto") |
|
|
|
for _, msg := range file.Messages() { |
|
if msg.DescriptorProto.GetOptions().GetMapEntry() { |
|
continue |
|
} |
|
if gogoproto.HasVerboseEqual(file.FileDescriptorProto, msg.DescriptorProto) { |
|
p.generateMessage(file, msg, true) |
|
} |
|
if gogoproto.HasEqual(file.FileDescriptorProto, msg.DescriptorProto) { |
|
p.generateMessage(file, msg, false) |
|
} |
|
} |
|
} |
|
|
|
func (p *plugin) generateNullableField(fieldname string, verbose bool) { |
|
p.P(`if this.`, fieldname, ` != nil && that1.`, fieldname, ` != nil {`) |
|
p.In() |
|
p.P(`if *this.`, fieldname, ` != *that1.`, fieldname, `{`) |
|
p.In() |
|
if verbose { |
|
p.P(`return `, p.fmtPkg.Use(), `.Errorf("`, fieldname, ` this(%v) Not Equal that(%v)", *this.`, fieldname, `, *that1.`, fieldname, `)`) |
|
} else { |
|
p.P(`return false`) |
|
} |
|
p.Out() |
|
p.P(`}`) |
|
p.Out() |
|
p.P(`} else if this.`, fieldname, ` != nil {`) |
|
p.In() |
|
if verbose { |
|
p.P(`return `, p.fmtPkg.Use(), `.Errorf("this.`, fieldname, ` == nil && that.`, fieldname, ` != nil")`) |
|
} else { |
|
p.P(`return false`) |
|
} |
|
p.Out() |
|
p.P(`} else if that1.`, fieldname, ` != nil {`) |
|
} |
|
|
|
func (p *plugin) generateMsgNullAndTypeCheck(ccTypeName string, verbose bool) { |
|
p.P(`if that == nil {`) |
|
p.In() |
|
if verbose { |
|
p.P(`if this == nil {`) |
|
p.In() |
|
p.P(`return nil`) |
|
p.Out() |
|
p.P(`}`) |
|
p.P(`return `, p.fmtPkg.Use(), `.Errorf("that == nil && this != nil")`) |
|
} else { |
|
p.P(`return this == nil`) |
|
} |
|
p.Out() |
|
p.P(`}`) |
|
p.P(``) |
|
p.P(`that1, ok := that.(*`, ccTypeName, `)`) |
|
p.P(`if !ok {`) |
|
p.In() |
|
p.P(`that2, ok := that.(`, ccTypeName, `)`) |
|
p.P(`if ok {`) |
|
p.In() |
|
p.P(`that1 = &that2`) |
|
p.Out() |
|
p.P(`} else {`) |
|
p.In() |
|
if verbose { |
|
p.P(`return `, p.fmtPkg.Use(), `.Errorf("that is not of type *`, ccTypeName, `")`) |
|
} else { |
|
p.P(`return false`) |
|
} |
|
p.Out() |
|
p.P(`}`) |
|
p.Out() |
|
p.P(`}`) |
|
p.P(`if that1 == nil {`) |
|
p.In() |
|
if verbose { |
|
p.P(`if this == nil {`) |
|
p.In() |
|
p.P(`return nil`) |
|
p.Out() |
|
p.P(`}`) |
|
p.P(`return `, p.fmtPkg.Use(), `.Errorf("that is type *`, ccTypeName, ` but is nil && this != nil")`) |
|
} else { |
|
p.P(`return this == nil`) |
|
} |
|
p.Out() |
|
p.P(`} else if this == nil {`) |
|
p.In() |
|
if verbose { |
|
p.P(`return `, p.fmtPkg.Use(), `.Errorf("that is type *`, ccTypeName, ` but is not nil && this == nil")`) |
|
} else { |
|
p.P(`return false`) |
|
} |
|
p.Out() |
|
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) |
|
repeated := field.IsRepeated() |
|
ctype := gogoproto.IsCustomType(field) |
|
nullable := gogoproto.IsNullable(field) |
|
isDuration := gogoproto.IsStdDuration(field) |
|
isTimestamp := gogoproto.IsStdTime(field) |
|
// oneof := field.OneofIndex != nil |
|
if !repeated { |
|
if ctype || isTimestamp { |
|
if nullable { |
|
p.P(`if that1.`, fieldname, ` == nil {`) |
|
p.In() |
|
p.P(`if this.`, fieldname, ` != nil {`) |
|
p.In() |
|
if verbose { |
|
p.P(`return `, p.fmtPkg.Use(), `.Errorf("this.`, fieldname, ` != nil && that1.`, fieldname, ` == nil")`) |
|
} else { |
|
p.P(`return false`) |
|
} |
|
p.Out() |
|
p.P(`}`) |
|
p.Out() |
|
p.P(`} else if !this.`, fieldname, `.Equal(*that1.`, fieldname, `) {`) |
|
} else { |
|
p.P(`if !this.`, fieldname, `.Equal(that1.`, fieldname, `) {`) |
|
} |
|
p.In() |
|
if verbose { |
|
p.P(`return `, p.fmtPkg.Use(), `.Errorf("`, fieldname, ` this(%v) Not Equal that(%v)", this.`, fieldname, `, that1.`, fieldname, `)`) |
|
} else { |
|
p.P(`return false`) |
|
} |
|
p.Out() |
|
p.P(`}`) |
|
} else if isDuration { |
|
if nullable { |
|
p.generateNullableField(fieldname, verbose) |
|
} else { |
|
p.P(`if this.`, fieldname, ` != that1.`, fieldname, `{`) |
|
} |
|
p.In() |
|
if verbose { |
|
p.P(`return `, p.fmtPkg.Use(), `.Errorf("`, fieldname, ` this(%v) Not Equal that(%v)", this.`, fieldname, `, that1.`, fieldname, `)`) |
|
} else { |
|
p.P(`return false`) |
|
} |
|
p.Out() |
|
p.P(`}`) |
|
} else { |
|
if field.IsMessage() || p.IsGroup(field) { |
|
if nullable { |
|
p.P(`if !this.`, fieldname, `.Equal(that1.`, fieldname, `) {`) |
|
} else { |
|
p.P(`if !this.`, fieldname, `.Equal(&that1.`, fieldname, `) {`) |
|
} |
|
} else if field.IsBytes() { |
|
p.P(`if !`, p.bytesPkg.Use(), `.Equal(this.`, fieldname, `, that1.`, fieldname, `) {`) |
|
} else if field.IsString() { |
|
if nullable && !proto3 { |
|
p.generateNullableField(fieldname, verbose) |
|
} else { |
|
p.P(`if this.`, fieldname, ` != that1.`, fieldname, `{`) |
|
} |
|
} else { |
|
if nullable && !proto3 { |
|
p.generateNullableField(fieldname, verbose) |
|
} else { |
|
p.P(`if this.`, fieldname, ` != that1.`, fieldname, `{`) |
|
} |
|
} |
|
p.In() |
|
if verbose { |
|
p.P(`return `, p.fmtPkg.Use(), `.Errorf("`, fieldname, ` this(%v) Not Equal that(%v)", this.`, fieldname, `, that1.`, fieldname, `)`) |
|
} else { |
|
p.P(`return false`) |
|
} |
|
p.Out() |
|
p.P(`}`) |
|
} |
|
} else { |
|
p.P(`if len(this.`, fieldname, `) != len(that1.`, fieldname, `) {`) |
|
p.In() |
|
if verbose { |
|
p.P(`return `, p.fmtPkg.Use(), `.Errorf("`, fieldname, ` this(%v) Not Equal that(%v)", len(this.`, fieldname, `), len(that1.`, fieldname, `))`) |
|
} else { |
|
p.P(`return false`) |
|
} |
|
p.Out() |
|
p.P(`}`) |
|
p.P(`for i := range this.`, fieldname, ` {`) |
|
p.In() |
|
if ctype && !p.IsMap(field) { |
|
p.P(`if !this.`, fieldname, `[i].Equal(that1.`, fieldname, `[i]) {`) |
|
} else if isTimestamp { |
|
if nullable { |
|
p.P(`if !this.`, fieldname, `[i].Equal(*that1.`, fieldname, `[i]) {`) |
|
} else { |
|
p.P(`if !this.`, fieldname, `[i].Equal(that1.`, fieldname, `[i]) {`) |
|
} |
|
} else if isDuration { |
|
if nullable { |
|
p.P(`if dthis, dthat := this.`, fieldname, `[i], that1.`, fieldname, `[i]; (dthis != nil && dthat != nil && *dthis != *dthat) || (dthis != nil && dthat == nil) || (dthis == nil && dthat != nil) {`) |
|
} else { |
|
p.P(`if this.`, fieldname, `[i] != that1.`, fieldname, `[i] {`) |
|
} |
|
} 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) |
|
|
|
mapValue := m.ValueAliasField |
|
if mapValue.IsMessage() || p.IsGroup(mapValue) { |
|
if nullable && valuegoTyp == valuegoAliasTyp { |
|
p.P(`if !this.`, fieldname, `[i].Equal(that1.`, fieldname, `[i]) {`) |
|
} else { |
|
// Equal() has a pointer receiver, but map value is a value type |
|
a := `this.` + fieldname + `[i]` |
|
b := `that1.` + fieldname + `[i]` |
|
if valuegoTyp != valuegoAliasTyp { |
|
// cast back to the type that has the generated methods on it |
|
a = `(` + valuegoTyp + `)(` + a + `)` |
|
b = `(` + valuegoTyp + `)(` + b + `)` |
|
} |
|
p.P(`a := `, a) |
|
p.P(`b := `, b) |
|
if nullable { |
|
p.P(`if !a.Equal(b) {`) |
|
} else { |
|
p.P(`if !(&a).Equal(&b) {`) |
|
} |
|
} |
|
} else if mapValue.IsBytes() { |
|
if ctype { |
|
if nullable { |
|
p.P(`if !this.`, fieldname, `[i].Equal(*that1.`, fieldname, `[i]) { //nullable`) |
|
} else { |
|
p.P(`if !this.`, fieldname, `[i].Equal(that1.`, fieldname, `[i]) { //not nullable`) |
|
} |
|
} else { |
|
p.P(`if !`, p.bytesPkg.Use(), `.Equal(this.`, fieldname, `[i], that1.`, fieldname, `[i]) {`) |
|
} |
|
} else if mapValue.IsString() { |
|
p.P(`if this.`, fieldname, `[i] != that1.`, fieldname, `[i] {`) |
|
} else { |
|
p.P(`if this.`, fieldname, `[i] != that1.`, fieldname, `[i] {`) |
|
} |
|
} else if field.IsMessage() || p.IsGroup(field) { |
|
if nullable { |
|
p.P(`if !this.`, fieldname, `[i].Equal(that1.`, fieldname, `[i]) {`) |
|
} else { |
|
p.P(`if !this.`, fieldname, `[i].Equal(&that1.`, fieldname, `[i]) {`) |
|
} |
|
} else if field.IsBytes() { |
|
p.P(`if !`, p.bytesPkg.Use(), `.Equal(this.`, fieldname, `[i], that1.`, fieldname, `[i]) {`) |
|
} else if field.IsString() { |
|
p.P(`if this.`, fieldname, `[i] != that1.`, fieldname, `[i] {`) |
|
} else { |
|
p.P(`if this.`, fieldname, `[i] != that1.`, fieldname, `[i] {`) |
|
} |
|
} |
|
p.In() |
|
if verbose { |
|
p.P(`return `, p.fmtPkg.Use(), `.Errorf("`, fieldname, ` this[%v](%v) Not Equal that[%v](%v)", i, this.`, fieldname, `[i], i, that1.`, fieldname, `[i])`) |
|
} else { |
|
p.P(`return false`) |
|
} |
|
p.Out() |
|
p.P(`}`) |
|
p.Out() |
|
p.P(`}`) |
|
} |
|
} |
|
|
|
func (p *plugin) generateMessage(file *generator.FileDescriptor, message *generator.Descriptor, verbose bool) { |
|
ccTypeName := generator.CamelCaseSlice(message.TypeName()) |
|
if verbose { |
|
p.P(`func (this *`, ccTypeName, `) VerboseEqual(that interface{}) error {`) |
|
} else { |
|
p.P(`func (this *`, ccTypeName, `) Equal(that interface{}) bool {`) |
|
} |
|
p.In() |
|
p.generateMsgNullAndTypeCheck(ccTypeName, verbose) |
|
oneofs := make(map[string]struct{}) |
|
|
|
for _, field := range message.Field { |
|
oneof := field.OneofIndex != nil |
|
if oneof { |
|
fieldname := p.GetFieldName(message, field) |
|
if _, ok := oneofs[fieldname]; ok { |
|
continue |
|
} else { |
|
oneofs[fieldname] = struct{}{} |
|
} |
|
p.P(`if that1.`, fieldname, ` == nil {`) |
|
p.In() |
|
p.P(`if this.`, fieldname, ` != nil {`) |
|
p.In() |
|
if verbose { |
|
p.P(`return `, p.fmtPkg.Use(), `.Errorf("this.`, fieldname, ` != nil && that1.`, fieldname, ` == nil")`) |
|
} else { |
|
p.P(`return false`) |
|
} |
|
p.Out() |
|
p.P(`}`) |
|
p.Out() |
|
p.P(`} else if this.`, fieldname, ` == nil {`) |
|
p.In() |
|
if verbose { |
|
p.P(`return `, p.fmtPkg.Use(), `.Errorf("this.`, fieldname, ` == nil && that1.`, fieldname, ` != nil")`) |
|
} else { |
|
p.P(`return false`) |
|
} |
|
p.Out() |
|
if verbose { |
|
p.P(`} else if err := this.`, fieldname, `.VerboseEqual(that1.`, fieldname, `); err != nil {`) |
|
} else { |
|
p.P(`} else if !this.`, fieldname, `.Equal(that1.`, fieldname, `) {`) |
|
} |
|
p.In() |
|
if verbose { |
|
p.P(`return err`) |
|
} else { |
|
p.P(`return false`) |
|
} |
|
p.Out() |
|
p.P(`}`) |
|
} else { |
|
p.generateField(file, message, field, verbose) |
|
} |
|
} |
|
if message.DescriptorProto.HasExtension() { |
|
if gogoproto.HasExtensionsMap(file.FileDescriptorProto, message.DescriptorProto) { |
|
fieldname := "XXX_InternalExtensions" |
|
p.P(`thismap := `, p.protoPkg.Use(), `.GetUnsafeExtensionsMap(this)`) |
|
p.P(`thatmap := `, p.protoPkg.Use(), `.GetUnsafeExtensionsMap(that1)`) |
|
p.P(`for k, v := range thismap {`) |
|
p.In() |
|
p.P(`if v2, ok := thatmap[k]; ok {`) |
|
p.In() |
|
p.P(`if !v.Equal(&v2) {`) |
|
p.In() |
|
if verbose { |
|
p.P(`return `, p.fmtPkg.Use(), `.Errorf("`, fieldname, ` this[%v](%v) Not Equal that[%v](%v)", k, thismap[k], k, thatmap[k])`) |
|
} else { |
|
p.P(`return false`) |
|
} |
|
p.Out() |
|
p.P(`}`) |
|
p.Out() |
|
p.P(`} else {`) |
|
p.In() |
|
if verbose { |
|
p.P(`return `, p.fmtPkg.Use(), `.Errorf("`, fieldname, `[%v] Not In that", k)`) |
|
} else { |
|
p.P(`return false`) |
|
} |
|
p.Out() |
|
p.P(`}`) |
|
p.Out() |
|
p.P(`}`) |
|
|
|
p.P(`for k, _ := range thatmap {`) |
|
p.In() |
|
p.P(`if _, ok := thismap[k]; !ok {`) |
|
p.In() |
|
if verbose { |
|
p.P(`return `, p.fmtPkg.Use(), `.Errorf("`, fieldname, `[%v] Not In this", k)`) |
|
} else { |
|
p.P(`return false`) |
|
} |
|
p.Out() |
|
p.P(`}`) |
|
p.Out() |
|
p.P(`}`) |
|
} else { |
|
fieldname := "XXX_extensions" |
|
p.P(`if !`, p.bytesPkg.Use(), `.Equal(this.`, fieldname, `, that1.`, fieldname, `) {`) |
|
p.In() |
|
if verbose { |
|
p.P(`return `, p.fmtPkg.Use(), `.Errorf("`, fieldname, ` this(%v) Not Equal that(%v)", this.`, fieldname, `, that1.`, fieldname, `)`) |
|
} else { |
|
p.P(`return false`) |
|
} |
|
p.Out() |
|
p.P(`}`) |
|
} |
|
} |
|
if gogoproto.HasUnrecognized(file.FileDescriptorProto, message.DescriptorProto) { |
|
fieldname := "XXX_unrecognized" |
|
p.P(`if !`, p.bytesPkg.Use(), `.Equal(this.`, fieldname, `, that1.`, fieldname, `) {`) |
|
p.In() |
|
if verbose { |
|
p.P(`return `, p.fmtPkg.Use(), `.Errorf("`, fieldname, ` this(%v) Not Equal that(%v)", this.`, fieldname, `, that1.`, fieldname, `)`) |
|
} else { |
|
p.P(`return false`) |
|
} |
|
p.Out() |
|
p.P(`}`) |
|
} |
|
if verbose { |
|
p.P(`return nil`) |
|
} else { |
|
p.P(`return true`) |
|
} |
|
p.Out() |
|
p.P(`}`) |
|
|
|
//Generate Equal methods for oneof fields |
|
m := proto.Clone(message.DescriptorProto).(*descriptor.DescriptorProto) |
|
for _, field := range m.Field { |
|
oneof := field.OneofIndex != nil |
|
if !oneof { |
|
continue |
|
} |
|
ccTypeName := p.OneOfTypeName(message, field) |
|
if verbose { |
|
p.P(`func (this *`, ccTypeName, `) VerboseEqual(that interface{}) error {`) |
|
} else { |
|
p.P(`func (this *`, ccTypeName, `) Equal(that interface{}) bool {`) |
|
} |
|
p.In() |
|
|
|
p.generateMsgNullAndTypeCheck(ccTypeName, verbose) |
|
vanity.TurnOffNullableForNativeTypes(field) |
|
p.generateField(file, message, field, verbose) |
|
|
|
if verbose { |
|
p.P(`return nil`) |
|
} else { |
|
p.P(`return true`) |
|
} |
|
p.Out() |
|
p.P(`}`) |
|
} |
|
} |
|
|
|
func init() { |
|
generator.RegisterPlugin(NewPlugin()) |
|
}
|
|
|