OSDN Git Service

Hulk did something
[bytom/vapor.git] / vendor / github.com / stretchr / testify / vendor / github.com / davecgh / go-spew / spew / dump.go
1 /*
2  * Copyright (c) 2013 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         "encoding/hex"
22         "fmt"
23         "io"
24         "os"
25         "reflect"
26         "regexp"
27         "strconv"
28         "strings"
29 )
30
31 var (
32         // uint8Type is a reflect.Type representing a uint8.  It is used to
33         // convert cgo types to uint8 slices for hexdumping.
34         uint8Type = reflect.TypeOf(uint8(0))
35
36         // cCharRE is a regular expression that matches a cgo char.
37         // It is used to detect character arrays to hexdump them.
38         cCharRE = regexp.MustCompile("^.*\\._Ctype_char$")
39
40         // cUnsignedCharRE is a regular expression that matches a cgo unsigned
41         // char.  It is used to detect unsigned character arrays to hexdump
42         // them.
43         cUnsignedCharRE = regexp.MustCompile("^.*\\._Ctype_unsignedchar$")
44
45         // cUint8tCharRE is a regular expression that matches a cgo uint8_t.
46         // It is used to detect uint8_t arrays to hexdump them.
47         cUint8tCharRE = regexp.MustCompile("^.*\\._Ctype_uint8_t$")
48 )
49
50 // dumpState contains information about the state of a dump operation.
51 type dumpState struct {
52         w                io.Writer
53         depth            int
54         pointers         map[uintptr]int
55         ignoreNextType   bool
56         ignoreNextIndent bool
57         cs               *ConfigState
58 }
59
60 // indent performs indentation according to the depth level and cs.Indent
61 // option.
62 func (d *dumpState) indent() {
63         if d.ignoreNextIndent {
64                 d.ignoreNextIndent = false
65                 return
66         }
67         d.w.Write(bytes.Repeat([]byte(d.cs.Indent), d.depth))
68 }
69
70 // unpackValue returns values inside of non-nil interfaces when possible.
71 // This is useful for data types like structs, arrays, slices, and maps which
72 // can contain varying types packed inside an interface.
73 func (d *dumpState) unpackValue(v reflect.Value) reflect.Value {
74         if v.Kind() == reflect.Interface && !v.IsNil() {
75                 v = v.Elem()
76         }
77         return v
78 }
79
80 // dumpPtr handles formatting of pointers by indirecting them as necessary.
81 func (d *dumpState) dumpPtr(v reflect.Value) {
82         // Remove pointers at or below the current depth from map used to detect
83         // circular refs.
84         for k, depth := range d.pointers {
85                 if depth >= d.depth {
86                         delete(d.pointers, k)
87                 }
88         }
89
90         // Keep list of all dereferenced pointers to show later.
91         pointerChain := make([]uintptr, 0)
92
93         // Figure out how many levels of indirection there are by dereferencing
94         // pointers and unpacking interfaces down the chain while detecting circular
95         // references.
96         nilFound := false
97         cycleFound := false
98         indirects := 0
99         ve := v
100         for ve.Kind() == reflect.Ptr {
101                 if ve.IsNil() {
102                         nilFound = true
103                         break
104                 }
105                 indirects++
106                 addr := ve.Pointer()
107                 pointerChain = append(pointerChain, addr)
108                 if pd, ok := d.pointers[addr]; ok && pd < d.depth {
109                         cycleFound = true
110                         indirects--
111                         break
112                 }
113                 d.pointers[addr] = d.depth
114
115                 ve = ve.Elem()
116                 if ve.Kind() == reflect.Interface {
117                         if ve.IsNil() {
118                                 nilFound = true
119                                 break
120                         }
121                         ve = ve.Elem()
122                 }
123         }
124
125         // Display type information.
126         d.w.Write(openParenBytes)
127         d.w.Write(bytes.Repeat(asteriskBytes, indirects))
128         d.w.Write([]byte(ve.Type().String()))
129         d.w.Write(closeParenBytes)
130
131         // Display pointer information.
132         if !d.cs.DisablePointerAddresses && len(pointerChain) > 0 {
133                 d.w.Write(openParenBytes)
134                 for i, addr := range pointerChain {
135                         if i > 0 {
136                                 d.w.Write(pointerChainBytes)
137                         }
138                         printHexPtr(d.w, addr)
139                 }
140                 d.w.Write(closeParenBytes)
141         }
142
143         // Display dereferenced value.
144         d.w.Write(openParenBytes)
145         switch {
146         case nilFound == true:
147                 d.w.Write(nilAngleBytes)
148
149         case cycleFound == true:
150                 d.w.Write(circularBytes)
151
152         default:
153                 d.ignoreNextType = true
154                 d.dump(ve)
155         }
156         d.w.Write(closeParenBytes)
157 }
158
159 // dumpSlice handles formatting of arrays and slices.  Byte (uint8 under
160 // reflection) arrays and slices are dumped in hexdump -C fashion.
161 func (d *dumpState) dumpSlice(v reflect.Value) {
162         // Determine whether this type should be hex dumped or not.  Also,
163         // for types which should be hexdumped, try to use the underlying data
164         // first, then fall back to trying to convert them to a uint8 slice.
165         var buf []uint8
166         doConvert := false
167         doHexDump := false
168         numEntries := v.Len()
169         if numEntries > 0 {
170                 vt := v.Index(0).Type()
171                 vts := vt.String()
172                 switch {
173                 // C types that need to be converted.
174                 case cCharRE.MatchString(vts):
175                         fallthrough
176                 case cUnsignedCharRE.MatchString(vts):
177                         fallthrough
178                 case cUint8tCharRE.MatchString(vts):
179                         doConvert = true
180
181                 // Try to use existing uint8 slices and fall back to converting
182                 // and copying if that fails.
183                 case vt.Kind() == reflect.Uint8:
184                         // We need an addressable interface to convert the type
185                         // to a byte slice.  However, the reflect package won't
186                         // give us an interface on certain things like
187                         // unexported struct fields in order to enforce
188                         // visibility rules.  We use unsafe, when available, to
189                         // bypass these restrictions since this package does not
190                         // mutate the values.
191                         vs := v
192                         if !vs.CanInterface() || !vs.CanAddr() {
193                                 vs = unsafeReflectValue(vs)
194                         }
195                         if !UnsafeDisabled {
196                                 vs = vs.Slice(0, numEntries)
197
198                                 // Use the existing uint8 slice if it can be
199                                 // type asserted.
200                                 iface := vs.Interface()
201                                 if slice, ok := iface.([]uint8); ok {
202                                         buf = slice
203                                         doHexDump = true
204                                         break
205                                 }
206                         }
207
208                         // The underlying data needs to be converted if it can't
209                         // be type asserted to a uint8 slice.
210                         doConvert = true
211                 }
212
213                 // Copy and convert the underlying type if needed.
214                 if doConvert && vt.ConvertibleTo(uint8Type) {
215                         // Convert and copy each element into a uint8 byte
216                         // slice.
217                         buf = make([]uint8, numEntries)
218                         for i := 0; i < numEntries; i++ {
219                                 vv := v.Index(i)
220                                 buf[i] = uint8(vv.Convert(uint8Type).Uint())
221                         }
222                         doHexDump = true
223                 }
224         }
225
226         // Hexdump the entire slice as needed.
227         if doHexDump {
228                 indent := strings.Repeat(d.cs.Indent, d.depth)
229                 str := indent + hex.Dump(buf)
230                 str = strings.Replace(str, "\n", "\n"+indent, -1)
231                 str = strings.TrimRight(str, d.cs.Indent)
232                 d.w.Write([]byte(str))
233                 return
234         }
235
236         // Recursively call dump for each item.
237         for i := 0; i < numEntries; i++ {
238                 d.dump(d.unpackValue(v.Index(i)))
239                 if i < (numEntries - 1) {
240                         d.w.Write(commaNewlineBytes)
241                 } else {
242                         d.w.Write(newlineBytes)
243                 }
244         }
245 }
246
247 // dump is the main workhorse for dumping a value.  It uses the passed reflect
248 // value to figure out what kind of object we are dealing with and formats it
249 // appropriately.  It is a recursive function, however circular data structures
250 // are detected and handled properly.
251 func (d *dumpState) dump(v reflect.Value) {
252         // Handle invalid reflect values immediately.
253         kind := v.Kind()
254         if kind == reflect.Invalid {
255                 d.w.Write(invalidAngleBytes)
256                 return
257         }
258
259         // Handle pointers specially.
260         if kind == reflect.Ptr {
261                 d.indent()
262                 d.dumpPtr(v)
263                 return
264         }
265
266         // Print type information unless already handled elsewhere.
267         if !d.ignoreNextType {
268                 d.indent()
269                 d.w.Write(openParenBytes)
270                 d.w.Write([]byte(v.Type().String()))
271                 d.w.Write(closeParenBytes)
272                 d.w.Write(spaceBytes)
273         }
274         d.ignoreNextType = false
275
276         // Display length and capacity if the built-in len and cap functions
277         // work with the value's kind and the len/cap itself is non-zero.
278         valueLen, valueCap := 0, 0
279         switch v.Kind() {
280         case reflect.Array, reflect.Slice, reflect.Chan:
281                 valueLen, valueCap = v.Len(), v.Cap()
282         case reflect.Map, reflect.String:
283                 valueLen = v.Len()
284         }
285         if valueLen != 0 || !d.cs.DisableCapacities && valueCap != 0 {
286                 d.w.Write(openParenBytes)
287                 if valueLen != 0 {
288                         d.w.Write(lenEqualsBytes)
289                         printInt(d.w, int64(valueLen), 10)
290                 }
291                 if !d.cs.DisableCapacities && valueCap != 0 {
292                         if valueLen != 0 {
293                                 d.w.Write(spaceBytes)
294                         }
295                         d.w.Write(capEqualsBytes)
296                         printInt(d.w, int64(valueCap), 10)
297                 }
298                 d.w.Write(closeParenBytes)
299                 d.w.Write(spaceBytes)
300         }
301
302         // Call Stringer/error interfaces if they exist and the handle methods flag
303         // is enabled
304         if !d.cs.DisableMethods {
305                 if (kind != reflect.Invalid) && (kind != reflect.Interface) {
306                         if handled := handleMethods(d.cs, d.w, v); handled {
307                                 return
308                         }
309                 }
310         }
311
312         switch kind {
313         case reflect.Invalid:
314                 // Do nothing.  We should never get here since invalid has already
315                 // been handled above.
316
317         case reflect.Bool:
318                 printBool(d.w, v.Bool())
319
320         case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
321                 printInt(d.w, v.Int(), 10)
322
323         case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
324                 printUint(d.w, v.Uint(), 10)
325
326         case reflect.Float32:
327                 printFloat(d.w, v.Float(), 32)
328
329         case reflect.Float64:
330                 printFloat(d.w, v.Float(), 64)
331
332         case reflect.Complex64:
333                 printComplex(d.w, v.Complex(), 32)
334
335         case reflect.Complex128:
336                 printComplex(d.w, v.Complex(), 64)
337
338         case reflect.Slice:
339                 if v.IsNil() {
340                         d.w.Write(nilAngleBytes)
341                         break
342                 }
343                 fallthrough
344
345         case reflect.Array:
346                 d.w.Write(openBraceNewlineBytes)
347                 d.depth++
348                 if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
349                         d.indent()
350                         d.w.Write(maxNewlineBytes)
351                 } else {
352                         d.dumpSlice(v)
353                 }
354                 d.depth--
355                 d.indent()
356                 d.w.Write(closeBraceBytes)
357
358         case reflect.String:
359                 d.w.Write([]byte(strconv.Quote(v.String())))
360
361         case reflect.Interface:
362                 // The only time we should get here is for nil interfaces due to
363                 // unpackValue calls.
364                 if v.IsNil() {
365                         d.w.Write(nilAngleBytes)
366                 }
367
368         case reflect.Ptr:
369                 // Do nothing.  We should never get here since pointers have already
370                 // been handled above.
371
372         case reflect.Map:
373                 // nil maps should be indicated as different than empty maps
374                 if v.IsNil() {
375                         d.w.Write(nilAngleBytes)
376                         break
377                 }
378
379                 d.w.Write(openBraceNewlineBytes)
380                 d.depth++
381                 if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
382                         d.indent()
383                         d.w.Write(maxNewlineBytes)
384                 } else {
385                         numEntries := v.Len()
386                         keys := v.MapKeys()
387                         if d.cs.SortKeys {
388                                 sortValues(keys, d.cs)
389                         }
390                         for i, key := range keys {
391                                 d.dump(d.unpackValue(key))
392                                 d.w.Write(colonSpaceBytes)
393                                 d.ignoreNextIndent = true
394                                 d.dump(d.unpackValue(v.MapIndex(key)))
395                                 if i < (numEntries - 1) {
396                                         d.w.Write(commaNewlineBytes)
397                                 } else {
398                                         d.w.Write(newlineBytes)
399                                 }
400                         }
401                 }
402                 d.depth--
403                 d.indent()
404                 d.w.Write(closeBraceBytes)
405
406         case reflect.Struct:
407                 d.w.Write(openBraceNewlineBytes)
408                 d.depth++
409                 if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
410                         d.indent()
411                         d.w.Write(maxNewlineBytes)
412                 } else {
413                         vt := v.Type()
414                         numFields := v.NumField()
415                         for i := 0; i < numFields; i++ {
416                                 d.indent()
417                                 vtf := vt.Field(i)
418                                 d.w.Write([]byte(vtf.Name))
419                                 d.w.Write(colonSpaceBytes)
420                                 d.ignoreNextIndent = true
421                                 d.dump(d.unpackValue(v.Field(i)))
422                                 if i < (numFields - 1) {
423                                         d.w.Write(commaNewlineBytes)
424                                 } else {
425                                         d.w.Write(newlineBytes)
426                                 }
427                         }
428                 }
429                 d.depth--
430                 d.indent()
431                 d.w.Write(closeBraceBytes)
432
433         case reflect.Uintptr:
434                 printHexPtr(d.w, uintptr(v.Uint()))
435
436         case reflect.UnsafePointer, reflect.Chan, reflect.Func:
437                 printHexPtr(d.w, v.Pointer())
438
439         // There were not any other types at the time this code was written, but
440         // fall back to letting the default fmt package handle it in case any new
441         // types are added.
442         default:
443                 if v.CanInterface() {
444                         fmt.Fprintf(d.w, "%v", v.Interface())
445                 } else {
446                         fmt.Fprintf(d.w, "%v", v.String())
447                 }
448         }
449 }
450
451 // fdump is a helper function to consolidate the logic from the various public
452 // methods which take varying writers and config states.
453 func fdump(cs *ConfigState, w io.Writer, a ...interface{}) {
454         for _, arg := range a {
455                 if arg == nil {
456                         w.Write(interfaceBytes)
457                         w.Write(spaceBytes)
458                         w.Write(nilAngleBytes)
459                         w.Write(newlineBytes)
460                         continue
461                 }
462
463                 d := dumpState{w: w, cs: cs}
464                 d.pointers = make(map[uintptr]int)
465                 d.dump(reflect.ValueOf(arg))
466                 d.w.Write(newlineBytes)
467         }
468 }
469
470 // Fdump formats and displays the passed arguments to io.Writer w.  It formats
471 // exactly the same as Dump.
472 func Fdump(w io.Writer, a ...interface{}) {
473         fdump(&Config, w, a...)
474 }
475
476 // Sdump returns a string with the passed arguments formatted exactly the same
477 // as Dump.
478 func Sdump(a ...interface{}) string {
479         var buf bytes.Buffer
480         fdump(&Config, &buf, a...)
481         return buf.String()
482 }
483
484 /*
485 Dump displays the passed parameters to standard out with newlines, customizable
486 indentation, and additional debug information such as complete types and all
487 pointer addresses used to indirect to the final value.  It provides the
488 following features over the built-in printing facilities provided by the fmt
489 package:
490
491         * Pointers are dereferenced and followed
492         * Circular data structures are detected and handled properly
493         * Custom Stringer/error interfaces are optionally invoked, including
494           on unexported types
495         * Custom types which only implement the Stringer/error interfaces via
496           a pointer receiver are optionally invoked when passing non-pointer
497           variables
498         * Byte arrays and slices are dumped like the hexdump -C command which
499           includes offsets, byte values in hex, and ASCII output
500
501 The configuration options are controlled by an exported package global,
502 spew.Config.  See ConfigState for options documentation.
503
504 See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to
505 get the formatted result as a string.
506 */
507 func Dump(a ...interface{}) {
508         fdump(&Config, os.Stdout, a...)
509 }