| Index: render/render.go
|
| diff --git a/render/render.go b/render/render.go
|
| index e070a6b3b58151070bafd171a9f4f5336d4ab39c..bdb307ce9d49be5f2662606dbe61c7e6485edea8 100644
|
| --- a/render/render.go
|
| +++ b/render/render.go
|
| @@ -12,32 +12,46 @@ import (
|
| "strconv"
|
| )
|
|
|
| -var implicitTypeMap = map[reflect.Kind]string{
|
| +var builtinTypeMap = map[reflect.Kind]string{
|
| reflect.Bool: "bool",
|
| - reflect.String: "string",
|
| - reflect.Int: "int",
|
| - reflect.Int8: "int8",
|
| + reflect.Complex128: "complex128",
|
| + reflect.Complex64: "complex64",
|
| + reflect.Float32: "float32",
|
| + reflect.Float64: "float64",
|
| reflect.Int16: "int16",
|
| reflect.Int32: "int32",
|
| reflect.Int64: "int64",
|
| - reflect.Uint: "uint",
|
| - reflect.Uint8: "uint8",
|
| + reflect.Int8: "int8",
|
| + reflect.Int: "int",
|
| + reflect.String: "string",
|
| reflect.Uint16: "uint16",
|
| reflect.Uint32: "uint32",
|
| reflect.Uint64: "uint64",
|
| - reflect.Float32: "float32",
|
| - reflect.Float64: "float64",
|
| - reflect.Complex64: "complex64",
|
| - reflect.Complex128: "complex128",
|
| + reflect.Uint8: "uint8",
|
| + reflect.Uint: "uint",
|
| + reflect.Uintptr: "uintptr",
|
| +}
|
| +
|
| +var builtinTypeSet = map[string]struct{}{}
|
| +
|
| +func init() {
|
| + for _, v := range builtinTypeMap {
|
| + builtinTypeSet[v] = struct{}{}
|
| + }
|
| }
|
|
|
| +var typeOfString = reflect.TypeOf("")
|
| +var typeOfInt = reflect.TypeOf(int(1))
|
| +var typeOfUint = reflect.TypeOf(uint(1))
|
| +var typeOfFloat = reflect.TypeOf(10.1)
|
| +
|
| // Render converts a structure to a string representation. Unline the "%#v"
|
| // format string, this resolves pointer types' contents in structs, maps, and
|
| // slices/arrays and prints their field values.
|
| func Render(v interface{}) string {
|
| buf := bytes.Buffer{}
|
| s := (*traverseState)(nil)
|
| - s.render(&buf, 0, reflect.ValueOf(v))
|
| + s.render(&buf, 0, reflect.ValueOf(v), false)
|
| return buf.String()
|
| }
|
|
|
| @@ -72,7 +86,7 @@ func (s *traverseState) forkFor(ptr uintptr) *traverseState {
|
| return fs
|
| }
|
|
|
| -func (s *traverseState) render(buf *bytes.Buffer, ptrs int, v reflect.Value) {
|
| +func (s *traverseState) render(buf *bytes.Buffer, ptrs int, v reflect.Value, implicit bool) {
|
| if v.Kind() == reflect.Invalid {
|
| buf.WriteString("nil")
|
| return
|
| @@ -107,49 +121,76 @@ func (s *traverseState) render(buf *bytes.Buffer, ptrs int, v reflect.Value) {
|
| s = s.forkFor(pe)
|
| if s == nil {
|
| buf.WriteString("<REC(")
|
| - writeType(buf, ptrs, vt)
|
| + if !implicit {
|
| + writeType(buf, ptrs, vt)
|
| + }
|
| buf.WriteString(")>")
|
| return
|
| }
|
| }
|
|
|
| + isAnon := func(t reflect.Type) bool {
|
| + if t.Name() != "" {
|
| + if _, ok := builtinTypeSet[t.Name()]; !ok {
|
| + return false
|
| + }
|
| + }
|
| + return t.Kind() != reflect.Interface
|
| + }
|
| +
|
| switch vk {
|
| case reflect.Struct:
|
| - writeType(buf, ptrs, vt)
|
| + if !implicit {
|
| + writeType(buf, ptrs, vt)
|
| + }
|
| + structAnon := vt.Name() == ""
|
| buf.WriteRune('{')
|
| for i := 0; i < vt.NumField(); i++ {
|
| if i > 0 {
|
| buf.WriteString(", ")
|
| }
|
| - buf.WriteString(vt.Field(i).Name)
|
| - buf.WriteRune(':')
|
| + anon := structAnon && isAnon(vt.Field(i).Type)
|
| +
|
| + if !anon {
|
| + buf.WriteString(vt.Field(i).Name)
|
| + buf.WriteRune(':')
|
| + }
|
|
|
| - s.render(buf, 0, v.Field(i))
|
| + s.render(buf, 0, v.Field(i), anon)
|
| }
|
| buf.WriteRune('}')
|
|
|
| case reflect.Slice:
|
| if v.IsNil() {
|
| - writeType(buf, ptrs, vt)
|
| - buf.WriteString("(nil)")
|
| + if !implicit {
|
| + writeType(buf, ptrs, vt)
|
| + buf.WriteString("(nil)")
|
| + } else {
|
| + buf.WriteString("nil")
|
| + }
|
| return
|
| }
|
| fallthrough
|
|
|
| case reflect.Array:
|
| - writeType(buf, ptrs, vt)
|
| + if !implicit {
|
| + writeType(buf, ptrs, vt)
|
| + }
|
| + anon := vt.Name() == "" && isAnon(vt.Elem())
|
| buf.WriteString("{")
|
| for i := 0; i < v.Len(); i++ {
|
| if i > 0 {
|
| buf.WriteString(", ")
|
| }
|
|
|
| - s.render(buf, 0, v.Index(i))
|
| + s.render(buf, 0, v.Index(i), anon)
|
| }
|
| buf.WriteRune('}')
|
|
|
| case reflect.Map:
|
| - writeType(buf, ptrs, vt)
|
| + if !implicit {
|
| + writeType(buf, ptrs, vt)
|
| + }
|
| if v.IsNil() {
|
| buf.WriteString("(nil)")
|
| } else {
|
| @@ -158,14 +199,17 @@ func (s *traverseState) render(buf *bytes.Buffer, ptrs int, v reflect.Value) {
|
| mkeys := v.MapKeys()
|
| tryAndSortMapKeys(vt, mkeys)
|
|
|
| + kt := vt.Key()
|
| + keyAnon := typeOfString.ConvertibleTo(kt) || typeOfInt.ConvertibleTo(kt) || typeOfUint.ConvertibleTo(kt) || typeOfFloat.ConvertibleTo(kt)
|
| + valAnon := vt.Name() == "" && isAnon(vt.Elem())
|
| for i, mk := range mkeys {
|
| if i > 0 {
|
| buf.WriteString(", ")
|
| }
|
|
|
| - s.render(buf, 0, mk)
|
| + s.render(buf, 0, mk, keyAnon)
|
| buf.WriteString(":")
|
| - s.render(buf, 0, v.MapIndex(mk))
|
| + s.render(buf, 0, v.MapIndex(mk), valAnon)
|
| }
|
| buf.WriteRune('}')
|
| }
|
| @@ -176,11 +220,9 @@ func (s *traverseState) render(buf *bytes.Buffer, ptrs int, v reflect.Value) {
|
| case reflect.Interface:
|
| if v.IsNil() {
|
| writeType(buf, ptrs, v.Type())
|
| - buf.WriteRune('(')
|
| - fmt.Fprint(buf, "nil")
|
| - buf.WriteRune(')')
|
| + buf.WriteString("(nil)")
|
| } else {
|
| - s.render(buf, ptrs, v.Elem())
|
| + s.render(buf, ptrs, v.Elem(), false)
|
| }
|
|
|
| case reflect.Chan, reflect.Func, reflect.UnsafePointer:
|
| @@ -191,7 +233,7 @@ func (s *traverseState) render(buf *bytes.Buffer, ptrs int, v reflect.Value) {
|
|
|
| default:
|
| tstr := vt.String()
|
| - implicit := ptrs == 0 && implicitTypeMap[vk] == tstr
|
| + implicit = implicit || (ptrs == 0 && builtinTypeMap[vk] == tstr)
|
| if !implicit {
|
| writeType(buf, ptrs, vt)
|
| buf.WriteRune('(')
|
| @@ -206,7 +248,7 @@ func (s *traverseState) render(buf *bytes.Buffer, ptrs int, v reflect.Value) {
|
| case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
| fmt.Fprintf(buf, "%d", v.Int())
|
|
|
| - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
| + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
| fmt.Fprintf(buf, "%d", v.Uint())
|
|
|
| case reflect.Float32, reflect.Float64:
|
|
|