Scott Baker | eee8dd8 | 2019-09-24 12:52:34 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2013-2016 Dave Collins <dave@davec.name> |
| 3 | * |
| 4 | * Permission to use, copy, modify, and distribute this software for any |
| 5 | * purpose with or without fee is hereby granted, provided that the above |
| 6 | * copyright notice and this permission notice appear in all copies. |
| 7 | * |
| 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
| 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| 15 | */ |
| 16 | |
| 17 | package spew |
| 18 | |
| 19 | import ( |
| 20 | "bytes" |
| 21 | "fmt" |
| 22 | "io" |
| 23 | "reflect" |
| 24 | "sort" |
| 25 | "strconv" |
| 26 | ) |
| 27 | |
| 28 | // Some constants in the form of bytes to avoid string overhead. This mirrors |
| 29 | // the technique used in the fmt package. |
| 30 | var ( |
| 31 | panicBytes = []byte("(PANIC=") |
| 32 | plusBytes = []byte("+") |
| 33 | iBytes = []byte("i") |
| 34 | trueBytes = []byte("true") |
| 35 | falseBytes = []byte("false") |
| 36 | interfaceBytes = []byte("(interface {})") |
| 37 | commaNewlineBytes = []byte(",\n") |
| 38 | newlineBytes = []byte("\n") |
| 39 | openBraceBytes = []byte("{") |
| 40 | openBraceNewlineBytes = []byte("{\n") |
| 41 | closeBraceBytes = []byte("}") |
| 42 | asteriskBytes = []byte("*") |
| 43 | colonBytes = []byte(":") |
| 44 | colonSpaceBytes = []byte(": ") |
| 45 | openParenBytes = []byte("(") |
| 46 | closeParenBytes = []byte(")") |
| 47 | spaceBytes = []byte(" ") |
| 48 | pointerChainBytes = []byte("->") |
| 49 | nilAngleBytes = []byte("<nil>") |
| 50 | maxNewlineBytes = []byte("<max depth reached>\n") |
| 51 | maxShortBytes = []byte("<max>") |
| 52 | circularBytes = []byte("<already shown>") |
| 53 | circularShortBytes = []byte("<shown>") |
| 54 | invalidAngleBytes = []byte("<invalid>") |
| 55 | openBracketBytes = []byte("[") |
| 56 | closeBracketBytes = []byte("]") |
| 57 | percentBytes = []byte("%") |
| 58 | precisionBytes = []byte(".") |
| 59 | openAngleBytes = []byte("<") |
| 60 | closeAngleBytes = []byte(">") |
| 61 | openMapBytes = []byte("map[") |
| 62 | closeMapBytes = []byte("]") |
| 63 | lenEqualsBytes = []byte("len=") |
| 64 | capEqualsBytes = []byte("cap=") |
| 65 | ) |
| 66 | |
| 67 | // hexDigits is used to map a decimal value to a hex digit. |
| 68 | var hexDigits = "0123456789abcdef" |
| 69 | |
| 70 | // catchPanic handles any panics that might occur during the handleMethods |
| 71 | // calls. |
| 72 | func catchPanic(w io.Writer, v reflect.Value) { |
| 73 | if err := recover(); err != nil { |
| 74 | w.Write(panicBytes) |
| 75 | fmt.Fprintf(w, "%v", err) |
| 76 | w.Write(closeParenBytes) |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | // handleMethods attempts to call the Error and String methods on the underlying |
| 81 | // type the passed reflect.Value represents and outputes the result to Writer w. |
| 82 | // |
| 83 | // It handles panics in any called methods by catching and displaying the error |
| 84 | // as the formatted value. |
| 85 | func handleMethods(cs *ConfigState, w io.Writer, v reflect.Value) (handled bool) { |
| 86 | // We need an interface to check if the type implements the error or |
| 87 | // Stringer interface. However, the reflect package won't give us an |
| 88 | // interface on certain things like unexported struct fields in order |
| 89 | // to enforce visibility rules. We use unsafe, when it's available, |
| 90 | // to bypass these restrictions since this package does not mutate the |
| 91 | // values. |
| 92 | if !v.CanInterface() { |
| 93 | if UnsafeDisabled { |
| 94 | return false |
| 95 | } |
| 96 | |
| 97 | v = unsafeReflectValue(v) |
| 98 | } |
| 99 | |
| 100 | // Choose whether or not to do error and Stringer interface lookups against |
| 101 | // the base type or a pointer to the base type depending on settings. |
| 102 | // Technically calling one of these methods with a pointer receiver can |
| 103 | // mutate the value, however, types which choose to satisify an error or |
| 104 | // Stringer interface with a pointer receiver should not be mutating their |
| 105 | // state inside these interface methods. |
| 106 | if !cs.DisablePointerMethods && !UnsafeDisabled && !v.CanAddr() { |
| 107 | v = unsafeReflectValue(v) |
| 108 | } |
| 109 | if v.CanAddr() { |
| 110 | v = v.Addr() |
| 111 | } |
| 112 | |
| 113 | // Is it an error or Stringer? |
| 114 | switch iface := v.Interface().(type) { |
| 115 | case error: |
| 116 | defer catchPanic(w, v) |
| 117 | if cs.ContinueOnMethod { |
| 118 | w.Write(openParenBytes) |
| 119 | w.Write([]byte(iface.Error())) |
| 120 | w.Write(closeParenBytes) |
| 121 | w.Write(spaceBytes) |
| 122 | return false |
| 123 | } |
| 124 | |
| 125 | w.Write([]byte(iface.Error())) |
| 126 | return true |
| 127 | |
| 128 | case fmt.Stringer: |
| 129 | defer catchPanic(w, v) |
| 130 | if cs.ContinueOnMethod { |
| 131 | w.Write(openParenBytes) |
| 132 | w.Write([]byte(iface.String())) |
| 133 | w.Write(closeParenBytes) |
| 134 | w.Write(spaceBytes) |
| 135 | return false |
| 136 | } |
| 137 | w.Write([]byte(iface.String())) |
| 138 | return true |
| 139 | } |
| 140 | return false |
| 141 | } |
| 142 | |
| 143 | // printBool outputs a boolean value as true or false to Writer w. |
| 144 | func printBool(w io.Writer, val bool) { |
| 145 | if val { |
| 146 | w.Write(trueBytes) |
| 147 | } else { |
| 148 | w.Write(falseBytes) |
| 149 | } |
| 150 | } |
| 151 | |
| 152 | // printInt outputs a signed integer value to Writer w. |
| 153 | func printInt(w io.Writer, val int64, base int) { |
| 154 | w.Write([]byte(strconv.FormatInt(val, base))) |
| 155 | } |
| 156 | |
| 157 | // printUint outputs an unsigned integer value to Writer w. |
| 158 | func printUint(w io.Writer, val uint64, base int) { |
| 159 | w.Write([]byte(strconv.FormatUint(val, base))) |
| 160 | } |
| 161 | |
| 162 | // printFloat outputs a floating point value using the specified precision, |
| 163 | // which is expected to be 32 or 64bit, to Writer w. |
| 164 | func printFloat(w io.Writer, val float64, precision int) { |
| 165 | w.Write([]byte(strconv.FormatFloat(val, 'g', -1, precision))) |
| 166 | } |
| 167 | |
| 168 | // printComplex outputs a complex value using the specified float precision |
| 169 | // for the real and imaginary parts to Writer w. |
| 170 | func printComplex(w io.Writer, c complex128, floatPrecision int) { |
| 171 | r := real(c) |
| 172 | w.Write(openParenBytes) |
| 173 | w.Write([]byte(strconv.FormatFloat(r, 'g', -1, floatPrecision))) |
| 174 | i := imag(c) |
| 175 | if i >= 0 { |
| 176 | w.Write(plusBytes) |
| 177 | } |
| 178 | w.Write([]byte(strconv.FormatFloat(i, 'g', -1, floatPrecision))) |
| 179 | w.Write(iBytes) |
| 180 | w.Write(closeParenBytes) |
| 181 | } |
| 182 | |
| 183 | // printHexPtr outputs a uintptr formatted as hexadecimal with a leading '0x' |
| 184 | // prefix to Writer w. |
| 185 | func printHexPtr(w io.Writer, p uintptr) { |
| 186 | // Null pointer. |
| 187 | num := uint64(p) |
| 188 | if num == 0 { |
| 189 | w.Write(nilAngleBytes) |
| 190 | return |
| 191 | } |
| 192 | |
| 193 | // Max uint64 is 16 bytes in hex + 2 bytes for '0x' prefix |
| 194 | buf := make([]byte, 18) |
| 195 | |
| 196 | // It's simpler to construct the hex string right to left. |
| 197 | base := uint64(16) |
| 198 | i := len(buf) - 1 |
| 199 | for num >= base { |
| 200 | buf[i] = hexDigits[num%base] |
| 201 | num /= base |
| 202 | i-- |
| 203 | } |
| 204 | buf[i] = hexDigits[num] |
| 205 | |
| 206 | // Add '0x' prefix. |
| 207 | i-- |
| 208 | buf[i] = 'x' |
| 209 | i-- |
| 210 | buf[i] = '0' |
| 211 | |
| 212 | // Strip unused leading bytes. |
| 213 | buf = buf[i:] |
| 214 | w.Write(buf) |
| 215 | } |
| 216 | |
| 217 | // valuesSorter implements sort.Interface to allow a slice of reflect.Value |
| 218 | // elements to be sorted. |
| 219 | type valuesSorter struct { |
| 220 | values []reflect.Value |
| 221 | strings []string // either nil or same len and values |
| 222 | cs *ConfigState |
| 223 | } |
| 224 | |
| 225 | // newValuesSorter initializes a valuesSorter instance, which holds a set of |
| 226 | // surrogate keys on which the data should be sorted. It uses flags in |
| 227 | // ConfigState to decide if and how to populate those surrogate keys. |
| 228 | func newValuesSorter(values []reflect.Value, cs *ConfigState) sort.Interface { |
| 229 | vs := &valuesSorter{values: values, cs: cs} |
| 230 | if canSortSimply(vs.values[0].Kind()) { |
| 231 | return vs |
| 232 | } |
| 233 | if !cs.DisableMethods { |
| 234 | vs.strings = make([]string, len(values)) |
| 235 | for i := range vs.values { |
| 236 | b := bytes.Buffer{} |
| 237 | if !handleMethods(cs, &b, vs.values[i]) { |
| 238 | vs.strings = nil |
| 239 | break |
| 240 | } |
| 241 | vs.strings[i] = b.String() |
| 242 | } |
| 243 | } |
| 244 | if vs.strings == nil && cs.SpewKeys { |
| 245 | vs.strings = make([]string, len(values)) |
| 246 | for i := range vs.values { |
| 247 | vs.strings[i] = Sprintf("%#v", vs.values[i].Interface()) |
| 248 | } |
| 249 | } |
| 250 | return vs |
| 251 | } |
| 252 | |
| 253 | // canSortSimply tests whether a reflect.Kind is a primitive that can be sorted |
| 254 | // directly, or whether it should be considered for sorting by surrogate keys |
| 255 | // (if the ConfigState allows it). |
| 256 | func canSortSimply(kind reflect.Kind) bool { |
| 257 | // This switch parallels valueSortLess, except for the default case. |
| 258 | switch kind { |
| 259 | case reflect.Bool: |
| 260 | return true |
| 261 | case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: |
| 262 | return true |
| 263 | case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: |
| 264 | return true |
| 265 | case reflect.Float32, reflect.Float64: |
| 266 | return true |
| 267 | case reflect.String: |
| 268 | return true |
| 269 | case reflect.Uintptr: |
| 270 | return true |
| 271 | case reflect.Array: |
| 272 | return true |
| 273 | } |
| 274 | return false |
| 275 | } |
| 276 | |
| 277 | // Len returns the number of values in the slice. It is part of the |
| 278 | // sort.Interface implementation. |
| 279 | func (s *valuesSorter) Len() int { |
| 280 | return len(s.values) |
| 281 | } |
| 282 | |
| 283 | // Swap swaps the values at the passed indices. It is part of the |
| 284 | // sort.Interface implementation. |
| 285 | func (s *valuesSorter) Swap(i, j int) { |
| 286 | s.values[i], s.values[j] = s.values[j], s.values[i] |
| 287 | if s.strings != nil { |
| 288 | s.strings[i], s.strings[j] = s.strings[j], s.strings[i] |
| 289 | } |
| 290 | } |
| 291 | |
| 292 | // valueSortLess returns whether the first value should sort before the second |
| 293 | // value. It is used by valueSorter.Less as part of the sort.Interface |
| 294 | // implementation. |
| 295 | func valueSortLess(a, b reflect.Value) bool { |
| 296 | switch a.Kind() { |
| 297 | case reflect.Bool: |
| 298 | return !a.Bool() && b.Bool() |
| 299 | case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: |
| 300 | return a.Int() < b.Int() |
| 301 | case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: |
| 302 | return a.Uint() < b.Uint() |
| 303 | case reflect.Float32, reflect.Float64: |
| 304 | return a.Float() < b.Float() |
| 305 | case reflect.String: |
| 306 | return a.String() < b.String() |
| 307 | case reflect.Uintptr: |
| 308 | return a.Uint() < b.Uint() |
| 309 | case reflect.Array: |
| 310 | // Compare the contents of both arrays. |
| 311 | l := a.Len() |
| 312 | for i := 0; i < l; i++ { |
| 313 | av := a.Index(i) |
| 314 | bv := b.Index(i) |
| 315 | if av.Interface() == bv.Interface() { |
| 316 | continue |
| 317 | } |
| 318 | return valueSortLess(av, bv) |
| 319 | } |
| 320 | } |
| 321 | return a.String() < b.String() |
| 322 | } |
| 323 | |
| 324 | // Less returns whether the value at index i should sort before the |
| 325 | // value at index j. It is part of the sort.Interface implementation. |
| 326 | func (s *valuesSorter) Less(i, j int) bool { |
| 327 | if s.strings == nil { |
| 328 | return valueSortLess(s.values[i], s.values[j]) |
| 329 | } |
| 330 | return s.strings[i] < s.strings[j] |
| 331 | } |
| 332 | |
| 333 | // sortValues is a sort function that handles both native types and any type that |
| 334 | // can be converted to error or Stringer. Other inputs are sorted according to |
| 335 | // their Value.String() value to ensure display stability. |
| 336 | func sortValues(values []reflect.Value, cs *ConfigState) { |
| 337 | if len(values) == 0 { |
| 338 | return |
| 339 | } |
| 340 | sort.Sort(newValuesSorter(values, cs)) |
| 341 | } |