github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+incompatible/cmds/core/elvish/util/deepprint.go (about) 1 package util 2 3 import ( 4 "bytes" 5 "fmt" 6 "reflect" 7 ) 8 9 // DeepPrint is like printing with the %#v formatter of fmt, but it prints 10 // pointer fields recursively. 11 func DeepPrint(x interface{}) string { 12 b := &bytes.Buffer{} 13 deepPrint(b, reflect.ValueOf(x)) 14 return b.String() 15 } 16 17 func deepPrint(b *bytes.Buffer, v reflect.Value) { 18 i := v.Interface() 19 t := v.Type() 20 21 // GoStringer 22 if g, ok := i.(fmt.GoStringer); ok { 23 b.WriteString(g.GoString()) 24 return 25 } 26 27 // nil 28 switch v.Kind() { 29 case reflect.Interface, reflect.Map, reflect.Slice, reflect.Ptr: 30 if v.IsNil() { 31 b.WriteString("nil") 32 return 33 } 34 } 35 36 switch v.Kind() { 37 case reflect.Array, reflect.Slice, reflect.Map, reflect.Struct: 38 // Composite kinds 39 b.WriteString(t.String()) 40 b.WriteRune('{') 41 switch v.Kind() { 42 case reflect.Array, reflect.Slice: 43 for i := 0; i < v.Len(); i++ { 44 if i > 0 { 45 b.WriteString(", ") 46 } 47 deepPrint(b, v.Index(i)) 48 } 49 case reflect.Map: 50 keys := v.MapKeys() 51 for i, k := range keys { 52 if i > 0 { 53 b.WriteString(", ") 54 } 55 deepPrint(b, k) 56 b.WriteString(": ") 57 deepPrint(b, v.MapIndex(k)) 58 } 59 case reflect.Struct: 60 for i := 0; i < t.NumField(); i++ { 61 if i > 0 { 62 b.WriteString(", ") 63 } 64 b.WriteString(t.Field(i).Name) 65 b.WriteString(": ") 66 deepPrint(b, v.Field(i)) 67 } 68 } 69 b.WriteRune('}') 70 case reflect.Ptr: 71 b.WriteRune('&') 72 deepPrint(b, reflect.Indirect(v)) 73 return 74 case reflect.Interface: 75 deepPrint(b, v.Elem()) 76 return 77 default: 78 fmt.Fprintf(b, "%#v", i) 79 return 80 } 81 }