github.com/matm/etcd@v0.3.1-0.20140328024009-5b4a473f1453/third_party/code.google.com/p/goprotobuf/proto/equal.go (about)

     1  // Go support for Protocol Buffers - Google's data interchange format
     2  //
     3  // Copyright 2011 The Go Authors.  All rights reserved.
     4  // http://code.google.com/p/goprotobuf/
     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  //     * Neither the name of Google Inc. nor the names of its
    17  // contributors may be used to endorse or promote products derived from
    18  // this software without specific prior written permission.
    19  //
    20  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    21  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    22  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    23  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    24  // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    25  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    26  // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    27  // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    28  // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    29  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    30  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    31  
    32  // Protocol buffer comparison.
    33  // TODO: MessageSet.
    34  
    35  package proto
    36  
    37  import (
    38  	"bytes"
    39  	"log"
    40  	"reflect"
    41  	"strings"
    42  )
    43  
    44  /*
    45  Equal returns true iff protocol buffers a and b are equal.
    46  The arguments must both be pointers to protocol buffer structs.
    47  
    48  Equality is defined in this way:
    49    - Two messages are equal iff they are the same type,
    50      corresponding fields are equal, unknown field sets
    51      are equal, and extensions sets are equal.
    52    - Two set scalar fields are equal iff their values are equal.
    53      If the fields are of a floating-point type, remember that
    54      NaN != x for all x, including NaN.
    55    - Two repeated fields are equal iff their lengths are the same,
    56      and their corresponding elements are equal (a "bytes" field,
    57      although represented by []byte, is not a repeated field)
    58    - Two unset fields are equal.
    59    - Two unknown field sets are equal if their current
    60      encoded state is equal. (TODO)
    61    - Two extension sets are equal iff they have corresponding
    62      elements that are pairwise equal.
    63    - Every other combination of things are not equal.
    64  
    65  The return value is undefined if a and b are not protocol buffers.
    66  */
    67  func Equal(a, b Message) bool {
    68  	if a == nil || b == nil {
    69  		return a == b
    70  	}
    71  	v1, v2 := reflect.ValueOf(a), reflect.ValueOf(b)
    72  	if v1.Type() != v2.Type() {
    73  		return false
    74  	}
    75  	if v1.Kind() == reflect.Ptr {
    76  		if v1.IsNil() {
    77  			return v2.IsNil()
    78  		}
    79  		if v2.IsNil() {
    80  			return false
    81  		}
    82  		v1, v2 = v1.Elem(), v2.Elem()
    83  	}
    84  	if v1.Kind() != reflect.Struct {
    85  		return false
    86  	}
    87  	return equalStruct(v1, v2)
    88  }
    89  
    90  // v1 and v2 are known to have the same type.
    91  func equalStruct(v1, v2 reflect.Value) bool {
    92  	for i := 0; i < v1.NumField(); i++ {
    93  		f := v1.Type().Field(i)
    94  		if strings.HasPrefix(f.Name, "XXX_") {
    95  			continue
    96  		}
    97  		f1, f2 := v1.Field(i), v2.Field(i)
    98  		if f.Type.Kind() == reflect.Ptr {
    99  			if n1, n2 := f1.IsNil(), f2.IsNil(); n1 && n2 {
   100  				// both unset
   101  				continue
   102  			} else if n1 != n2 {
   103  				// set/unset mismatch
   104  				return false
   105  			}
   106  			b1, ok := f1.Interface().(raw)
   107  			if ok {
   108  				b2 := f2.Interface().(raw)
   109  				// RawMessage
   110  				if !bytes.Equal(b1.Bytes(), b2.Bytes()) {
   111  					return false
   112  				}
   113  				continue
   114  			}
   115  			f1, f2 = f1.Elem(), f2.Elem()
   116  		}
   117  		if !equalAny(f1, f2) {
   118  			return false
   119  		}
   120  	}
   121  
   122  	if em1 := v1.FieldByName("XXX_extensions"); em1.IsValid() {
   123  		em2 := v2.FieldByName("XXX_extensions")
   124  		if !equalExtensions(v1.Type(), em1.Interface().(map[int32]Extension), em2.Interface().(map[int32]Extension)) {
   125  			return false
   126  		}
   127  	}
   128  
   129  	uf := v1.FieldByName("XXX_unrecognized")
   130  	if !uf.IsValid() {
   131  		return true
   132  	}
   133  
   134  	u1 := uf.Bytes()
   135  	u2 := v2.FieldByName("XXX_unrecognized").Bytes()
   136  	if !bytes.Equal(u1, u2) {
   137  		return false
   138  	}
   139  
   140  	return true
   141  }
   142  
   143  // v1 and v2 are known to have the same type.
   144  func equalAny(v1, v2 reflect.Value) bool {
   145  	if v1.Type() == protoMessageType {
   146  		m1, _ := v1.Interface().(Message)
   147  		m2, _ := v2.Interface().(Message)
   148  		return Equal(m1, m2)
   149  	}
   150  	switch v1.Kind() {
   151  	case reflect.Bool:
   152  		return v1.Bool() == v2.Bool()
   153  	case reflect.Float32, reflect.Float64:
   154  		return v1.Float() == v2.Float()
   155  	case reflect.Int32, reflect.Int64:
   156  		return v1.Int() == v2.Int()
   157  	case reflect.Ptr:
   158  		return equalAny(v1.Elem(), v2.Elem())
   159  	case reflect.Slice:
   160  		if v1.Type().Elem().Kind() == reflect.Uint8 {
   161  			// short circuit: []byte
   162  			if v1.IsNil() != v2.IsNil() {
   163  				return false
   164  			}
   165  			return bytes.Equal(v1.Interface().([]byte), v2.Interface().([]byte))
   166  		}
   167  
   168  		if v1.Len() != v2.Len() {
   169  			return false
   170  		}
   171  		for i := 0; i < v1.Len(); i++ {
   172  			if !equalAny(v1.Index(i), v2.Index(i)) {
   173  				return false
   174  			}
   175  		}
   176  		return true
   177  	case reflect.String:
   178  		return v1.Interface().(string) == v2.Interface().(string)
   179  	case reflect.Struct:
   180  		return equalStruct(v1, v2)
   181  	case reflect.Uint32, reflect.Uint64:
   182  		return v1.Uint() == v2.Uint()
   183  	}
   184  
   185  	// unknown type, so not a protocol buffer
   186  	log.Printf("proto: don't know how to compare %v", v1)
   187  	return false
   188  }
   189  
   190  // base is the struct type that the extensions are based on.
   191  // em1 and em2 are extension maps.
   192  func equalExtensions(base reflect.Type, em1, em2 map[int32]Extension) bool {
   193  	if len(em1) != len(em2) {
   194  		return false
   195  	}
   196  
   197  	for extNum, e1 := range em1 {
   198  		e2, ok := em2[extNum]
   199  		if !ok {
   200  			return false
   201  		}
   202  
   203  		m1, m2 := e1.value, e2.value
   204  
   205  		if m1 != nil && m2 != nil {
   206  			// Both are unencoded.
   207  			if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2)) {
   208  				return false
   209  			}
   210  			continue
   211  		}
   212  
   213  		// At least one is encoded. To do a semantically correct comparison
   214  		// we need to unmarshal them first.
   215  		var desc *ExtensionDesc
   216  		if m := extensionMaps[base]; m != nil {
   217  			desc = m[extNum]
   218  		}
   219  		if desc == nil {
   220  			log.Printf("proto: don't know how to compare extension %d of %v", extNum, base)
   221  			continue
   222  		}
   223  		var err error
   224  		if m1 == nil {
   225  			m1, err = decodeExtension(e1.enc, desc)
   226  		}
   227  		if m2 == nil && err == nil {
   228  			m2, err = decodeExtension(e2.enc, desc)
   229  		}
   230  		if err != nil {
   231  			// The encoded form is invalid.
   232  			log.Printf("proto: badly encoded extension %d of %v: %v", extNum, base, err)
   233  			return false
   234  		}
   235  		if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2)) {
   236  			return false
   237  		}
   238  	}
   239  
   240  	return true
   241  }