342 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			342 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
 | |
|  *
 | |
|  * Permission to use, copy, modify, and distribute this software for any
 | |
|  * purpose with or without fee is hereby granted, provided that the above
 | |
|  * copyright notice and this permission notice appear in all copies.
 | |
|  *
 | |
|  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 | |
|  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 | |
|  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 | |
|  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | |
|  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 | |
|  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 | |
|  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | |
|  */
 | |
| 
 | |
| package spew
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 	"reflect"
 | |
| 	"sort"
 | |
| 	"strconv"
 | |
| )
 | |
| 
 | |
| // Some constants in the form of bytes to avoid string overhead.  This mirrors
 | |
| // the technique used in the fmt package.
 | |
| var (
 | |
| 	panicBytes            = []byte("(PANIC=")
 | |
| 	plusBytes             = []byte("+")
 | |
| 	iBytes                = []byte("i")
 | |
| 	trueBytes             = []byte("true")
 | |
| 	falseBytes            = []byte("false")
 | |
| 	interfaceBytes        = []byte("(interface {})")
 | |
| 	commaNewlineBytes     = []byte(",\n")
 | |
| 	newlineBytes          = []byte("\n")
 | |
| 	openBraceBytes        = []byte("{")
 | |
| 	openBraceNewlineBytes = []byte("{\n")
 | |
| 	closeBraceBytes       = []byte("}")
 | |
| 	asteriskBytes         = []byte("*")
 | |
| 	colonBytes            = []byte(":")
 | |
| 	colonSpaceBytes       = []byte(": ")
 | |
| 	openParenBytes        = []byte("(")
 | |
| 	closeParenBytes       = []byte(")")
 | |
| 	spaceBytes            = []byte(" ")
 | |
| 	pointerChainBytes     = []byte("->")
 | |
| 	nilAngleBytes         = []byte("<nil>")
 | |
| 	maxNewlineBytes       = []byte("<max depth reached>\n")
 | |
| 	maxShortBytes         = []byte("<max>")
 | |
| 	circularBytes         = []byte("<already shown>")
 | |
| 	circularShortBytes    = []byte("<shown>")
 | |
| 	invalidAngleBytes     = []byte("<invalid>")
 | |
| 	openBracketBytes      = []byte("[")
 | |
| 	closeBracketBytes     = []byte("]")
 | |
| 	percentBytes          = []byte("%")
 | |
| 	precisionBytes        = []byte(".")
 | |
| 	openAngleBytes        = []byte("<")
 | |
| 	closeAngleBytes       = []byte(">")
 | |
| 	openMapBytes          = []byte("map[")
 | |
| 	closeMapBytes         = []byte("]")
 | |
| 	lenEqualsBytes        = []byte("len=")
 | |
| 	capEqualsBytes        = []byte("cap=")
 | |
| )
 | |
| 
 | |
| // hexDigits is used to map a decimal value to a hex digit.
 | |
| var hexDigits = "0123456789abcdef"
 | |
| 
 | |
| // catchPanic handles any panics that might occur during the handleMethods
 | |
| // calls.
 | |
| func catchPanic(w io.Writer, v reflect.Value) {
 | |
| 	if err := recover(); err != nil {
 | |
| 		w.Write(panicBytes)
 | |
| 		fmt.Fprintf(w, "%v", err)
 | |
| 		w.Write(closeParenBytes)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // handleMethods attempts to call the Error and String methods on the underlying
 | |
| // type the passed reflect.Value represents and outputes the result to Writer w.
 | |
| //
 | |
| // It handles panics in any called methods by catching and displaying the error
 | |
| // as the formatted value.
 | |
| func handleMethods(cs *ConfigState, w io.Writer, v reflect.Value) (handled bool) {
 | |
| 	// We need an interface to check if the type implements the error or
 | |
| 	// Stringer interface.  However, the reflect package won't give us an
 | |
| 	// interface on certain things like unexported struct fields in order
 | |
| 	// to enforce visibility rules.  We use unsafe, when it's available,
 | |
| 	// to bypass these restrictions since this package does not mutate the
 | |
| 	// values.
 | |
| 	if !v.CanInterface() {
 | |
| 		if UnsafeDisabled {
 | |
| 			return false
 | |
| 		}
 | |
| 
 | |
| 		v = unsafeReflectValue(v)
 | |
| 	}
 | |
| 
 | |
| 	// Choose whether or not to do error and Stringer interface lookups against
 | |
| 	// the base type or a pointer to the base type depending on settings.
 | |
| 	// Technically calling one of these methods with a pointer receiver can
 | |
| 	// mutate the value, however, types which choose to satisify an error or
 | |
| 	// Stringer interface with a pointer receiver should not be mutating their
 | |
| 	// state inside these interface methods.
 | |
| 	if !cs.DisablePointerMethods && !UnsafeDisabled && !v.CanAddr() {
 | |
| 		v = unsafeReflectValue(v)
 | |
| 	}
 | |
| 	if v.CanAddr() {
 | |
| 		v = v.Addr()
 | |
| 	}
 | |
| 
 | |
| 	// Is it an error or Stringer?
 | |
| 	switch iface := v.Interface().(type) {
 | |
| 	case error:
 | |
| 		defer catchPanic(w, v)
 | |
| 		if cs.ContinueOnMethod {
 | |
| 			w.Write(openParenBytes)
 | |
| 			w.Write([]byte(iface.Error()))
 | |
| 			w.Write(closeParenBytes)
 | |
| 			w.Write(spaceBytes)
 | |
| 			return false
 | |
| 		}
 | |
| 
 | |
| 		w.Write([]byte(iface.Error()))
 | |
| 		return true
 | |
| 
 | |
| 	case fmt.Stringer:
 | |
| 		defer catchPanic(w, v)
 | |
| 		if cs.ContinueOnMethod {
 | |
| 			w.Write(openParenBytes)
 | |
| 			w.Write([]byte(iface.String()))
 | |
| 			w.Write(closeParenBytes)
 | |
| 			w.Write(spaceBytes)
 | |
| 			return false
 | |
| 		}
 | |
| 		w.Write([]byte(iface.String()))
 | |
| 		return true
 | |
| 	}
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| // printBool outputs a boolean value as true or false to Writer w.
 | |
| func printBool(w io.Writer, val bool) {
 | |
| 	if val {
 | |
| 		w.Write(trueBytes)
 | |
| 	} else {
 | |
| 		w.Write(falseBytes)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // printInt outputs a signed integer value to Writer w.
 | |
| func printInt(w io.Writer, val int64, base int) {
 | |
| 	w.Write([]byte(strconv.FormatInt(val, base)))
 | |
| }
 | |
| 
 | |
| // printUint outputs an unsigned integer value to Writer w.
 | |
| func printUint(w io.Writer, val uint64, base int) {
 | |
| 	w.Write([]byte(strconv.FormatUint(val, base)))
 | |
| }
 | |
| 
 | |
| // printFloat outputs a floating point value using the specified precision,
 | |
| // which is expected to be 32 or 64bit, to Writer w.
 | |
| func printFloat(w io.Writer, val float64, precision int) {
 | |
| 	w.Write([]byte(strconv.FormatFloat(val, 'g', -1, precision)))
 | |
| }
 | |
| 
 | |
| // printComplex outputs a complex value using the specified float precision
 | |
| // for the real and imaginary parts to Writer w.
 | |
| func printComplex(w io.Writer, c complex128, floatPrecision int) {
 | |
| 	r := real(c)
 | |
| 	w.Write(openParenBytes)
 | |
| 	w.Write([]byte(strconv.FormatFloat(r, 'g', -1, floatPrecision)))
 | |
| 	i := imag(c)
 | |
| 	if i >= 0 {
 | |
| 		w.Write(plusBytes)
 | |
| 	}
 | |
| 	w.Write([]byte(strconv.FormatFloat(i, 'g', -1, floatPrecision)))
 | |
| 	w.Write(iBytes)
 | |
| 	w.Write(closeParenBytes)
 | |
| }
 | |
| 
 | |
| // printHexPtr outputs a uintptr formatted as hexadecimal with a leading '0x'
 | |
| // prefix to Writer w.
 | |
| func printHexPtr(w io.Writer, p uintptr) {
 | |
| 	// Null pointer.
 | |
| 	num := uint64(p)
 | |
| 	if num == 0 {
 | |
| 		w.Write(nilAngleBytes)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// Max uint64 is 16 bytes in hex + 2 bytes for '0x' prefix
 | |
| 	buf := make([]byte, 18)
 | |
| 
 | |
| 	// It's simpler to construct the hex string right to left.
 | |
| 	base := uint64(16)
 | |
| 	i := len(buf) - 1
 | |
| 	for num >= base {
 | |
| 		buf[i] = hexDigits[num%base]
 | |
| 		num /= base
 | |
| 		i--
 | |
| 	}
 | |
| 	buf[i] = hexDigits[num]
 | |
| 
 | |
| 	// Add '0x' prefix.
 | |
| 	i--
 | |
| 	buf[i] = 'x'
 | |
| 	i--
 | |
| 	buf[i] = '0'
 | |
| 
 | |
| 	// Strip unused leading bytes.
 | |
| 	buf = buf[i:]
 | |
| 	w.Write(buf)
 | |
| }
 | |
| 
 | |
| // valuesSorter implements sort.Interface to allow a slice of reflect.Value
 | |
| // elements to be sorted.
 | |
| type valuesSorter struct {
 | |
| 	values  []reflect.Value
 | |
| 	strings []string // either nil or same len and values
 | |
| 	cs      *ConfigState
 | |
| }
 | |
| 
 | |
| // newValuesSorter initializes a valuesSorter instance, which holds a set of
 | |
| // surrogate keys on which the data should be sorted.  It uses flags in
 | |
| // ConfigState to decide if and how to populate those surrogate keys.
 | |
| func newValuesSorter(values []reflect.Value, cs *ConfigState) sort.Interface {
 | |
| 	vs := &valuesSorter{values: values, cs: cs}
 | |
| 	if canSortSimply(vs.values[0].Kind()) {
 | |
| 		return vs
 | |
| 	}
 | |
| 	if !cs.DisableMethods {
 | |
| 		vs.strings = make([]string, len(values))
 | |
| 		for i := range vs.values {
 | |
| 			b := bytes.Buffer{}
 | |
| 			if !handleMethods(cs, &b, vs.values[i]) {
 | |
| 				vs.strings = nil
 | |
| 				break
 | |
| 			}
 | |
| 			vs.strings[i] = b.String()
 | |
| 		}
 | |
| 	}
 | |
| 	if vs.strings == nil && cs.SpewKeys {
 | |
| 		vs.strings = make([]string, len(values))
 | |
| 		for i := range vs.values {
 | |
| 			vs.strings[i] = Sprintf("%#v", vs.values[i].Interface())
 | |
| 		}
 | |
| 	}
 | |
| 	return vs
 | |
| }
 | |
| 
 | |
| // canSortSimply tests whether a reflect.Kind is a primitive that can be sorted
 | |
| // directly, or whether it should be considered for sorting by surrogate keys
 | |
| // (if the ConfigState allows it).
 | |
| func canSortSimply(kind reflect.Kind) bool {
 | |
| 	// This switch parallels valueSortLess, except for the default case.
 | |
| 	switch kind {
 | |
| 	case reflect.Bool:
 | |
| 		return true
 | |
| 	case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
 | |
| 		return true
 | |
| 	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
 | |
| 		return true
 | |
| 	case reflect.Float32, reflect.Float64:
 | |
| 		return true
 | |
| 	case reflect.String:
 | |
| 		return true
 | |
| 	case reflect.Uintptr:
 | |
| 		return true
 | |
| 	case reflect.Array:
 | |
| 		return true
 | |
| 	}
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| // Len returns the number of values in the slice.  It is part of the
 | |
| // sort.Interface implementation.
 | |
| func (s *valuesSorter) Len() int {
 | |
| 	return len(s.values)
 | |
| }
 | |
| 
 | |
| // Swap swaps the values at the passed indices.  It is part of the
 | |
| // sort.Interface implementation.
 | |
| func (s *valuesSorter) Swap(i, j int) {
 | |
| 	s.values[i], s.values[j] = s.values[j], s.values[i]
 | |
| 	if s.strings != nil {
 | |
| 		s.strings[i], s.strings[j] = s.strings[j], s.strings[i]
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // valueSortLess returns whether the first value should sort before the second
 | |
| // value.  It is used by valueSorter.Less as part of the sort.Interface
 | |
| // implementation.
 | |
| func valueSortLess(a, b reflect.Value) bool {
 | |
| 	switch a.Kind() {
 | |
| 	case reflect.Bool:
 | |
| 		return !a.Bool() && b.Bool()
 | |
| 	case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
 | |
| 		return a.Int() < b.Int()
 | |
| 	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
 | |
| 		return a.Uint() < b.Uint()
 | |
| 	case reflect.Float32, reflect.Float64:
 | |
| 		return a.Float() < b.Float()
 | |
| 	case reflect.String:
 | |
| 		return a.String() < b.String()
 | |
| 	case reflect.Uintptr:
 | |
| 		return a.Uint() < b.Uint()
 | |
| 	case reflect.Array:
 | |
| 		// Compare the contents of both arrays.
 | |
| 		l := a.Len()
 | |
| 		for i := 0; i < l; i++ {
 | |
| 			av := a.Index(i)
 | |
| 			bv := b.Index(i)
 | |
| 			if av.Interface() == bv.Interface() {
 | |
| 				continue
 | |
| 			}
 | |
| 			return valueSortLess(av, bv)
 | |
| 		}
 | |
| 	}
 | |
| 	return a.String() < b.String()
 | |
| }
 | |
| 
 | |
| // Less returns whether the value at index i should sort before the
 | |
| // value at index j.  It is part of the sort.Interface implementation.
 | |
| func (s *valuesSorter) Less(i, j int) bool {
 | |
| 	if s.strings == nil {
 | |
| 		return valueSortLess(s.values[i], s.values[j])
 | |
| 	}
 | |
| 	return s.strings[i] < s.strings[j]
 | |
| }
 | |
| 
 | |
| // sortValues is a sort function that handles both native types and any type that
 | |
| // can be converted to error or Stringer.  Other inputs are sorted according to
 | |
| // their Value.String() value to ensure display stability.
 | |
| func sortValues(values []reflect.Value, cs *ConfigState) {
 | |
| 	if len(values) == 0 {
 | |
| 		return
 | |
| 	}
 | |
| 	sort.Sort(newValuesSorter(values, cs))
 | |
| }
 | 
