| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- /*
- * Copyright (c) 2013 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 (
- "fmt"
- "io"
- "reflect"
- "strconv"
- "unsafe"
- )
- // reflectValue mirrors the struct layout of the reflect package Value type.
- var reflectValue struct {
- typ unsafe.Pointer
- val unsafe.Pointer
- flag uintptr
- }
- // flagIndir indicates whether the value field of a reflect.Value is the actual
- // data or a pointer to the data.
- const flagIndir = 1 << 1
- // unsafeReflectValue converts the passed reflect.Value into a one that bypasses
- // the typical safety restrictions preventing access to unaddressable and
- // unexported data. It works by digging the raw pointer to the underlying
- // value out of the protected value and generating a new unprotected (unsafe)
- // reflect.Value to it.
- //
- // This allows us to check for implementations of the Stringer and error
- // interfaces to be used for pretty printing ordinarily unaddressable and
- // inaccessible values such as unexported struct fields.
- func unsafeReflectValue(v reflect.Value) (rv reflect.Value) {
- indirects := 1
- vt := v.Type()
- upv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + unsafe.Offsetof(reflectValue.val))
- rvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + unsafe.Offsetof(reflectValue.flag)))
- if rvf&flagIndir != 0 {
- vt = reflect.PtrTo(v.Type())
- indirects++
- }
- pv := reflect.NewAt(vt, upv)
- rv = pv
- for i := 0; i < indirects; i++ {
- rv = rv.Elem()
- }
- return rv
- }
- // 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("]")
- )
- // 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
- // an interface on certain things like unexported struct fields in order
- // to enforce visibility rules. We use unsafe to bypass these restrictions
- // since this package does not mutate the values.
- if !v.CanInterface() {
- 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.
- var viface interface{}
- if !cs.DisablePointerMethods {
- if !v.CanAddr() {
- v = unsafeReflectValue(v)
- }
- viface = v.Addr().Interface()
- } else {
- viface = v.Interface()
- }
- // Is it an error or Stringer?
- switch iface := viface.(type) {
- case error:
- defer catchPanic(w, v)
- w.Write([]byte(iface.Error()))
- return true
- case fmt.Stringer:
- defer catchPanic(w, v)
- 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) {
- w.Write([]byte(strconv.FormatInt(val, 10)))
- }
- // printUint outputs an unsigned integer value to Writer w.
- func printUint(w io.Writer, val uint64) {
- w.Write([]byte(strconv.FormatUint(val, 10)))
- }
- // 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 hexidecimal 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)
- }
|