Blame vendor/github.com/davecgh/go-spew/spew/format.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
	"reflect"
Packit 63bb0d
	"strconv"
Packit 63bb0d
	"strings"
Packit 63bb0d
)
Packit 63bb0d
Packit 63bb0d
// supportedFlags is a list of all the character flags supported by fmt package.
Packit 63bb0d
const supportedFlags = "0-+# "
Packit 63bb0d
Packit 63bb0d
// formatState implements the fmt.Formatter interface and contains information
Packit 63bb0d
// about the state of a formatting operation.  The NewFormatter function can
Packit 63bb0d
// be used to get a new Formatter which can be used directly as arguments
Packit 63bb0d
// in standard fmt package printing calls.
Packit 63bb0d
type formatState struct {
Packit 63bb0d
	value          interface{}
Packit 63bb0d
	fs             fmt.State
Packit 63bb0d
	depth          int
Packit 63bb0d
	pointers       map[uintptr]int
Packit 63bb0d
	ignoreNextType bool
Packit 63bb0d
	cs             *ConfigState
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// buildDefaultFormat recreates the original format string without precision
Packit 63bb0d
// and width information to pass in to fmt.Sprintf in the case of an
Packit 63bb0d
// unrecognized type.  Unless new types are added to the language, this
Packit 63bb0d
// function won't ever be called.
Packit 63bb0d
func (f *formatState) buildDefaultFormat() (format string) {
Packit 63bb0d
	buf := bytes.NewBuffer(percentBytes)
Packit 63bb0d
Packit 63bb0d
	for _, flag := range supportedFlags {
Packit 63bb0d
		if f.fs.Flag(int(flag)) {
Packit 63bb0d
			buf.WriteRune(flag)
Packit 63bb0d
		}
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	buf.WriteRune('v')
Packit 63bb0d
Packit 63bb0d
	format = buf.String()
Packit 63bb0d
	return format
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// constructOrigFormat recreates the original format string including precision
Packit 63bb0d
// and width information to pass along to the standard fmt package.  This allows
Packit 63bb0d
// automatic deferral of all format strings this package doesn't support.
Packit 63bb0d
func (f *formatState) constructOrigFormat(verb rune) (format string) {
Packit 63bb0d
	buf := bytes.NewBuffer(percentBytes)
Packit 63bb0d
Packit 63bb0d
	for _, flag := range supportedFlags {
Packit 63bb0d
		if f.fs.Flag(int(flag)) {
Packit 63bb0d
			buf.WriteRune(flag)
Packit 63bb0d
		}
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	if width, ok := f.fs.Width(); ok {
Packit 63bb0d
		buf.WriteString(strconv.Itoa(width))
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	if precision, ok := f.fs.Precision(); ok {
Packit 63bb0d
		buf.Write(precisionBytes)
Packit 63bb0d
		buf.WriteString(strconv.Itoa(precision))
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	buf.WriteRune(verb)
Packit 63bb0d
Packit 63bb0d
	format = buf.String()
Packit 63bb0d
	return format
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// unpackValue returns values inside of non-nil interfaces when possible and
Packit 63bb0d
// ensures that types for values which have been unpacked from an interface
Packit 63bb0d
// are displayed when the show types flag is also set.
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 (f *formatState) unpackValue(v reflect.Value) reflect.Value {
Packit 63bb0d
	if v.Kind() == reflect.Interface {
Packit 63bb0d
		f.ignoreNextType = false
Packit 63bb0d
		if !v.IsNil() {
Packit 63bb0d
			v = v.Elem()
Packit 63bb0d
		}
Packit 63bb0d
	}
Packit 63bb0d
	return v
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// formatPtr handles formatting of pointers by indirecting them as necessary.
Packit 63bb0d
func (f *formatState) formatPtr(v reflect.Value) {
Packit 63bb0d
	// Display nil if top level pointer is nil.
Packit 63bb0d
	showTypes := f.fs.Flag('#')
Packit 63bb0d
	if v.IsNil() && (!showTypes || f.ignoreNextType) {
Packit 63bb0d
		f.fs.Write(nilAngleBytes)
Packit 63bb0d
		return
Packit 63bb0d
	}
Packit 63bb0d
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 f.pointers {
Packit 63bb0d
		if depth >= f.depth {
Packit 63bb0d
			delete(f.pointers, k)
Packit 63bb0d
		}
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	// Keep list of all dereferenced pointers to possibly show later.
Packit 63bb0d
	pointerChain := make([]uintptr, 0)
Packit 63bb0d
Packit 63bb0d
	// Figure out how many levels of indirection there are by derferencing
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 := f.pointers[addr]; ok && pd < f.depth {
Packit 63bb0d
			cycleFound = true
Packit 63bb0d
			indirects--
Packit 63bb0d
			break
Packit 63bb0d
		}
Packit 63bb0d
		f.pointers[addr] = f.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 or indirection level depending on flags.
Packit 63bb0d
	if showTypes && !f.ignoreNextType {
Packit 63bb0d
		f.fs.Write(openParenBytes)
Packit 63bb0d
		f.fs.Write(bytes.Repeat(asteriskBytes, indirects))
Packit 63bb0d
		f.fs.Write([]byte(ve.Type().String()))
Packit 63bb0d
		f.fs.Write(closeParenBytes)
Packit 63bb0d
	} else {
Packit 63bb0d
		if nilFound || cycleFound {
Packit 63bb0d
			indirects += strings.Count(ve.Type().String(), "*")
Packit 63bb0d
		}
Packit 63bb0d
		f.fs.Write(openAngleBytes)
Packit 63bb0d
		f.fs.Write([]byte(strings.Repeat("*", indirects)))
Packit 63bb0d
		f.fs.Write(closeAngleBytes)
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	// Display pointer information depending on flags.
Packit 63bb0d
	if f.fs.Flag('+') && (len(pointerChain) > 0) {
Packit 63bb0d
		f.fs.Write(openParenBytes)
Packit 63bb0d
		for i, addr := range pointerChain {
Packit 63bb0d
			if i > 0 {
Packit 63bb0d
				f.fs.Write(pointerChainBytes)
Packit 63bb0d
			}
Packit 63bb0d
			printHexPtr(f.fs, addr)
Packit 63bb0d
		}
Packit 63bb0d
		f.fs.Write(closeParenBytes)
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	// Display dereferenced value.
Packit 63bb0d
	switch {
Packit Service 509fd4
	case nilFound:
Packit 63bb0d
		f.fs.Write(nilAngleBytes)
Packit 63bb0d
Packit Service 509fd4
	case cycleFound:
Packit 63bb0d
		f.fs.Write(circularShortBytes)
Packit 63bb0d
Packit 63bb0d
	default:
Packit 63bb0d
		f.ignoreNextType = true
Packit 63bb0d
		f.format(ve)
Packit 63bb0d
	}
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// format is the main workhorse for providing the Formatter interface.  It
Packit 63bb0d
// uses the passed reflect value to figure out what kind of object we are
Packit 63bb0d
// dealing with and formats it appropriately.  It is a recursive function,
Packit 63bb0d
// however circular data structures are detected and handled properly.
Packit 63bb0d
func (f *formatState) format(v reflect.Value) {
Packit 63bb0d
	// Handle invalid reflect values immediately.
Packit 63bb0d
	kind := v.Kind()
Packit 63bb0d
	if kind == reflect.Invalid {
Packit 63bb0d
		f.fs.Write(invalidAngleBytes)
Packit 63bb0d
		return
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	// Handle pointers specially.
Packit 63bb0d
	if kind == reflect.Ptr {
Packit 63bb0d
		f.formatPtr(v)
Packit 63bb0d
		return
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	// Print type information unless already handled elsewhere.
Packit 63bb0d
	if !f.ignoreNextType && f.fs.Flag('#') {
Packit 63bb0d
		f.fs.Write(openParenBytes)
Packit 63bb0d
		f.fs.Write([]byte(v.Type().String()))
Packit 63bb0d
		f.fs.Write(closeParenBytes)
Packit 63bb0d
	}
Packit 63bb0d
	f.ignoreNextType = false
Packit 63bb0d
Packit 63bb0d
	// Call Stringer/error interfaces if they exist and the handle methods
Packit 63bb0d
	// flag is enabled.
Packit 63bb0d
	if !f.cs.DisableMethods {
Packit 63bb0d
		if (kind != reflect.Invalid) && (kind != reflect.Interface) {
Packit 63bb0d
			if handled := handleMethods(f.cs, f.fs, 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(f.fs, v.Bool())
Packit 63bb0d
Packit 63bb0d
	case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
Packit 63bb0d
		printInt(f.fs, v.Int(), 10)
Packit 63bb0d
Packit 63bb0d
	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
Packit 63bb0d
		printUint(f.fs, v.Uint(), 10)
Packit 63bb0d
Packit 63bb0d
	case reflect.Float32:
Packit 63bb0d
		printFloat(f.fs, v.Float(), 32)
Packit 63bb0d
Packit 63bb0d
	case reflect.Float64:
Packit 63bb0d
		printFloat(f.fs, v.Float(), 64)
Packit 63bb0d
Packit 63bb0d
	case reflect.Complex64:
Packit 63bb0d
		printComplex(f.fs, v.Complex(), 32)
Packit 63bb0d
Packit 63bb0d
	case reflect.Complex128:
Packit 63bb0d
		printComplex(f.fs, v.Complex(), 64)
Packit 63bb0d
Packit 63bb0d
	case reflect.Slice:
Packit 63bb0d
		if v.IsNil() {
Packit 63bb0d
			f.fs.Write(nilAngleBytes)
Packit 63bb0d
			break
Packit 63bb0d
		}
Packit 63bb0d
		fallthrough
Packit 63bb0d
Packit 63bb0d
	case reflect.Array:
Packit 63bb0d
		f.fs.Write(openBracketBytes)
Packit 63bb0d
		f.depth++
Packit 63bb0d
		if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
Packit 63bb0d
			f.fs.Write(maxShortBytes)
Packit 63bb0d
		} else {
Packit 63bb0d
			numEntries := v.Len()
Packit 63bb0d
			for i := 0; i < numEntries; i++ {
Packit 63bb0d
				if i > 0 {
Packit 63bb0d
					f.fs.Write(spaceBytes)
Packit 63bb0d
				}
Packit 63bb0d
				f.ignoreNextType = true
Packit 63bb0d
				f.format(f.unpackValue(v.Index(i)))
Packit 63bb0d
			}
Packit 63bb0d
		}
Packit 63bb0d
		f.depth--
Packit 63bb0d
		f.fs.Write(closeBracketBytes)
Packit 63bb0d
Packit 63bb0d
	case reflect.String:
Packit 63bb0d
		f.fs.Write([]byte(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
			f.fs.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
			f.fs.Write(nilAngleBytes)
Packit 63bb0d
			break
Packit 63bb0d
		}
Packit 63bb0d
Packit 63bb0d
		f.fs.Write(openMapBytes)
Packit 63bb0d
		f.depth++
Packit 63bb0d
		if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
Packit 63bb0d
			f.fs.Write(maxShortBytes)
Packit 63bb0d
		} else {
Packit 63bb0d
			keys := v.MapKeys()
Packit 63bb0d
			if f.cs.SortKeys {
Packit 63bb0d
				sortValues(keys, f.cs)
Packit 63bb0d
			}
Packit 63bb0d
			for i, key := range keys {
Packit 63bb0d
				if i > 0 {
Packit 63bb0d
					f.fs.Write(spaceBytes)
Packit 63bb0d
				}
Packit 63bb0d
				f.ignoreNextType = true
Packit 63bb0d
				f.format(f.unpackValue(key))
Packit 63bb0d
				f.fs.Write(colonBytes)
Packit 63bb0d
				f.ignoreNextType = true
Packit 63bb0d
				f.format(f.unpackValue(v.MapIndex(key)))
Packit 63bb0d
			}
Packit 63bb0d
		}
Packit 63bb0d
		f.depth--
Packit 63bb0d
		f.fs.Write(closeMapBytes)
Packit 63bb0d
Packit 63bb0d
	case reflect.Struct:
Packit 63bb0d
		numFields := v.NumField()
Packit 63bb0d
		f.fs.Write(openBraceBytes)
Packit 63bb0d
		f.depth++
Packit 63bb0d
		if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
Packit 63bb0d
			f.fs.Write(maxShortBytes)
Packit 63bb0d
		} else {
Packit 63bb0d
			vt := v.Type()
Packit 63bb0d
			for i := 0; i < numFields; i++ {
Packit 63bb0d
				if i > 0 {
Packit 63bb0d
					f.fs.Write(spaceBytes)
Packit 63bb0d
				}
Packit 63bb0d
				vtf := vt.Field(i)
Packit 63bb0d
				if f.fs.Flag('+') || f.fs.Flag('#') {
Packit 63bb0d
					f.fs.Write([]byte(vtf.Name))
Packit 63bb0d
					f.fs.Write(colonBytes)
Packit 63bb0d
				}
Packit 63bb0d
				f.format(f.unpackValue(v.Field(i)))
Packit 63bb0d
			}
Packit 63bb0d
		}
Packit 63bb0d
		f.depth--
Packit 63bb0d
		f.fs.Write(closeBraceBytes)
Packit 63bb0d
Packit 63bb0d
	case reflect.Uintptr:
Packit 63bb0d
		printHexPtr(f.fs, uintptr(v.Uint()))
Packit 63bb0d
Packit 63bb0d
	case reflect.UnsafePointer, reflect.Chan, reflect.Func:
Packit 63bb0d
		printHexPtr(f.fs, 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 if any get added.
Packit 63bb0d
	default:
Packit 63bb0d
		format := f.buildDefaultFormat()
Packit 63bb0d
		if v.CanInterface() {
Packit 63bb0d
			fmt.Fprintf(f.fs, format, v.Interface())
Packit 63bb0d
		} else {
Packit 63bb0d
			fmt.Fprintf(f.fs, format, v.String())
Packit 63bb0d
		}
Packit 63bb0d
	}
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// Format satisfies the fmt.Formatter interface. See NewFormatter for usage
Packit 63bb0d
// details.
Packit 63bb0d
func (f *formatState) Format(fs fmt.State, verb rune) {
Packit 63bb0d
	f.fs = fs
Packit 63bb0d
Packit 63bb0d
	// Use standard formatting for verbs that are not v.
Packit 63bb0d
	if verb != 'v' {
Packit 63bb0d
		format := f.constructOrigFormat(verb)
Packit 63bb0d
		fmt.Fprintf(fs, format, f.value)
Packit 63bb0d
		return
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	if f.value == nil {
Packit 63bb0d
		if fs.Flag('#') {
Packit 63bb0d
			fs.Write(interfaceBytes)
Packit 63bb0d
		}
Packit 63bb0d
		fs.Write(nilAngleBytes)
Packit 63bb0d
		return
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	f.format(reflect.ValueOf(f.value))
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// newFormatter is a helper function to consolidate the logic from the various
Packit 63bb0d
// public methods which take varying config states.
Packit 63bb0d
func newFormatter(cs *ConfigState, v interface{}) fmt.Formatter {
Packit 63bb0d
	fs := &formatState{value: v, cs: cs}
Packit 63bb0d
	fs.pointers = make(map[uintptr]int)
Packit 63bb0d
	return fs
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
/*
Packit 63bb0d
NewFormatter returns a custom formatter that satisfies the fmt.Formatter
Packit 63bb0d
interface.  As a result, it integrates cleanly with standard fmt package
Packit 63bb0d
printing functions.  The formatter is useful for inline printing of smaller data
Packit 63bb0d
types similar to the standard %v format specifier.
Packit 63bb0d
Packit 63bb0d
The custom formatter only responds to the %v (most compact), %+v (adds pointer
Packit 63bb0d
addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb
Packit 63bb0d
combinations.  Any other verbs such as %x and %q will be sent to the the
Packit 63bb0d
standard fmt package for formatting.  In addition, the custom formatter ignores
Packit 63bb0d
the width and precision arguments (however they will still work on the format
Packit 63bb0d
specifiers not handled by the custom formatter).
Packit 63bb0d
Packit 63bb0d
Typically this function shouldn't be called directly.  It is much easier to make
Packit 63bb0d
use of the custom formatter by calling one of the convenience functions such as
Packit 63bb0d
Printf, Println, or Fprintf.
Packit 63bb0d
*/
Packit 63bb0d
func NewFormatter(v interface{}) fmt.Formatter {
Packit 63bb0d
	return newFormatter(&Config, v)
Packit 63bb0d
}