format.go

  1/*
  2 * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
  3 *
  4 * Permission to use, copy, modify, and distribute this software for any
  5 * purpose with or without fee is hereby granted, provided that the above
  6 * copyright notice and this permission notice appear in all copies.
  7 *
  8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 15 */
 16
 17package spew
 18
 19import (
 20	"bytes"
 21	"fmt"
 22	"reflect"
 23	"strconv"
 24	"strings"
 25)
 26
 27// supportedFlags is a list of all the character flags supported by fmt package.
 28const supportedFlags = "0-+# "
 29
 30// formatState implements the fmt.Formatter interface and contains information
 31// about the state of a formatting operation.  The NewFormatter function can
 32// be used to get a new Formatter which can be used directly as arguments
 33// in standard fmt package printing calls.
 34type formatState struct {
 35	value          interface{}
 36	fs             fmt.State
 37	depth          int
 38	pointers       map[uintptr]int
 39	ignoreNextType bool
 40	cs             *ConfigState
 41}
 42
 43// buildDefaultFormat recreates the original format string without precision
 44// and width information to pass in to fmt.Sprintf in the case of an
 45// unrecognized type.  Unless new types are added to the language, this
 46// function won't ever be called.
 47func (f *formatState) buildDefaultFormat() (format string) {
 48	buf := bytes.NewBuffer(percentBytes)
 49
 50	for _, flag := range supportedFlags {
 51		if f.fs.Flag(int(flag)) {
 52			buf.WriteRune(flag)
 53		}
 54	}
 55
 56	buf.WriteRune('v')
 57
 58	format = buf.String()
 59	return format
 60}
 61
 62// constructOrigFormat recreates the original format string including precision
 63// and width information to pass along to the standard fmt package.  This allows
 64// automatic deferral of all format strings this package doesn't support.
 65func (f *formatState) constructOrigFormat(verb rune) (format string) {
 66	buf := bytes.NewBuffer(percentBytes)
 67
 68	for _, flag := range supportedFlags {
 69		if f.fs.Flag(int(flag)) {
 70			buf.WriteRune(flag)
 71		}
 72	}
 73
 74	if width, ok := f.fs.Width(); ok {
 75		buf.WriteString(strconv.Itoa(width))
 76	}
 77
 78	if precision, ok := f.fs.Precision(); ok {
 79		buf.Write(precisionBytes)
 80		buf.WriteString(strconv.Itoa(precision))
 81	}
 82
 83	buf.WriteRune(verb)
 84
 85	format = buf.String()
 86	return format
 87}
 88
 89// unpackValue returns values inside of non-nil interfaces when possible and
 90// ensures that types for values which have been unpacked from an interface
 91// are displayed when the show types flag is also set.
 92// This is useful for data types like structs, arrays, slices, and maps which
 93// can contain varying types packed inside an interface.
 94func (f *formatState) unpackValue(v reflect.Value) reflect.Value {
 95	if v.Kind() == reflect.Interface {
 96		f.ignoreNextType = false
 97		if !v.IsNil() {
 98			v = v.Elem()
 99		}
100	}
101	return v
102}
103
104// formatPtr handles formatting of pointers by indirecting them as necessary.
105func (f *formatState) formatPtr(v reflect.Value) {
106	// Display nil if top level pointer is nil.
107	showTypes := f.fs.Flag('#')
108	if v.IsNil() && (!showTypes || f.ignoreNextType) {
109		f.fs.Write(nilAngleBytes)
110		return
111	}
112
113	// Remove pointers at or below the current depth from map used to detect
114	// circular refs.
115	for k, depth := range f.pointers {
116		if depth >= f.depth {
117			delete(f.pointers, k)
118		}
119	}
120
121	// Keep list of all dereferenced pointers to possibly show later.
122	pointerChain := make([]uintptr, 0)
123
124	// Figure out how many levels of indirection there are by derferencing
125	// pointers and unpacking interfaces down the chain while detecting circular
126	// references.
127	nilFound := false
128	cycleFound := false
129	indirects := 0
130	ve := v
131	for ve.Kind() == reflect.Ptr {
132		if ve.IsNil() {
133			nilFound = true
134			break
135		}
136		indirects++
137		addr := ve.Pointer()
138		pointerChain = append(pointerChain, addr)
139		if pd, ok := f.pointers[addr]; ok && pd < f.depth {
140			cycleFound = true
141			indirects--
142			break
143		}
144		f.pointers[addr] = f.depth
145
146		ve = ve.Elem()
147		if ve.Kind() == reflect.Interface {
148			if ve.IsNil() {
149				nilFound = true
150				break
151			}
152			ve = ve.Elem()
153		}
154	}
155
156	// Display type or indirection level depending on flags.
157	if showTypes && !f.ignoreNextType {
158		f.fs.Write(openParenBytes)
159		f.fs.Write(bytes.Repeat(asteriskBytes, indirects))
160		f.fs.Write([]byte(ve.Type().String()))
161		f.fs.Write(closeParenBytes)
162	} else {
163		if nilFound || cycleFound {
164			indirects += strings.Count(ve.Type().String(), "*")
165		}
166		f.fs.Write(openAngleBytes)
167		f.fs.Write([]byte(strings.Repeat("*", indirects)))
168		f.fs.Write(closeAngleBytes)
169	}
170
171	// Display pointer information depending on flags.
172	if f.fs.Flag('+') && (len(pointerChain) > 0) {
173		f.fs.Write(openParenBytes)
174		for i, addr := range pointerChain {
175			if i > 0 {
176				f.fs.Write(pointerChainBytes)
177			}
178			printHexPtr(f.fs, addr)
179		}
180		f.fs.Write(closeParenBytes)
181	}
182
183	// Display dereferenced value.
184	switch {
185	case nilFound:
186		f.fs.Write(nilAngleBytes)
187
188	case cycleFound:
189		f.fs.Write(circularShortBytes)
190
191	default:
192		f.ignoreNextType = true
193		f.format(ve)
194	}
195}
196
197// format is the main workhorse for providing the Formatter interface.  It
198// uses the passed reflect value to figure out what kind of object we are
199// dealing with and formats it appropriately.  It is a recursive function,
200// however circular data structures are detected and handled properly.
201func (f *formatState) format(v reflect.Value) {
202	// Handle invalid reflect values immediately.
203	kind := v.Kind()
204	if kind == reflect.Invalid {
205		f.fs.Write(invalidAngleBytes)
206		return
207	}
208
209	// Handle pointers specially.
210	if kind == reflect.Ptr {
211		f.formatPtr(v)
212		return
213	}
214
215	// Print type information unless already handled elsewhere.
216	if !f.ignoreNextType && f.fs.Flag('#') {
217		f.fs.Write(openParenBytes)
218		f.fs.Write([]byte(v.Type().String()))
219		f.fs.Write(closeParenBytes)
220	}
221	f.ignoreNextType = false
222
223	// Call Stringer/error interfaces if they exist and the handle methods
224	// flag is enabled.
225	if !f.cs.DisableMethods {
226		if (kind != reflect.Invalid) && (kind != reflect.Interface) {
227			if handled := handleMethods(f.cs, f.fs, v); handled {
228				return
229			}
230		}
231	}
232
233	switch kind {
234	case reflect.Invalid:
235		// Do nothing.  We should never get here since invalid has already
236		// been handled above.
237
238	case reflect.Bool:
239		printBool(f.fs, v.Bool())
240
241	case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
242		printInt(f.fs, v.Int(), 10)
243
244	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
245		printUint(f.fs, v.Uint(), 10)
246
247	case reflect.Float32:
248		printFloat(f.fs, v.Float(), 32)
249
250	case reflect.Float64:
251		printFloat(f.fs, v.Float(), 64)
252
253	case reflect.Complex64:
254		printComplex(f.fs, v.Complex(), 32)
255
256	case reflect.Complex128:
257		printComplex(f.fs, v.Complex(), 64)
258
259	case reflect.Slice:
260		if v.IsNil() {
261			f.fs.Write(nilAngleBytes)
262			break
263		}
264		fallthrough
265
266	case reflect.Array:
267		f.fs.Write(openBracketBytes)
268		f.depth++
269		if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
270			f.fs.Write(maxShortBytes)
271		} else {
272			numEntries := v.Len()
273			for i := 0; i < numEntries; i++ {
274				if i > 0 {
275					f.fs.Write(spaceBytes)
276				}
277				f.ignoreNextType = true
278				f.format(f.unpackValue(v.Index(i)))
279			}
280		}
281		f.depth--
282		f.fs.Write(closeBracketBytes)
283
284	case reflect.String:
285		f.fs.Write([]byte(v.String()))
286
287	case reflect.Interface:
288		// The only time we should get here is for nil interfaces due to
289		// unpackValue calls.
290		if v.IsNil() {
291			f.fs.Write(nilAngleBytes)
292		}
293
294	case reflect.Ptr:
295		// Do nothing.  We should never get here since pointers have already
296		// been handled above.
297
298	case reflect.Map:
299		// nil maps should be indicated as different than empty maps
300		if v.IsNil() {
301			f.fs.Write(nilAngleBytes)
302			break
303		}
304
305		f.fs.Write(openMapBytes)
306		f.depth++
307		if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
308			f.fs.Write(maxShortBytes)
309		} else {
310			keys := v.MapKeys()
311			if f.cs.SortKeys {
312				sortValues(keys, f.cs)
313			}
314			for i, key := range keys {
315				if i > 0 {
316					f.fs.Write(spaceBytes)
317				}
318				f.ignoreNextType = true
319				f.format(f.unpackValue(key))
320				f.fs.Write(colonBytes)
321				f.ignoreNextType = true
322				f.format(f.unpackValue(v.MapIndex(key)))
323			}
324		}
325		f.depth--
326		f.fs.Write(closeMapBytes)
327
328	case reflect.Struct:
329		numFields := v.NumField()
330		f.fs.Write(openBraceBytes)
331		f.depth++
332		if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
333			f.fs.Write(maxShortBytes)
334		} else {
335			vt := v.Type()
336			for i := 0; i < numFields; i++ {
337				if i > 0 {
338					f.fs.Write(spaceBytes)
339				}
340				vtf := vt.Field(i)
341				if f.fs.Flag('+') || f.fs.Flag('#') {
342					f.fs.Write([]byte(vtf.Name))
343					f.fs.Write(colonBytes)
344				}
345				f.format(f.unpackValue(v.Field(i)))
346			}
347		}
348		f.depth--
349		f.fs.Write(closeBraceBytes)
350
351	case reflect.Uintptr:
352		printHexPtr(f.fs, uintptr(v.Uint()))
353
354	case reflect.UnsafePointer, reflect.Chan, reflect.Func:
355		printHexPtr(f.fs, v.Pointer())
356
357	// There were not any other types at the time this code was written, but
358	// fall back to letting the default fmt package handle it if any get added.
359	default:
360		format := f.buildDefaultFormat()
361		if v.CanInterface() {
362			fmt.Fprintf(f.fs, format, v.Interface())
363		} else {
364			fmt.Fprintf(f.fs, format, v.String())
365		}
366	}
367}
368
369// Format satisfies the fmt.Formatter interface. See NewFormatter for usage
370// details.
371func (f *formatState) Format(fs fmt.State, verb rune) {
372	f.fs = fs
373
374	// Use standard formatting for verbs that are not v.
375	if verb != 'v' {
376		format := f.constructOrigFormat(verb)
377		fmt.Fprintf(fs, format, f.value)
378		return
379	}
380
381	if f.value == nil {
382		if fs.Flag('#') {
383			fs.Write(interfaceBytes)
384		}
385		fs.Write(nilAngleBytes)
386		return
387	}
388
389	f.format(reflect.ValueOf(f.value))
390}
391
392// newFormatter is a helper function to consolidate the logic from the various
393// public methods which take varying config states.
394func newFormatter(cs *ConfigState, v interface{}) fmt.Formatter {
395	fs := &formatState{value: v, cs: cs}
396	fs.pointers = make(map[uintptr]int)
397	return fs
398}
399
400/*
401NewFormatter returns a custom formatter that satisfies the fmt.Formatter
402interface.  As a result, it integrates cleanly with standard fmt package
403printing functions.  The formatter is useful for inline printing of smaller data
404types similar to the standard %v format specifier.
405
406The custom formatter only responds to the %v (most compact), %+v (adds pointer
407addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb
408combinations.  Any other verbs such as %x and %q will be sent to the the
409standard fmt package for formatting.  In addition, the custom formatter ignores
410the width and precision arguments (however they will still work on the format
411specifiers not handled by the custom formatter).
412
413Typically this function shouldn't be called directly.  It is much easier to make
414use of the custom formatter by calling one of the convenience functions such as
415Printf, Println, or Fprintf.
416*/
417func NewFormatter(v interface{}) fmt.Formatter {
418	return newFormatter(&Config, v)
419}