Dump byte arrays and slices like hexdump -C.
This commit modifies the Dump family functions to output byte arrays and slices like hexdump -C as specified in issue #9.
This commit is contained in:
parent
471552e81e
commit
70d81533ec
|
@ -120,7 +120,7 @@ func catchPanic(w io.Writer, v reflect.Value) {
|
||||||
func handleMethods(cs *ConfigState, w io.Writer, v reflect.Value) (handled bool) {
|
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
|
// We need an interface to check if the type implements the error or
|
||||||
// Stringer interface. However, the reflect package won't give us an
|
// Stringer interface. However, the reflect package won't give us an
|
||||||
// an interface on certain things like unexported struct fields in order
|
// interface on certain things like unexported struct fields in order
|
||||||
// to enforce visibility rules. We use unsafe to bypass these restrictions
|
// to enforce visibility rules. We use unsafe to bypass these restrictions
|
||||||
// since this package does not mutate the values.
|
// since this package does not mutate the values.
|
||||||
if !v.CanInterface() {
|
if !v.CanInterface() {
|
||||||
|
|
56
spew/dump.go
56
spew/dump.go
|
@ -18,11 +18,13 @@ package spew
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// dumpState contains information about the state of a dump operation.
|
// dumpState contains information about the state of a dump operation.
|
||||||
|
@ -134,6 +136,50 @@ func (d *dumpState) dumpPtr(v reflect.Value) {
|
||||||
d.w.Write(closeParenBytes)
|
d.w.Write(closeParenBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dumpSlice handles formatting of arrays and slices. Byte (uint8 under
|
||||||
|
// reflection) arrays and slices are dumped in hexdump -C fashion.
|
||||||
|
func (d *dumpState) dumpSlice(v reflect.Value) {
|
||||||
|
// Handle byte (uint8 under reflection) arrays and slices uniquely.
|
||||||
|
numEntries := v.Len()
|
||||||
|
if (numEntries > 0) && (v.Index(0).Kind() == reflect.Uint8) {
|
||||||
|
// We need an addressable interface to convert the type back into a byte
|
||||||
|
// slice. 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 to bypass these restrictions since
|
||||||
|
// this package does not mutate the values.
|
||||||
|
vs := v
|
||||||
|
if !vs.CanInterface() || !vs.CanAddr() {
|
||||||
|
vs = unsafeReflectValue(vs)
|
||||||
|
}
|
||||||
|
vs = vs.Slice(0, numEntries)
|
||||||
|
|
||||||
|
// Type assert a uint8 slice and hexdump it. Also fix indentation
|
||||||
|
// based on the depth.
|
||||||
|
iface := vs.Interface()
|
||||||
|
if buf, ok := iface.([]uint8); ok {
|
||||||
|
indent := strings.Repeat(d.cs.Indent, d.depth)
|
||||||
|
str := indent + hex.Dump(buf)
|
||||||
|
str = strings.Replace(str, "\n", "\n"+indent, -1)
|
||||||
|
str = strings.TrimRight(str, d.cs.Indent)
|
||||||
|
d.w.Write([]byte(str))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// We shouldn't ever get here, but the return is intentionally in the
|
||||||
|
// above if statement to ensure we fall through to normal behavior if
|
||||||
|
// the type assertion fails for some reason.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recursively call dump for each item.
|
||||||
|
for i := 0; i < numEntries; i++ {
|
||||||
|
d.dump(d.unpackValue(v.Index(i)))
|
||||||
|
if i < (numEntries - 1) {
|
||||||
|
d.w.Write(commaNewlineBytes)
|
||||||
|
} else {
|
||||||
|
d.w.Write(newlineBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// dump is the main workhorse for dumping a value. It uses the passed reflect
|
// dump is the main workhorse for dumping a value. It uses the passed reflect
|
||||||
// value to figure out what kind of object we are dealing with and formats it
|
// value to figure out what kind of object we are dealing with and formats it
|
||||||
// appropriately. It is a recursive function, however circular data structures
|
// appropriately. It is a recursive function, however circular data structures
|
||||||
|
@ -206,15 +252,7 @@ func (d *dumpState) dump(v reflect.Value) {
|
||||||
d.indent()
|
d.indent()
|
||||||
d.w.Write(maxNewlineBytes)
|
d.w.Write(maxNewlineBytes)
|
||||||
} else {
|
} else {
|
||||||
numEntries := v.Len()
|
d.dumpSlice(v)
|
||||||
for i := 0; i < numEntries; i++ {
|
|
||||||
d.dump(d.unpackValue(v.Index(i)))
|
|
||||||
if i < (numEntries - 1) {
|
|
||||||
d.w.Write(commaNewlineBytes)
|
|
||||||
} else {
|
|
||||||
d.w.Write(newlineBytes)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
d.depth--
|
d.depth--
|
||||||
d.indent()
|
d.indent()
|
||||||
|
|
Loading…
Reference in New Issue