forked from cerc-io/ipld-eth-server
166 lines
4.2 KiB
Go
166 lines
4.2 KiB
Go
|
// 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()))
|
||
|
}
|
||
|
}
|