aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/google/go-cmp/cmp/path.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/google/go-cmp/cmp/path.go')
-rw-r--r--vendor/github.com/google/go-cmp/cmp/path.go339
1 files changed, 169 insertions, 170 deletions
diff --git a/vendor/github.com/google/go-cmp/cmp/path.go b/vendor/github.com/google/go-cmp/cmp/path.go
index c08a3cf..96fffd2 100644
--- a/vendor/github.com/google/go-cmp/cmp/path.go
+++ b/vendor/github.com/google/go-cmp/cmp/path.go
@@ -12,80 +12,52 @@ import (
12 "unicode/utf8" 12 "unicode/utf8"
13) 13)
14 14
15type ( 15// Path is a list of PathSteps describing the sequence of operations to get
16 // Path is a list of PathSteps describing the sequence of operations to get 16// from some root type to the current position in the value tree.
17 // from some root type to the current position in the value tree. 17// The first Path element is always an operation-less PathStep that exists
18 // The first Path element is always an operation-less PathStep that exists 18// simply to identify the initial type.
19 // simply to identify the initial type. 19//
20 // 20// When traversing structs with embedded structs, the embedded struct will
21 // When traversing structs with embedded structs, the embedded struct will 21// always be accessed as a field before traversing the fields of the
22 // always be accessed as a field before traversing the fields of the 22// embedded struct themselves. That is, an exported field from the
23 // embedded struct themselves. That is, an exported field from the 23// embedded struct will never be accessed directly from the parent struct.
24 // embedded struct will never be accessed directly from the parent struct. 24type Path []PathStep
25 Path []PathStep
26
27 // PathStep is a union-type for specific operations to traverse
28 // a value's tree structure. Users of this package never need to implement
29 // these types as values of this type will be returned by this package.
30 PathStep interface {
31 String() string
32 Type() reflect.Type // Resulting type after performing the path step
33 isPathStep()
34 }
35 25
36 // SliceIndex is an index operation on a slice or array at some index Key. 26// PathStep is a union-type for specific operations to traverse
37 SliceIndex interface { 27// a value's tree structure. Users of this package never need to implement
38 PathStep 28// these types as values of this type will be returned by this package.
39 Key() int // May return -1 if in a split state 29//
40 30// Implementations of this interface are
41 // SplitKeys returns the indexes for indexing into slices in the 31// StructField, SliceIndex, MapIndex, Indirect, TypeAssertion, and Transform.
42 // x and y values, respectively. These indexes may differ due to the 32type PathStep interface {
43 // insertion or removal of an element in one of the slices, causing 33 String() string
44 // all of the indexes to be shifted. If an index is -1, then that
45 // indicates that the element does not exist in the associated slice.
46 //
47 // Key is guaranteed to return -1 if and only if the indexes returned
48 // by SplitKeys are not the same. SplitKeys will never return -1 for
49 // both indexes.
50 SplitKeys() (x int, y int)
51
52 isSliceIndex()
53 }
54 // MapIndex is an index operation on a map at some index Key.
55 MapIndex interface {
56 PathStep
57 Key() reflect.Value
58 isMapIndex()
59 }
60 // TypeAssertion represents a type assertion on an interface.
61 TypeAssertion interface {
62 PathStep
63 isTypeAssertion()
64 }
65 // StructField represents a struct field access on a field called Name.
66 StructField interface {
67 PathStep
68 Name() string
69 Index() int
70 isStructField()
71 }
72 // Indirect represents pointer indirection on the parent type.
73 Indirect interface {
74 PathStep
75 isIndirect()
76 }
77 // Transform is a transformation from the parent type to the current type.
78 Transform interface {
79 PathStep
80 Name() string
81 Func() reflect.Value
82 34
83 // Option returns the originally constructed Transformer option. 35 // Type is the resulting type after performing the path step.
84 // The == operator can be used to detect the exact option used. 36 Type() reflect.Type
85 Option() Option
86 37
87 isTransform() 38 // Values is the resulting values after performing the path step.
88 } 39 // The type of each valid value is guaranteed to be identical to Type.
40 //
41 // In some cases, one or both may be invalid or have restrictions:
42 // • For StructField, both are not interface-able if the current field
43 // is unexported and the struct type is not explicitly permitted by
44 // AllowUnexported to traverse unexported fields.
45 // • For SliceIndex, one may be invalid if an element is missing from
46 // either the x or y slice.
47 // • For MapIndex, one may be invalid if an entry is missing from
48 // either the x or y map.
49 //
50 // The provided values must not be mutated.
51 Values() (vx, vy reflect.Value)
52}
53
54var (
55 _ PathStep = StructField{}
56 _ PathStep = SliceIndex{}
57 _ PathStep = MapIndex{}
58 _ PathStep = Indirect{}
59 _ PathStep = TypeAssertion{}
60 _ PathStep = Transform{}
89) 61)
90 62
91func (pa *Path) push(s PathStep) { 63func (pa *Path) push(s PathStep) {
@@ -124,7 +96,7 @@ func (pa Path) Index(i int) PathStep {
124func (pa Path) String() string { 96func (pa Path) String() string {
125 var ss []string 97 var ss []string
126 for _, s := range pa { 98 for _, s := range pa {
127 if _, ok := s.(*structField); ok { 99 if _, ok := s.(StructField); ok {
128 ss = append(ss, s.String()) 100 ss = append(ss, s.String())
129 } 101 }
130 } 102 }
@@ -144,13 +116,13 @@ func (pa Path) GoString() string {
144 nextStep = pa[i+1] 116 nextStep = pa[i+1]
145 } 117 }
146 switch s := s.(type) { 118 switch s := s.(type) {
147 case *indirect: 119 case Indirect:
148 numIndirect++ 120 numIndirect++
149 pPre, pPost := "(", ")" 121 pPre, pPost := "(", ")"
150 switch nextStep.(type) { 122 switch nextStep.(type) {
151 case *indirect: 123 case Indirect:
152 continue // Next step is indirection, so let them batch up 124 continue // Next step is indirection, so let them batch up
153 case *structField: 125 case StructField:
154 numIndirect-- // Automatic indirection on struct fields 126 numIndirect-- // Automatic indirection on struct fields
155 case nil: 127 case nil:
156 pPre, pPost = "", "" // Last step; no need for parenthesis 128 pPre, pPost = "", "" // Last step; no need for parenthesis
@@ -161,19 +133,10 @@ func (pa Path) GoString() string {
161 } 133 }
162 numIndirect = 0 134 numIndirect = 0
163 continue 135 continue
164 case *transform: 136 case Transform:
165 ssPre = append(ssPre, s.trans.name+"(") 137 ssPre = append(ssPre, s.trans.name+"(")
166 ssPost = append(ssPost, ")") 138 ssPost = append(ssPost, ")")
167 continue 139 continue
168 case *typeAssertion:
169 // As a special-case, elide type assertions on anonymous types
170 // since they are typically generated dynamically and can be very
171 // verbose. For example, some transforms return interface{} because
172 // of Go's lack of generics, but typically take in and return the
173 // exact same concrete type.
174 if s.Type().PkgPath() == "" {
175 continue
176 }
177 } 140 }
178 ssPost = append(ssPost, s.String()) 141 ssPost = append(ssPost, s.String())
179 } 142 }
@@ -183,44 +146,13 @@ func (pa Path) GoString() string {
183 return strings.Join(ssPre, "") + strings.Join(ssPost, "") 146 return strings.Join(ssPre, "") + strings.Join(ssPost, "")
184} 147}
185 148
186type ( 149type pathStep struct {
187 pathStep struct { 150 typ reflect.Type
188 typ reflect.Type 151 vx, vy reflect.Value
189 } 152}
190
191 sliceIndex struct {
192 pathStep
193 xkey, ykey int
194 }
195 mapIndex struct {
196 pathStep
197 key reflect.Value
198 }
199 typeAssertion struct {
200 pathStep
201 }
202 structField struct {
203 pathStep
204 name string
205 idx int
206
207 // These fields are used for forcibly accessing an unexported field.
208 // pvx, pvy, and field are only valid if unexported is true.
209 unexported bool
210 force bool // Forcibly allow visibility
211 pvx, pvy reflect.Value // Parent values
212 field reflect.StructField // Field information
213 }
214 indirect struct {
215 pathStep
216 }
217 transform struct {
218 pathStep
219 trans *transformer
220 }
221)
222 153
223func (ps pathStep) Type() reflect.Type { return ps.typ } 154func (ps pathStep) Type() reflect.Type { return ps.typ }
155func (ps pathStep) Values() (vx, vy reflect.Value) { return ps.vx, ps.vy }
224func (ps pathStep) String() string { 156func (ps pathStep) String() string {
225 if ps.typ == nil { 157 if ps.typ == nil {
226 return "<nil>" 158 return "<nil>"
@@ -232,7 +164,54 @@ func (ps pathStep) String() string {
232 return fmt.Sprintf("{%s}", s) 164 return fmt.Sprintf("{%s}", s)
233} 165}
234 166
235func (si sliceIndex) String() string { 167// StructField represents a struct field access on a field called Name.
168type StructField struct{ *structField }
169type structField struct {
170 pathStep
171 name string
172 idx int
173
174 // These fields are used for forcibly accessing an unexported field.
175 // pvx, pvy, and field are only valid if unexported is true.
176 unexported bool
177 mayForce bool // Forcibly allow visibility
178 pvx, pvy reflect.Value // Parent values
179 field reflect.StructField // Field information
180}
181
182func (sf StructField) Type() reflect.Type { return sf.typ }
183func (sf StructField) Values() (vx, vy reflect.Value) {
184 if !sf.unexported {
185 return sf.vx, sf.vy // CanInterface reports true
186 }
187
188 // Forcibly obtain read-write access to an unexported struct field.
189 if sf.mayForce {
190 vx = retrieveUnexportedField(sf.pvx, sf.field)
191 vy = retrieveUnexportedField(sf.pvy, sf.field)
192 return vx, vy // CanInterface reports true
193 }
194 return sf.vx, sf.vy // CanInterface reports false
195}
196func (sf StructField) String() string { return fmt.Sprintf(".%s", sf.name) }
197
198// Name is the field name.
199func (sf StructField) Name() string { return sf.name }
200
201// Index is the index of the field in the parent struct type.
202// See reflect.Type.Field.
203func (sf StructField) Index() int { return sf.idx }
204
205// SliceIndex is an index operation on a slice or array at some index Key.
206type SliceIndex struct{ *sliceIndex }
207type sliceIndex struct {
208 pathStep
209 xkey, ykey int
210}
211
212func (si SliceIndex) Type() reflect.Type { return si.typ }
213func (si SliceIndex) Values() (vx, vy reflect.Value) { return si.vx, si.vy }
214func (si SliceIndex) String() string {
236 switch { 215 switch {
237 case si.xkey == si.ykey: 216 case si.xkey == si.ykey:
238 return fmt.Sprintf("[%d]", si.xkey) 217 return fmt.Sprintf("[%d]", si.xkey)
@@ -247,63 +226,83 @@ func (si sliceIndex) String() string {
247 return fmt.Sprintf("[%d->%d]", si.xkey, si.ykey) 226 return fmt.Sprintf("[%d->%d]", si.xkey, si.ykey)
248 } 227 }
249} 228}
250func (mi mapIndex) String() string { return fmt.Sprintf("[%#v]", mi.key) }
251func (ta typeAssertion) String() string { return fmt.Sprintf(".(%v)", ta.typ) }
252func (sf structField) String() string { return fmt.Sprintf(".%s", sf.name) }
253func (in indirect) String() string { return "*" }
254func (tf transform) String() string { return fmt.Sprintf("%s()", tf.trans.name) }
255 229
256func (si sliceIndex) Key() int { 230// Key is the index key; it may return -1 if in a split state
231func (si SliceIndex) Key() int {
257 if si.xkey != si.ykey { 232 if si.xkey != si.ykey {
258 return -1 233 return -1
259 } 234 }
260 return si.xkey 235 return si.xkey
261} 236}
262func (si sliceIndex) SplitKeys() (x, y int) { return si.xkey, si.ykey }
263func (mi mapIndex) Key() reflect.Value { return mi.key }
264func (sf structField) Name() string { return sf.name }
265func (sf structField) Index() int { return sf.idx }
266func (tf transform) Name() string { return tf.trans.name }
267func (tf transform) Func() reflect.Value { return tf.trans.fnc }
268func (tf transform) Option() Option { return tf.trans }
269
270func (pathStep) isPathStep() {}
271func (sliceIndex) isSliceIndex() {}
272func (mapIndex) isMapIndex() {}
273func (typeAssertion) isTypeAssertion() {}
274func (structField) isStructField() {}
275func (indirect) isIndirect() {}
276func (transform) isTransform() {}
277 237
278var ( 238// SplitKeys are the indexes for indexing into slices in the
279 _ SliceIndex = sliceIndex{} 239// x and y values, respectively. These indexes may differ due to the
280 _ MapIndex = mapIndex{} 240// insertion or removal of an element in one of the slices, causing
281 _ TypeAssertion = typeAssertion{} 241// all of the indexes to be shifted. If an index is -1, then that
282 _ StructField = structField{} 242// indicates that the element does not exist in the associated slice.
283 _ Indirect = indirect{} 243//
284 _ Transform = transform{} 244// Key is guaranteed to return -1 if and only if the indexes returned
285 245// by SplitKeys are not the same. SplitKeys will never return -1 for
286 _ PathStep = sliceIndex{} 246// both indexes.
287 _ PathStep = mapIndex{} 247func (si SliceIndex) SplitKeys() (ix, iy int) { return si.xkey, si.ykey }
288 _ PathStep = typeAssertion{} 248
289 _ PathStep = structField{} 249// MapIndex is an index operation on a map at some index Key.
290 _ PathStep = indirect{} 250type MapIndex struct{ *mapIndex }
291 _ PathStep = transform{} 251type mapIndex struct {
292) 252 pathStep
253 key reflect.Value
254}
255
256func (mi MapIndex) Type() reflect.Type { return mi.typ }
257func (mi MapIndex) Values() (vx, vy reflect.Value) { return mi.vx, mi.vy }
258func (mi MapIndex) String() string { return fmt.Sprintf("[%#v]", mi.key) }
259
260// Key is the value of the map key.
261func (mi MapIndex) Key() reflect.Value { return mi.key }
262
263// Indirect represents pointer indirection on the parent type.
264type Indirect struct{ *indirect }
265type indirect struct {
266 pathStep
267}
268
269func (in Indirect) Type() reflect.Type { return in.typ }
270func (in Indirect) Values() (vx, vy reflect.Value) { return in.vx, in.vy }
271func (in Indirect) String() string { return "*" }
272
273// TypeAssertion represents a type assertion on an interface.
274type TypeAssertion struct{ *typeAssertion }
275type typeAssertion struct {
276 pathStep
277}
278
279func (ta TypeAssertion) Type() reflect.Type { return ta.typ }
280func (ta TypeAssertion) Values() (vx, vy reflect.Value) { return ta.vx, ta.vy }
281func (ta TypeAssertion) String() string { return fmt.Sprintf(".(%v)", ta.typ) }
282
283// Transform is a transformation from the parent type to the current type.
284type Transform struct{ *transform }
285type transform struct {
286 pathStep
287 trans *transformer
288}
289
290func (tf Transform) Type() reflect.Type { return tf.typ }
291func (tf Transform) Values() (vx, vy reflect.Value) { return tf.vx, tf.vy }
292func (tf Transform) String() string { return fmt.Sprintf("%s()", tf.trans.name) }
293
294// Name is the name of the Transformer.
295func (tf Transform) Name() string { return tf.trans.name }
296
297// Func is the function pointer to the transformer function.
298func (tf Transform) Func() reflect.Value { return tf.trans.fnc }
299
300// Option returns the originally constructed Transformer option.
301// The == operator can be used to detect the exact option used.
302func (tf Transform) Option() Option { return tf.trans }
293 303
294// isExported reports whether the identifier is exported. 304// isExported reports whether the identifier is exported.
295func isExported(id string) bool { 305func isExported(id string) bool {
296 r, _ := utf8.DecodeRuneInString(id) 306 r, _ := utf8.DecodeRuneInString(id)
297 return unicode.IsUpper(r) 307 return unicode.IsUpper(r)
298} 308}
299
300// isValid reports whether the identifier is valid.
301// Empty and underscore-only strings are not valid.
302func isValid(id string) bool {
303 ok := id != "" && id != "_"
304 for j, c := range id {
305 ok = ok && (j > 0 || !unicode.IsDigit(c))
306 ok = ok && (c == '_' || unicode.IsLetter(c) || unicode.IsDigit(c))
307 }
308 return ok
309}