pretty.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. // Copyright (c) 2015 Arista Networks, Inc.
  2. // Use of this source code is governed by the Apache License 2.0
  3. // that can be found in the COPYING file.
  4. package test
  5. import (
  6. "fmt"
  7. "os"
  8. "reflect"
  9. "sort"
  10. "strconv"
  11. "notabug.org/themusicgod1/goarista/areflect"
  12. )
  13. // PrettyPrint tries to display a human readable version of an interface
  14. func PrettyPrint(v interface{}) string {
  15. return PrettyPrintWithDepth(v, prettyPrintDepth)
  16. }
  17. // PrettyPrintWithDepth tries to display a human readable version of an interface
  18. // and allows to define the depth of the print
  19. func PrettyPrintWithDepth(v interface{}, depth int) string {
  20. return prettyPrint(reflect.ValueOf(v), ptrSet{}, depth)
  21. }
  22. var prettyPrintDepth = 8
  23. func init() {
  24. d := os.Getenv("PPDEPTH")
  25. if d, ok := strconv.Atoi(d); ok == nil && d >= 0 {
  26. prettyPrintDepth = d
  27. }
  28. }
  29. type ptrSet map[uintptr]struct{}
  30. func prettyPrint(v reflect.Value, done ptrSet, depth int) string {
  31. return prettyPrintWithType(v, done, depth, true)
  32. }
  33. func prettyPrintWithType(v reflect.Value, done ptrSet, depth int, showType bool) string {
  34. if depth < 0 {
  35. return "<max_depth>"
  36. }
  37. switch v.Kind() {
  38. case reflect.Invalid:
  39. return "nil"
  40. case reflect.Bool:
  41. return fmt.Sprintf("%t", v.Bool())
  42. case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
  43. reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
  44. reflect.Float32, reflect.Float64,
  45. reflect.Int, reflect.Uint, reflect.Uintptr,
  46. reflect.Complex64, reflect.Complex128:
  47. i := areflect.ForceExport(v).Interface()
  48. if showType {
  49. return fmt.Sprintf("%s(%v)", v.Type().Name(), i)
  50. }
  51. return fmt.Sprintf("%v", i)
  52. case reflect.String:
  53. return fmt.Sprintf("%q", v.String())
  54. case reflect.Ptr:
  55. return "*" + prettyPrintWithType(v.Elem(), done, depth-1, showType)
  56. case reflect.Interface:
  57. return prettyPrintWithType(v.Elem(), done, depth-1, showType)
  58. case reflect.Map:
  59. var r []byte
  60. r = append(r, []byte(v.Type().String())...)
  61. r = append(r, '{')
  62. var elems mapEntries
  63. for _, k := range v.MapKeys() {
  64. elem := &mapEntry{
  65. k: prettyPrint(k, done, depth-1),
  66. v: prettyPrint(v.MapIndex(k), done, depth-1),
  67. }
  68. elems.entries = append(elems.entries, elem)
  69. }
  70. sort.Sort(&elems)
  71. for i, e := range elems.entries {
  72. if i > 0 {
  73. r = append(r, []byte(", ")...)
  74. }
  75. r = append(r, []byte(e.k)...)
  76. r = append(r, ':')
  77. r = append(r, []byte(e.v)...)
  78. }
  79. r = append(r, '}')
  80. return string(r)
  81. case reflect.Struct:
  82. // Circular dependency?
  83. if v.CanAddr() {
  84. ptr := v.UnsafeAddr()
  85. if _, ok := done[ptr]; ok {
  86. return fmt.Sprintf("%s{<circular dependency>}", v.Type().String())
  87. }
  88. done[ptr] = struct{}{}
  89. }
  90. var r []byte
  91. r = append(r, []byte(v.Type().String())...)
  92. r = append(r, '{')
  93. for i := 0; i < v.NumField(); i++ {
  94. if i > 0 {
  95. r = append(r, []byte(", ")...)
  96. }
  97. sf := v.Type().Field(i)
  98. r = append(r, sf.Name...)
  99. r = append(r, ':')
  100. r = append(r, prettyPrint(v.Field(i), done, depth-1)...)
  101. }
  102. r = append(r, '}')
  103. return string(r)
  104. case reflect.Chan:
  105. var ptr, bufsize string
  106. if v.Pointer() == 0 {
  107. ptr = "nil"
  108. } else {
  109. ptr = fmt.Sprintf("0x%x", v.Pointer())
  110. }
  111. if v.Cap() > 0 {
  112. bufsize = fmt.Sprintf("[%d]", v.Cap())
  113. }
  114. return fmt.Sprintf("(%s)(%s)%s", v.Type().String(), ptr, bufsize)
  115. case reflect.Func:
  116. return "func(...)"
  117. case reflect.Array, reflect.Slice:
  118. l := v.Len()
  119. var r []byte
  120. if v.Type().Elem().Kind() == reflect.Uint8 && v.Kind() != reflect.Array {
  121. b := areflect.ForceExport(v).Interface().([]byte)
  122. r = append(r, []byte(`[]byte(`)...)
  123. if b == nil {
  124. r = append(r, []byte("nil")...)
  125. } else {
  126. r = append(r, []byte(fmt.Sprintf("%q", b))...)
  127. }
  128. r = append(r, ')')
  129. return string(r)
  130. }
  131. r = append(r, []byte(v.Type().String())...)
  132. r = append(r, '{')
  133. for i := 0; i < l; i++ {
  134. if i > 0 {
  135. r = append(r, []byte(", ")...)
  136. }
  137. r = append(r, prettyPrintWithType(v.Index(i), done, depth-1, false)...)
  138. }
  139. r = append(r, '}')
  140. return string(r)
  141. case reflect.UnsafePointer:
  142. var ptr string
  143. if v.Pointer() == 0 {
  144. ptr = "nil"
  145. } else {
  146. ptr = fmt.Sprintf("0x%x", v.Pointer())
  147. }
  148. if showType {
  149. ptr = fmt.Sprintf("(unsafe.Pointer)(%s)", ptr)
  150. }
  151. return ptr
  152. default:
  153. panic(fmt.Errorf("Unhandled kind of reflect.Value: %v", v.Kind()))
  154. }
  155. }