Blame vendor/github.com/davecgh/go-spew/spew/common.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
	"fmt"
Packit 63bb0d
	"io"
Packit 63bb0d
	"reflect"
Packit 63bb0d
	"sort"
Packit 63bb0d
	"strconv"
Packit 63bb0d
)
Packit 63bb0d
Packit 63bb0d
// Some constants in the form of bytes to avoid string overhead.  This mirrors
Packit 63bb0d
// the technique used in the fmt package.
Packit 63bb0d
var (
Packit 63bb0d
	panicBytes            = []byte("(PANIC=")
Packit 63bb0d
	plusBytes             = []byte("+")
Packit 63bb0d
	iBytes                = []byte("i")
Packit 63bb0d
	trueBytes             = []byte("true")
Packit 63bb0d
	falseBytes            = []byte("false")
Packit 63bb0d
	interfaceBytes        = []byte("(interface {})")
Packit 63bb0d
	commaNewlineBytes     = []byte(",\n")
Packit 63bb0d
	newlineBytes          = []byte("\n")
Packit 63bb0d
	openBraceBytes        = []byte("{")
Packit 63bb0d
	openBraceNewlineBytes = []byte("{\n")
Packit 63bb0d
	closeBraceBytes       = []byte("}")
Packit 63bb0d
	asteriskBytes         = []byte("*")
Packit 63bb0d
	colonBytes            = []byte(":")
Packit 63bb0d
	colonSpaceBytes       = []byte(": ")
Packit 63bb0d
	openParenBytes        = []byte("(")
Packit 63bb0d
	closeParenBytes       = []byte(")")
Packit 63bb0d
	spaceBytes            = []byte(" ")
Packit 63bb0d
	pointerChainBytes     = []byte("->")
Packit 63bb0d
	nilAngleBytes         = []byte("<nil>")
Packit 63bb0d
	maxNewlineBytes       = []byte("<max depth reached>\n")
Packit 63bb0d
	maxShortBytes         = []byte("<max>")
Packit 63bb0d
	circularBytes         = []byte("<already shown>")
Packit 63bb0d
	circularShortBytes    = []byte("<shown>")
Packit 63bb0d
	invalidAngleBytes     = []byte("<invalid>")
Packit 63bb0d
	openBracketBytes      = []byte("[")
Packit 63bb0d
	closeBracketBytes     = []byte("]")
Packit 63bb0d
	percentBytes          = []byte("%")
Packit 63bb0d
	precisionBytes        = []byte(".")
Packit 63bb0d
	openAngleBytes        = []byte("<")
Packit 63bb0d
	closeAngleBytes       = []byte(">")
Packit 63bb0d
	openMapBytes          = []byte("map[")
Packit 63bb0d
	closeMapBytes         = []byte("]")
Packit 63bb0d
	lenEqualsBytes        = []byte("len=")
Packit 63bb0d
	capEqualsBytes        = []byte("cap=")
Packit 63bb0d
)
Packit 63bb0d
Packit 63bb0d
// hexDigits is used to map a decimal value to a hex digit.
Packit 63bb0d
var hexDigits = "0123456789abcdef"
Packit 63bb0d
Packit 63bb0d
// catchPanic handles any panics that might occur during the handleMethods
Packit 63bb0d
// calls.
Packit 63bb0d
func catchPanic(w io.Writer, v reflect.Value) {
Packit 63bb0d
	if err := recover(); err != nil {
Packit 63bb0d
		w.Write(panicBytes)
Packit 63bb0d
		fmt.Fprintf(w, "%v", err)
Packit 63bb0d
		w.Write(closeParenBytes)
Packit 63bb0d
	}
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// handleMethods attempts to call the Error and String methods on the underlying
Packit 63bb0d
// type the passed reflect.Value represents and outputes the result to Writer w.
Packit 63bb0d
//
Packit 63bb0d
// It handles panics in any called methods by catching and displaying the error
Packit 63bb0d
// as the formatted value.
Packit 63bb0d
func handleMethods(cs *ConfigState, w io.Writer, v reflect.Value) (handled bool) {
Packit 63bb0d
	// We need an interface to check if the type implements the error or
Packit 63bb0d
	// Stringer interface.  However, the reflect package won't give us an
Packit 63bb0d
	// interface on certain things like unexported struct fields in order
Packit 63bb0d
	// to enforce visibility rules.  We use unsafe, when it's available,
Packit 63bb0d
	// to bypass these restrictions since this package does not mutate the
Packit 63bb0d
	// values.
Packit 63bb0d
	if !v.CanInterface() {
Packit 63bb0d
		if UnsafeDisabled {
Packit 63bb0d
			return false
Packit 63bb0d
		}
Packit 63bb0d
Packit 63bb0d
		v = unsafeReflectValue(v)
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	// Choose whether or not to do error and Stringer interface lookups against
Packit 63bb0d
	// the base type or a pointer to the base type depending on settings.
Packit 63bb0d
	// Technically calling one of these methods with a pointer receiver can
Packit 63bb0d
	// mutate the value, however, types which choose to satisify an error or
Packit 63bb0d
	// Stringer interface with a pointer receiver should not be mutating their
Packit 63bb0d
	// state inside these interface methods.
Packit 63bb0d
	if !cs.DisablePointerMethods && !UnsafeDisabled && !v.CanAddr() {
Packit 63bb0d
		v = unsafeReflectValue(v)
Packit 63bb0d
	}
Packit 63bb0d
	if v.CanAddr() {
Packit 63bb0d
		v = v.Addr()
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	// Is it an error or Stringer?
Packit 63bb0d
	switch iface := v.Interface().(type) {
Packit 63bb0d
	case error:
Packit 63bb0d
		defer catchPanic(w, v)
Packit 63bb0d
		if cs.ContinueOnMethod {
Packit 63bb0d
			w.Write(openParenBytes)
Packit 63bb0d
			w.Write([]byte(iface.Error()))
Packit 63bb0d
			w.Write(closeParenBytes)
Packit 63bb0d
			w.Write(spaceBytes)
Packit 63bb0d
			return false
Packit 63bb0d
		}
Packit 63bb0d
Packit 63bb0d
		w.Write([]byte(iface.Error()))
Packit 63bb0d
		return true
Packit 63bb0d
Packit 63bb0d
	case fmt.Stringer:
Packit 63bb0d
		defer catchPanic(w, v)
Packit 63bb0d
		if cs.ContinueOnMethod {
Packit 63bb0d
			w.Write(openParenBytes)
Packit 63bb0d
			w.Write([]byte(iface.String()))
Packit 63bb0d
			w.Write(closeParenBytes)
Packit 63bb0d
			w.Write(spaceBytes)
Packit 63bb0d
			return false
Packit 63bb0d
		}
Packit 63bb0d
		w.Write([]byte(iface.String()))
Packit 63bb0d
		return true
Packit 63bb0d
	}
Packit 63bb0d
	return false
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// printBool outputs a boolean value as true or false to Writer w.
Packit 63bb0d
func printBool(w io.Writer, val bool) {
Packit 63bb0d
	if val {
Packit 63bb0d
		w.Write(trueBytes)
Packit 63bb0d
	} else {
Packit 63bb0d
		w.Write(falseBytes)
Packit 63bb0d
	}
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// printInt outputs a signed integer value to Writer w.
Packit 63bb0d
func printInt(w io.Writer, val int64, base int) {
Packit 63bb0d
	w.Write([]byte(strconv.FormatInt(val, base)))
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// printUint outputs an unsigned integer value to Writer w.
Packit 63bb0d
func printUint(w io.Writer, val uint64, base int) {
Packit 63bb0d
	w.Write([]byte(strconv.FormatUint(val, base)))
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// printFloat outputs a floating point value using the specified precision,
Packit 63bb0d
// which is expected to be 32 or 64bit, to Writer w.
Packit 63bb0d
func printFloat(w io.Writer, val float64, precision int) {
Packit 63bb0d
	w.Write([]byte(strconv.FormatFloat(val, 'g', -1, precision)))
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// printComplex outputs a complex value using the specified float precision
Packit 63bb0d
// for the real and imaginary parts to Writer w.
Packit 63bb0d
func printComplex(w io.Writer, c complex128, floatPrecision int) {
Packit 63bb0d
	r := real(c)
Packit 63bb0d
	w.Write(openParenBytes)
Packit 63bb0d
	w.Write([]byte(strconv.FormatFloat(r, 'g', -1, floatPrecision)))
Packit 63bb0d
	i := imag(c)
Packit 63bb0d
	if i >= 0 {
Packit 63bb0d
		w.Write(plusBytes)
Packit 63bb0d
	}
Packit 63bb0d
	w.Write([]byte(strconv.FormatFloat(i, 'g', -1, floatPrecision)))
Packit 63bb0d
	w.Write(iBytes)
Packit 63bb0d
	w.Write(closeParenBytes)
Packit 63bb0d
}
Packit 63bb0d
Packit Service 509fd4
// printHexPtr outputs a uintptr formatted as hexadecimal with a leading '0x'
Packit 63bb0d
// prefix to Writer w.
Packit 63bb0d
func printHexPtr(w io.Writer, p uintptr) {
Packit 63bb0d
	// Null pointer.
Packit 63bb0d
	num := uint64(p)
Packit 63bb0d
	if num == 0 {
Packit 63bb0d
		w.Write(nilAngleBytes)
Packit 63bb0d
		return
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	// Max uint64 is 16 bytes in hex + 2 bytes for '0x' prefix
Packit 63bb0d
	buf := make([]byte, 18)
Packit 63bb0d
Packit 63bb0d
	// It's simpler to construct the hex string right to left.
Packit 63bb0d
	base := uint64(16)
Packit 63bb0d
	i := len(buf) - 1
Packit 63bb0d
	for num >= base {
Packit 63bb0d
		buf[i] = hexDigits[num%base]
Packit 63bb0d
		num /= base
Packit 63bb0d
		i--
Packit 63bb0d
	}
Packit 63bb0d
	buf[i] = hexDigits[num]
Packit 63bb0d
Packit 63bb0d
	// Add '0x' prefix.
Packit 63bb0d
	i--
Packit 63bb0d
	buf[i] = 'x'
Packit 63bb0d
	i--
Packit 63bb0d
	buf[i] = '0'
Packit 63bb0d
Packit 63bb0d
	// Strip unused leading bytes.
Packit 63bb0d
	buf = buf[i:]
Packit 63bb0d
	w.Write(buf)
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// valuesSorter implements sort.Interface to allow a slice of reflect.Value
Packit 63bb0d
// elements to be sorted.
Packit 63bb0d
type valuesSorter struct {
Packit 63bb0d
	values  []reflect.Value
Packit 63bb0d
	strings []string // either nil or same len and values
Packit 63bb0d
	cs      *ConfigState
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// newValuesSorter initializes a valuesSorter instance, which holds a set of
Packit 63bb0d
// surrogate keys on which the data should be sorted.  It uses flags in
Packit 63bb0d
// ConfigState to decide if and how to populate those surrogate keys.
Packit 63bb0d
func newValuesSorter(values []reflect.Value, cs *ConfigState) sort.Interface {
Packit 63bb0d
	vs := &valuesSorter{values: values, cs: cs}
Packit 63bb0d
	if canSortSimply(vs.values[0].Kind()) {
Packit 63bb0d
		return vs
Packit 63bb0d
	}
Packit 63bb0d
	if !cs.DisableMethods {
Packit 63bb0d
		vs.strings = make([]string, len(values))
Packit 63bb0d
		for i := range vs.values {
Packit 63bb0d
			b := bytes.Buffer{}
Packit 63bb0d
			if !handleMethods(cs, &b, vs.values[i]) {
Packit 63bb0d
				vs.strings = nil
Packit 63bb0d
				break
Packit 63bb0d
			}
Packit 63bb0d
			vs.strings[i] = b.String()
Packit 63bb0d
		}
Packit 63bb0d
	}
Packit 63bb0d
	if vs.strings == nil && cs.SpewKeys {
Packit 63bb0d
		vs.strings = make([]string, len(values))
Packit 63bb0d
		for i := range vs.values {
Packit 63bb0d
			vs.strings[i] = Sprintf("%#v", vs.values[i].Interface())
Packit 63bb0d
		}
Packit 63bb0d
	}
Packit 63bb0d
	return vs
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// canSortSimply tests whether a reflect.Kind is a primitive that can be sorted
Packit 63bb0d
// directly, or whether it should be considered for sorting by surrogate keys
Packit 63bb0d
// (if the ConfigState allows it).
Packit 63bb0d
func canSortSimply(kind reflect.Kind) bool {
Packit 63bb0d
	// This switch parallels valueSortLess, except for the default case.
Packit 63bb0d
	switch kind {
Packit 63bb0d
	case reflect.Bool:
Packit 63bb0d
		return true
Packit 63bb0d
	case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
Packit 63bb0d
		return true
Packit 63bb0d
	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
Packit 63bb0d
		return true
Packit 63bb0d
	case reflect.Float32, reflect.Float64:
Packit 63bb0d
		return true
Packit 63bb0d
	case reflect.String:
Packit 63bb0d
		return true
Packit 63bb0d
	case reflect.Uintptr:
Packit 63bb0d
		return true
Packit 63bb0d
	case reflect.Array:
Packit 63bb0d
		return true
Packit 63bb0d
	}
Packit 63bb0d
	return false
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// Len returns the number of values in the slice.  It is part of the
Packit 63bb0d
// sort.Interface implementation.
Packit 63bb0d
func (s *valuesSorter) Len() int {
Packit 63bb0d
	return len(s.values)
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// Swap swaps the values at the passed indices.  It is part of the
Packit 63bb0d
// sort.Interface implementation.
Packit 63bb0d
func (s *valuesSorter) Swap(i, j int) {
Packit 63bb0d
	s.values[i], s.values[j] = s.values[j], s.values[i]
Packit 63bb0d
	if s.strings != nil {
Packit 63bb0d
		s.strings[i], s.strings[j] = s.strings[j], s.strings[i]
Packit 63bb0d
	}
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// valueSortLess returns whether the first value should sort before the second
Packit 63bb0d
// value.  It is used by valueSorter.Less as part of the sort.Interface
Packit 63bb0d
// implementation.
Packit 63bb0d
func valueSortLess(a, b reflect.Value) bool {
Packit 63bb0d
	switch a.Kind() {
Packit 63bb0d
	case reflect.Bool:
Packit 63bb0d
		return !a.Bool() && b.Bool()
Packit 63bb0d
	case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
Packit 63bb0d
		return a.Int() < b.Int()
Packit 63bb0d
	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
Packit 63bb0d
		return a.Uint() < b.Uint()
Packit 63bb0d
	case reflect.Float32, reflect.Float64:
Packit 63bb0d
		return a.Float() < b.Float()
Packit 63bb0d
	case reflect.String:
Packit 63bb0d
		return a.String() < b.String()
Packit 63bb0d
	case reflect.Uintptr:
Packit 63bb0d
		return a.Uint() < b.Uint()
Packit 63bb0d
	case reflect.Array:
Packit 63bb0d
		// Compare the contents of both arrays.
Packit 63bb0d
		l := a.Len()
Packit 63bb0d
		for i := 0; i < l; i++ {
Packit 63bb0d
			av := a.Index(i)
Packit 63bb0d
			bv := b.Index(i)
Packit 63bb0d
			if av.Interface() == bv.Interface() {
Packit 63bb0d
				continue
Packit 63bb0d
			}
Packit 63bb0d
			return valueSortLess(av, bv)
Packit 63bb0d
		}
Packit 63bb0d
	}
Packit 63bb0d
	return a.String() < b.String()
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// Less returns whether the value at index i should sort before the
Packit 63bb0d
// value at index j.  It is part of the sort.Interface implementation.
Packit 63bb0d
func (s *valuesSorter) Less(i, j int) bool {
Packit 63bb0d
	if s.strings == nil {
Packit 63bb0d
		return valueSortLess(s.values[i], s.values[j])
Packit 63bb0d
	}
Packit 63bb0d
	return s.strings[i] < s.strings[j]
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// sortValues is a sort function that handles both native types and any type that
Packit 63bb0d
// can be converted to error or Stringer.  Other inputs are sorted according to
Packit 63bb0d
// their Value.String() value to ensure display stability.
Packit 63bb0d
func sortValues(values []reflect.Value, cs *ConfigState) {
Packit 63bb0d
	if len(values) == 0 {
Packit 63bb0d
		return
Packit 63bb0d
	}
Packit 63bb0d
	sort.Sort(newValuesSorter(values, cs))
Packit 63bb0d
}