Codebase list golang-github-mitchellh-reflectwalk / b8954db
Imported Upstream version 0.0~git20161004.0.9ad27c4 Dr. Tobias Quathamer 7 years ago
3 changed file(s) with 364 addition(s) and 40 deletion(s). Raw diff Collapse all Expand all
0 language: go
44 package reflectwalk
55
66 import (
7 "errors"
78 "reflect"
89 )
910
1718 Primitive(reflect.Value) error
1819 }
1920
21 // InterfaceWalker implementations are able to handle interface values as they
22 // are encountered during the walk.
23 type InterfaceWalker interface {
24 Interface(reflect.Value) error
25 }
26
2027 // MapWalker implementations are able to handle individual elements
2128 // found within a map structure.
2229 type MapWalker interface {
5360 PointerEnter(bool) error
5461 PointerExit(bool) error
5562 }
63
64 // SkipEntry can be returned from walk functions to skip walking
65 // the value of this field. This is only valid in the following functions:
66 //
67 // - StructField: skips walking the struct value
68 //
69 var SkipEntry = errors.New("skip this entry")
5670
5771 // Walk takes an arbitrary value and an interface and traverses the
5872 // value, calling callbacks on the interface if they are supported.
7892
7993 func walk(v reflect.Value, w interface{}) (err error) {
8094 // Determine if we're receiving a pointer and if so notify the walker.
95 // The logic here is convoluted but very important (tests will fail if
96 // almost any part is changed). I will try to explain here.
97 //
98 // First, we check if the value is an interface, if so, we really need
99 // to check the interface's VALUE to see whether it is a pointer.
100 //
101 // Check whether the value is then a pointer. If so, then set pointer
102 // to true to notify the user.
103 //
104 // If we still have a pointer or an interface after the indirections, then
105 // we unwrap another level
106 //
107 // At this time, we also set "v" to be the dereferenced value. This is
108 // because once we've unwrapped the pointer we want to use that value.
81109 pointer := false
82 if v.Kind() == reflect.Ptr {
83 pointer = true
84 v = reflect.Indirect(v)
85 }
86 if pw, ok := w.(PointerWalker); ok {
87 if err = pw.PointerEnter(pointer); err != nil {
88 return
89 }
90
91 defer func() {
92 if err != nil {
110 pointerV := v
111
112 for {
113 if pointerV.Kind() == reflect.Interface {
114 if iw, ok := w.(InterfaceWalker); ok {
115 if err = iw.Interface(pointerV); err != nil {
116 return
117 }
118 }
119
120 pointerV = pointerV.Elem()
121 }
122
123 if pointerV.Kind() == reflect.Ptr {
124 pointer = true
125 v = reflect.Indirect(pointerV)
126 }
127 if pw, ok := w.(PointerWalker); ok {
128 if err = pw.PointerEnter(pointer); err != nil {
93129 return
94130 }
95131
96 err = pw.PointerExit(pointer)
97 }()
132 defer func(pointer bool) {
133 if err != nil {
134 return
135 }
136
137 err = pw.PointerExit(pointer)
138 }(pointer)
139 }
140
141 if pointer {
142 pointerV = v
143 }
144 pointer = false
145
146 // If we still have a pointer or interface we have to indirect another level.
147 switch pointerV.Kind() {
148 case reflect.Ptr, reflect.Interface:
149 continue
150 }
151 break
98152 }
99153
100154 // We preserve the original value here because if it is an interface
250304
251305 if sw, ok := w.(StructWalker); ok {
252306 err = sw.StructField(sf, f)
307
308 // SkipEntry just pretends this field doesn't even exist
309 if err == SkipEntry {
310 continue
311 }
312
253313 if err != nil {
254314 return
255315 }
00 package reflectwalk
11
22 import (
3 "fmt"
34 "reflect"
45 "testing"
56 )
2324 }
2425
2526 type TestPointerWalker struct {
26 Ps []bool
27 pointers []bool
28 count int
29 enters int
30 exits int
2731 }
2832
2933 func (t *TestPointerWalker) PointerEnter(v bool) error {
30 t.Ps = append(t.Ps, v)
34 t.pointers = append(t.pointers, v)
35 t.enters++
36 if v {
37 t.count++
38 }
3139 return nil
3240 }
3341
3442 func (t *TestPointerWalker) PointerExit(v bool) error {
43 t.exits++
44 if t.pointers[len(t.pointers)-1] != v {
45 return fmt.Errorf("bad pointer exit '%t' at exit %d", v, t.exits)
46 }
47 t.pointers = t.pointers[:len(t.pointers)-1]
3548 return nil
3649 }
3750
6477
6578 type TestMapWalker struct {
6679 MapVal reflect.Value
67 Keys []string
68 Values []string
80 Keys map[string]bool
81 Values map[string]bool
6982 }
7083
7184 func (t *TestMapWalker) Map(m reflect.Value) error {
7588
7689 func (t *TestMapWalker) MapElem(m, k, v reflect.Value) error {
7790 if t.Keys == nil {
78 t.Keys = make([]string, 0, 1)
79 t.Values = make([]string, 0, 1)
80 }
81
82 t.Keys = append(t.Keys, k.Interface().(string))
83 t.Values = append(t.Values, v.Interface().(string))
91 t.Keys = make(map[string]bool)
92 t.Values = make(map[string]bool)
93 }
94
95 t.Keys[k.Interface().(string)] = true
96 t.Values[v.Interface().(string)] = true
8497 return nil
8598 }
8699
188201 }
189202 if data.Bar[0].([]string)[0] != "bar" {
190203 t.Fatalf("bad: %#v", data.Bar)
204 }
205 }
206
207 func TestWalk_Basic_ReplaceInterface(t *testing.T) {
208 w := new(TestPrimitiveReplaceWalker)
209
210 type S struct {
211 Foo []interface{}
212 }
213
214 data := &S{
215 Foo: []interface{}{"foo"},
216 }
217
218 err := Walk(data, w)
219 if err != nil {
220 t.Fatalf("err: %s", err)
191221 }
192222 }
193223
293323 t.Fatalf("Bad: %#v", w.MapVal.Interface())
294324 }
295325
296 expectedK := []string{"foo", "bar"}
326 expectedK := map[string]bool{"foo": true, "bar": true}
297327 if !reflect.DeepEqual(w.Keys, expectedK) {
298328 t.Fatalf("Bad keys: %#v", w.Keys)
299329 }
300330
301 expectedV := []string{"foov", "barv"}
331 expectedV := map[string]bool{"foov": true, "barv": true}
302332 if !reflect.DeepEqual(w.Values, expectedV) {
303333 t.Fatalf("Bad values: %#v", w.Values)
304334 }
309339
310340 type S struct {
311341 Foo string
312 }
313
314 data := &S{
315 Foo: "foo",
316 }
317
318 err := Walk(data, w)
319 if err != nil {
320 t.Fatalf("err: %s", err)
321 }
322
323 expected := []bool{true, false}
324 if !reflect.DeepEqual(w.Ps, expected) {
325 t.Fatalf("bad: %#v", w.Ps)
342 Bar *string
343 Baz **string
344 }
345
346 s := ""
347 sp := &s
348
349 data := &S{
350 Baz: &sp,
351 }
352
353 err := Walk(data, w)
354 if err != nil {
355 t.Fatalf("err: %s", err)
356 }
357
358 if w.enters != 5 {
359 t.Fatal("expected 4 values, saw", w.enters)
360 }
361
362 if w.count != 4 {
363 t.Fatal("exptec 3 pointers, saw", w.count)
364 }
365
366 if w.exits != w.enters {
367 t.Fatalf("number of enters (%d) and exits (%d) don't match", w.enters, w.exits)
368 }
369 }
370
371 func TestWalk_PointerPointer(t *testing.T) {
372 w := new(TestPointerWalker)
373
374 s := ""
375 sp := &s
376 pp := &sp
377
378 err := Walk(pp, w)
379 if err != nil {
380 t.Fatalf("err: %s", err)
381 }
382
383 if w.enters != 2 {
384 t.Fatal("expected 2 values, saw", w.enters)
385 }
386
387 if w.count != 2 {
388 t.Fatal("expected 2 pointers, saw", w.count)
389 }
390
391 if w.exits != w.enters {
392 t.Fatalf("number of enters (%d) and exits (%d) don't match", w.enters, w.exits)
326393 }
327394 }
328395
351418 }
352419 }
353420
421 func TestWalk_SliceWithPtr(t *testing.T) {
422 w := new(TestSliceWalker)
423
424 // This is key, the panic only happened when the slice field was
425 // an interface!
426 type I interface{}
427
428 type S struct {
429 Foo []I
430 }
431
432 type Empty struct{}
433
434 data := &S{
435 Foo: []I{&Empty{}},
436 }
437
438 err := Walk(data, w)
439 if err != nil {
440 t.Fatalf("err: %s", err)
441 }
442
443 if !reflect.DeepEqual(w.SliceVal.Interface(), data.Foo) {
444 t.Fatalf("bad: %#v", w.SliceVal.Interface())
445 }
446
447 if w.Count != 1 {
448 t.Fatalf("Bad count: %d", w.Count)
449 }
450 }
451
452 type testErr struct{}
453
454 func (t *testErr) Error() string {
455 return "test error"
456 }
457
354458 func TestWalk_Struct(t *testing.T) {
355459 w := new(TestStructWalker)
356460
461 // This makes sure we can also walk over pointer-to-pointers, and the ever
462 // so rare pointer-to-interface
463 type S struct {
464 Foo string
465 Bar *string
466 Baz **string
467 Err *error
468 }
469
470 bar := "ptr"
471 baz := &bar
472 e := error(&testErr{})
473
474 data := &S{
475 Foo: "foo",
476 Bar: &bar,
477 Baz: &baz,
478 Err: &e,
479 }
480
481 err := Walk(data, w)
482 if err != nil {
483 t.Fatalf("err: %s", err)
484 }
485
486 expected := []string{"Foo", "Bar", "Baz", "Err"}
487 if !reflect.DeepEqual(w.Fields, expected) {
488 t.Fatalf("bad: %#v", w.Fields)
489 }
490 }
491
492 // Very similar to above test but used to fail for #2, copied here for
493 // regression testing
494 func TestWalk_StructWithPtr(t *testing.T) {
495 w := new(TestStructWalker)
496
357497 type S struct {
358498 Foo string
359499 Bar string
500 Baz *int
360501 }
361502
362503 data := &S{
369510 t.Fatalf("err: %s", err)
370511 }
371512
372 expected := []string{"Foo", "Bar"}
513 expected := []string{"Foo", "Bar", "Baz"}
373514 if !reflect.DeepEqual(w.Fields, expected) {
374515 t.Fatalf("bad: %#v", w.Fields)
375516 }
376517 }
518
519 type TestInterfaceMapWalker struct {
520 MapVal reflect.Value
521 Keys map[string]bool
522 Values map[interface{}]bool
523 }
524
525 func (t *TestInterfaceMapWalker) Map(m reflect.Value) error {
526 t.MapVal = m
527 return nil
528 }
529
530 func (t *TestInterfaceMapWalker) MapElem(m, k, v reflect.Value) error {
531 if t.Keys == nil {
532 t.Keys = make(map[string]bool)
533 t.Values = make(map[interface{}]bool)
534 }
535
536 t.Keys[k.Interface().(string)] = true
537 t.Values[v.Interface()] = true
538 return nil
539 }
540
541 func TestWalk_MapWithPointers(t *testing.T) {
542 w := new(TestInterfaceMapWalker)
543
544 type S struct {
545 Foo map[string]interface{}
546 }
547
548 a := "a"
549 b := "b"
550
551 data := &S{
552 Foo: map[string]interface{}{
553 "foo": &a,
554 "bar": &b,
555 "baz": 11,
556 "zab": (*int)(nil),
557 },
558 }
559
560 err := Walk(data, w)
561 if err != nil {
562 t.Fatalf("err: %s", err)
563 }
564
565 if !reflect.DeepEqual(w.MapVal.Interface(), data.Foo) {
566 t.Fatalf("Bad: %#v", w.MapVal.Interface())
567 }
568
569 expectedK := map[string]bool{"foo": true, "bar": true, "baz": true, "zab": true}
570 if !reflect.DeepEqual(w.Keys, expectedK) {
571 t.Fatalf("Bad keys: %#v", w.Keys)
572 }
573
574 expectedV := map[interface{}]bool{&a: true, &b: true, 11: true, (*int)(nil): true}
575 if !reflect.DeepEqual(w.Values, expectedV) {
576 t.Fatalf("Bad values: %#v", w.Values)
577 }
578 }
579
580 type TestStructWalker_fieldSkip struct {
581 Skip bool
582 Fields int
583 }
584
585 func (t *TestStructWalker_fieldSkip) Enter(l Location) error {
586 if l == StructField {
587 t.Fields++
588 }
589
590 return nil
591 }
592
593 func (t *TestStructWalker_fieldSkip) Exit(Location) error {
594 return nil
595 }
596
597 func (t *TestStructWalker_fieldSkip) Struct(v reflect.Value) error {
598 return nil
599 }
600
601 func (t *TestStructWalker_fieldSkip) StructField(sf reflect.StructField, v reflect.Value) error {
602 if t.Skip && sf.Name[0] == '_' {
603 return SkipEntry
604 }
605
606 return nil
607 }
608
609 func TestWalk_StructWithSkipEntry(t *testing.T) {
610 data := &struct {
611 Foo, _Bar int
612 }{
613 Foo: 1,
614 _Bar: 2,
615 }
616
617 {
618 var s TestStructWalker_fieldSkip
619 if err := Walk(data, &s); err != nil {
620 t.Fatalf("err: %s", err)
621 }
622
623 if s.Fields != 2 {
624 t.Fatalf("bad: %d", s.Fields)
625 }
626 }
627
628 {
629 var s TestStructWalker_fieldSkip
630 s.Skip = true
631 if err := Walk(data, &s); err != nil {
632 t.Fatalf("err: %s", err)
633 }
634
635 if s.Fields != 1 {
636 t.Fatalf("bad: %d", s.Fields)
637 }
638 }
639 }