From 22fc3a988c3f9ce4e953f119c8d5b3cfe9f3beae Mon Sep 17 00:00:00 2001 From: Mitar Date: Sun, 28 Apr 2024 00:46:13 +0200 Subject: [PATCH] Allow setting floating point precision in JSON. Fixes #557. --- array.go | 6 +++--- context.go | 12 +++++------ encoder.go | 12 +++++------ event.go | 14 ++++++------- fields.go | 18 ++++++++-------- globals.go | 5 +++++ internal/cbor/time.go | 10 ++++----- internal/cbor/types.go | 12 +++++------ internal/cbor/types_test.go | 6 +++--- internal/json/time.go | 10 ++++----- internal/json/types.go | 35 ++++++++++++++++--------------- internal/json/types_test.go | 41 +++++++++++++++++++++---------------- 12 files changed, 97 insertions(+), 84 deletions(-) diff --git a/array.go b/array.go index 99612ee9..ba35b283 100644 --- a/array.go +++ b/array.go @@ -183,13 +183,13 @@ func (a *Array) Uint64(i uint64) *Array { // Float32 appends f as a float32 to the array. func (a *Array) Float32(f float32) *Array { - a.buf = enc.AppendFloat32(enc.AppendArrayDelim(a.buf), f) + a.buf = enc.AppendFloat32(enc.AppendArrayDelim(a.buf), f, FloatingPointPrecision) return a } // Float64 appends f as a float64 to the array. func (a *Array) Float64(f float64) *Array { - a.buf = enc.AppendFloat64(enc.AppendArrayDelim(a.buf), f) + a.buf = enc.AppendFloat64(enc.AppendArrayDelim(a.buf), f, FloatingPointPrecision) return a } @@ -201,7 +201,7 @@ func (a *Array) Time(t time.Time) *Array { // Dur appends d to the array. func (a *Array) Dur(d time.Duration) *Array { - a.buf = enc.AppendDuration(enc.AppendArrayDelim(a.buf), d, DurationFieldUnit, DurationFieldInteger) + a.buf = enc.AppendDuration(enc.AppendArrayDelim(a.buf), d, DurationFieldUnit, DurationFieldInteger, FloatingPointPrecision) return a } diff --git a/context.go b/context.go index 49711fb6..4f746b9b 100644 --- a/context.go +++ b/context.go @@ -325,25 +325,25 @@ func (c Context) Uints64(key string, i []uint64) Context { // Float32 adds the field key with f as a float32 to the logger context. func (c Context) Float32(key string, f float32) Context { - c.l.context = enc.AppendFloat32(enc.AppendKey(c.l.context, key), f) + c.l.context = enc.AppendFloat32(enc.AppendKey(c.l.context, key), f, FloatingPointPrecision) return c } // Floats32 adds the field key with f as a []float32 to the logger context. func (c Context) Floats32(key string, f []float32) Context { - c.l.context = enc.AppendFloats32(enc.AppendKey(c.l.context, key), f) + c.l.context = enc.AppendFloats32(enc.AppendKey(c.l.context, key), f, FloatingPointPrecision) return c } // Float64 adds the field key with f as a float64 to the logger context. func (c Context) Float64(key string, f float64) Context { - c.l.context = enc.AppendFloat64(enc.AppendKey(c.l.context, key), f) + c.l.context = enc.AppendFloat64(enc.AppendKey(c.l.context, key), f, FloatingPointPrecision) return c } // Floats64 adds the field key with f as a []float64 to the logger context. func (c Context) Floats64(key string, f []float64) Context { - c.l.context = enc.AppendFloats64(enc.AppendKey(c.l.context, key), f) + c.l.context = enc.AppendFloats64(enc.AppendKey(c.l.context, key), f, FloatingPointPrecision) return c } @@ -379,13 +379,13 @@ func (c Context) Times(key string, t []time.Time) Context { // Dur adds the fields key with d divided by unit and stored as a float. func (c Context) Dur(key string, d time.Duration) Context { - c.l.context = enc.AppendDuration(enc.AppendKey(c.l.context, key), d, DurationFieldUnit, DurationFieldInteger) + c.l.context = enc.AppendDuration(enc.AppendKey(c.l.context, key), d, DurationFieldUnit, DurationFieldInteger, FloatingPointPrecision) return c } // Durs adds the fields key with d divided by unit and stored as a float. func (c Context) Durs(key string, d []time.Duration) Context { - c.l.context = enc.AppendDurations(enc.AppendKey(c.l.context, key), d, DurationFieldUnit, DurationFieldInteger) + c.l.context = enc.AppendDurations(enc.AppendKey(c.l.context, key), d, DurationFieldUnit, DurationFieldInteger, FloatingPointPrecision) return c } diff --git a/encoder.go b/encoder.go index 09b24e80..4dbaf380 100644 --- a/encoder.go +++ b/encoder.go @@ -13,13 +13,13 @@ type encoder interface { AppendBool(dst []byte, val bool) []byte AppendBools(dst []byte, vals []bool) []byte AppendBytes(dst, s []byte) []byte - AppendDuration(dst []byte, d time.Duration, unit time.Duration, useInt bool) []byte - AppendDurations(dst []byte, vals []time.Duration, unit time.Duration, useInt bool) []byte + AppendDuration(dst []byte, d time.Duration, unit time.Duration, useInt bool, precision int) []byte + AppendDurations(dst []byte, vals []time.Duration, unit time.Duration, useInt bool, precision int) []byte AppendEndMarker(dst []byte) []byte - AppendFloat32(dst []byte, val float32) []byte - AppendFloat64(dst []byte, val float64) []byte - AppendFloats32(dst []byte, vals []float32) []byte - AppendFloats64(dst []byte, vals []float64) []byte + AppendFloat32(dst []byte, val float32, precision int) []byte + AppendFloat64(dst []byte, val float64, precision int) []byte + AppendFloats32(dst []byte, vals []float32, precision int) []byte + AppendFloats64(dst []byte, vals []float64, precision int) []byte AppendHex(dst, s []byte) []byte AppendIPAddr(dst []byte, ip net.IP) []byte AppendIPPrefix(dst []byte, pfx net.IPNet) []byte diff --git a/event.go b/event.go index 5c949f8a..56de6061 100644 --- a/event.go +++ b/event.go @@ -644,7 +644,7 @@ func (e *Event) Float32(key string, f float32) *Event { if e == nil { return e } - e.buf = enc.AppendFloat32(enc.AppendKey(e.buf, key), f) + e.buf = enc.AppendFloat32(enc.AppendKey(e.buf, key), f, FloatingPointPrecision) return e } @@ -653,7 +653,7 @@ func (e *Event) Floats32(key string, f []float32) *Event { if e == nil { return e } - e.buf = enc.AppendFloats32(enc.AppendKey(e.buf, key), f) + e.buf = enc.AppendFloats32(enc.AppendKey(e.buf, key), f, FloatingPointPrecision) return e } @@ -662,7 +662,7 @@ func (e *Event) Float64(key string, f float64) *Event { if e == nil { return e } - e.buf = enc.AppendFloat64(enc.AppendKey(e.buf, key), f) + e.buf = enc.AppendFloat64(enc.AppendKey(e.buf, key), f, FloatingPointPrecision) return e } @@ -671,7 +671,7 @@ func (e *Event) Floats64(key string, f []float64) *Event { if e == nil { return e } - e.buf = enc.AppendFloats64(enc.AppendKey(e.buf, key), f) + e.buf = enc.AppendFloats64(enc.AppendKey(e.buf, key), f, FloatingPointPrecision) return e } @@ -713,7 +713,7 @@ func (e *Event) Dur(key string, d time.Duration) *Event { if e == nil { return e } - e.buf = enc.AppendDuration(enc.AppendKey(e.buf, key), d, DurationFieldUnit, DurationFieldInteger) + e.buf = enc.AppendDuration(enc.AppendKey(e.buf, key), d, DurationFieldUnit, DurationFieldInteger, FloatingPointPrecision) return e } @@ -724,7 +724,7 @@ func (e *Event) Durs(key string, d []time.Duration) *Event { if e == nil { return e } - e.buf = enc.AppendDurations(enc.AppendKey(e.buf, key), d, DurationFieldUnit, DurationFieldInteger) + e.buf = enc.AppendDurations(enc.AppendKey(e.buf, key), d, DurationFieldUnit, DurationFieldInteger, FloatingPointPrecision) return e } @@ -739,7 +739,7 @@ func (e *Event) TimeDiff(key string, t time.Time, start time.Time) *Event { if t.After(start) { d = t.Sub(start) } - e.buf = enc.AppendDuration(enc.AppendKey(e.buf, key), d, DurationFieldUnit, DurationFieldInteger) + e.buf = enc.AppendDuration(enc.AppendKey(e.buf, key), d, DurationFieldUnit, DurationFieldInteger, FloatingPointPrecision) return e } diff --git a/fields.go b/fields.go index 23606ddd..99f52718 100644 --- a/fields.go +++ b/fields.go @@ -139,13 +139,13 @@ func appendFieldList(dst []byte, kvList []interface{}, stack bool) []byte { case uint64: dst = enc.AppendUint64(dst, val) case float32: - dst = enc.AppendFloat32(dst, val) + dst = enc.AppendFloat32(dst, val, FloatingPointPrecision) case float64: - dst = enc.AppendFloat64(dst, val) + dst = enc.AppendFloat64(dst, val, FloatingPointPrecision) case time.Time: dst = enc.AppendTime(dst, val, TimeFieldFormat) case time.Duration: - dst = enc.AppendDuration(dst, val, DurationFieldUnit, DurationFieldInteger) + dst = enc.AppendDuration(dst, val, DurationFieldUnit, DurationFieldInteger, FloatingPointPrecision) case *string: if val != nil { dst = enc.AppendString(dst, *val) @@ -220,13 +220,13 @@ func appendFieldList(dst []byte, kvList []interface{}, stack bool) []byte { } case *float32: if val != nil { - dst = enc.AppendFloat32(dst, *val) + dst = enc.AppendFloat32(dst, *val, FloatingPointPrecision) } else { dst = enc.AppendNil(dst) } case *float64: if val != nil { - dst = enc.AppendFloat64(dst, *val) + dst = enc.AppendFloat64(dst, *val, FloatingPointPrecision) } else { dst = enc.AppendNil(dst) } @@ -238,7 +238,7 @@ func appendFieldList(dst []byte, kvList []interface{}, stack bool) []byte { } case *time.Duration: if val != nil { - dst = enc.AppendDuration(dst, *val, DurationFieldUnit, DurationFieldInteger) + dst = enc.AppendDuration(dst, *val, DurationFieldUnit, DurationFieldInteger, FloatingPointPrecision) } else { dst = enc.AppendNil(dst) } @@ -267,13 +267,13 @@ func appendFieldList(dst []byte, kvList []interface{}, stack bool) []byte { case []uint64: dst = enc.AppendUints64(dst, val) case []float32: - dst = enc.AppendFloats32(dst, val) + dst = enc.AppendFloats32(dst, val, FloatingPointPrecision) case []float64: - dst = enc.AppendFloats64(dst, val) + dst = enc.AppendFloats64(dst, val, FloatingPointPrecision) case []time.Time: dst = enc.AppendTimes(dst, val, TimeFieldFormat) case []time.Duration: - dst = enc.AppendDurations(dst, val, DurationFieldUnit, DurationFieldInteger) + dst = enc.AppendDurations(dst, val, DurationFieldUnit, DurationFieldInteger, FloatingPointPrecision) case nil: dst = enc.AppendNil(dst) case net.IP: diff --git a/globals.go b/globals.go index aec83190..76221944 100644 --- a/globals.go +++ b/globals.go @@ -151,6 +151,11 @@ var ( // TriggerLevelWriterBufferReuseLimit is a limit in bytes that a buffer is dropped // from the TriggerLevelWriter buffer pool if the buffer grows above the limit. TriggerLevelWriterBufferReuseLimit = 64 * 1024 + + // FloatingPointPrecision, if set to a value other than -1, controls the number + // of digits when formatting float numbers in JSON. See strconv.FormatFloat for + // more details. + FloatingPointPrecision = -1 ) var ( diff --git a/internal/cbor/time.go b/internal/cbor/time.go index d81fb125..7c0eccee 100644 --- a/internal/cbor/time.go +++ b/internal/cbor/time.go @@ -29,7 +29,7 @@ func (e Encoder) appendFloatTimestamp(dst []byte, t time.Time) []byte { nanos := t.Nanosecond() var val float64 val = float64(secs)*1.0 + float64(nanos)*1e-9 - return e.AppendFloat64(dst, val) + return e.AppendFloat64(dst, val, -1) } // AppendTime encodes and adds a timestamp to the dst byte array. @@ -64,17 +64,17 @@ func (e Encoder) AppendTimes(dst []byte, vals []time.Time, unused string) []byte // AppendDuration encodes and adds a duration to the dst byte array. // useInt field indicates whether to store the duration as seconds (integer) or // as seconds+nanoseconds (float). -func (e Encoder) AppendDuration(dst []byte, d time.Duration, unit time.Duration, useInt bool) []byte { +func (e Encoder) AppendDuration(dst []byte, d time.Duration, unit time.Duration, useInt bool, unused int) []byte { if useInt { return e.AppendInt64(dst, int64(d/unit)) } - return e.AppendFloat64(dst, float64(d)/float64(unit)) + return e.AppendFloat64(dst, float64(d)/float64(unit), unused) } // AppendDurations encodes and adds an array of durations to the dst byte array. // useInt field indicates whether to store the duration as seconds (integer) or // as seconds+nanoseconds (float). -func (e Encoder) AppendDurations(dst []byte, vals []time.Duration, unit time.Duration, useInt bool) []byte { +func (e Encoder) AppendDurations(dst []byte, vals []time.Duration, unit time.Duration, useInt bool, unused int) []byte { major := majorTypeArray l := len(vals) if l == 0 { @@ -87,7 +87,7 @@ func (e Encoder) AppendDurations(dst []byte, vals []time.Duration, unit time.Dur dst = appendCborTypePrefix(dst, major, uint64(l)) } for _, d := range vals { - dst = e.AppendDuration(dst, d, unit, useInt) + dst = e.AppendDuration(dst, d, unit, useInt, unused) } return dst } diff --git a/internal/cbor/types.go b/internal/cbor/types.go index 6f538328..454d68bd 100644 --- a/internal/cbor/types.go +++ b/internal/cbor/types.go @@ -352,7 +352,7 @@ func (e Encoder) AppendUints64(dst []byte, vals []uint64) []byte { } // AppendFloat32 encodes and inserts a single precision float value into the dst byte array. -func (Encoder) AppendFloat32(dst []byte, val float32) []byte { +func (Encoder) AppendFloat32(dst []byte, val float32, unused int) []byte { switch { case math.IsNaN(float64(val)): return append(dst, "\xfa\x7f\xc0\x00\x00"...) @@ -372,7 +372,7 @@ func (Encoder) AppendFloat32(dst []byte, val float32) []byte { } // AppendFloats32 encodes and inserts an array of single precision float value into the dst byte array. -func (e Encoder) AppendFloats32(dst []byte, vals []float32) []byte { +func (e Encoder) AppendFloats32(dst []byte, vals []float32, unused int) []byte { major := majorTypeArray l := len(vals) if l == 0 { @@ -385,13 +385,13 @@ func (e Encoder) AppendFloats32(dst []byte, vals []float32) []byte { dst = appendCborTypePrefix(dst, major, uint64(l)) } for _, v := range vals { - dst = e.AppendFloat32(dst, v) + dst = e.AppendFloat32(dst, v, unused) } return dst } // AppendFloat64 encodes and inserts a double precision float value into the dst byte array. -func (Encoder) AppendFloat64(dst []byte, val float64) []byte { +func (Encoder) AppendFloat64(dst []byte, val float64, unused int) []byte { switch { case math.IsNaN(val): return append(dst, "\xfb\x7f\xf8\x00\x00\x00\x00\x00\x00"...) @@ -412,7 +412,7 @@ func (Encoder) AppendFloat64(dst []byte, val float64) []byte { } // AppendFloats64 encodes and inserts an array of double precision float values into the dst byte array. -func (e Encoder) AppendFloats64(dst []byte, vals []float64) []byte { +func (e Encoder) AppendFloats64(dst []byte, vals []float64, unused int) []byte { major := majorTypeArray l := len(vals) if l == 0 { @@ -425,7 +425,7 @@ func (e Encoder) AppendFloats64(dst []byte, vals []float64) []byte { dst = appendCborTypePrefix(dst, major, uint64(l)) } for _, v := range vals { - dst = e.AppendFloat64(dst, v) + dst = e.AppendFloat64(dst, v, unused) } return dst } diff --git a/internal/cbor/types_test.go b/internal/cbor/types_test.go index 2fbb162a..23093b12 100644 --- a/internal/cbor/types_test.go +++ b/internal/cbor/types_test.go @@ -169,7 +169,7 @@ var float32TestCases = []struct { func TestAppendFloat32(t *testing.T) { for _, tc := range float32TestCases { - s := enc.AppendFloat32([]byte{}, tc.val) + s := enc.AppendFloat32([]byte{}, tc.val, -1) got := string(s) if got != tc.binary { t.Errorf("AppendFloat32(%f)=0x%s, want: 0x%s", @@ -306,9 +306,9 @@ func BenchmarkAppendFloat(b *testing.B) { for i := 0; i < b.N; i++ { switch str.sz { case 4: - _ = enc.AppendFloat32(buf, float32(str.val)) + _ = enc.AppendFloat32(buf, float32(str.val), -1) case 8: - _ = enc.AppendFloat64(buf, str.val) + _ = enc.AppendFloat64(buf, str.val, -1) } } }) diff --git a/internal/json/time.go b/internal/json/time.go index 6a8dc912..08cbbd9b 100644 --- a/internal/json/time.go +++ b/internal/json/time.go @@ -88,24 +88,24 @@ func appendUnixNanoTimes(dst []byte, vals []time.Time, div int64) []byte { // AppendDuration formats the input duration with the given unit & format // and appends the encoded string to the input byte slice. -func (e Encoder) AppendDuration(dst []byte, d time.Duration, unit time.Duration, useInt bool) []byte { +func (e Encoder) AppendDuration(dst []byte, d time.Duration, unit time.Duration, useInt bool, precision int) []byte { if useInt { return strconv.AppendInt(dst, int64(d/unit), 10) } - return e.AppendFloat64(dst, float64(d)/float64(unit)) + return e.AppendFloat64(dst, float64(d)/float64(unit), precision) } // AppendDurations formats the input durations with the given unit & format // and appends the encoded string list to the input byte slice. -func (e Encoder) AppendDurations(dst []byte, vals []time.Duration, unit time.Duration, useInt bool) []byte { +func (e Encoder) AppendDurations(dst []byte, vals []time.Duration, unit time.Duration, useInt bool, precision int) []byte { if len(vals) == 0 { return append(dst, '[', ']') } dst = append(dst, '[') - dst = e.AppendDuration(dst, vals[0], unit, useInt) + dst = e.AppendDuration(dst, vals[0], unit, useInt, precision) if len(vals) > 1 { for _, d := range vals[1:] { - dst = e.AppendDuration(append(dst, ','), d, unit, useInt) + dst = e.AppendDuration(append(dst, ','), d, unit, useInt, precision) } } dst = append(dst, ']') diff --git a/internal/json/types.go b/internal/json/types.go index 43feaaa8..7930491a 100644 --- a/internal/json/types.go +++ b/internal/json/types.go @@ -299,7 +299,7 @@ func (Encoder) AppendUints64(dst []byte, vals []uint64) []byte { return dst } -func appendFloat(dst []byte, val float64, bitSize int) []byte { +func appendFloat(dst []byte, val float64, bitSize, precision int) []byte { // JSON does not permit NaN or Infinity. A typical JSON encoder would fail // with an error, but a logging library wants the data to get through so we // make a tradeoff and store those types as string. @@ -314,13 +314,16 @@ func appendFloat(dst []byte, val float64, bitSize int) []byte { // convert as if by es6 number to string conversion // see also https://cs.opensource.google/go/go/+/refs/tags/go1.20.3:src/encoding/json/encode.go;l=573 strFmt := byte('f') - // Use float32 comparisons for underlying float32 value to get precise cutoffs right. - if abs := math.Abs(val); abs != 0 { - if bitSize == 64 && (abs < 1e-6 || abs >= 1e21) || bitSize == 32 && (float32(abs) < 1e-6 || float32(abs) >= 1e21) { - strFmt = 'e' + // If precision is set to a value other than -1, we always just format the float using that precision. + if precision == -1 { + // Use float32 comparisons for underlying float32 value to get precise cutoffs right. + if abs := math.Abs(val); abs != 0 { + if bitSize == 64 && (abs < 1e-6 || abs >= 1e21) || bitSize == 32 && (float32(abs) < 1e-6 || float32(abs) >= 1e21) { + strFmt = 'e' + } } } - dst = strconv.AppendFloat(dst, val, strFmt, -1, bitSize) + dst = strconv.AppendFloat(dst, val, strFmt, precision, bitSize) if strFmt == 'e' { // Clean up e-09 to e-9 n := len(dst) @@ -334,21 +337,21 @@ func appendFloat(dst []byte, val float64, bitSize int) []byte { // AppendFloat32 converts the input float32 to a string and // appends the encoded string to the input byte slice. -func (Encoder) AppendFloat32(dst []byte, val float32) []byte { - return appendFloat(dst, float64(val), 32) +func (Encoder) AppendFloat32(dst []byte, val float32, precision int) []byte { + return appendFloat(dst, float64(val), 32, precision) } // AppendFloats32 encodes the input float32s to json and // appends the encoded string list to the input byte slice. -func (Encoder) AppendFloats32(dst []byte, vals []float32) []byte { +func (Encoder) AppendFloats32(dst []byte, vals []float32, precision int) []byte { if len(vals) == 0 { return append(dst, '[', ']') } dst = append(dst, '[') - dst = appendFloat(dst, float64(vals[0]), 32) + dst = appendFloat(dst, float64(vals[0]), 32, precision) if len(vals) > 1 { for _, val := range vals[1:] { - dst = appendFloat(append(dst, ','), float64(val), 32) + dst = appendFloat(append(dst, ','), float64(val), 32, precision) } } dst = append(dst, ']') @@ -357,21 +360,21 @@ func (Encoder) AppendFloats32(dst []byte, vals []float32) []byte { // AppendFloat64 converts the input float64 to a string and // appends the encoded string to the input byte slice. -func (Encoder) AppendFloat64(dst []byte, val float64) []byte { - return appendFloat(dst, val, 64) +func (Encoder) AppendFloat64(dst []byte, val float64, precision int) []byte { + return appendFloat(dst, val, 64, precision) } // AppendFloats64 encodes the input float64s to json and // appends the encoded string list to the input byte slice. -func (Encoder) AppendFloats64(dst []byte, vals []float64) []byte { +func (Encoder) AppendFloats64(dst []byte, vals []float64, precision int) []byte { if len(vals) == 0 { return append(dst, '[', ']') } dst = append(dst, '[') - dst = appendFloat(dst, vals[0], 64) + dst = appendFloat(dst, vals[0], 64, precision) if len(vals) > 1 { for _, val := range vals[1:] { - dst = appendFloat(append(dst, ','), val, 64) + dst = appendFloat(append(dst, ','), val, 64, precision) } } dst = append(dst, ']') diff --git a/internal/json/types_test.go b/internal/json/types_test.go index 350affef..217cd3a2 100644 --- a/internal/json/types_test.go +++ b/internal/json/types_test.go @@ -11,18 +11,20 @@ import ( func TestAppendType(t *testing.T) { w := map[string]func(interface{}) []byte{ - "AppendInt": func(v interface{}) []byte { return enc.AppendInt([]byte{}, v.(int)) }, - "AppendInt8": func(v interface{}) []byte { return enc.AppendInt8([]byte{}, v.(int8)) }, - "AppendInt16": func(v interface{}) []byte { return enc.AppendInt16([]byte{}, v.(int16)) }, - "AppendInt32": func(v interface{}) []byte { return enc.AppendInt32([]byte{}, v.(int32)) }, - "AppendInt64": func(v interface{}) []byte { return enc.AppendInt64([]byte{}, v.(int64)) }, - "AppendUint": func(v interface{}) []byte { return enc.AppendUint([]byte{}, v.(uint)) }, - "AppendUint8": func(v interface{}) []byte { return enc.AppendUint8([]byte{}, v.(uint8)) }, - "AppendUint16": func(v interface{}) []byte { return enc.AppendUint16([]byte{}, v.(uint16)) }, - "AppendUint32": func(v interface{}) []byte { return enc.AppendUint32([]byte{}, v.(uint32)) }, - "AppendUint64": func(v interface{}) []byte { return enc.AppendUint64([]byte{}, v.(uint64)) }, - "AppendFloat32": func(v interface{}) []byte { return enc.AppendFloat32([]byte{}, v.(float32)) }, - "AppendFloat64": func(v interface{}) []byte { return enc.AppendFloat64([]byte{}, v.(float64)) }, + "AppendInt": func(v interface{}) []byte { return enc.AppendInt([]byte{}, v.(int)) }, + "AppendInt8": func(v interface{}) []byte { return enc.AppendInt8([]byte{}, v.(int8)) }, + "AppendInt16": func(v interface{}) []byte { return enc.AppendInt16([]byte{}, v.(int16)) }, + "AppendInt32": func(v interface{}) []byte { return enc.AppendInt32([]byte{}, v.(int32)) }, + "AppendInt64": func(v interface{}) []byte { return enc.AppendInt64([]byte{}, v.(int64)) }, + "AppendUint": func(v interface{}) []byte { return enc.AppendUint([]byte{}, v.(uint)) }, + "AppendUint8": func(v interface{}) []byte { return enc.AppendUint8([]byte{}, v.(uint8)) }, + "AppendUint16": func(v interface{}) []byte { return enc.AppendUint16([]byte{}, v.(uint16)) }, + "AppendUint32": func(v interface{}) []byte { return enc.AppendUint32([]byte{}, v.(uint32)) }, + "AppendUint64": func(v interface{}) []byte { return enc.AppendUint64([]byte{}, v.(uint64)) }, + "AppendFloat32": func(v interface{}) []byte { return enc.AppendFloat32([]byte{}, v.(float32), -1) }, + "AppendFloat64": func(v interface{}) []byte { return enc.AppendFloat64([]byte{}, v.(float64), -1) }, + "AppendFloat32SmallPrecision": func(v interface{}) []byte { return enc.AppendFloat32([]byte{}, v.(float32), 1) }, + "AppendFloat64SmallPrecision": func(v interface{}) []byte { return enc.AppendFloat64([]byte{}, v.(float64), 1) }, } tests := []struct { name string @@ -55,6 +57,9 @@ func TestAppendType(t *testing.T) { {"AppendFloat64(-1.1)", "AppendFloat64", float64(-1.1), []byte(`-1.1`)}, {"AppendFloat64(1e20)", "AppendFloat64", float64(1e20), []byte(`100000000000000000000`)}, {"AppendFloat64(1e21)", "AppendFloat64", float64(1e21), []byte(`1e+21`)}, + + {"AppendFloat32SmallPrecision(-1.123)", "AppendFloat32SmallPrecision", float32(-1.123), []byte(`-1.1`)}, + {"AppendFloat64SmallPrecision(-1.123)", "AppendFloat64SmallPrecision", float64(-1.123), []byte(`-1.1`)}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -301,7 +306,7 @@ func TestEncoder_AppendFloat64(t *testing.T) { for _, tc := range float64Tests { t.Run(tc.Name, func(t *testing.T) { var b []byte - b = (Encoder{}).AppendFloat64(b, tc.Val) + b = (Encoder{}).AppendFloat64(b, tc.Val, -1) if s := string(b); tc.Want != s { t.Errorf("%q", s) } @@ -314,7 +319,7 @@ func FuzzEncoder_AppendFloat64(f *testing.F) { f.Add(tc.Val) } f.Fuzz(func(t *testing.T, val float64) { - actual := (Encoder{}).AppendFloat64(nil, val) + actual := (Encoder{}).AppendFloat64(nil, val, -1) if len(actual) == 0 { t.Fatal("empty buffer") } @@ -447,7 +452,7 @@ func TestEncoder_AppendFloat32(t *testing.T) { for _, tc := range float32Tests { t.Run(tc.Name, func(t *testing.T) { var b []byte - b = (Encoder{}).AppendFloat32(b, tc.Val) + b = (Encoder{}).AppendFloat32(b, tc.Val, -1) if s := string(b); tc.Want != s { t.Errorf("%q", s) } @@ -460,7 +465,7 @@ func FuzzEncoder_AppendFloat32(f *testing.F) { f.Add(tc.Val) } f.Fuzz(func(t *testing.T, val float32) { - actual := (Encoder{}).AppendFloat32(nil, val) + actual := (Encoder{}).AppendFloat32(nil, val, -1) if len(actual) == 0 { t.Fatal("empty buffer") } @@ -528,7 +533,7 @@ func BenchmarkEncoder_AppendFloat32(b *testing.B) { for i := 0; i < b.N; i++ { for _, f := range floats { - dst = (Encoder{}).AppendFloat32(dst[:0], f) + dst = (Encoder{}).AppendFloat32(dst[:0], f, -1) } } } @@ -542,7 +547,7 @@ func BenchmarkEncoder_AppendFloat64(b *testing.B) { for i := 0; i < b.N; i++ { for _, f := range floats { - dst = (Encoder{}).AppendFloat64(dst[:0], f) + dst = (Encoder{}).AppendFloat64(dst[:0], f, -1) } } }