Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / github.com / google / go-cmp@v0.5.1 / cmp / cmpopts / ignore.go
1 // Copyright 2017, The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE.md file.
4
5 package cmpopts
6
7 import (
8         "fmt"
9         "reflect"
10         "unicode"
11         "unicode/utf8"
12
13         "github.com/google/go-cmp/cmp"
14         "github.com/google/go-cmp/cmp/internal/function"
15 )
16
17 // IgnoreFields returns an Option that ignores fields of the
18 // given names on a single struct type. It respects the names of exported fields
19 // that are forwarded due to struct embedding.
20 // The struct type is specified by passing in a value of that type.
21 //
22 // The name may be a dot-delimited string (e.g., "Foo.Bar") to ignore a
23 // specific sub-field that is embedded or nested within the parent struct.
24 func IgnoreFields(typ interface{}, names ...string) cmp.Option {
25         sf := newStructFilter(typ, names...)
26         return cmp.FilterPath(sf.filter, cmp.Ignore())
27 }
28
29 // IgnoreTypes returns an Option that ignores all values assignable to
30 // certain types, which are specified by passing in a value of each type.
31 func IgnoreTypes(typs ...interface{}) cmp.Option {
32         tf := newTypeFilter(typs...)
33         return cmp.FilterPath(tf.filter, cmp.Ignore())
34 }
35
36 type typeFilter []reflect.Type
37
38 func newTypeFilter(typs ...interface{}) (tf typeFilter) {
39         for _, typ := range typs {
40                 t := reflect.TypeOf(typ)
41                 if t == nil {
42                         // This occurs if someone tries to pass in sync.Locker(nil)
43                         panic("cannot determine type; consider using IgnoreInterfaces")
44                 }
45                 tf = append(tf, t)
46         }
47         return tf
48 }
49 func (tf typeFilter) filter(p cmp.Path) bool {
50         if len(p) < 1 {
51                 return false
52         }
53         t := p.Last().Type()
54         for _, ti := range tf {
55                 if t.AssignableTo(ti) {
56                         return true
57                 }
58         }
59         return false
60 }
61
62 // IgnoreInterfaces returns an Option that ignores all values or references of
63 // values assignable to certain interface types. These interfaces are specified
64 // by passing in an anonymous struct with the interface types embedded in it.
65 // For example, to ignore sync.Locker, pass in struct{sync.Locker}{}.
66 func IgnoreInterfaces(ifaces interface{}) cmp.Option {
67         tf := newIfaceFilter(ifaces)
68         return cmp.FilterPath(tf.filter, cmp.Ignore())
69 }
70
71 type ifaceFilter []reflect.Type
72
73 func newIfaceFilter(ifaces interface{}) (tf ifaceFilter) {
74         t := reflect.TypeOf(ifaces)
75         if ifaces == nil || t.Name() != "" || t.Kind() != reflect.Struct {
76                 panic("input must be an anonymous struct")
77         }
78         for i := 0; i < t.NumField(); i++ {
79                 fi := t.Field(i)
80                 switch {
81                 case !fi.Anonymous:
82                         panic("struct cannot have named fields")
83                 case fi.Type.Kind() != reflect.Interface:
84                         panic("embedded field must be an interface type")
85                 case fi.Type.NumMethod() == 0:
86                         // This matches everything; why would you ever want this?
87                         panic("cannot ignore empty interface")
88                 default:
89                         tf = append(tf, fi.Type)
90                 }
91         }
92         return tf
93 }
94 func (tf ifaceFilter) filter(p cmp.Path) bool {
95         if len(p) < 1 {
96                 return false
97         }
98         t := p.Last().Type()
99         for _, ti := range tf {
100                 if t.AssignableTo(ti) {
101                         return true
102                 }
103                 if t.Kind() != reflect.Ptr && reflect.PtrTo(t).AssignableTo(ti) {
104                         return true
105                 }
106         }
107         return false
108 }
109
110 // IgnoreUnexported returns an Option that only ignores the immediate unexported
111 // fields of a struct, including anonymous fields of unexported types.
112 // In particular, unexported fields within the struct's exported fields
113 // of struct types, including anonymous fields, will not be ignored unless the
114 // type of the field itself is also passed to IgnoreUnexported.
115 //
116 // Avoid ignoring unexported fields of a type which you do not control (i.e. a
117 // type from another repository), as changes to the implementation of such types
118 // may change how the comparison behaves. Prefer a custom Comparer instead.
119 func IgnoreUnexported(typs ...interface{}) cmp.Option {
120         ux := newUnexportedFilter(typs...)
121         return cmp.FilterPath(ux.filter, cmp.Ignore())
122 }
123
124 type unexportedFilter struct{ m map[reflect.Type]bool }
125
126 func newUnexportedFilter(typs ...interface{}) unexportedFilter {
127         ux := unexportedFilter{m: make(map[reflect.Type]bool)}
128         for _, typ := range typs {
129                 t := reflect.TypeOf(typ)
130                 if t == nil || t.Kind() != reflect.Struct {
131                         panic(fmt.Sprintf("%T must be a non-pointer struct", typ))
132                 }
133                 ux.m[t] = true
134         }
135         return ux
136 }
137 func (xf unexportedFilter) filter(p cmp.Path) bool {
138         sf, ok := p.Index(-1).(cmp.StructField)
139         if !ok {
140                 return false
141         }
142         return xf.m[p.Index(-2).Type()] && !isExported(sf.Name())
143 }
144
145 // isExported reports whether the identifier is exported.
146 func isExported(id string) bool {
147         r, _ := utf8.DecodeRuneInString(id)
148         return unicode.IsUpper(r)
149 }
150
151 // IgnoreSliceElements returns an Option that ignores elements of []V.
152 // The discard function must be of the form "func(T) bool" which is used to
153 // ignore slice elements of type V, where V is assignable to T.
154 // Elements are ignored if the function reports true.
155 func IgnoreSliceElements(discardFunc interface{}) cmp.Option {
156         vf := reflect.ValueOf(discardFunc)
157         if !function.IsType(vf.Type(), function.ValuePredicate) || vf.IsNil() {
158                 panic(fmt.Sprintf("invalid discard function: %T", discardFunc))
159         }
160         return cmp.FilterPath(func(p cmp.Path) bool {
161                 si, ok := p.Index(-1).(cmp.SliceIndex)
162                 if !ok {
163                         return false
164                 }
165                 if !si.Type().AssignableTo(vf.Type().In(0)) {
166                         return false
167                 }
168                 vx, vy := si.Values()
169                 if vx.IsValid() && vf.Call([]reflect.Value{vx})[0].Bool() {
170                         return true
171                 }
172                 if vy.IsValid() && vf.Call([]reflect.Value{vy})[0].Bool() {
173                         return true
174                 }
175                 return false
176         }, cmp.Ignore())
177 }
178
179 // IgnoreMapEntries returns an Option that ignores entries of map[K]V.
180 // The discard function must be of the form "func(T, R) bool" which is used to
181 // ignore map entries of type K and V, where K and V are assignable to T and R.
182 // Entries are ignored if the function reports true.
183 func IgnoreMapEntries(discardFunc interface{}) cmp.Option {
184         vf := reflect.ValueOf(discardFunc)
185         if !function.IsType(vf.Type(), function.KeyValuePredicate) || vf.IsNil() {
186                 panic(fmt.Sprintf("invalid discard function: %T", discardFunc))
187         }
188         return cmp.FilterPath(func(p cmp.Path) bool {
189                 mi, ok := p.Index(-1).(cmp.MapIndex)
190                 if !ok {
191                         return false
192                 }
193                 if !mi.Key().Type().AssignableTo(vf.Type().In(0)) || !mi.Type().AssignableTo(vf.Type().In(1)) {
194                         return false
195                 }
196                 k := mi.Key()
197                 vx, vy := mi.Values()
198                 if vx.IsValid() && vf.Call([]reflect.Value{k, vx})[0].Bool() {
199                         return true
200                 }
201                 if vy.IsValid() && vf.Call([]reflect.Value{k, vy})[0].Bool() {
202                         return true
203                 }
204                 return false
205         }, cmp.Ignore())
206 }