1
2
3
4
5 package reflectwalk
6
7 import (
8 "errors"
9 "reflect"
10 )
11
12
13
14
15
16
17
18 type PrimitiveWalker interface {
19 Primitive(reflect.Value) error
20 }
21
22
23
24 type InterfaceWalker interface {
25 Interface(reflect.Value) error
26 }
27
28
29
30 type MapWalker interface {
31 Map(m reflect.Value) error
32 MapElem(m, k, v reflect.Value) error
33 }
34
35
36
37 type SliceWalker interface {
38 Slice(reflect.Value) error
39 SliceElem(int, reflect.Value) error
40 }
41
42
43
44 type ArrayWalker interface {
45 Array(reflect.Value) error
46 ArrayElem(int, reflect.Value) error
47 }
48
49
50
51 type StructWalker interface {
52 Struct(reflect.Value) error
53 StructField(reflect.StructField, reflect.Value) error
54 }
55
56
57
58
59 type EnterExitWalker interface {
60 Enter(Location) error
61 Exit(Location) error
62 }
63
64
65
66
67 type PointerWalker interface {
68 PointerEnter(bool) error
69 PointerExit(bool) error
70 }
71
72
73
74
75 type PointerValueWalker interface {
76 Pointer(reflect.Value) error
77 }
78
79
80
81
82
83
84
85 var SkipEntry = errors.New("skip this entry")
86
87
88
89
90
91 func Walk(data, walker interface{}) (err error) {
92 v := reflect.ValueOf(data)
93 ew, ok := walker.(EnterExitWalker)
94 if ok {
95 err = ew.Enter(WalkLoc)
96 }
97
98 if err == nil {
99 err = walk(v, walker)
100 }
101
102 if ok && err == nil {
103 err = ew.Exit(WalkLoc)
104 }
105
106 return
107 }
108
109 func walk(v reflect.Value, w interface{}) (err error) {
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125 pointer := false
126 pointerV := v
127
128 for {
129 if pointerV.Kind() == reflect.Interface {
130 if iw, ok := w.(InterfaceWalker); ok {
131 if err = iw.Interface(pointerV); err != nil {
132 return
133 }
134 }
135
136 pointerV = pointerV.Elem()
137 }
138
139 if pointerV.Kind() == reflect.Ptr {
140 if pw, ok := w.(PointerValueWalker); ok {
141 if err = pw.Pointer(pointerV); err != nil {
142 if err == SkipEntry {
143
144 return nil
145 }
146
147 return
148 }
149 }
150
151 pointer = true
152 v = reflect.Indirect(pointerV)
153 }
154 if pw, ok := w.(PointerWalker); ok {
155 if err = pw.PointerEnter(pointer); err != nil {
156 return
157 }
158
159 defer func(pointer bool) {
160 if err != nil {
161 return
162 }
163
164 err = pw.PointerExit(pointer)
165 }(pointer)
166 }
167
168 if pointer {
169 pointerV = v
170 }
171 pointer = false
172
173
174 switch pointerV.Kind() {
175 case reflect.Ptr, reflect.Interface:
176 continue
177 }
178 break
179 }
180
181
182
183
184 originalV := v
185 if v.Kind() == reflect.Interface {
186 v = v.Elem()
187 }
188
189 k := v.Kind()
190 if k >= reflect.Int && k <= reflect.Complex128 {
191 k = reflect.Int
192 }
193
194 switch k {
195
196 case reflect.Bool, reflect.Chan, reflect.Func, reflect.Int, reflect.String, reflect.Invalid:
197 err = walkPrimitive(originalV, w)
198 return
199 case reflect.Map:
200 err = walkMap(v, w)
201 return
202 case reflect.Slice:
203 err = walkSlice(v, w)
204 return
205 case reflect.Struct:
206 err = walkStruct(v, w)
207 return
208 case reflect.Array:
209 err = walkArray(v, w)
210 return
211 default:
212 panic("unsupported type: " + k.String())
213 }
214 }
215
216 func walkMap(v reflect.Value, w interface{}) error {
217 ew, ewok := w.(EnterExitWalker)
218 if ewok {
219 ew.Enter(Map)
220 }
221
222 if mw, ok := w.(MapWalker); ok {
223 if err := mw.Map(v); err != nil {
224 return err
225 }
226 }
227
228 for _, k := range v.MapKeys() {
229 kv := v.MapIndex(k)
230
231 if mw, ok := w.(MapWalker); ok {
232 if err := mw.MapElem(v, k, kv); err != nil {
233 return err
234 }
235 }
236
237 ew, ok := w.(EnterExitWalker)
238 if ok {
239 ew.Enter(MapKey)
240 }
241
242 if err := walk(k, w); err != nil {
243 return err
244 }
245
246 if ok {
247 ew.Exit(MapKey)
248 ew.Enter(MapValue)
249 }
250
251
252 if err := walk(v.MapIndex(k), w); err != nil {
253 return err
254 }
255
256 if ok {
257 ew.Exit(MapValue)
258 }
259 }
260
261 if ewok {
262 ew.Exit(Map)
263 }
264
265 return nil
266 }
267
268 func walkPrimitive(v reflect.Value, w interface{}) error {
269 if pw, ok := w.(PrimitiveWalker); ok {
270 return pw.Primitive(v)
271 }
272
273 return nil
274 }
275
276 func walkSlice(v reflect.Value, w interface{}) (err error) {
277 ew, ok := w.(EnterExitWalker)
278 if ok {
279 ew.Enter(Slice)
280 }
281
282 if sw, ok := w.(SliceWalker); ok {
283 if err := sw.Slice(v); err != nil {
284 return err
285 }
286 }
287
288 for i := 0; i < v.Len(); i++ {
289 elem := v.Index(i)
290
291 if sw, ok := w.(SliceWalker); ok {
292 if err := sw.SliceElem(i, elem); err != nil {
293 return err
294 }
295 }
296
297 ew, ok := w.(EnterExitWalker)
298 if ok {
299 ew.Enter(SliceElem)
300 }
301
302 if err := walk(elem, w); err != nil {
303 return err
304 }
305
306 if ok {
307 ew.Exit(SliceElem)
308 }
309 }
310
311 ew, ok = w.(EnterExitWalker)
312 if ok {
313 ew.Exit(Slice)
314 }
315
316 return nil
317 }
318
319 func walkArray(v reflect.Value, w interface{}) (err error) {
320 ew, ok := w.(EnterExitWalker)
321 if ok {
322 ew.Enter(Array)
323 }
324
325 if aw, ok := w.(ArrayWalker); ok {
326 if err := aw.Array(v); err != nil {
327 return err
328 }
329 }
330
331 for i := 0; i < v.Len(); i++ {
332 elem := v.Index(i)
333
334 if aw, ok := w.(ArrayWalker); ok {
335 if err := aw.ArrayElem(i, elem); err != nil {
336 return err
337 }
338 }
339
340 ew, ok := w.(EnterExitWalker)
341 if ok {
342 ew.Enter(ArrayElem)
343 }
344
345 if err := walk(elem, w); err != nil {
346 return err
347 }
348
349 if ok {
350 ew.Exit(ArrayElem)
351 }
352 }
353
354 ew, ok = w.(EnterExitWalker)
355 if ok {
356 ew.Exit(Array)
357 }
358
359 return nil
360 }
361
362 func walkStruct(v reflect.Value, w interface{}) (err error) {
363 ew, ewok := w.(EnterExitWalker)
364 if ewok {
365 ew.Enter(Struct)
366 }
367
368 skip := false
369 if sw, ok := w.(StructWalker); ok {
370 err = sw.Struct(v)
371 if err == SkipEntry {
372 skip = true
373 err = nil
374 }
375 if err != nil {
376 return
377 }
378 }
379
380 if !skip {
381 vt := v.Type()
382 for i := 0; i < vt.NumField(); i++ {
383 sf := vt.Field(i)
384 f := v.FieldByIndex([]int{i})
385
386 if sw, ok := w.(StructWalker); ok {
387 err = sw.StructField(sf, f)
388
389
390 if err == SkipEntry {
391 continue
392 }
393
394 if err != nil {
395 return
396 }
397 }
398
399 ew, ok := w.(EnterExitWalker)
400 if ok {
401 ew.Enter(StructField)
402 }
403
404 err = walk(f, w)
405 if err != nil {
406 return
407 }
408
409 if ok {
410 ew.Exit(StructField)
411 }
412 }
413 }
414
415 if ewok {
416 ew.Exit(Struct)
417 }
418
419 return nil
420 }
421
View as plain text