github.com/ladydascalie/elvish@v0.0.0-20170703214355-2964dd3ece7f/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  }