github.com/gogo/protobuf@v1.3.2/plugin/equal/equal.go (about) 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 }