-
Notifications
You must be signed in to change notification settings - Fork 0
/
helpers.go
122 lines (109 loc) · 2.54 KB
/
helpers.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package laravalidate
import "reflect"
// equal is a helper function to compare two reflect.Value
// This method is similar to reflect.DeepEqual but it's less strict
// for example pointers don't have to point to the same memory address
func equal(a reflect.Value, b reflect.Value) bool {
if a.Kind() != b.Kind() {
return false
}
switch a.Kind() {
case reflect.Invalid:
return true
case reflect.Bool:
return a.Bool() == b.Bool()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return a.Int() == b.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return a.Uint() == b.Uint()
case reflect.Float64, reflect.Float32:
return a.Float() == b.Float()
case reflect.Uintptr, reflect.Complex64, reflect.Complex128, reflect.UnsafePointer:
// FIXME, not comparing these values
return false
case reflect.Slice:
if a.IsNil() && b.IsNil() {
return true
}
if a.IsNil() || b.IsNil() {
return false
}
fallthrough
case reflect.Array:
if a.Len() != b.Len() {
return false
}
for idx := 0; idx < a.Len(); idx++ {
if !equal(a.Index(idx), b.Index(idx)) {
return false
}
}
return true
case reflect.Chan, reflect.Func:
// Uncomparable
return false
case reflect.Interface:
// We cannot compare interfaces
return false
case reflect.Map:
if a.IsNil() && b.IsNil() {
return true
}
if a.IsNil() || b.IsNil() {
return false
}
if a.Len() != b.Len() {
return false
}
aType := a.Type()
bType := b.Type()
if aType.Key().Kind() != bType.Key().Kind() {
return false
}
if aType.Elem().Kind() != bType.Elem().Kind() {
return false
}
iter := a.MapRange()
for iter.Next() {
key := iter.Key()
bValue := b.MapIndex(key)
if bValue.Kind() == reflect.Invalid {
return false
}
aValue := iter.Value()
if !equal(aValue, bValue) {
return false
}
}
return true
case reflect.Pointer:
if a.IsNil() && b.IsNil() {
return true
}
if a.IsNil() || b.IsNil() {
return false
}
return equal(a.Elem(), b.Elem())
case reflect.String:
return a.String() == b.String()
case reflect.Struct:
aType := a.Type()
bType := b.Type()
if aType.Name() != bType.Name() || aType.PkgPath() != bType.PkgPath() {
return false
}
if a.NumField() != b.NumField() {
// This should not be needed but just to be sure
return false
}
for idx := 0; idx < a.NumField(); idx++ {
aValue := a.Field(idx)
bValue := b.Field(idx)
if !equal(aValue, bValue) {
return false
}
}
return true
}
return false
}