Skip to content

Commit 8ca8745

Browse files
authored
Reorder logic to be consistent (#107)
Reorder logic to consistently handle steps in the order of: StructField, SliceIndex, MapIndex, Indirect, TypeAssertion
1 parent fb7c318 commit 8ca8745

File tree

2 files changed

+102
-106
lines changed

2 files changed

+102
-106
lines changed

cmp/compare.go

Lines changed: 51 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,21 @@ func (s *state) compareAny(vx, vy reflect.Value) {
240240
case reflect.Func:
241241
s.report(vx.IsNil() && vy.IsNil(), vx, vy)
242242
return
243+
case reflect.Struct:
244+
s.compareStruct(vx, vy, t)
245+
return
246+
case reflect.Slice:
247+
if vx.IsNil() || vy.IsNil() {
248+
s.report(vx.IsNil() && vy.IsNil(), vx, vy)
249+
return
250+
}
251+
fallthrough
252+
case reflect.Array:
253+
s.compareSlice(vx, vy, t)
254+
return
255+
case reflect.Map:
256+
s.compareMap(vx, vy, t)
257+
return
243258
case reflect.Ptr:
244259
if vx.IsNil() || vy.IsNil() {
245260
s.report(vx.IsNil() && vy.IsNil(), vx, vy)
@@ -262,21 +277,6 @@ func (s *state) compareAny(vx, vy reflect.Value) {
262277
defer s.curPath.pop()
263278
s.compareAny(vx.Elem(), vy.Elem())
264279
return
265-
case reflect.Slice:
266-
if vx.IsNil() || vy.IsNil() {
267-
s.report(vx.IsNil() && vy.IsNil(), vx, vy)
268-
return
269-
}
270-
fallthrough
271-
case reflect.Array:
272-
s.compareArray(vx, vy, t)
273-
return
274-
case reflect.Map:
275-
s.compareMap(vx, vy, t)
276-
return
277-
case reflect.Struct:
278-
s.compareStruct(vx, vy, t)
279-
return
280280
default:
281281
panic(fmt.Sprintf("%v kind not handled", t.Kind()))
282282
}
@@ -393,7 +393,42 @@ func sanitizeValue(v reflect.Value, t reflect.Type) reflect.Value {
393393
return v
394394
}
395395

396-
func (s *state) compareArray(vx, vy reflect.Value, t reflect.Type) {
396+
func (s *state) compareStruct(vx, vy reflect.Value, t reflect.Type) {
397+
var vax, vay reflect.Value // Addressable versions of vx and vy
398+
399+
step := &structField{}
400+
s.curPath.push(step)
401+
defer s.curPath.pop()
402+
for i := 0; i < t.NumField(); i++ {
403+
vvx := vx.Field(i)
404+
vvy := vy.Field(i)
405+
step.typ = t.Field(i).Type
406+
step.name = t.Field(i).Name
407+
step.idx = i
408+
step.unexported = !isExported(step.name)
409+
if step.unexported {
410+
if step.name == "_" {
411+
continue
412+
}
413+
// Defer checking of unexported fields until later to give an
414+
// Ignore a chance to ignore the field.
415+
if !vax.IsValid() || !vay.IsValid() {
416+
// For unsafeRetrieveField to work, the parent struct must
417+
// be addressable. Create a new copy of the values if
418+
// necessary to make them addressable.
419+
vax = makeAddressable(vx)
420+
vay = makeAddressable(vy)
421+
}
422+
step.force = s.exporters[t]
423+
step.pvx = vax
424+
step.pvy = vay
425+
step.field = t.Field(i)
426+
}
427+
s.compareAny(vvx, vvy)
428+
}
429+
}
430+
431+
func (s *state) compareSlice(vx, vy reflect.Value, t reflect.Type) {
397432
step := &sliceIndex{pathStep{t.Elem()}, 0, 0}
398433
s.curPath.push(step)
399434

@@ -477,41 +512,6 @@ func (s *state) compareMap(vx, vy reflect.Value, t reflect.Type) {
477512
}
478513
}
479514

480-
func (s *state) compareStruct(vx, vy reflect.Value, t reflect.Type) {
481-
var vax, vay reflect.Value // Addressable versions of vx and vy
482-
483-
step := &structField{}
484-
s.curPath.push(step)
485-
defer s.curPath.pop()
486-
for i := 0; i < t.NumField(); i++ {
487-
vvx := vx.Field(i)
488-
vvy := vy.Field(i)
489-
step.typ = t.Field(i).Type
490-
step.name = t.Field(i).Name
491-
step.idx = i
492-
step.unexported = !isExported(step.name)
493-
if step.unexported {
494-
if step.name == "_" {
495-
continue
496-
}
497-
// Defer checking of unexported fields until later to give an
498-
// Ignore a chance to ignore the field.
499-
if !vax.IsValid() || !vay.IsValid() {
500-
// For unsafeRetrieveField to work, the parent struct must
501-
// be addressable. Create a new copy of the values if
502-
// necessary to make them addressable.
503-
vax = makeAddressable(vx)
504-
vay = makeAddressable(vy)
505-
}
506-
step.force = s.exporters[t]
507-
step.pvx = vax
508-
step.pvy = vay
509-
step.field = t.Field(i)
510-
}
511-
s.compareAny(vvx, vvy)
512-
}
513-
}
514-
515515
// report records the result of a single comparison.
516516
// It also calls Report if any reporter is registered.
517517
func (s *state) report(eq bool, vx, vy reflect.Value) {

cmp/path.go

Lines changed: 51 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,13 @@ type (
3333
isPathStep()
3434
}
3535

36+
// StructField represents a struct field access on a field called Name.
37+
StructField interface {
38+
PathStep
39+
Name() string
40+
Index() int
41+
isStructField()
42+
}
3643
// SliceIndex is an index operation on a slice or array at some index Key.
3744
SliceIndex interface {
3845
PathStep
@@ -57,23 +64,16 @@ type (
5764
Key() reflect.Value
5865
isMapIndex()
5966
}
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-
}
7267
// Indirect represents pointer indirection on the parent type.
7368
Indirect interface {
7469
PathStep
7570
isIndirect()
7671
}
72+
// TypeAssertion represents a type assertion on an interface.
73+
TypeAssertion interface {
74+
PathStep
75+
isTypeAssertion()
76+
}
7777
// Transform is a transformation from the parent type to the current type.
7878
Transform interface {
7979
PathStep
@@ -188,17 +188,6 @@ type (
188188
typ reflect.Type
189189
}
190190

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-
}
202191
structField struct {
203192
pathStep
204193
name string
@@ -211,9 +200,20 @@ type (
211200
pvx, pvy reflect.Value // Parent values
212201
field reflect.StructField // Field information
213202
}
203+
sliceIndex struct {
204+
pathStep
205+
xkey, ykey int
206+
}
207+
mapIndex struct {
208+
pathStep
209+
key reflect.Value
210+
}
214211
indirect struct {
215212
pathStep
216213
}
214+
typeAssertion struct {
215+
pathStep
216+
}
217217
transform struct {
218218
pathStep
219219
trans *transformer
@@ -231,6 +231,12 @@ func (ps pathStep) String() string {
231231
}
232232
return fmt.Sprintf("{%s}", s)
233233
}
234+
func (ps pathStep) isPathStep() {}
235+
236+
func (sf structField) String() string { return fmt.Sprintf(".%s", sf.name) }
237+
func (sf structField) Name() string { return sf.name }
238+
func (sf structField) Index() int { return sf.idx }
239+
func (sf structField) isStructField() {}
234240

235241
func (si sliceIndex) String() string {
236242
switch {
@@ -247,48 +253,38 @@ func (si sliceIndex) String() string {
247253
return fmt.Sprintf("[%d->%d]", si.xkey, si.ykey)
248254
}
249255
}
250-
func (mi mapIndex) String() string { return fmt.Sprintf("[%#v]", mi.key) }
251-
func (ta typeAssertion) String() string { return fmt.Sprintf(".(%v)", ta.typ) }
252-
func (sf structField) String() string { return fmt.Sprintf(".%s", sf.name) }
253-
func (in indirect) String() string { return "*" }
254-
func (tf transform) String() string { return fmt.Sprintf("%s()", tf.trans.name) }
255-
256256
func (si sliceIndex) Key() int {
257257
if si.xkey != si.ykey {
258258
return -1
259259
}
260260
return si.xkey
261261
}
262262
func (si sliceIndex) SplitKeys() (x, y int) { return si.xkey, si.ykey }
263-
func (mi mapIndex) Key() reflect.Value { return mi.key }
264-
func (sf structField) Name() string { return sf.name }
265-
func (sf structField) Index() int { return sf.idx }
266-
func (tf transform) Name() string { return tf.trans.name }
267-
func (tf transform) Func() reflect.Value { return tf.trans.fnc }
268-
func (tf transform) Option() Option { return tf.trans }
263+
func (si sliceIndex) isSliceIndex() {}
269264

270-
func (pathStep) isPathStep() {}
271-
func (sliceIndex) isSliceIndex() {}
272-
func (mapIndex) isMapIndex() {}
273-
func (typeAssertion) isTypeAssertion() {}
274-
func (structField) isStructField() {}
275-
func (indirect) isIndirect() {}
276-
func (transform) isTransform() {}
265+
func (mi mapIndex) String() string { return fmt.Sprintf("[%#v]", mi.key) }
266+
func (mi mapIndex) Key() reflect.Value { return mi.key }
267+
func (mi mapIndex) isMapIndex() {}
277268

278-
var (
279-
_ SliceIndex = sliceIndex{}
280-
_ MapIndex = mapIndex{}
281-
_ TypeAssertion = typeAssertion{}
282-
_ StructField = structField{}
283-
_ Indirect = indirect{}
284-
_ Transform = transform{}
269+
func (in indirect) String() string { return "*" }
270+
func (in indirect) isIndirect() {}
285271

286-
_ PathStep = sliceIndex{}
287-
_ PathStep = mapIndex{}
288-
_ PathStep = typeAssertion{}
289-
_ PathStep = structField{}
290-
_ PathStep = indirect{}
291-
_ PathStep = transform{}
272+
func (ta typeAssertion) String() string { return fmt.Sprintf(".(%v)", ta.typ) }
273+
func (ta typeAssertion) isTypeAssertion() {}
274+
275+
func (tf transform) String() string { return fmt.Sprintf("%s()", tf.trans.name) }
276+
func (tf transform) Name() string { return tf.trans.name }
277+
func (tf transform) Func() reflect.Value { return tf.trans.fnc }
278+
func (tf transform) Option() Option { return tf.trans }
279+
func (tf transform) isTransform() {}
280+
281+
var (
282+
_ PathStep = StructField(structField{})
283+
_ PathStep = SliceIndex(sliceIndex{})
284+
_ PathStep = MapIndex(mapIndex{})
285+
_ PathStep = Indirect(indirect{})
286+
_ PathStep = TypeAssertion(typeAssertion{})
287+
_ PathStep = Transform(transform{})
292288
)
293289

294290
// isExported reports whether the identifier is exported.

0 commit comments

Comments
 (0)