...

Source file src/github.com/gogo/protobuf/plugin/equal/equal.go

Documentation: github.com/gogo/protobuf/plugin/equal

     1  // Protocol Buffers for Go with Gadgets
     2  //
     3  // Copyright (c) 2013, The GoGo Authors. All rights reserved.
     4  // http://github.com/gogo/protobuf
     5  //
     6  // Redistribution and use in source and binary forms, with or without
     7  // modification, are permitted provided that the following conditions are
     8  // met:
     9  //
    10  //     * Redistributions of source code must retain the above copyright
    11  // notice, this list of conditions and the following disclaimer.
    12  //     * Redistributions in binary form must reproduce the above
    13  // copyright notice, this list of conditions and the following disclaimer
    14  // in the documentation and/or other materials provided with the
    15  // distribution.
    16  //
    17  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    18  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    19  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    20  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    21  // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    22  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    23  // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    24  // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    25  // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    26  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    27  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    28  
    29  /*
    30  The equal plugin generates an Equal and a VerboseEqual method for each message.
    31  These equal methods are quite obvious.
    32  The only difference is that VerboseEqual returns a non nil error if it is not equal.
    33  This error contains more detail on exactly which part of the message was not equal to the other message.
    34  The idea is that this is useful for debugging.
    35  
    36  Equal is enabled using the following extensions:
    37  
    38    - equal
    39    - equal_all
    40  
    41  While VerboseEqual is enable dusing the following extensions:
    42  
    43    - verbose_equal
    44    - verbose_equal_all
    45  
    46  The equal plugin also generates a test given it is enabled using one of the following extensions:
    47  
    48    - testgen
    49    - testgen_all
    50  
    51  Let us look at:
    52  
    53    github.com/gogo/protobuf/test/example/example.proto
    54  
    55  Btw all the output can be seen at:
    56  
    57    github.com/gogo/protobuf/test/example/*
    58  
    59  The following message:
    60  
    61    option (gogoproto.equal_all) = true;
    62    option (gogoproto.verbose_equal_all) = true;
    63  
    64    message B {
    65  	optional A A = 1 [(gogoproto.nullable) = false, (gogoproto.embed) = true];
    66  	repeated bytes G = 2 [(gogoproto.customtype) = "github.com/gogo/protobuf/test/custom.Uint128", (gogoproto.nullable) = false];
    67    }
    68  
    69  given to the equal plugin, will generate the following code:
    70  
    71  	func (this *B) VerboseEqual(that interface{}) error {
    72  		if that == nil {
    73  			if this == nil {
    74  				return nil
    75  			}
    76  			return fmt2.Errorf("that == nil && this != nil")
    77  		}
    78  
    79  		that1, ok := that.(*B)
    80  		if !ok {
    81  			return fmt2.Errorf("that is not of type *B")
    82  		}
    83  		if that1 == nil {
    84  			if this == nil {
    85  				return nil
    86  			}
    87  			return fmt2.Errorf("that is type *B but is nil && this != nil")
    88  		} else if this == nil {
    89  			return fmt2.Errorf("that is type *B but is not nil && this == nil")
    90  		}
    91  		if !this.A.Equal(&that1.A) {
    92  			return fmt2.Errorf("A this(%v) Not Equal that(%v)", this.A, that1.A)
    93  		}
    94  		if len(this.G) != len(that1.G) {
    95  			return fmt2.Errorf("G this(%v) Not Equal that(%v)", len(this.G), len(that1.G))
    96  		}
    97  		for i := range this.G {
    98  			if !this.G[i].Equal(that1.G[i]) {
    99  				return fmt2.Errorf("G this[%v](%v) Not Equal that[%v](%v)", i, this.G[i], i, that1.G[i])
   100  			}
   101  		}
   102  		if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {
   103  			return fmt2.Errorf("XXX_unrecognized this(%v) Not Equal that(%v)", this.XXX_unrecognized, that1.XXX_unrecognized)
   104  		}
   105  		return nil
   106  	}
   107  
   108  	func (this *B) Equal(that interface{}) bool {
   109  		if that == nil {
   110  			return this == nil
   111  		}
   112  
   113  		that1, ok := that.(*B)
   114  		if !ok {
   115  			return false
   116  		}
   117  		if that1 == nil {
   118  			return this == nil
   119  		} else if this == nil {
   120  			return false
   121  		}
   122  		if !this.A.Equal(&that1.A) {
   123  			return false
   124  		}
   125  		if len(this.G) != len(that1.G) {
   126  			return false
   127  		}
   128  		for i := range this.G {
   129  			if !this.G[i].Equal(that1.G[i]) {
   130  				return false
   131  			}
   132  		}
   133  		if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {
   134  			return false
   135  		}
   136  		return true
   137  	}
   138  
   139  and the following test code:
   140  
   141  	func TestBVerboseEqual(t *testing8.T) {
   142  		popr := math_rand8.New(math_rand8.NewSource(time8.Now().UnixNano()))
   143  		p := NewPopulatedB(popr, false)
   144  		dAtA, err := github_com_gogo_protobuf_proto2.Marshal(p)
   145  		if err != nil {
   146  			panic(err)
   147  		}
   148  		msg := &B{}
   149  		if err := github_com_gogo_protobuf_proto2.Unmarshal(dAtA, msg); err != nil {
   150  			panic(err)
   151  		}
   152  		if err := p.VerboseEqual(msg); err != nil {
   153  			t.Fatalf("%#v !VerboseEqual %#v, since %v", msg, p, err)
   154  	}
   155  
   156  */
   157  package equal
   158  
   159  import (
   160  	"github.com/gogo/protobuf/gogoproto"
   161  	"github.com/gogo/protobuf/proto"
   162  	descriptor "github.com/gogo/protobuf/protoc-gen-gogo/descriptor"
   163  	"github.com/gogo/protobuf/protoc-gen-gogo/generator"
   164  	"github.com/gogo/protobuf/vanity"
   165  )
   166  
   167  type plugin struct {
   168  	*generator.Generator
   169  	generator.PluginImports
   170  	fmtPkg   generator.Single
   171  	bytesPkg generator.Single
   172  	protoPkg generator.Single
   173  }
   174  
   175  func NewPlugin() *plugin {
   176  	return &plugin{}
   177  }
   178  
   179  func (p *plugin) Name() string {
   180  	return "equal"
   181  }
   182  
   183  func (p *plugin) Init(g *generator.Generator) {
   184  	p.Generator = g
   185  }
   186  
   187  func (p *plugin) Generate(file *generator.FileDescriptor) {
   188  	p.PluginImports = generator.NewPluginImports(p.Generator)
   189  	p.fmtPkg = p.NewImport("fmt")
   190  	p.bytesPkg = p.NewImport("bytes")
   191  	p.protoPkg = p.NewImport("github.com/gogo/protobuf/proto")
   192  
   193  	for _, msg := range file.Messages() {
   194  		if msg.DescriptorProto.GetOptions().GetMapEntry() {
   195  			continue
   196  		}
   197  		if gogoproto.HasVerboseEqual(file.FileDescriptorProto, msg.DescriptorProto) {
   198  			p.generateMessage(file, msg, true)
   199  		}
   200  		if gogoproto.HasEqual(file.FileDescriptorProto, msg.DescriptorProto) {
   201  			p.generateMessage(file, msg, false)
   202  		}
   203  	}
   204  }
   205  
   206  func (p *plugin) generateNullableField(fieldname string, verbose bool) {
   207  	p.P(`if this.`, fieldname, ` != nil && that1.`, fieldname, ` != nil {`)
   208  	p.In()
   209  	p.P(`if *this.`, fieldname, ` != *that1.`, fieldname, `{`)
   210  	p.In()
   211  	if verbose {
   212  		p.P(`return `, p.fmtPkg.Use(), `.Errorf("`, fieldname, ` this(%v) Not Equal that(%v)", *this.`, fieldname, `, *that1.`, fieldname, `)`)
   213  	} else {
   214  		p.P(`return false`)
   215  	}
   216  	p.Out()
   217  	p.P(`}`)
   218  	p.Out()
   219  	p.P(`} else if this.`, fieldname, ` != nil {`)
   220  	p.In()
   221  	if verbose {
   222  		p.P(`return `, p.fmtPkg.Use(), `.Errorf("this.`, fieldname, ` == nil && that.`, fieldname, ` != nil")`)
   223  	} else {
   224  		p.P(`return false`)
   225  	}
   226  	p.Out()
   227  	p.P(`} else if that1.`, fieldname, ` != nil {`)
   228  }
   229  
   230  func (p *plugin) generateMsgNullAndTypeCheck(ccTypeName string, verbose bool) {
   231  	p.P(`if that == nil {`)
   232  	p.In()
   233  	if verbose {
   234  		p.P(`if this == nil {`)
   235  		p.In()
   236  		p.P(`return nil`)
   237  		p.Out()
   238  		p.P(`}`)
   239  		p.P(`return `, p.fmtPkg.Use(), `.Errorf("that == nil && this != nil")`)
   240  	} else {
   241  		p.P(`return this == nil`)
   242  	}
   243  	p.Out()
   244  	p.P(`}`)
   245  	p.P(``)
   246  	p.P(`that1, ok := that.(*`, ccTypeName, `)`)
   247  	p.P(`if !ok {`)
   248  	p.In()
   249  	p.P(`that2, ok := that.(`, ccTypeName, `)`)
   250  	p.P(`if ok {`)
   251  	p.In()
   252  	p.P(`that1 = &that2`)
   253  	p.Out()
   254  	p.P(`} else {`)
   255  	p.In()
   256  	if verbose {
   257  		p.P(`return `, p.fmtPkg.Use(), `.Errorf("that is not of type *`, ccTypeName, `")`)
   258  	} else {
   259  		p.P(`return false`)
   260  	}
   261  	p.Out()
   262  	p.P(`}`)
   263  	p.Out()
   264  	p.P(`}`)
   265  	p.P(`if that1 == nil {`)
   266  	p.In()
   267  	if verbose {
   268  		p.P(`if this == nil {`)
   269  		p.In()
   270  		p.P(`return nil`)
   271  		p.Out()
   272  		p.P(`}`)
   273  		p.P(`return `, p.fmtPkg.Use(), `.Errorf("that is type *`, ccTypeName, ` but is nil && this != nil")`)
   274  	} else {
   275  		p.P(`return this == nil`)
   276  	}
   277  	p.Out()
   278  	p.P(`} else if this == nil {`)
   279  	p.In()
   280  	if verbose {
   281  		p.P(`return `, p.fmtPkg.Use(), `.Errorf("that is type *`, ccTypeName, ` but is not nil && this == nil")`)
   282  	} else {
   283  		p.P(`return false`)
   284  	}
   285  	p.Out()
   286  	p.P(`}`)
   287  }
   288  
   289  func (p *plugin) generateField(file *generator.FileDescriptor, message *generator.Descriptor, field *descriptor.FieldDescriptorProto, verbose bool) {
   290  	proto3 := gogoproto.IsProto3(file.FileDescriptorProto)
   291  	fieldname := p.GetOneOfFieldName(message, field)
   292  	repeated := field.IsRepeated()
   293  	ctype := gogoproto.IsCustomType(field)
   294  	nullable := gogoproto.IsNullable(field)
   295  	isNormal := (gogoproto.IsStdDuration(field) ||
   296  		gogoproto.IsStdDouble(field) ||
   297  		gogoproto.IsStdFloat(field) ||
   298  		gogoproto.IsStdInt64(field) ||
   299  		gogoproto.IsStdUInt64(field) ||
   300  		gogoproto.IsStdInt32(field) ||
   301  		gogoproto.IsStdUInt32(field) ||
   302  		gogoproto.IsStdBool(field) ||
   303  		gogoproto.IsStdString(field))
   304  	isBytes := gogoproto.IsStdBytes(field)
   305  	isTimestamp := gogoproto.IsStdTime(field)
   306  	// oneof := field.OneofIndex != nil
   307  	if !repeated {
   308  		if ctype || isTimestamp {
   309  			if nullable {
   310  				p.P(`if that1.`, fieldname, ` == nil {`)
   311  				p.In()
   312  				p.P(`if this.`, fieldname, ` != nil {`)
   313  				p.In()
   314  				if verbose {
   315  					p.P(`return `, p.fmtPkg.Use(), `.Errorf("this.`, fieldname, ` != nil && that1.`, fieldname, ` == nil")`)
   316  				} else {
   317  					p.P(`return false`)
   318  				}
   319  				p.Out()
   320  				p.P(`}`)
   321  				p.Out()
   322  				p.P(`} else if !this.`, fieldname, `.Equal(*that1.`, fieldname, `) {`)
   323  			} else {
   324  				p.P(`if !this.`, fieldname, `.Equal(that1.`, fieldname, `) {`)
   325  			}
   326  			p.In()
   327  			if verbose {
   328  				p.P(`return `, p.fmtPkg.Use(), `.Errorf("`, fieldname, ` this(%v) Not Equal that(%v)", this.`, fieldname, `, that1.`, fieldname, `)`)
   329  			} else {
   330  				p.P(`return false`)
   331  			}
   332  			p.Out()
   333  			p.P(`}`)
   334  		} else if isNormal {
   335  			if nullable {
   336  				p.generateNullableField(fieldname, verbose)
   337  			} else {
   338  				p.P(`if this.`, fieldname, ` != that1.`, fieldname, `{`)
   339  			}
   340  			p.In()
   341  			if verbose {
   342  				p.P(`return `, p.fmtPkg.Use(), `.Errorf("`, fieldname, ` this(%v) Not Equal that(%v)", this.`, fieldname, `, that1.`, fieldname, `)`)
   343  			} else {
   344  				p.P(`return false`)
   345  			}
   346  			p.Out()
   347  			p.P(`}`)
   348  		} else if isBytes {
   349  			if nullable {
   350  				p.P(`if that1.`, fieldname, ` == nil {`)
   351  				p.In()
   352  				p.P(`if this.`, fieldname, ` != nil {`)
   353  				p.In()
   354  				if verbose {
   355  					p.P(`return `, p.fmtPkg.Use(), `.Errorf("this.`, fieldname, ` != nil && that1.`, fieldname, ` == nil")`)
   356  				} else {
   357  					p.P(`return false`)
   358  				}
   359  				p.Out()
   360  				p.P(`}`)
   361  				p.Out()
   362  				p.P(`} else if !`, p.bytesPkg.Use(), `.Equal(*this.`, fieldname, `, *that1.`, fieldname, `) {`)
   363  			} else {
   364  				p.P(`if !`, p.bytesPkg.Use(), `.Equal(this.`, fieldname, `, that1.`, fieldname, `) {`)
   365  			}
   366  			p.In()
   367  			if verbose {
   368  				p.P(`return `, p.fmtPkg.Use(), `.Errorf("`, fieldname, ` this(%v) Not Equal that(%v)", this.`, fieldname, `, that1.`, fieldname, `)`)
   369  			} else {
   370  				p.P(`return false`)
   371  			}
   372  			p.Out()
   373  			p.P(`}`)
   374  		} else {
   375  			if field.IsMessage() || p.IsGroup(field) {
   376  				if nullable {
   377  					p.P(`if !this.`, fieldname, `.Equal(that1.`, fieldname, `) {`)
   378  				} else {
   379  					p.P(`if !this.`, fieldname, `.Equal(&that1.`, fieldname, `) {`)
   380  				}
   381  			} else if field.IsBytes() {
   382  				p.P(`if !`, p.bytesPkg.Use(), `.Equal(this.`, fieldname, `, that1.`, fieldname, `) {`)
   383  			} else if field.IsString() {
   384  				if nullable && !proto3 {
   385  					p.generateNullableField(fieldname, verbose)
   386  				} else {
   387  					p.P(`if this.`, fieldname, ` != that1.`, fieldname, `{`)
   388  				}
   389  			} else {
   390  				if nullable && !proto3 {
   391  					p.generateNullableField(fieldname, verbose)
   392  				} else {
   393  					p.P(`if this.`, fieldname, ` != that1.`, fieldname, `{`)
   394  				}
   395  			}
   396  			p.In()
   397  			if verbose {
   398  				p.P(`return `, p.fmtPkg.Use(), `.Errorf("`, fieldname, ` this(%v) Not Equal that(%v)", this.`, fieldname, `, that1.`, fieldname, `)`)
   399  			} else {
   400  				p.P(`return false`)
   401  			}
   402  			p.Out()
   403  			p.P(`}`)
   404  		}
   405  	} else {
   406  		p.P(`if len(this.`, fieldname, `) != len(that1.`, fieldname, `) {`)
   407  		p.In()
   408  		if verbose {
   409  			p.P(`return `, p.fmtPkg.Use(), `.Errorf("`, fieldname, ` this(%v) Not Equal that(%v)", len(this.`, fieldname, `), len(that1.`, fieldname, `))`)
   410  		} else {
   411  			p.P(`return false`)
   412  		}
   413  		p.Out()
   414  		p.P(`}`)
   415  		p.P(`for i := range this.`, fieldname, ` {`)
   416  		p.In()
   417  		if ctype && !p.IsMap(field) {
   418  			p.P(`if !this.`, fieldname, `[i].Equal(that1.`, fieldname, `[i]) {`)
   419  		} else if isTimestamp {
   420  			if nullable {
   421  				p.P(`if !this.`, fieldname, `[i].Equal(*that1.`, fieldname, `[i]) {`)
   422  			} else {
   423  				p.P(`if !this.`, fieldname, `[i].Equal(that1.`, fieldname, `[i]) {`)
   424  			}
   425  		} else if isNormal {
   426  			if nullable {
   427  				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)  {`)
   428  			} else {
   429  				p.P(`if this.`, fieldname, `[i] != that1.`, fieldname, `[i] {`)
   430  			}
   431  		} else if isBytes {
   432  			if nullable {
   433  				p.P(`if !`, p.bytesPkg.Use(), `.Equal(*this.`, fieldname, `[i], *that1.`, fieldname, `[i]) {`)
   434  			} else {
   435  				p.P(`if !`, p.bytesPkg.Use(), `.Equal(this.`, fieldname, `[i], that1.`, fieldname, `[i]) {`)
   436  			}
   437  		} else {
   438  			if p.IsMap(field) {
   439  				m := p.GoMapType(nil, field)
   440  				valuegoTyp, _ := p.GoType(nil, m.ValueField)
   441  				valuegoAliasTyp, _ := p.GoType(nil, m.ValueAliasField)
   442  				nullable, valuegoTyp, valuegoAliasTyp = generator.GoMapValueTypes(field, m.ValueField, valuegoTyp, valuegoAliasTyp)
   443  
   444  				mapValue := m.ValueAliasField
   445  				mapValueNormal := (gogoproto.IsStdDuration(mapValue) ||
   446  					gogoproto.IsStdDouble(mapValue) ||
   447  					gogoproto.IsStdFloat(mapValue) ||
   448  					gogoproto.IsStdInt64(mapValue) ||
   449  					gogoproto.IsStdUInt64(mapValue) ||
   450  					gogoproto.IsStdInt32(mapValue) ||
   451  					gogoproto.IsStdUInt32(mapValue) ||
   452  					gogoproto.IsStdBool(mapValue) ||
   453  					gogoproto.IsStdString(mapValue))
   454  				mapValueBytes := gogoproto.IsStdBytes(mapValue)
   455  				if mapValue.IsMessage() || p.IsGroup(mapValue) {
   456  					if nullable && valuegoTyp == valuegoAliasTyp {
   457  						p.P(`if !this.`, fieldname, `[i].Equal(that1.`, fieldname, `[i]) {`)
   458  					} else {
   459  						// Equal() has a pointer receiver, but map value is a value type
   460  						a := `this.` + fieldname + `[i]`
   461  						b := `that1.` + fieldname + `[i]`
   462  						if !mapValueNormal && !mapValueBytes && valuegoTyp != valuegoAliasTyp {
   463  							// cast back to the type that has the generated methods on it
   464  							a = `(` + valuegoTyp + `)(` + a + `)`
   465  							b = `(` + valuegoTyp + `)(` + b + `)`
   466  						}
   467  						p.P(`a := `, a)
   468  						p.P(`b := `, b)
   469  						if mapValueNormal {
   470  							if nullable {
   471  								p.P(`if *a != *b {`)
   472  							} else {
   473  								p.P(`if a != b {`)
   474  							}
   475  						} else if mapValueBytes {
   476  							if nullable {
   477  								p.P(`if !`, p.bytesPkg.Use(), `.Equal(*a, *b) {`)
   478  							} else {
   479  								p.P(`if !`, p.bytesPkg.Use(), `.Equal(a, b) {`)
   480  							}
   481  						} else if nullable {
   482  							p.P(`if !a.Equal(b) {`)
   483  						} else {
   484  							p.P(`if !(&a).Equal(&b) {`)
   485  						}
   486  					}
   487  				} else if mapValue.IsBytes() {
   488  					if ctype {
   489  						if nullable {
   490  							p.P(`if !this.`, fieldname, `[i].Equal(*that1.`, fieldname, `[i]) { //nullable`)
   491  						} else {
   492  							p.P(`if !this.`, fieldname, `[i].Equal(that1.`, fieldname, `[i]) { //not nullable`)
   493  						}
   494  					} else {
   495  						p.P(`if !`, p.bytesPkg.Use(), `.Equal(this.`, fieldname, `[i], that1.`, fieldname, `[i]) {`)
   496  					}
   497  				} else if mapValue.IsString() {
   498  					p.P(`if this.`, fieldname, `[i] != that1.`, fieldname, `[i] {`)
   499  				} else {
   500  					p.P(`if this.`, fieldname, `[i] != that1.`, fieldname, `[i] {`)
   501  				}
   502  			} else if field.IsMessage() || p.IsGroup(field) {
   503  				if nullable {
   504  					p.P(`if !this.`, fieldname, `[i].Equal(that1.`, fieldname, `[i]) {`)
   505  				} else {
   506  					p.P(`if !this.`, fieldname, `[i].Equal(&that1.`, fieldname, `[i]) {`)
   507  				}
   508  			} else if field.IsBytes() {
   509  				p.P(`if !`, p.bytesPkg.Use(), `.Equal(this.`, fieldname, `[i], that1.`, fieldname, `[i]) {`)
   510  			} else if field.IsString() {
   511  				p.P(`if this.`, fieldname, `[i] != that1.`, fieldname, `[i] {`)
   512  			} else {
   513  				p.P(`if this.`, fieldname, `[i] != that1.`, fieldname, `[i] {`)
   514  			}
   515  		}
   516  		p.In()
   517  		if verbose {
   518  			p.P(`return `, p.fmtPkg.Use(), `.Errorf("`, fieldname, ` this[%v](%v) Not Equal that[%v](%v)", i, this.`, fieldname, `[i], i, that1.`, fieldname, `[i])`)
   519  		} else {
   520  			p.P(`return false`)
   521  		}
   522  		p.Out()
   523  		p.P(`}`)
   524  		p.Out()
   525  		p.P(`}`)
   526  	}
   527  }
   528  
   529  func (p *plugin) generateMessage(file *generator.FileDescriptor, message *generator.Descriptor, verbose bool) {
   530  	ccTypeName := generator.CamelCaseSlice(message.TypeName())
   531  	if verbose {
   532  		p.P(`func (this *`, ccTypeName, `) VerboseEqual(that interface{}) error {`)
   533  	} else {
   534  		p.P(`func (this *`, ccTypeName, `) Equal(that interface{}) bool {`)
   535  	}
   536  	p.In()
   537  	p.generateMsgNullAndTypeCheck(ccTypeName, verbose)
   538  	oneofs := make(map[string]struct{})
   539  
   540  	for _, field := range message.Field {
   541  		oneof := field.OneofIndex != nil
   542  		if oneof {
   543  			fieldname := p.GetFieldName(message, field)
   544  			if _, ok := oneofs[fieldname]; ok {
   545  				continue
   546  			} else {
   547  				oneofs[fieldname] = struct{}{}
   548  			}
   549  			p.P(`if that1.`, fieldname, ` == nil {`)
   550  			p.In()
   551  			p.P(`if this.`, fieldname, ` != nil {`)
   552  			p.In()
   553  			if verbose {
   554  				p.P(`return `, p.fmtPkg.Use(), `.Errorf("this.`, fieldname, ` != nil && that1.`, fieldname, ` == nil")`)
   555  			} else {
   556  				p.P(`return false`)
   557  			}
   558  			p.Out()
   559  			p.P(`}`)
   560  			p.Out()
   561  			p.P(`} else if this.`, fieldname, ` == nil {`)
   562  			p.In()
   563  			if verbose {
   564  				p.P(`return `, p.fmtPkg.Use(), `.Errorf("this.`, fieldname, ` == nil && that1.`, fieldname, ` != nil")`)
   565  			} else {
   566  				p.P(`return false`)
   567  			}
   568  			p.Out()
   569  			if verbose {
   570  				p.P(`} else if err := this.`, fieldname, `.VerboseEqual(that1.`, fieldname, `); err != nil {`)
   571  			} else {
   572  				p.P(`} else if !this.`, fieldname, `.Equal(that1.`, fieldname, `) {`)
   573  			}
   574  			p.In()
   575  			if verbose {
   576  				p.P(`return err`)
   577  			} else {
   578  				p.P(`return false`)
   579  			}
   580  			p.Out()
   581  			p.P(`}`)
   582  		} else {
   583  			p.generateField(file, message, field, verbose)
   584  		}
   585  	}
   586  	if message.DescriptorProto.HasExtension() {
   587  		if gogoproto.HasExtensionsMap(file.FileDescriptorProto, message.DescriptorProto) {
   588  			fieldname := "XXX_InternalExtensions"
   589  			p.P(`thismap := `, p.protoPkg.Use(), `.GetUnsafeExtensionsMap(this)`)
   590  			p.P(`thatmap := `, p.protoPkg.Use(), `.GetUnsafeExtensionsMap(that1)`)
   591  			p.P(`for k, v := range thismap {`)
   592  			p.In()
   593  			p.P(`if v2, ok := thatmap[k]; ok {`)
   594  			p.In()
   595  			p.P(`if !v.Equal(&v2) {`)
   596  			p.In()
   597  			if verbose {
   598  				p.P(`return `, p.fmtPkg.Use(), `.Errorf("`, fieldname, ` this[%v](%v) Not Equal that[%v](%v)", k, thismap[k], k, thatmap[k])`)
   599  			} else {
   600  				p.P(`return false`)
   601  			}
   602  			p.Out()
   603  			p.P(`}`)
   604  			p.Out()
   605  			p.P(`} else  {`)
   606  			p.In()
   607  			if verbose {
   608  				p.P(`return `, p.fmtPkg.Use(), `.Errorf("`, fieldname, `[%v] Not In that", k)`)
   609  			} else {
   610  				p.P(`return false`)
   611  			}
   612  			p.Out()
   613  			p.P(`}`)
   614  			p.Out()
   615  			p.P(`}`)
   616  
   617  			p.P(`for k, _ := range thatmap {`)
   618  			p.In()
   619  			p.P(`if _, ok := thismap[k]; !ok {`)
   620  			p.In()
   621  			if verbose {
   622  				p.P(`return `, p.fmtPkg.Use(), `.Errorf("`, fieldname, `[%v] Not In this", k)`)
   623  			} else {
   624  				p.P(`return false`)
   625  			}
   626  			p.Out()
   627  			p.P(`}`)
   628  			p.Out()
   629  			p.P(`}`)
   630  		} else {
   631  			fieldname := "XXX_extensions"
   632  			p.P(`if !`, p.bytesPkg.Use(), `.Equal(this.`, fieldname, `, that1.`, fieldname, `) {`)
   633  			p.In()
   634  			if verbose {
   635  				p.P(`return `, p.fmtPkg.Use(), `.Errorf("`, fieldname, ` this(%v) Not Equal that(%v)", this.`, fieldname, `, that1.`, fieldname, `)`)
   636  			} else {
   637  				p.P(`return false`)
   638  			}
   639  			p.Out()
   640  			p.P(`}`)
   641  		}
   642  	}
   643  	if gogoproto.HasUnrecognized(file.FileDescriptorProto, message.DescriptorProto) {
   644  		fieldname := "XXX_unrecognized"
   645  		p.P(`if !`, p.bytesPkg.Use(), `.Equal(this.`, fieldname, `, that1.`, fieldname, `) {`)
   646  		p.In()
   647  		if verbose {
   648  			p.P(`return `, p.fmtPkg.Use(), `.Errorf("`, fieldname, ` this(%v) Not Equal that(%v)", this.`, fieldname, `, that1.`, fieldname, `)`)
   649  		} else {
   650  			p.P(`return false`)
   651  		}
   652  		p.Out()
   653  		p.P(`}`)
   654  	}
   655  	if verbose {
   656  		p.P(`return nil`)
   657  	} else {
   658  		p.P(`return true`)
   659  	}
   660  	p.Out()
   661  	p.P(`}`)
   662  
   663  	//Generate Equal methods for oneof fields
   664  	m := proto.Clone(message.DescriptorProto).(*descriptor.DescriptorProto)
   665  	for _, field := range m.Field {
   666  		oneof := field.OneofIndex != nil
   667  		if !oneof {
   668  			continue
   669  		}
   670  		ccTypeName := p.OneOfTypeName(message, field)
   671  		if verbose {
   672  			p.P(`func (this *`, ccTypeName, `) VerboseEqual(that interface{}) error {`)
   673  		} else {
   674  			p.P(`func (this *`, ccTypeName, `) Equal(that interface{}) bool {`)
   675  		}
   676  		p.In()
   677  
   678  		p.generateMsgNullAndTypeCheck(ccTypeName, verbose)
   679  		vanity.TurnOffNullableForNativeTypes(field)
   680  		p.generateField(file, message, field, verbose)
   681  
   682  		if verbose {
   683  			p.P(`return nil`)
   684  		} else {
   685  			p.P(`return true`)
   686  		}
   687  		p.Out()
   688  		p.P(`}`)
   689  	}
   690  }
   691  
   692  func init() {
   693  	generator.RegisterPlugin(NewPlugin())
   694  }
   695  

View as plain text