// Go support for Protocol Buffers - Google's data interchange format//// Copyright 2011 The Go Authors. All rights reserved.// https://github.com/golang/protobuf//// Redistribution and use in source and binary forms, with or without// modification, are permitted provided that the following conditions are// met://// * Redistributions of source code must retain the above copyright// notice, this list of conditions and the following disclaimer.// * Redistributions in binary form must reproduce the above// copyright notice, this list of conditions and the following disclaimer// in the documentation and/or other materials provided with the// distribution.// * Neither the name of Google Inc. nor the names of its// contributors may be used to endorse or promote products derived from// this software without specific prior written permission.//// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.// Protocol buffer comparison.package protoimport ()/*Equal returns true iff protocol buffers a and b are equal.The arguments must both be pointers to protocol buffer structs.Equality is defined in this way: - Two messages are equal iff they are the same type, corresponding fields are equal, unknown field sets are equal, and extensions sets are equal. - Two set scalar fields are equal iff their values are equal. If the fields are of a floating-point type, remember that NaN != x for all x, including NaN. If the message is defined in a proto3 .proto file, fields are not "set"; specifically, zero length proto3 "bytes" fields are equal (nil == {}). - Two repeated fields are equal iff their lengths are the same, and their corresponding elements are equal. Note a "bytes" field, although represented by []byte, is not a repeated field and the rule for the scalar fields described above applies. - Two unset fields are equal. - Two unknown field sets are equal if their current encoded state is equal. - Two extension sets are equal iff they have corresponding elements that are pairwise equal. - Two map fields are equal iff their lengths are the same, and they contain the same set of elements. Zero-length map fields are equal. - Every other combination of things are not equal.The return value is undefined if a and b are not protocol buffers.*/func (, Message) bool {if == nil || == nil {return == } , := reflect.ValueOf(), reflect.ValueOf()if .Type() != .Type() {returnfalse }if .Kind() == reflect.Ptr {if .IsNil() {return .IsNil() }if .IsNil() {returnfalse } , = .Elem(), .Elem() }if .Kind() != reflect.Struct {returnfalse }returnequalStruct(, )}// v1 and v2 are known to have the same type.func equalStruct(, reflect.Value) bool { := GetProperties(.Type())for := 0; < .NumField(); ++ { := .Type().Field()ifstrings.HasPrefix(.Name, "XXX_") {continue } , := .Field(), .Field()if .Type.Kind() == reflect.Ptr {if , := .IsNil(), .IsNil(); && {// both unsetcontinue } elseif != {// set/unset mismatchreturnfalse } , = .Elem(), .Elem() }if !equalAny(, , .Prop[]) {returnfalse } }if := .FieldByName("XXX_InternalExtensions"); .IsValid() { := .FieldByName("XXX_InternalExtensions")if !equalExtensions(.Type(), .Interface().(XXX_InternalExtensions), .Interface().(XXX_InternalExtensions)) {returnfalse } }if := .FieldByName("XXX_extensions"); .IsValid() { := .FieldByName("XXX_extensions")if !equalExtMap(.Type(), .Interface().(map[int32]Extension), .Interface().(map[int32]Extension)) {returnfalse } } := .FieldByName("XXX_unrecognized")if !.IsValid() {returntrue } := .Bytes() := .FieldByName("XXX_unrecognized").Bytes()returnbytes.Equal(, )}// v1 and v2 are known to have the same type.// prop may be nil.func equalAny(, reflect.Value, *Properties) bool {if .Type() == protoMessageType { , := .Interface().(Message) , := .Interface().(Message)returnEqual(, ) }switch .Kind() {casereflect.Bool:return .Bool() == .Bool()casereflect.Float32, reflect.Float64:return .Float() == .Float()casereflect.Int32, reflect.Int64:return .Int() == .Int()casereflect.Interface:// Probably a oneof field; compare the inner values. , := .IsNil(), .IsNil()if || {return == } , := .Elem(), .Elem()if .Type() != .Type() {returnfalse }return (, , nil)casereflect.Map:if .Len() != .Len() {returnfalse }for , := range .MapKeys() { := .MapIndex()if !.IsValid() {// This key was not found in the second map.returnfalse }if !(.MapIndex(), , nil) {returnfalse } }returntruecasereflect.Ptr:// Maps may have nil values in them, so check for nil.if .IsNil() && .IsNil() {returntrue }if .IsNil() != .IsNil() {returnfalse }return (.Elem(), .Elem(), )casereflect.Slice:if .Type().Elem().Kind() == reflect.Uint8 {// short circuit: []byte// Edge case: if this is in a proto3 message, a zero length // bytes field is considered the zero value.if != nil && .proto3 && .Len() == 0 && .Len() == 0 {returntrue }if .IsNil() != .IsNil() {returnfalse }returnbytes.Equal(.Interface().([]byte), .Interface().([]byte)) }if .Len() != .Len() {returnfalse }for := 0; < .Len(); ++ {if !(.Index(), .Index(), ) {returnfalse } }returntruecasereflect.String:return .Interface().(string) == .Interface().(string)casereflect.Struct:returnequalStruct(, )casereflect.Uint32, reflect.Uint64:return .Uint() == .Uint() }// unknown type, so not a protocol bufferlog.Printf("proto: don't know how to compare %v", )returnfalse}// base is the struct type that the extensions are based on.// x1 and x2 are InternalExtensions.func equalExtensions( reflect.Type, , XXX_InternalExtensions) bool { , := .extensionsRead() , := .extensionsRead()returnequalExtMap(, , )}func equalExtMap( reflect.Type, , map[int32]Extension) bool {iflen() != len() {returnfalse }for , := range { , := []if ! {returnfalse } , := .value, .valueif == nil && == nil {// Both have only encoded form.ifbytes.Equal(.enc, .enc) {continue }// The bytes are different, but the extensions might still be // equal. We need to decode them to compare. }if != nil && != nil {// Both are unencoded.if !equalAny(reflect.ValueOf(), reflect.ValueOf(), nil) {returnfalse }continue }// At least one is encoded. To do a semantically correct comparison // we need to unmarshal them first.var *ExtensionDescif := extensionMaps[]; != nil { = [] }if == nil {// If both have only encoded form and the bytes are the same, // it is handled above. We get here when the bytes are different. // We don't know how to decode it, so just compare them as byte // slices.log.Printf("proto: don't know how to compare extension %d of %v", , )returnfalse }varerrorif == nil { , = decodeExtension(.enc, ) }if == nil && == nil { , = decodeExtension(.enc, ) }if != nil {// The encoded form is invalid.log.Printf("proto: badly encoded extension %d of %v: %v", , , )returnfalse }if !equalAny(reflect.ValueOf(), reflect.ValueOf(), nil) {returnfalse } }returntrue}
The pages are generated with Goldsv0.8.2. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.