...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package genericwebhook
17
18 import (
19 "container/list"
20 "reflect"
21
22 "k8s.io/apimachinery/pkg/util/validation/field"
23 )
24
25 type fieldCallback func(path *field.Path, obj interface{}, field *reflect.StructField) bool
26
27 type FieldWalker struct {
28 obj interface{}
29 callback fieldCallback
30 }
31
32 func NewFieldWalker(obj interface{}, callback fieldCallback) *FieldWalker {
33 return &FieldWalker{
34 obj: obj,
35 callback: callback,
36 }
37 }
38
39 type iterateNode struct {
40 Val reflect.Value
41 Path *field.Path
42 Field *reflect.StructField
43 }
44
45 func (w *FieldWalker) Walk() {
46 objVal := reflect.ValueOf(w.obj)
47
48 items := list.New()
49 items.PushBack(iterateNode{
50 Val: objVal,
51 Path: nil,
52 })
53
54 for {
55 if items.Len() == 0 {
56 break
57 }
58
59 item := items.Front()
60 items.Remove(item)
61
62 node := item.Value.(iterateNode)
63
64
65 if node.Path != nil {
66 val := node.Val
67 if val.Kind() != reflect.Ptr {
68
69
70 val = val.Addr()
71 }
72 if !w.callback(node.Path, val.Interface(), node.Field) {
73 continue
74 }
75 }
76
77 if node.Val.Kind() == reflect.Ptr && node.Val.IsZero() {
78 continue
79 }
80 objVal = reflect.Indirect(node.Val)
81 objType := objVal.Type()
82 switch objType.Kind() {
83 case reflect.Struct:
84 for i := 0; i < objVal.NumField(); i++ {
85 field := objType.Field(i)
86 fieldVal := objVal.Field(i)
87
88
89 if fieldVal.CanInterface() {
90 items.PushBack(iterateNode{
91 Val: fieldVal,
92 Path: node.Path.Child(field.Name),
93 Field: &field,
94 })
95 }
96 }
97 case reflect.Slice:
98 for i := 0; i < objVal.Len(); i++ {
99 items.PushBack(iterateNode{
100 Val: objVal.Index(i),
101 Path: node.Path.Index(i),
102 Field: nil,
103 })
104 }
105 }
106
107 }
108 }
109