ipld-eth-server/vendor/github.com/aristanetworks/goarista/test/pretty.go

166 lines
4.2 KiB
Go
Raw Normal View History

// Copyright (c) 2015 Arista Networks, Inc.
// Use of this source code is governed by the Apache License 2.0
// that can be found in the COPYING file.
package test
import (
"fmt"
"os"
"reflect"
"sort"
"strconv"
"github.com/aristanetworks/goarista/areflect"
)
// PrettyPrint tries to display a human readable version of an interface
func PrettyPrint(v interface{}) string {
return PrettyPrintWithDepth(v, prettyPrintDepth)
}
// PrettyPrintWithDepth tries to display a human readable version of an interface
// and allows to define the depth of the print
func PrettyPrintWithDepth(v interface{}, depth int) string {
return prettyPrint(reflect.ValueOf(v), ptrSet{}, depth)
}
var prettyPrintDepth = 8
func init() {
d := os.Getenv("PPDEPTH")
if d, ok := strconv.Atoi(d); ok == nil && d >= 0 {
prettyPrintDepth = d
}
}
type ptrSet map[uintptr]struct{}
func prettyPrint(v reflect.Value, done ptrSet, depth int) string {
return prettyPrintWithType(v, done, depth, true)
}
func prettyPrintWithType(v reflect.Value, done ptrSet, depth int, showType bool) string {
if depth < 0 {
return "<max_depth>"
}
switch v.Kind() {
case reflect.Invalid:
return "nil"
case reflect.Bool:
return fmt.Sprintf("%t", v.Bool())
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Float32, reflect.Float64,
reflect.Int, reflect.Uint, reflect.Uintptr,
reflect.Complex64, reflect.Complex128:
i := areflect.ForceExport(v).Interface()
if showType {
return fmt.Sprintf("%s(%v)", v.Type().Name(), i)
}
return fmt.Sprintf("%v", i)
case reflect.String:
return fmt.Sprintf("%q", v.String())
case reflect.Ptr:
return "*" + prettyPrintWithType(v.Elem(), done, depth-1, showType)
case reflect.Interface:
return prettyPrintWithType(v.Elem(), done, depth-1, showType)
case reflect.Map:
var r []byte
r = append(r, []byte(v.Type().String())...)
r = append(r, '{')
var elems mapEntries
for _, k := range v.MapKeys() {
elem := &mapEntry{
k: prettyPrint(k, done, depth-1),
v: prettyPrint(v.MapIndex(k), done, depth-1),
}
elems.entries = append(elems.entries, elem)
}
sort.Sort(&elems)
for i, e := range elems.entries {
if i > 0 {
r = append(r, []byte(", ")...)
}
r = append(r, []byte(e.k)...)
r = append(r, ':')
r = append(r, []byte(e.v)...)
}
r = append(r, '}')
return string(r)
case reflect.Struct:
// Circular dependency?
if v.CanAddr() {
ptr := v.UnsafeAddr()
if _, ok := done[ptr]; ok {
return fmt.Sprintf("%s{<circular dependency>}", v.Type().String())
}
done[ptr] = struct{}{}
}
var r []byte
r = append(r, []byte(v.Type().String())...)
r = append(r, '{')
for i := 0; i < v.NumField(); i++ {
if i > 0 {
r = append(r, []byte(", ")...)
}
sf := v.Type().Field(i)
r = append(r, sf.Name...)
r = append(r, ':')
r = append(r, prettyPrint(v.Field(i), done, depth-1)...)
}
r = append(r, '}')
return string(r)
case reflect.Chan:
var ptr, bufsize string
if v.Pointer() == 0 {
ptr = "nil"
} else {
ptr = fmt.Sprintf("0x%x", v.Pointer())
}
if v.Cap() > 0 {
bufsize = fmt.Sprintf("[%d]", v.Cap())
}
return fmt.Sprintf("(%s)(%s)%s", v.Type().String(), ptr, bufsize)
case reflect.Func:
return "func(...)"
case reflect.Array, reflect.Slice:
l := v.Len()
var r []byte
if v.Type().Elem().Kind() == reflect.Uint8 && v.Kind() != reflect.Array {
b := areflect.ForceExport(v).Interface().([]byte)
r = append(r, []byte(`[]byte(`)...)
if b == nil {
r = append(r, []byte("nil")...)
} else {
r = append(r, []byte(fmt.Sprintf("%q", b))...)
}
r = append(r, ')')
return string(r)
}
r = append(r, []byte(v.Type().String())...)
r = append(r, '{')
for i := 0; i < l; i++ {
if i > 0 {
r = append(r, []byte(", ")...)
}
r = append(r, prettyPrintWithType(v.Index(i), done, depth-1, false)...)
}
r = append(r, '}')
return string(r)
case reflect.UnsafePointer:
var ptr string
if v.Pointer() == 0 {
ptr = "nil"
} else {
ptr = fmt.Sprintf("0x%x", v.Pointer())
}
if showType {
ptr = fmt.Sprintf("(unsafe.Pointer)(%s)", ptr)
}
return ptr
default:
panic(fmt.Errorf("Unhandled kind of reflect.Value: %v", v.Kind()))
}
}