1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
|
package binutil
import (
"errors"
"fmt"
"path"
"reflect"
)
var (
WALK_SKIP = errors.New("")
)
type Walker func(v reflect.Value, path string) error
func Walk(value interface{}, walker Walker) error {
err := walk(reflect.ValueOf(value), "/", walker)
if err == WALK_SKIP {
err = nil
}
return err
}
func stopping(err error) bool {
return err != nil && err != WALK_SKIP
}
func walk(v reflect.Value, spath string, walker Walker) error {
err := walker(v, spath)
if err != nil {
return err
}
v = reflect.Indirect(v)
switch v.Kind() {
case reflect.Slice, reflect.Array:
for i := 0; i < v.Len(); i++ {
err = walk(v.Index(i), spath+fmt.Sprintf("[%d]", i), walker)
if stopping(err) {
return err
}
}
case reflect.Interface:
err = walk(v.Elem(), spath, walker)
if stopping(err) {
return err
}
case reflect.Struct:
//t := v.Type()
for i := 0; i < v.NumField(); i++ {
//f := t.Field(i) //TODO: handle unexported fields
vv := v.Field(i)
err = walk(vv, path.Join(spath, v.Type().Field(i).Name), walker)
if stopping(err) {
return err
}
}
default:
// FIXME: handle other special cases too
// String
return nil
}
return nil
}
|