Zack Williams | e940c7a | 2019-08-21 14:25:39 -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 | "reflect" |
| 23 | "strconv" |
| 24 | "strings" |
| 25 | ) |
| 26 | |
| 27 | // supportedFlags is a list of all the character flags supported by fmt package. |
| 28 | const supportedFlags = "0-+# " |
| 29 | |
| 30 | // formatState implements the fmt.Formatter interface and contains information |
| 31 | // about the state of a formatting operation. The NewFormatter function can |
| 32 | // be used to get a new Formatter which can be used directly as arguments |
| 33 | // in standard fmt package printing calls. |
| 34 | type formatState struct { |
| 35 | value interface{} |
| 36 | fs fmt.State |
| 37 | depth int |
| 38 | pointers map[uintptr]int |
| 39 | ignoreNextType bool |
| 40 | cs *ConfigState |
| 41 | } |
| 42 | |
| 43 | // buildDefaultFormat recreates the original format string without precision |
| 44 | // and width information to pass in to fmt.Sprintf in the case of an |
| 45 | // unrecognized type. Unless new types are added to the language, this |
| 46 | // function won't ever be called. |
| 47 | func (f *formatState) buildDefaultFormat() (format string) { |
| 48 | buf := bytes.NewBuffer(percentBytes) |
| 49 | |
| 50 | for _, flag := range supportedFlags { |
| 51 | if f.fs.Flag(int(flag)) { |
| 52 | buf.WriteRune(flag) |
| 53 | } |
| 54 | } |
| 55 | |
| 56 | buf.WriteRune('v') |
| 57 | |
| 58 | format = buf.String() |
| 59 | return format |
| 60 | } |
| 61 | |
| 62 | // constructOrigFormat recreates the original format string including precision |
| 63 | // and width information to pass along to the standard fmt package. This allows |
| 64 | // automatic deferral of all format strings this package doesn't support. |
| 65 | func (f *formatState) constructOrigFormat(verb rune) (format string) { |
| 66 | buf := bytes.NewBuffer(percentBytes) |
| 67 | |
| 68 | for _, flag := range supportedFlags { |
| 69 | if f.fs.Flag(int(flag)) { |
| 70 | buf.WriteRune(flag) |
| 71 | } |
| 72 | } |
| 73 | |
| 74 | if width, ok := f.fs.Width(); ok { |
| 75 | buf.WriteString(strconv.Itoa(width)) |
| 76 | } |
| 77 | |
| 78 | if precision, ok := f.fs.Precision(); ok { |
| 79 | buf.Write(precisionBytes) |
| 80 | buf.WriteString(strconv.Itoa(precision)) |
| 81 | } |
| 82 | |
| 83 | buf.WriteRune(verb) |
| 84 | |
| 85 | format = buf.String() |
| 86 | return format |
| 87 | } |
| 88 | |
| 89 | // unpackValue returns values inside of non-nil interfaces when possible and |
| 90 | // ensures that types for values which have been unpacked from an interface |
| 91 | // are displayed when the show types flag is also set. |
| 92 | // This is useful for data types like structs, arrays, slices, and maps which |
| 93 | // can contain varying types packed inside an interface. |
| 94 | func (f *formatState) unpackValue(v reflect.Value) reflect.Value { |
| 95 | if v.Kind() == reflect.Interface { |
| 96 | f.ignoreNextType = false |
| 97 | if !v.IsNil() { |
| 98 | v = v.Elem() |
| 99 | } |
| 100 | } |
| 101 | return v |
| 102 | } |
| 103 | |
| 104 | // formatPtr handles formatting of pointers by indirecting them as necessary. |
| 105 | func (f *formatState) formatPtr(v reflect.Value) { |
| 106 | // Display nil if top level pointer is nil. |
| 107 | showTypes := f.fs.Flag('#') |
| 108 | if v.IsNil() && (!showTypes || f.ignoreNextType) { |
| 109 | f.fs.Write(nilAngleBytes) |
| 110 | return |
| 111 | } |
| 112 | |
| 113 | // Remove pointers at or below the current depth from map used to detect |
| 114 | // circular refs. |
| 115 | for k, depth := range f.pointers { |
| 116 | if depth >= f.depth { |
| 117 | delete(f.pointers, k) |
| 118 | } |
| 119 | } |
| 120 | |
| 121 | // Keep list of all dereferenced pointers to possibly show later. |
| 122 | pointerChain := make([]uintptr, 0) |
| 123 | |
| 124 | // Figure out how many levels of indirection there are by derferencing |
| 125 | // pointers and unpacking interfaces down the chain while detecting circular |
| 126 | // references. |
| 127 | nilFound := false |
| 128 | cycleFound := false |
| 129 | indirects := 0 |
| 130 | ve := v |
| 131 | for ve.Kind() == reflect.Ptr { |
| 132 | if ve.IsNil() { |
| 133 | nilFound = true |
| 134 | break |
| 135 | } |
| 136 | indirects++ |
| 137 | addr := ve.Pointer() |
| 138 | pointerChain = append(pointerChain, addr) |
| 139 | if pd, ok := f.pointers[addr]; ok && pd < f.depth { |
| 140 | cycleFound = true |
| 141 | indirects-- |
| 142 | break |
| 143 | } |
| 144 | f.pointers[addr] = f.depth |
| 145 | |
| 146 | ve = ve.Elem() |
| 147 | if ve.Kind() == reflect.Interface { |
| 148 | if ve.IsNil() { |
| 149 | nilFound = true |
| 150 | break |
| 151 | } |
| 152 | ve = ve.Elem() |
| 153 | } |
| 154 | } |
| 155 | |
| 156 | // Display type or indirection level depending on flags. |
| 157 | if showTypes && !f.ignoreNextType { |
| 158 | f.fs.Write(openParenBytes) |
| 159 | f.fs.Write(bytes.Repeat(asteriskBytes, indirects)) |
| 160 | f.fs.Write([]byte(ve.Type().String())) |
| 161 | f.fs.Write(closeParenBytes) |
| 162 | } else { |
| 163 | if nilFound || cycleFound { |
| 164 | indirects += strings.Count(ve.Type().String(), "*") |
| 165 | } |
| 166 | f.fs.Write(openAngleBytes) |
| 167 | f.fs.Write([]byte(strings.Repeat("*", indirects))) |
| 168 | f.fs.Write(closeAngleBytes) |
| 169 | } |
| 170 | |
| 171 | // Display pointer information depending on flags. |
| 172 | if f.fs.Flag('+') && (len(pointerChain) > 0) { |
| 173 | f.fs.Write(openParenBytes) |
| 174 | for i, addr := range pointerChain { |
| 175 | if i > 0 { |
| 176 | f.fs.Write(pointerChainBytes) |
| 177 | } |
| 178 | printHexPtr(f.fs, addr) |
| 179 | } |
| 180 | f.fs.Write(closeParenBytes) |
| 181 | } |
| 182 | |
| 183 | // Display dereferenced value. |
| 184 | switch { |
| 185 | case nilFound: |
| 186 | f.fs.Write(nilAngleBytes) |
| 187 | |
| 188 | case cycleFound: |
| 189 | f.fs.Write(circularShortBytes) |
| 190 | |
| 191 | default: |
| 192 | f.ignoreNextType = true |
| 193 | f.format(ve) |
| 194 | } |
| 195 | } |
| 196 | |
| 197 | // format is the main workhorse for providing the Formatter interface. It |
| 198 | // uses the passed reflect value to figure out what kind of object we are |
| 199 | // dealing with and formats it appropriately. It is a recursive function, |
| 200 | // however circular data structures are detected and handled properly. |
| 201 | func (f *formatState) format(v reflect.Value) { |
| 202 | // Handle invalid reflect values immediately. |
| 203 | kind := v.Kind() |
| 204 | if kind == reflect.Invalid { |
| 205 | f.fs.Write(invalidAngleBytes) |
| 206 | return |
| 207 | } |
| 208 | |
| 209 | // Handle pointers specially. |
| 210 | if kind == reflect.Ptr { |
| 211 | f.formatPtr(v) |
| 212 | return |
| 213 | } |
| 214 | |
| 215 | // Print type information unless already handled elsewhere. |
| 216 | if !f.ignoreNextType && f.fs.Flag('#') { |
| 217 | f.fs.Write(openParenBytes) |
| 218 | f.fs.Write([]byte(v.Type().String())) |
| 219 | f.fs.Write(closeParenBytes) |
| 220 | } |
| 221 | f.ignoreNextType = false |
| 222 | |
| 223 | // Call Stringer/error interfaces if they exist and the handle methods |
| 224 | // flag is enabled. |
| 225 | if !f.cs.DisableMethods { |
| 226 | if (kind != reflect.Invalid) && (kind != reflect.Interface) { |
| 227 | if handled := handleMethods(f.cs, f.fs, v); handled { |
| 228 | return |
| 229 | } |
| 230 | } |
| 231 | } |
| 232 | |
| 233 | switch kind { |
| 234 | case reflect.Invalid: |
| 235 | // Do nothing. We should never get here since invalid has already |
| 236 | // been handled above. |
| 237 | |
| 238 | case reflect.Bool: |
| 239 | printBool(f.fs, v.Bool()) |
| 240 | |
| 241 | case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: |
| 242 | printInt(f.fs, v.Int(), 10) |
| 243 | |
| 244 | case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: |
| 245 | printUint(f.fs, v.Uint(), 10) |
| 246 | |
| 247 | case reflect.Float32: |
| 248 | printFloat(f.fs, v.Float(), 32) |
| 249 | |
| 250 | case reflect.Float64: |
| 251 | printFloat(f.fs, v.Float(), 64) |
| 252 | |
| 253 | case reflect.Complex64: |
| 254 | printComplex(f.fs, v.Complex(), 32) |
| 255 | |
| 256 | case reflect.Complex128: |
| 257 | printComplex(f.fs, v.Complex(), 64) |
| 258 | |
| 259 | case reflect.Slice: |
| 260 | if v.IsNil() { |
| 261 | f.fs.Write(nilAngleBytes) |
| 262 | break |
| 263 | } |
| 264 | fallthrough |
| 265 | |
| 266 | case reflect.Array: |
| 267 | f.fs.Write(openBracketBytes) |
| 268 | f.depth++ |
| 269 | if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { |
| 270 | f.fs.Write(maxShortBytes) |
| 271 | } else { |
| 272 | numEntries := v.Len() |
| 273 | for i := 0; i < numEntries; i++ { |
| 274 | if i > 0 { |
| 275 | f.fs.Write(spaceBytes) |
| 276 | } |
| 277 | f.ignoreNextType = true |
| 278 | f.format(f.unpackValue(v.Index(i))) |
| 279 | } |
| 280 | } |
| 281 | f.depth-- |
| 282 | f.fs.Write(closeBracketBytes) |
| 283 | |
| 284 | case reflect.String: |
| 285 | f.fs.Write([]byte(v.String())) |
| 286 | |
| 287 | case reflect.Interface: |
| 288 | // The only time we should get here is for nil interfaces due to |
| 289 | // unpackValue calls. |
| 290 | if v.IsNil() { |
| 291 | f.fs.Write(nilAngleBytes) |
| 292 | } |
| 293 | |
| 294 | case reflect.Ptr: |
| 295 | // Do nothing. We should never get here since pointers have already |
| 296 | // been handled above. |
| 297 | |
| 298 | case reflect.Map: |
| 299 | // nil maps should be indicated as different than empty maps |
| 300 | if v.IsNil() { |
| 301 | f.fs.Write(nilAngleBytes) |
| 302 | break |
| 303 | } |
| 304 | |
| 305 | f.fs.Write(openMapBytes) |
| 306 | f.depth++ |
| 307 | if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { |
| 308 | f.fs.Write(maxShortBytes) |
| 309 | } else { |
| 310 | keys := v.MapKeys() |
| 311 | if f.cs.SortKeys { |
| 312 | sortValues(keys, f.cs) |
| 313 | } |
| 314 | for i, key := range keys { |
| 315 | if i > 0 { |
| 316 | f.fs.Write(spaceBytes) |
| 317 | } |
| 318 | f.ignoreNextType = true |
| 319 | f.format(f.unpackValue(key)) |
| 320 | f.fs.Write(colonBytes) |
| 321 | f.ignoreNextType = true |
| 322 | f.format(f.unpackValue(v.MapIndex(key))) |
| 323 | } |
| 324 | } |
| 325 | f.depth-- |
| 326 | f.fs.Write(closeMapBytes) |
| 327 | |
| 328 | case reflect.Struct: |
| 329 | numFields := v.NumField() |
| 330 | f.fs.Write(openBraceBytes) |
| 331 | f.depth++ |
| 332 | if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { |
| 333 | f.fs.Write(maxShortBytes) |
| 334 | } else { |
| 335 | vt := v.Type() |
| 336 | for i := 0; i < numFields; i++ { |
| 337 | if i > 0 { |
| 338 | f.fs.Write(spaceBytes) |
| 339 | } |
| 340 | vtf := vt.Field(i) |
| 341 | if f.fs.Flag('+') || f.fs.Flag('#') { |
| 342 | f.fs.Write([]byte(vtf.Name)) |
| 343 | f.fs.Write(colonBytes) |
| 344 | } |
| 345 | f.format(f.unpackValue(v.Field(i))) |
| 346 | } |
| 347 | } |
| 348 | f.depth-- |
| 349 | f.fs.Write(closeBraceBytes) |
| 350 | |
| 351 | case reflect.Uintptr: |
| 352 | printHexPtr(f.fs, uintptr(v.Uint())) |
| 353 | |
| 354 | case reflect.UnsafePointer, reflect.Chan, reflect.Func: |
| 355 | printHexPtr(f.fs, v.Pointer()) |
| 356 | |
| 357 | // There were not any other types at the time this code was written, but |
| 358 | // fall back to letting the default fmt package handle it if any get added. |
| 359 | default: |
| 360 | format := f.buildDefaultFormat() |
| 361 | if v.CanInterface() { |
| 362 | fmt.Fprintf(f.fs, format, v.Interface()) |
| 363 | } else { |
| 364 | fmt.Fprintf(f.fs, format, v.String()) |
| 365 | } |
| 366 | } |
| 367 | } |
| 368 | |
| 369 | // Format satisfies the fmt.Formatter interface. See NewFormatter for usage |
| 370 | // details. |
| 371 | func (f *formatState) Format(fs fmt.State, verb rune) { |
| 372 | f.fs = fs |
| 373 | |
| 374 | // Use standard formatting for verbs that are not v. |
| 375 | if verb != 'v' { |
| 376 | format := f.constructOrigFormat(verb) |
| 377 | fmt.Fprintf(fs, format, f.value) |
| 378 | return |
| 379 | } |
| 380 | |
| 381 | if f.value == nil { |
| 382 | if fs.Flag('#') { |
| 383 | fs.Write(interfaceBytes) |
| 384 | } |
| 385 | fs.Write(nilAngleBytes) |
| 386 | return |
| 387 | } |
| 388 | |
| 389 | f.format(reflect.ValueOf(f.value)) |
| 390 | } |
| 391 | |
| 392 | // newFormatter is a helper function to consolidate the logic from the various |
| 393 | // public methods which take varying config states. |
| 394 | func newFormatter(cs *ConfigState, v interface{}) fmt.Formatter { |
| 395 | fs := &formatState{value: v, cs: cs} |
| 396 | fs.pointers = make(map[uintptr]int) |
| 397 | return fs |
| 398 | } |
| 399 | |
| 400 | /* |
| 401 | NewFormatter returns a custom formatter that satisfies the fmt.Formatter |
| 402 | interface. As a result, it integrates cleanly with standard fmt package |
| 403 | printing functions. The formatter is useful for inline printing of smaller data |
| 404 | types similar to the standard %v format specifier. |
| 405 | |
| 406 | The custom formatter only responds to the %v (most compact), %+v (adds pointer |
| 407 | addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb |
| 408 | combinations. Any other verbs such as %x and %q will be sent to the the |
| 409 | standard fmt package for formatting. In addition, the custom formatter ignores |
| 410 | the width and precision arguments (however they will still work on the format |
| 411 | specifiers not handled by the custom formatter). |
| 412 | |
| 413 | Typically this function shouldn't be called directly. It is much easier to make |
| 414 | use of the custom formatter by calling one of the convenience functions such as |
| 415 | Printf, Println, or Fprintf. |
| 416 | */ |
| 417 | func NewFormatter(v interface{}) fmt.Formatter { |
| 418 | return newFormatter(&Config, v) |
| 419 | } |