pax_global_header00006660000000000000000000000064141105207510014506gustar00rootroot0000000000000052 comment=3d9c32567049cdb9abf305daf37d87224398b41d golang-github-powerman-deepequal-0.1.0/000077500000000000000000000000001411052075100200245ustar00rootroot00000000000000golang-github-powerman-deepequal-0.1.0/LICENSE000066400000000000000000000020531411052075100210310ustar00rootroot00000000000000MIT License Copyright (c) 2021 Alex Efros Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. golang-github-powerman-deepequal-0.1.0/LICENSE-go000066400000000000000000000027071411052075100214420ustar00rootroot00000000000000Copyright (c) 2009 The Go Authors. All rights reserved. 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. golang-github-powerman-deepequal-0.1.0/README.md000066400000000000000000000010541411052075100213030ustar00rootroot00000000000000# Go package with improved reflect.DeepEqual Most of the code is copied from Go reflect package with slight modifications. Differences from reflect.DeepEqual: - If compared value implements `.Equal(valueOfSameType) bool` method then it will be called instead of comparing values as is. - If called `Equal` method will panics then whole DeepEqual will panics too. This means you can use this DeepEqual method to correctly compare types like time.Time or decimal.Decimal, without taking in account unimportant differences (like time zone or exponent). golang-github-powerman-deepequal-0.1.0/all_test.go000066400000000000000000000077241411052075100221740ustar00rootroot00000000000000// Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE-go file. package deepequal_test import ( "math" "testing" "github.com/powerman/deepequal" ) type Basic struct { x int y float32 } type NotBasic Basic type DeepEqualTest struct { a, b interface{} eq bool } // Simple functions for DeepEqual tests. var ( fn1 func() // nil. fn2 func() // nil. fn3 = func() { fn1() } // Not nil. ) type self struct{} type Loop *Loop type Loopy interface{} var loop1, loop2 Loop var loopy1, loopy2 Loopy var cycleMap1, cycleMap2, cycleMap3 map[string]interface{} type structWithSelfPtr struct { p *structWithSelfPtr s string } func init() { loop1 = &loop2 loop2 = &loop1 loopy1 = &loopy2 loopy2 = &loopy1 cycleMap1 = map[string]interface{}{} cycleMap1["cycle"] = cycleMap1 cycleMap2 = map[string]interface{}{} cycleMap2["cycle"] = cycleMap2 cycleMap3 = map[string]interface{}{} cycleMap3["different"] = cycleMap3 } var deepEqualTests = []DeepEqualTest{ // Equalities {nil, nil, true}, {1, 1, true}, {int32(1), int32(1), true}, {0.5, 0.5, true}, {float32(0.5), float32(0.5), true}, {"hello", "hello", true}, {make([]int, 10), make([]int, 10), true}, {&[3]int{1, 2, 3}, &[3]int{1, 2, 3}, true}, {Basic{1, 0.5}, Basic{1, 0.5}, true}, {error(nil), error(nil), true}, {map[int]string{1: "one", 2: "two"}, map[int]string{2: "two", 1: "one"}, true}, {fn1, fn2, true}, // Inequalities {1, 2, false}, {int32(1), int32(2), false}, {0.5, 0.6, false}, {float32(0.5), float32(0.6), false}, {"hello", "hey", false}, {make([]int, 10), make([]int, 11), false}, {&[3]int{1, 2, 3}, &[3]int{1, 2, 4}, false}, {Basic{1, 0.5}, Basic{1, 0.6}, false}, {Basic{1, 0}, Basic{2, 0}, false}, {map[int]string{1: "one", 3: "two"}, map[int]string{2: "two", 1: "one"}, false}, {map[int]string{1: "one", 2: "txo"}, map[int]string{2: "two", 1: "one"}, false}, {map[int]string{1: "one"}, map[int]string{2: "two", 1: "one"}, false}, {map[int]string{2: "two", 1: "one"}, map[int]string{1: "one"}, false}, {nil, 1, false}, {1, nil, false}, {fn1, fn3, false}, {fn3, fn3, false}, {[][]int{{1}}, [][]int{{2}}, false}, {math.NaN(), math.NaN(), false}, {&[1]float64{math.NaN()}, &[1]float64{math.NaN()}, false}, {&[1]float64{math.NaN()}, self{}, true}, {[]float64{math.NaN()}, []float64{math.NaN()}, false}, {[]float64{math.NaN()}, self{}, true}, {map[float64]float64{math.NaN(): 1}, map[float64]float64{1: 2}, false}, {map[float64]float64{math.NaN(): 1}, self{}, true}, {&structWithSelfPtr{p: &structWithSelfPtr{s: "a"}}, &structWithSelfPtr{p: &structWithSelfPtr{s: "b"}}, false}, // Nil vs empty: not the same. {[]int{}, []int(nil), false}, {[]int{}, []int{}, true}, {[]int(nil), []int(nil), true}, {map[int]int{}, map[int]int(nil), false}, {map[int]int{}, map[int]int{}, true}, {map[int]int(nil), map[int]int(nil), true}, // Mismatched types {1, 1.0, false}, {int32(1), int64(1), false}, {0.5, "hello", false}, {[]int{1, 2, 3}, [3]int{1, 2, 3}, false}, {&[3]interface{}{1, 2, 4}, &[3]interface{}{1, 2, "s"}, false}, {Basic{1, 0.5}, NotBasic{1, 0.5}, false}, {map[uint]string{1: "one", 2: "two"}, map[int]string{2: "two", 1: "one"}, false}, // Possible loops. {&loop1, &loop1, true}, {&loop1, &loop2, true}, {&loopy1, &loopy1, true}, {&loopy1, &loopy2, true}, {&cycleMap1, &cycleMap2, true}, {&cycleMap1, &cycleMap3, false}, } func TestDeepEqual(t *testing.T) { for _, test := range deepEqualTests { if test.b == (self{}) { test.b = test.a } if r := deepequal.DeepEqual(test.a, test.b); r != test.eq { t.Errorf("DeepEqual(%#v, %#v) = %v, want %v", test.a, test.b, r, test.eq) } } } type Recursive struct { x int r *Recursive } func TestDeepEqualRecursiveStruct(t *testing.T) { a, b := new(Recursive), new(Recursive) *a = Recursive{12, a} *b = Recursive{12, b} if !deepequal.DeepEqual(a, b) { t.Error("DeepEqual(recursive same) = false, want true") } } golang-github-powerman-deepequal-0.1.0/custom.go000066400000000000000000000026041411052075100216670ustar00rootroot00000000000000// Package deepequal provides improved reflect.DeepEqual. // // Differences from reflect.DeepEqual: // // - If compared value implements `.Equal(valueOfSameType) bool` method then // it will be called instead of comparing values as is. // - If called `Equal` method will panics then whole DeepEqual will panics too. // // This means you can use this DeepEqual method to correctly compare types // like time.Time or decimal.Decimal, without taking in account unimportant // differences (like time zone or exponent). package deepequal import ( "reflect" "unsafe" ) // Disable check for unexported values. func forceExported(v *reflect.Value) (undo func()) { ref := (*value)(unsafe.Pointer(v)) flag := ref.flag ref.flag &^= flagRO return func() { ref.flag = flag } } func valueInterface(v reflect.Value) interface{} { defer forceExported(&v)() return v.Interface() } func call(v reflect.Value, in []reflect.Value) []reflect.Value { defer forceExported(&v)() for i := range in { defer forceExported(&in[i])() } return v.Call(in) } var ( zeroValue reflect.Value boolType = reflect.TypeOf(true) ) func equalFunc(v reflect.Value) (equal reflect.Value, ok bool) { equal = v.MethodByName("Equal") if equal == zeroValue { return zeroValue, false } typ := equal.Type() ok = typ.NumIn() == 1 && typ.In(0) == v.Type() && typ.NumOut() == 1 && typ.Out(0) == boolType return equal, ok } golang-github-powerman-deepequal-0.1.0/custom_test.go000066400000000000000000000020011411052075100227150ustar00rootroot00000000000000package deepequal_test import ( "testing" "time" "github.com/powerman/deepequal" ) type Time time.Time func (Time) Equal(time.Time) bool { return true } // Invalid signature. func TestDeepEqualEqual(t *testing.T) { t.Parallel() type T struct { t1 time.Time t2 *time.Time } var ( zero time.Time now = time.Now().In(time.FixedZone("test", 3600)) now2 = now.UTC() nowTime = Time(now) now2Time = Time(now2) ) tests := []struct { a, b interface{} want bool }{ {now, now, true}, {now, zero, false}, {&now, now, false}, {&now, &now, true}, {now, now2, true}, {&now, &now2, true}, {T{now, &now}, T{now2, &now2}, true}, {T{now, &now}, T{now2, &zero}, false}, {nowTime, now, false}, {nowTime, nowTime, true}, {nowTime, now2Time, false}, } for _, tc := range tests { tc := tc t.Run("", func(t *testing.T) { if res := deepequal.DeepEqual(tc.a, tc.b); res != tc.want { t.Errorf("DeepEqual(%v, %v) = %v, want %v", tc.a, tc.b, res, tc.want) } }) } } golang-github-powerman-deepequal-0.1.0/deepequal.go000066400000000000000000000156541411052075100223330ustar00rootroot00000000000000// Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE-go file. // Deep equality test via reflection package deepequal import ( "reflect" "unsafe" ) // During deepValueEqual, must keep track of checks that are // in progress. The comparison algorithm assumes that all // checks in progress are true when it reencounters them. // Visited comparisons are stored in a map indexed by visit. type visit struct { a1 unsafe.Pointer a2 unsafe.Pointer typ reflect.Type } // Tests for deep equality using reflected types. The map argument tracks // comparisons that have already been seen, which allows short circuiting on // recursive types. func deepValueEqual(v1, v2 reflect.Value, visited map[visit]bool) bool { if !v1.IsValid() || !v2.IsValid() { return v1.IsValid() == v2.IsValid() } if v1.Type() != v2.Type() { return false } // We want to avoid putting more in the visited map than we need to. // For any possible reference cycle that might be encountered, // hard(v1, v2) needs to return true for at least one of the types in the cycle, // and it's safe and valid to get Value's internal pointer. hard := func(v1, v2 reflect.Value) bool { switch v1.Kind() { case reflect.Ptr: fallthrough case reflect.Map, reflect.Slice, reflect.Interface: // Nil pointers cannot be cyclic. Avoid putting them in the visited map. return !v1.IsNil() && !v2.IsNil() } return false } if hard(v1, v2) { // For a Ptr or Map value, we need to check flagIndir, // which we do by calling the pointer method. // For Slice or Interface, flagIndir is always set, // and using v.ptr suffices. ptrval := func(v reflect.Value) unsafe.Pointer { switch v.Kind() { case reflect.Ptr, reflect.Map: return (unsafe.Pointer)(v.Pointer()) default: vRef := (*value)(unsafe.Pointer(&v)) return vRef.ptr } } addr1 := ptrval(v1) addr2 := ptrval(v2) if uintptr(addr1) > uintptr(addr2) { // Canonicalize order to reduce number of entries in visited. // Assumes non-moving garbage collector. addr1, addr2 = addr2, addr1 } // Short circuit if references are already seen. typ := v1.Type() v := visit{addr1, addr2, typ} if visited[v] { return true } // Remember for later. visited[v] = true } if equal, ok := equalFunc(v1); ok { return call(equal, []reflect.Value{v2})[0].Bool() } switch v1.Kind() { case reflect.Array: for i := 0; i < v1.Len(); i++ { if !deepValueEqual(v1.Index(i), v2.Index(i), visited) { return false } } return true case reflect.Slice: if v1.IsNil() != v2.IsNil() { return false } if v1.Len() != v2.Len() { return false } if v1.Pointer() == v2.Pointer() { return true } for i := 0; i < v1.Len(); i++ { if !deepValueEqual(v1.Index(i), v2.Index(i), visited) { return false } } return true case reflect.Interface: if v1.IsNil() || v2.IsNil() { return v1.IsNil() == v2.IsNil() } return deepValueEqual(v1.Elem(), v2.Elem(), visited) case reflect.Ptr: if v1.Pointer() == v2.Pointer() { return true } return deepValueEqual(v1.Elem(), v2.Elem(), visited) case reflect.Struct: for i, n := 0, v1.NumField(); i < n; i++ { if !deepValueEqual(v1.Field(i), v2.Field(i), visited) { return false } } return true case reflect.Map: if v1.IsNil() != v2.IsNil() { return false } if v1.Len() != v2.Len() { return false } if v1.Pointer() == v2.Pointer() { return true } for _, k := range v1.MapKeys() { val1 := v1.MapIndex(k) val2 := v2.MapIndex(k) if !val1.IsValid() || !val2.IsValid() || !deepValueEqual(val1, val2, visited) { return false } } return true case reflect.Func: if v1.IsNil() && v2.IsNil() { return true } // Can't do better than this: return false default: // Normal equality suffices return valueInterface(v1) == valueInterface(v2) } } // DeepEqual reports whether x and y are ``deeply equal,'' defined as follows. // Two values of identical type are deeply equal if one of the following cases applies. // Values of distinct types are never deeply equal. // // If x's type implements Equal method such as x.Equal(y) returns true then // values are deeply equal. // // Array values are deeply equal when their corresponding elements are deeply equal. // // Struct values are deeply equal if their corresponding fields, // both exported and unexported, are deeply equal. // // Func values are deeply equal if both are nil; otherwise they are not deeply equal. // // Interface values are deeply equal if they hold deeply equal concrete values. // // Map values are deeply equal when all of the following are true: // they are both nil or both non-nil, they have the same length, // and either they are the same map object or their corresponding keys // (matched using Go equality) map to deeply equal values. // // Pointer values are deeply equal if they are equal using Go's == operator // or if they point to deeply equal values. // // Slice values are deeply equal when all of the following are true: // they are both nil or both non-nil, they have the same length, // and either they point to the same initial entry of the same underlying array // (that is, &x[0] == &y[0]) or their corresponding elements (up to length) are deeply equal. // Note that a non-nil empty slice and a nil slice (for example, []byte{} and []byte(nil)) // are not deeply equal. // // Other values - numbers, bools, strings, and channels - are deeply equal // if they are equal using Go's == operator. // // In general DeepEqual is a recursive relaxation of Go's == operator. // However, this idea is impossible to implement without some inconsistency. // Specifically, it is possible for a value to be unequal to itself, // either because it is of func type (uncomparable in general) // or because it is a floating-point NaN value (not equal to itself in floating-point comparison), // or because it is an array, struct, or interface containing // such a value. // On the other hand, pointer values are always equal to themselves, // even if they point at or contain such problematic values, // because they compare equal using Go's == operator, and that // is a sufficient condition to be deeply equal, regardless of content. // DeepEqual has been defined so that the same short-cut applies // to slices and maps: if x and y are the same slice or the same map, // they are deeply equal regardless of content. // // As DeepEqual traverses the data values it may find a cycle. The // second and subsequent times that DeepEqual compares two pointer // values that have been compared before, it treats the values as // equal rather than examining the values to which they point. // This ensures that DeepEqual terminates. func DeepEqual(x, y interface{}) bool { if x == nil || y == nil { return x == y } v1 := reflect.ValueOf(x) v2 := reflect.ValueOf(y) if v1.Type() != v2.Type() { return false } return deepValueEqual(v1, v2, make(map[visit]bool)) } golang-github-powerman-deepequal-0.1.0/go.mod000066400000000000000000000000561411052075100211330ustar00rootroot00000000000000module github.com/powerman/deepequal go 1.16 golang-github-powerman-deepequal-0.1.0/type.go000066400000000000000000000026501411052075100213370ustar00rootroot00000000000000// Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE-go file. package deepequal import "unsafe" // tflag is used by an rtype to signal what extra type information is // available in the memory directly following the rtype value. // // tflag values must be kept in sync with copies in: // cmd/compile/internal/gc/reflect.go // cmd/link/internal/ld/decodesym.go // runtime/type.go type tflag uint8 // rtype is the common implementation of most values. // It is embedded in other struct types. // // rtype must be kept in sync with ../runtime/type.go:/^type._type. type rtype struct { size uintptr ptrdata uintptr // number of bytes in the type that can contain pointers hash uint32 // hash of type; avoids computation in hash tables tflag tflag // extra type information flags align uint8 // alignment of variable with this type fieldAlign uint8 // alignment of struct field with this type kind uint8 // enumeration for C // function for comparing objects of this type // (ptr to object A, ptr to object B) -> ==? equal func(unsafe.Pointer, unsafe.Pointer) bool gcdata *byte // garbage collection data str nameOff // string form ptrToThis typeOff // type for pointer to this type, may be zero } type nameOff int32 // offset to a name type typeOff int32 // offset to an *rtype golang-github-powerman-deepequal-0.1.0/unsafe_test.go000066400000000000000000000006651411052075100227020ustar00rootroot00000000000000package deepequal import ( "reflect" "testing" ) // This test should break in reflect.Value will be modified in // incompatible way in future Go version. func TestForceExported(t *testing.T) { t.Parallel() var v struct{ a int } val := reflect.ValueOf(v).Field(0) var res interface{} func() { defer func() { res = recover() }() _ = valueInterface(val) }() if res != nil { t.Errorf("valueInterface panics: %v", res) } } golang-github-powerman-deepequal-0.1.0/value.go000066400000000000000000000033571411052075100214770ustar00rootroot00000000000000// Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE-go file. package deepequal import "unsafe" type value struct { // typ holds the type of the value represented by a Value. typ *rtype // Pointer-valued data or, if flagIndir is set, pointer to data. // Valid when either flagIndir is set or typ.pointers() is true. ptr unsafe.Pointer // flag holds metadata about the value. // The lowest bits are flag bits: // - flagStickyRO: obtained via unexported not embedded field, so read-only // - flagEmbedRO: obtained via unexported embedded field, so read-only // - flagIndir: val holds a pointer to the data // - flagAddr: v.CanAddr is true (implies flagIndir) // - flagMethod: v is a method value. // The next five bits give the Kind of the value. // This repeats typ.Kind() except for method values. // The remaining 23+ bits give a method number for method values. // If flag.kind() != Func, code can assume that flagMethod is unset. // If ifaceIndir(typ), code can assume that flagIndir is set. flag // A method value represents a curried method invocation // like r.Read for some receiver r. The typ+val+flag bits describe // the receiver r, but the flag's Kind bits say Func (methods are // functions), and the top bits of the flag give the method number // in r's type's method table. } type flag uintptr const ( flagKindWidth = 5 // there are 27 kinds flagKindMask flag = 1<