From da633fb3048d576c63bb1faf6f0e09aea55867e9 Mon Sep 17 00:00:00 2001 From: John Jeffery Date: Sun, 22 Jan 2017 11:22:45 +1000 Subject: [PATCH] Uses package kv to serialize key/value pairs. This package already depended on package kv for kv.Flatten, so it seems OK to use this new functionality from package kv. --- context.go | 152 ++----------------------------------------------- errors_test.go | 4 +- 2 files changed, 7 insertions(+), 149 deletions(-) diff --git a/context.go b/context.go index 446a7e1..1b82e75 100644 --- a/context.go +++ b/context.go @@ -2,9 +2,6 @@ package errors import ( "bytes" - "encoding" - "fmt" - "reflect" "strings" "github.com/jjeffery/kv" @@ -104,152 +101,13 @@ func (ctx context) appendKeyvals(keyvals []interface{}) []interface{} { // writeToBuf writes the context's key/value pairs to a buffer. func (ctx context) writeToBuf(buf *bytes.Buffer) { - keyvals := kv.Flatten(ctx.keyvals) - for i := 0; i < len(keyvals); i += 2 { - // kv.Flatten guarantees that every even-numbered index - // will contain a string, and that it will be followed by - // an odd-numbered index - key := keyvals[i].(string) - value := keyvals[i+1] - - if buf.Len() > 0 { - buf.WriteRune(' ') - } - buf.WriteString(key) - buf.WriteRune('=') - writeValue(buf, value) - } -} - -// constant byte values -var ( - bytesNull = []byte("null") - bytesPanic = []byte(`""`) - bytesError = []byte(`""`) -) - -func writeValue(buf *bytes.Buffer, value interface{}) { - defer func() { - if r := recover(); r != nil { - if buf != nil { - buf.Write(bytesPanic) - } - } - }() - switch v := value.(type) { - case nil: - writeBytesValue(buf, bytesNull) - return - case []byte: - writeBytesValue(buf, v) - return - case string: - writeStringValue(buf, v) - return - case bool, byte, int8, int16, uint16, int32, uint32, int64, uint64, int, uint, uintptr, float32, float64, complex64, complex128: - fmt.Fprint(buf, v) - return - case encoding.TextMarshaler: - writeTextMarshalerValue(buf, v) - return - case error: - writeStringValue(buf, v.Error()) - return - case fmt.Stringer: - writeStringValue(buf, v.String()) - return - default: - // handle pointer to any of the above - rv := reflect.ValueOf(value) - if rv.Kind() == reflect.Ptr { - if rv.IsNil() { - buf.Write(bytesNull) - return - } - writeValue(buf, rv.Elem().Interface()) - return - } - writeStringValue(buf, fmt.Sprint(value)) - } -} - -func writeBytesValue(buf *bytes.Buffer, b []byte) { - if b == nil { - buf.Write(bytesNull) + if len(ctx.keyvals) == 0 { return } - index := bytes.IndexFunc(b, needsQuote) - if index < 0 { - buf.Write(b) - return - } - buf.WriteRune('"') - if index > 0 { - buf.Write(b[0:index]) - b = b[index:] - } - for { - index = bytes.IndexFunc(b, needsBackslash) - if index < 0 { - break - } - if index > 0 { - buf.Write(b[:index]) - b = b[index:] - } - buf.WriteRune('\\') - // we know that the rune will be a single byte - buf.WriteByte(b[0]) - b = b[1:] + kvlist := kv.List(ctx.keyvals) + b, _ := kvlist.MarshalText() + if buf.Len() > 0 { + buf.WriteRune(' ') } buf.Write(b) - buf.WriteRune('"') -} - -func writeStringValue(buf *bytes.Buffer, s string) { - index := strings.IndexFunc(s, needsQuote) - if index < 0 { - buf.WriteString(s) - return - } - buf.WriteRune('"') - if index > 0 { - buf.WriteString(s[0:index]) - s = s[index:] - } - for { - index = strings.IndexFunc(s, needsBackslash) - if index < 0 { - break - } - if index > 0 { - buf.WriteString(s[0:index]) - s = s[index:] - } - buf.WriteRune('\\') - // we know that the rune will be a single byte - buf.WriteByte(s[0]) - s = s[1:] - } - buf.WriteString(s) - buf.WriteRune('"') -} - -func writeTextMarshalerValue(buf *bytes.Buffer, t encoding.TextMarshaler) { - b, err := t.MarshalText() - if err != nil { - buf.Write(bytesError) - return - } - writeBytesValue(buf, b) -} - -func needsQuote(c rune) bool { - // the single quote '\'' is not strictly necessary, but - // is more human readable if quoted - return c <= ' ' || c == '"' || c == '\\' || c == '\'' -} - -func needsBackslash(c rune) bool { - return c == '\\' || c == '"' } diff --git a/errors_test.go b/errors_test.go index d24b310..29d5695 100644 --- a/errors_test.go +++ b/errors_test.go @@ -71,7 +71,7 @@ func TestNew(t *testing.T) { opts: []interface{}{ "f1", failingTextMarshaler(0), }, - expect: `msg f1=""`, + expect: `msg f1=`, }, { msg: "msg", @@ -108,7 +108,7 @@ func TestNew(t *testing.T) { opts: []interface{}{ "p1", panicingStringer("I can't do this"), }, - expect: `msg p1=""`, + expect: `msg p1=`, }, }