Blame vendor/github.com/davecgh/go-spew/spew/dump.go

Packit 63bb0d
/*
Packit 63bb0d
 * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
Packit 63bb0d
 *
Packit 63bb0d
 * Permission to use, copy, modify, and distribute this software for any
Packit 63bb0d
 * purpose with or without fee is hereby granted, provided that the above
Packit 63bb0d
 * copyright notice and this permission notice appear in all copies.
Packit 63bb0d
 *
Packit 63bb0d
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
Packit 63bb0d
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
Packit 63bb0d
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
Packit 63bb0d
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
Packit 63bb0d
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
Packit 63bb0d
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
Packit 63bb0d
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Packit 63bb0d
 */
Packit 63bb0d
Packit 63bb0d
package spew
Packit 63bb0d
Packit 63bb0d
import (
Packit 63bb0d
	"bytes"
Packit 63bb0d
	"encoding/hex"
Packit 63bb0d
	"fmt"
Packit 63bb0d
	"io"
Packit 63bb0d
	"os"
Packit 63bb0d
	"reflect"
Packit 63bb0d
	"regexp"
Packit 63bb0d
	"strconv"
Packit 63bb0d
	"strings"
Packit 63bb0d
)
Packit 63bb0d
Packit 63bb0d
var (
Packit 63bb0d
	// uint8Type is a reflect.Type representing a uint8.  It is used to
Packit 63bb0d
	// convert cgo types to uint8 slices for hexdumping.
Packit 63bb0d
	uint8Type = reflect.TypeOf(uint8(0))
Packit 63bb0d
Packit 63bb0d
	// cCharRE is a regular expression that matches a cgo char.
Packit 63bb0d
	// It is used to detect character arrays to hexdump them.
Packit Service 509fd4
	cCharRE = regexp.MustCompile(`^.*\._Ctype_char$`)
Packit 63bb0d
Packit 63bb0d
	// cUnsignedCharRE is a regular expression that matches a cgo unsigned
Packit 63bb0d
	// char.  It is used to detect unsigned character arrays to hexdump
Packit 63bb0d
	// them.
Packit Service 509fd4
	cUnsignedCharRE = regexp.MustCompile(`^.*\._Ctype_unsignedchar$`)
Packit 63bb0d
Packit 63bb0d
	// cUint8tCharRE is a regular expression that matches a cgo uint8_t.
Packit 63bb0d
	// It is used to detect uint8_t arrays to hexdump them.
Packit Service 509fd4
	cUint8tCharRE = regexp.MustCompile(`^.*\._Ctype_uint8_t$`)
Packit 63bb0d
)
Packit 63bb0d
Packit 63bb0d
// dumpState contains information about the state of a dump operation.
Packit 63bb0d
type dumpState struct {
Packit 63bb0d
	w                io.Writer
Packit 63bb0d
	depth            int
Packit 63bb0d
	pointers         map[uintptr]int
Packit 63bb0d
	ignoreNextType   bool
Packit 63bb0d
	ignoreNextIndent bool
Packit 63bb0d
	cs               *ConfigState
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// indent performs indentation according to the depth level and cs.Indent
Packit 63bb0d
// option.
Packit 63bb0d
func (d *dumpState) indent() {
Packit 63bb0d
	if d.ignoreNextIndent {
Packit 63bb0d
		d.ignoreNextIndent = false
Packit 63bb0d
		return
Packit 63bb0d
	}
Packit 63bb0d
	d.w.Write(bytes.Repeat([]byte(d.cs.Indent), d.depth))
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// unpackValue returns values inside of non-nil interfaces when possible.
Packit 63bb0d
// This is useful for data types like structs, arrays, slices, and maps which
Packit 63bb0d
// can contain varying types packed inside an interface.
Packit 63bb0d
func (d *dumpState) unpackValue(v reflect.Value) reflect.Value {
Packit 63bb0d
	if v.Kind() == reflect.Interface && !v.IsNil() {
Packit 63bb0d
		v = v.Elem()
Packit 63bb0d
	}
Packit 63bb0d
	return v
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// dumpPtr handles formatting of pointers by indirecting them as necessary.
Packit 63bb0d
func (d *dumpState) dumpPtr(v reflect.Value) {
Packit 63bb0d
	// Remove pointers at or below the current depth from map used to detect
Packit 63bb0d
	// circular refs.
Packit 63bb0d
	for k, depth := range d.pointers {
Packit 63bb0d
		if depth >= d.depth {
Packit 63bb0d
			delete(d.pointers, k)
Packit 63bb0d
		}
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	// Keep list of all dereferenced pointers to show later.
Packit 63bb0d
	pointerChain := make([]uintptr, 0)
Packit 63bb0d
Packit 63bb0d
	// Figure out how many levels of indirection there are by dereferencing
Packit 63bb0d
	// pointers and unpacking interfaces down the chain while detecting circular
Packit 63bb0d
	// references.
Packit 63bb0d
	nilFound := false
Packit 63bb0d
	cycleFound := false
Packit 63bb0d
	indirects := 0
Packit 63bb0d
	ve := v
Packit 63bb0d
	for ve.Kind() == reflect.Ptr {
Packit 63bb0d
		if ve.IsNil() {
Packit 63bb0d
			nilFound = true
Packit 63bb0d
			break
Packit 63bb0d
		}
Packit 63bb0d
		indirects++
Packit 63bb0d
		addr := ve.Pointer()
Packit 63bb0d
		pointerChain = append(pointerChain, addr)
Packit 63bb0d
		if pd, ok := d.pointers[addr]; ok && pd < d.depth {
Packit 63bb0d
			cycleFound = true
Packit 63bb0d
			indirects--
Packit 63bb0d
			break
Packit 63bb0d
		}
Packit 63bb0d
		d.pointers[addr] = d.depth
Packit 63bb0d
Packit 63bb0d
		ve = ve.Elem()
Packit 63bb0d
		if ve.Kind() == reflect.Interface {
Packit 63bb0d
			if ve.IsNil() {
Packit 63bb0d
				nilFound = true
Packit 63bb0d
				break
Packit 63bb0d
			}
Packit 63bb0d
			ve = ve.Elem()
Packit 63bb0d
		}
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	// Display type information.
Packit 63bb0d
	d.w.Write(openParenBytes)
Packit 63bb0d
	d.w.Write(bytes.Repeat(asteriskBytes, indirects))
Packit 63bb0d
	d.w.Write([]byte(ve.Type().String()))
Packit 63bb0d
	d.w.Write(closeParenBytes)
Packit 63bb0d
Packit 63bb0d
	// Display pointer information.
Packit 63bb0d
	if !d.cs.DisablePointerAddresses && len(pointerChain) > 0 {
Packit 63bb0d
		d.w.Write(openParenBytes)
Packit 63bb0d
		for i, addr := range pointerChain {
Packit 63bb0d
			if i > 0 {
Packit 63bb0d
				d.w.Write(pointerChainBytes)
Packit 63bb0d
			}
Packit 63bb0d
			printHexPtr(d.w, addr)
Packit 63bb0d
		}
Packit 63bb0d
		d.w.Write(closeParenBytes)
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	// Display dereferenced value.
Packit 63bb0d
	d.w.Write(openParenBytes)
Packit 63bb0d
	switch {
Packit Service 509fd4
	case nilFound:
Packit 63bb0d
		d.w.Write(nilAngleBytes)
Packit 63bb0d
Packit Service 509fd4
	case cycleFound:
Packit 63bb0d
		d.w.Write(circularBytes)
Packit 63bb0d
Packit 63bb0d
	default:
Packit 63bb0d
		d.ignoreNextType = true
Packit 63bb0d
		d.dump(ve)
Packit 63bb0d
	}
Packit 63bb0d
	d.w.Write(closeParenBytes)
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// dumpSlice handles formatting of arrays and slices.  Byte (uint8 under
Packit 63bb0d
// reflection) arrays and slices are dumped in hexdump -C fashion.
Packit 63bb0d
func (d *dumpState) dumpSlice(v reflect.Value) {
Packit 63bb0d
	// Determine whether this type should be hex dumped or not.  Also,
Packit 63bb0d
	// for types which should be hexdumped, try to use the underlying data
Packit 63bb0d
	// first, then fall back to trying to convert them to a uint8 slice.
Packit 63bb0d
	var buf []uint8
Packit 63bb0d
	doConvert := false
Packit 63bb0d
	doHexDump := false
Packit 63bb0d
	numEntries := v.Len()
Packit 63bb0d
	if numEntries > 0 {
Packit 63bb0d
		vt := v.Index(0).Type()
Packit 63bb0d
		vts := vt.String()
Packit 63bb0d
		switch {
Packit 63bb0d
		// C types that need to be converted.
Packit 63bb0d
		case cCharRE.MatchString(vts):
Packit 63bb0d
			fallthrough
Packit 63bb0d
		case cUnsignedCharRE.MatchString(vts):
Packit 63bb0d
			fallthrough
Packit 63bb0d
		case cUint8tCharRE.MatchString(vts):
Packit 63bb0d
			doConvert = true
Packit 63bb0d
Packit 63bb0d
		// Try to use existing uint8 slices and fall back to converting
Packit 63bb0d
		// and copying if that fails.
Packit 63bb0d
		case vt.Kind() == reflect.Uint8:
Packit 63bb0d
			// We need an addressable interface to convert the type
Packit 63bb0d
			// to a byte slice.  However, the reflect package won't
Packit 63bb0d
			// give us an interface on certain things like
Packit 63bb0d
			// unexported struct fields in order to enforce
Packit 63bb0d
			// visibility rules.  We use unsafe, when available, to
Packit 63bb0d
			// bypass these restrictions since this package does not
Packit 63bb0d
			// mutate the values.
Packit 63bb0d
			vs := v
Packit 63bb0d
			if !vs.CanInterface() || !vs.CanAddr() {
Packit 63bb0d
				vs = unsafeReflectValue(vs)
Packit 63bb0d
			}
Packit 63bb0d
			if !UnsafeDisabled {
Packit 63bb0d
				vs = vs.Slice(0, numEntries)
Packit 63bb0d
Packit 63bb0d
				// Use the existing uint8 slice if it can be
Packit 63bb0d
				// type asserted.
Packit 63bb0d
				iface := vs.Interface()
Packit 63bb0d
				if slice, ok := iface.([]uint8); ok {
Packit 63bb0d
					buf = slice
Packit 63bb0d
					doHexDump = true
Packit 63bb0d
					break
Packit 63bb0d
				}
Packit 63bb0d
			}
Packit 63bb0d
Packit 63bb0d
			// The underlying data needs to be converted if it can't
Packit 63bb0d
			// be type asserted to a uint8 slice.
Packit 63bb0d
			doConvert = true
Packit 63bb0d
		}
Packit 63bb0d
Packit 63bb0d
		// Copy and convert the underlying type if needed.
Packit 63bb0d
		if doConvert && vt.ConvertibleTo(uint8Type) {
Packit 63bb0d
			// Convert and copy each element into a uint8 byte
Packit 63bb0d
			// slice.
Packit 63bb0d
			buf = make([]uint8, numEntries)
Packit 63bb0d
			for i := 0; i < numEntries; i++ {
Packit 63bb0d
				vv := v.Index(i)
Packit 63bb0d
				buf[i] = uint8(vv.Convert(uint8Type).Uint())
Packit 63bb0d
			}
Packit 63bb0d
			doHexDump = true
Packit 63bb0d
		}
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	// Hexdump the entire slice as needed.
Packit 63bb0d
	if doHexDump {
Packit 63bb0d
		indent := strings.Repeat(d.cs.Indent, d.depth)
Packit 63bb0d
		str := indent + hex.Dump(buf)
Packit 63bb0d
		str = strings.Replace(str, "\n", "\n"+indent, -1)
Packit 63bb0d
		str = strings.TrimRight(str, d.cs.Indent)
Packit 63bb0d
		d.w.Write([]byte(str))
Packit 63bb0d
		return
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	// Recursively call dump for each item.
Packit 63bb0d
	for i := 0; i < numEntries; i++ {
Packit 63bb0d
		d.dump(d.unpackValue(v.Index(i)))
Packit 63bb0d
		if i < (numEntries - 1) {
Packit 63bb0d
			d.w.Write(commaNewlineBytes)
Packit 63bb0d
		} else {
Packit 63bb0d
			d.w.Write(newlineBytes)
Packit 63bb0d
		}
Packit 63bb0d
	}
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// dump is the main workhorse for dumping a value.  It uses the passed reflect
Packit 63bb0d
// value to figure out what kind of object we are dealing with and formats it
Packit 63bb0d
// appropriately.  It is a recursive function, however circular data structures
Packit 63bb0d
// are detected and handled properly.
Packit 63bb0d
func (d *dumpState) dump(v reflect.Value) {
Packit 63bb0d
	// Handle invalid reflect values immediately.
Packit 63bb0d
	kind := v.Kind()
Packit 63bb0d
	if kind == reflect.Invalid {
Packit 63bb0d
		d.w.Write(invalidAngleBytes)
Packit 63bb0d
		return
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	// Handle pointers specially.
Packit 63bb0d
	if kind == reflect.Ptr {
Packit 63bb0d
		d.indent()
Packit 63bb0d
		d.dumpPtr(v)
Packit 63bb0d
		return
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	// Print type information unless already handled elsewhere.
Packit 63bb0d
	if !d.ignoreNextType {
Packit 63bb0d
		d.indent()
Packit 63bb0d
		d.w.Write(openParenBytes)
Packit 63bb0d
		d.w.Write([]byte(v.Type().String()))
Packit 63bb0d
		d.w.Write(closeParenBytes)
Packit 63bb0d
		d.w.Write(spaceBytes)
Packit 63bb0d
	}
Packit 63bb0d
	d.ignoreNextType = false
Packit 63bb0d
Packit 63bb0d
	// Display length and capacity if the built-in len and cap functions
Packit 63bb0d
	// work with the value's kind and the len/cap itself is non-zero.
Packit 63bb0d
	valueLen, valueCap := 0, 0
Packit 63bb0d
	switch v.Kind() {
Packit 63bb0d
	case reflect.Array, reflect.Slice, reflect.Chan:
Packit 63bb0d
		valueLen, valueCap = v.Len(), v.Cap()
Packit 63bb0d
	case reflect.Map, reflect.String:
Packit 63bb0d
		valueLen = v.Len()
Packit 63bb0d
	}
Packit 63bb0d
	if valueLen != 0 || !d.cs.DisableCapacities && valueCap != 0 {
Packit 63bb0d
		d.w.Write(openParenBytes)
Packit 63bb0d
		if valueLen != 0 {
Packit 63bb0d
			d.w.Write(lenEqualsBytes)
Packit 63bb0d
			printInt(d.w, int64(valueLen), 10)
Packit 63bb0d
		}
Packit 63bb0d
		if !d.cs.DisableCapacities && valueCap != 0 {
Packit 63bb0d
			if valueLen != 0 {
Packit 63bb0d
				d.w.Write(spaceBytes)
Packit 63bb0d
			}
Packit 63bb0d
			d.w.Write(capEqualsBytes)
Packit 63bb0d
			printInt(d.w, int64(valueCap), 10)
Packit 63bb0d
		}
Packit 63bb0d
		d.w.Write(closeParenBytes)
Packit 63bb0d
		d.w.Write(spaceBytes)
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	// Call Stringer/error interfaces if they exist and the handle methods flag
Packit 63bb0d
	// is enabled
Packit 63bb0d
	if !d.cs.DisableMethods {
Packit 63bb0d
		if (kind != reflect.Invalid) && (kind != reflect.Interface) {
Packit 63bb0d
			if handled := handleMethods(d.cs, d.w, v); handled {
Packit 63bb0d
				return
Packit 63bb0d
			}
Packit 63bb0d
		}
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	switch kind {
Packit 63bb0d
	case reflect.Invalid:
Packit 63bb0d
		// Do nothing.  We should never get here since invalid has already
Packit 63bb0d
		// been handled above.
Packit 63bb0d
Packit 63bb0d
	case reflect.Bool:
Packit 63bb0d
		printBool(d.w, v.Bool())
Packit 63bb0d
Packit 63bb0d
	case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
Packit 63bb0d
		printInt(d.w, v.Int(), 10)
Packit 63bb0d
Packit 63bb0d
	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
Packit 63bb0d
		printUint(d.w, v.Uint(), 10)
Packit 63bb0d
Packit 63bb0d
	case reflect.Float32:
Packit 63bb0d
		printFloat(d.w, v.Float(), 32)
Packit 63bb0d
Packit 63bb0d
	case reflect.Float64:
Packit 63bb0d
		printFloat(d.w, v.Float(), 64)
Packit 63bb0d
Packit 63bb0d
	case reflect.Complex64:
Packit 63bb0d
		printComplex(d.w, v.Complex(), 32)
Packit 63bb0d
Packit 63bb0d
	case reflect.Complex128:
Packit 63bb0d
		printComplex(d.w, v.Complex(), 64)
Packit 63bb0d
Packit 63bb0d
	case reflect.Slice:
Packit 63bb0d
		if v.IsNil() {
Packit 63bb0d
			d.w.Write(nilAngleBytes)
Packit 63bb0d
			break
Packit 63bb0d
		}
Packit 63bb0d
		fallthrough
Packit 63bb0d
Packit 63bb0d
	case reflect.Array:
Packit 63bb0d
		d.w.Write(openBraceNewlineBytes)
Packit 63bb0d
		d.depth++
Packit 63bb0d
		if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
Packit 63bb0d
			d.indent()
Packit 63bb0d
			d.w.Write(maxNewlineBytes)
Packit 63bb0d
		} else {
Packit 63bb0d
			d.dumpSlice(v)
Packit 63bb0d
		}
Packit 63bb0d
		d.depth--
Packit 63bb0d
		d.indent()
Packit 63bb0d
		d.w.Write(closeBraceBytes)
Packit 63bb0d
Packit 63bb0d
	case reflect.String:
Packit 63bb0d
		d.w.Write([]byte(strconv.Quote(v.String())))
Packit 63bb0d
Packit 63bb0d
	case reflect.Interface:
Packit 63bb0d
		// The only time we should get here is for nil interfaces due to
Packit 63bb0d
		// unpackValue calls.
Packit 63bb0d
		if v.IsNil() {
Packit 63bb0d
			d.w.Write(nilAngleBytes)
Packit 63bb0d
		}
Packit 63bb0d
Packit 63bb0d
	case reflect.Ptr:
Packit 63bb0d
		// Do nothing.  We should never get here since pointers have already
Packit 63bb0d
		// been handled above.
Packit 63bb0d
Packit 63bb0d
	case reflect.Map:
Packit 63bb0d
		// nil maps should be indicated as different than empty maps
Packit 63bb0d
		if v.IsNil() {
Packit 63bb0d
			d.w.Write(nilAngleBytes)
Packit 63bb0d
			break
Packit 63bb0d
		}
Packit 63bb0d
Packit 63bb0d
		d.w.Write(openBraceNewlineBytes)
Packit 63bb0d
		d.depth++
Packit 63bb0d
		if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
Packit 63bb0d
			d.indent()
Packit 63bb0d
			d.w.Write(maxNewlineBytes)
Packit 63bb0d
		} else {
Packit 63bb0d
			numEntries := v.Len()
Packit 63bb0d
			keys := v.MapKeys()
Packit 63bb0d
			if d.cs.SortKeys {
Packit 63bb0d
				sortValues(keys, d.cs)
Packit 63bb0d
			}
Packit 63bb0d
			for i, key := range keys {
Packit 63bb0d
				d.dump(d.unpackValue(key))
Packit 63bb0d
				d.w.Write(colonSpaceBytes)
Packit 63bb0d
				d.ignoreNextIndent = true
Packit 63bb0d
				d.dump(d.unpackValue(v.MapIndex(key)))
Packit 63bb0d
				if i < (numEntries - 1) {
Packit 63bb0d
					d.w.Write(commaNewlineBytes)
Packit 63bb0d
				} else {
Packit 63bb0d
					d.w.Write(newlineBytes)
Packit 63bb0d
				}
Packit 63bb0d
			}
Packit 63bb0d
		}
Packit 63bb0d
		d.depth--
Packit 63bb0d
		d.indent()
Packit 63bb0d
		d.w.Write(closeBraceBytes)
Packit 63bb0d
Packit 63bb0d
	case reflect.Struct:
Packit 63bb0d
		d.w.Write(openBraceNewlineBytes)
Packit 63bb0d
		d.depth++
Packit 63bb0d
		if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
Packit 63bb0d
			d.indent()
Packit 63bb0d
			d.w.Write(maxNewlineBytes)
Packit 63bb0d
		} else {
Packit 63bb0d
			vt := v.Type()
Packit 63bb0d
			numFields := v.NumField()
Packit 63bb0d
			for i := 0; i < numFields; i++ {
Packit 63bb0d
				d.indent()
Packit 63bb0d
				vtf := vt.Field(i)
Packit 63bb0d
				d.w.Write([]byte(vtf.Name))
Packit 63bb0d
				d.w.Write(colonSpaceBytes)
Packit 63bb0d
				d.ignoreNextIndent = true
Packit 63bb0d
				d.dump(d.unpackValue(v.Field(i)))
Packit 63bb0d
				if i < (numFields - 1) {
Packit 63bb0d
					d.w.Write(commaNewlineBytes)
Packit 63bb0d
				} else {
Packit 63bb0d
					d.w.Write(newlineBytes)
Packit 63bb0d
				}
Packit 63bb0d
			}
Packit 63bb0d
		}
Packit 63bb0d
		d.depth--
Packit 63bb0d
		d.indent()
Packit 63bb0d
		d.w.Write(closeBraceBytes)
Packit 63bb0d
Packit 63bb0d
	case reflect.Uintptr:
Packit 63bb0d
		printHexPtr(d.w, uintptr(v.Uint()))
Packit 63bb0d
Packit 63bb0d
	case reflect.UnsafePointer, reflect.Chan, reflect.Func:
Packit 63bb0d
		printHexPtr(d.w, v.Pointer())
Packit 63bb0d
Packit 63bb0d
	// There were not any other types at the time this code was written, but
Packit 63bb0d
	// fall back to letting the default fmt package handle it in case any new
Packit 63bb0d
	// types are added.
Packit 63bb0d
	default:
Packit 63bb0d
		if v.CanInterface() {
Packit 63bb0d
			fmt.Fprintf(d.w, "%v", v.Interface())
Packit 63bb0d
		} else {
Packit 63bb0d
			fmt.Fprintf(d.w, "%v", v.String())
Packit 63bb0d
		}
Packit 63bb0d
	}
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// fdump is a helper function to consolidate the logic from the various public
Packit 63bb0d
// methods which take varying writers and config states.
Packit 63bb0d
func fdump(cs *ConfigState, w io.Writer, a ...interface{}) {
Packit 63bb0d
	for _, arg := range a {
Packit 63bb0d
		if arg == nil {
Packit 63bb0d
			w.Write(interfaceBytes)
Packit 63bb0d
			w.Write(spaceBytes)
Packit 63bb0d
			w.Write(nilAngleBytes)
Packit 63bb0d
			w.Write(newlineBytes)
Packit 63bb0d
			continue
Packit 63bb0d
		}
Packit 63bb0d
Packit 63bb0d
		d := dumpState{w: w, cs: cs}
Packit 63bb0d
		d.pointers = make(map[uintptr]int)
Packit 63bb0d
		d.dump(reflect.ValueOf(arg))
Packit 63bb0d
		d.w.Write(newlineBytes)
Packit 63bb0d
	}
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// Fdump formats and displays the passed arguments to io.Writer w.  It formats
Packit 63bb0d
// exactly the same as Dump.
Packit 63bb0d
func Fdump(w io.Writer, a ...interface{}) {
Packit 63bb0d
	fdump(&Config, w, a...)
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// Sdump returns a string with the passed arguments formatted exactly the same
Packit 63bb0d
// as Dump.
Packit 63bb0d
func Sdump(a ...interface{}) string {
Packit 63bb0d
	var buf bytes.Buffer
Packit 63bb0d
	fdump(&Config, &buf, a...)
Packit 63bb0d
	return buf.String()
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
/*
Packit 63bb0d
Dump displays the passed parameters to standard out with newlines, customizable
Packit 63bb0d
indentation, and additional debug information such as complete types and all
Packit 63bb0d
pointer addresses used to indirect to the final value.  It provides the
Packit 63bb0d
following features over the built-in printing facilities provided by the fmt
Packit 63bb0d
package:
Packit 63bb0d
Packit 63bb0d
	* Pointers are dereferenced and followed
Packit 63bb0d
	* Circular data structures are detected and handled properly
Packit 63bb0d
	* Custom Stringer/error interfaces are optionally invoked, including
Packit 63bb0d
	  on unexported types
Packit 63bb0d
	* Custom types which only implement the Stringer/error interfaces via
Packit 63bb0d
	  a pointer receiver are optionally invoked when passing non-pointer
Packit 63bb0d
	  variables
Packit 63bb0d
	* Byte arrays and slices are dumped like the hexdump -C command which
Packit 63bb0d
	  includes offsets, byte values in hex, and ASCII output
Packit 63bb0d
Packit 63bb0d
The configuration options are controlled by an exported package global,
Packit 63bb0d
spew.Config.  See ConfigState for options documentation.
Packit 63bb0d
Packit 63bb0d
See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to
Packit 63bb0d
get the formatted result as a string.
Packit 63bb0d
*/
Packit 63bb0d
func Dump(a ...interface{}) {
Packit 63bb0d
	fdump(&Config, os.Stdout, a...)
Packit 63bb0d
}