/
equality.go
122 lines (102 loc) · 3.29 KB
/
equality.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 fields
import (
"errors"
"reflect"
)
// AreEqual is comparing two given Fields using DefaultEquality.
func AreEqual(left, right Fields) (bool, error) {
if v := DefaultEquality; v != nil {
return v.AreFieldsEqual(left, right)
}
return false, nil
}
// DefaultEquality is the default instance of a Equality. The initial
// initialization of this global variable should be able to deal with the
// majority of the cases. There is also a shortcut function:
// AreEqual(left,right)
var DefaultEquality Equality = &privateEqualityImpl{&EqualityImpl{
ValueEquality: NewValueEqualityFacade(func() ValueEquality {
return DefaultValueEquality
}),
}}
// Equality is comparing two Fields with each other and check if both are equal.
type Equality interface {
// AreFieldsEqual compares the two given Fields for their equality.
AreFieldsEqual(left, right Fields) (bool, error)
}
// EqualityFunc is wrapping a given func into Equality.
type EqualityFunc func(left, right Fields) (bool, error)
// AreFieldsEqual implements Equality.AreFieldsEqual().
func (instance EqualityFunc) AreFieldsEqual(left, right Fields) (bool, error) {
return instance(left, right)
}
// EqualityImpl is a default implementation of Equality which compares all its
// values using the configured ValueEquality.
type EqualityImpl struct {
// ValueEquality is used to compare the values of the given fields. If nil
// DefaultValueEquality is used. If this is nil too, there is always false
// returned.
ValueEquality ValueEquality
}
// AreFieldsEqual implements Equality.AreFieldsEqual().
func (instance *EqualityImpl) AreFieldsEqual(left, right Fields) (bool, error) {
if instance == nil {
return false, nil
}
ve := instance.ValueEquality
if left == nil && right == nil {
return true, nil
}
if left == nil {
left = Empty()
}
if right == nil {
right = Empty()
}
if left.Len() != right.Len() {
return false, nil
}
if ve != nil {
if err := left.ForEach(func(key string, lValue interface{}) error {
rValue, rExists := right.Get(key)
if !rExists {
return entriesNotEqualV
}
if equal, err := ve.AreValuesEqual(key, lValue, rValue); err != nil {
return err
} else if !equal {
return entriesNotEqualV
}
return nil
}); err == entriesNotEqualV {
return false, nil
} else if err != nil {
return false, err
}
}
return true, nil
}
// NewEqualityFacade creates a re-implementation of Equality which uses the
// given provider to retrieve the actual instance of Equality in the moment when
// it is used. This is useful especially in cases where you want to deal with
// concurrency while creation of objects that need to hold a reference to an
// Equality.
func NewEqualityFacade(provider func() Equality) Equality {
return equalityFacade(provider)
}
type equalityFacade func() Equality
func (instance equalityFacade) AreFieldsEqual(left, right Fields) (bool, error) {
return instance.Unwrap().AreFieldsEqual(left, right)
}
func (instance equalityFacade) Unwrap() Equality {
return instance()
}
type privateEqualityImpl struct {
inner *EqualityImpl
}
func (instance *privateEqualityImpl) AreFieldsEqual(left, right Fields) (bool, error) {
return instance.inner.AreFieldsEqual(left, right)
}
var (
entriesNotEqualV = errors.New(reflect.TypeOf((*Equality)(nil)).PkgPath() + "/both entries are not equal")
)