Skip to content
6 changes: 3 additions & 3 deletions benchmarks/decoder/decoder_bench_large_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"github.com/mailru/easyjson"
)

func BenchmarkJsonParserDecodeObjLarge(b *testing.B) {
func BenchmarkJSONParserDecodeObjLarge(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
jsonparser.ArrayEach(benchmarks.LargeFixture, func(value []byte, dataType jsonparser.ValueType, offset int, err error) {
Expand All @@ -26,15 +26,15 @@ func BenchmarkJsonParserDecodeObjLarge(b *testing.B) {
}
}

func BenchmarkJsonIterDecodeObjLarge(b *testing.B) {
func BenchmarkJSONIterDecodeObjLarge(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
result := benchmarks.LargePayload{}
jsoniter.Unmarshal(benchmarks.LargeFixture, &result)
}
}

func BenchmarkEasyJsonDecodeObjLarge(b *testing.B) {
func BenchmarkEasyJSONDecodeObjLarge(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
result := benchmarks.LargePayload{}
Expand Down
6 changes: 3 additions & 3 deletions benchmarks/decoder/decoder_bench_medium_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
"github.com/mailru/easyjson"
)

func BenchmarkJsonIterDecodeObjMedium(b *testing.B) {
func BenchmarkJSONIterDecodeObjMedium(b *testing.B) {
b.ReportAllocs()
for n := 0; n < b.N; n++ {
result := benchmarks.MediumPayload{}
Expand All @@ -36,14 +36,14 @@ func BenchmarkJSONParserDecodeObjMedium(b *testing.B) {
}
}

func BenchmarkEncodingJsonStructMedium(b *testing.B) {
func BenchmarkEncodingJSONDecodeObjMedium(b *testing.B) {
for i := 0; i < b.N; i++ {
var data = benchmarks.MediumPayload{}
json.Unmarshal(benchmarks.MediumFixture, &data)
}
}

func BenchmarkEasyJsonDecodeObjMedium(b *testing.B) {
func BenchmarkEasyJSONDecodeObjMedium(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
result := benchmarks.MediumPayload{}
Expand Down
6 changes: 3 additions & 3 deletions benchmarks/decoder/decoder_bench_small_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
"github.com/mailru/easyjson"
)

func BenchmarkJSONDecodeObjSmall(b *testing.B) {
func BenchmarkEncodingJSONDecodeObjSmall(b *testing.B) {
b.ReportAllocs()
for n := 0; n < b.N; n++ {
result := benchmarks.SmallPayload{}
Expand All @@ -36,15 +36,15 @@ func BenchmarkJSONParserSmall(b *testing.B) {
}
}

func BenchmarkJsonIterDecodeObjSmall(b *testing.B) {
func BenchmarkJSONIterDecodeObjSmall(b *testing.B) {
b.ReportAllocs()
for n := 0; n < b.N; n++ {
result := benchmarks.SmallPayload{}
jsoniter.Unmarshal(benchmarks.SmallFixture, &result)
}
}

func BenchmarkEasyJsonDecodeObjSmall(b *testing.B) {
func BenchmarkEasyJSONDecodeObjSmall(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
result := benchmarks.SmallPayload{}
Expand Down
36 changes: 27 additions & 9 deletions decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,22 @@ import (
// overflows the target type, UnmarshalJSONArray skips that field and completes the unmarshaling as best it can.
func UnmarshalJSONArray(data []byte, v UnmarshalerJSONArray) error {
dec := borrowDecoder(nil, 0)

defer dec.Release()

dec.data = make([]byte, len(data))
copy(dec.data, data)
dec.length = len(data)

_, err := dec.decodeArray(v)
if err != nil {
return err
}

if dec.err != nil {
return dec.err
}

return nil
}

Expand All @@ -35,14 +40,18 @@ func UnmarshalJSONArray(data []byte, v UnmarshalerJSONArray) error {
// overflows the target type, UnmarshalJSONObject skips that field and completes the unmarshaling as best it can.
func UnmarshalJSONObject(data []byte, v UnmarshalerJSONObject) error {
dec := borrowDecoder(nil, 0)

defer dec.Release()

dec.data = make([]byte, len(data))
copy(dec.data, data)
dec.length = len(data)

_, err := dec.decodeObject(v)
if err != nil {
return err
}

if dec.err != nil {
return dec.err
}
Expand Down Expand Up @@ -215,11 +224,14 @@ func Unmarshal(data []byte, v interface{}) error {
default:
return InvalidUnmarshalError(fmt.Sprintf(invalidUnmarshalErrorMsg, vt))
}
defer dec.Release()
if err != nil {
return err

if err == nil {
err = dec.err
}
return dec.err

dec.Release()

return err
}

// UnmarshalerJSONObject is the interface to implement to decode a JSON Object.
Expand Down Expand Up @@ -257,7 +269,9 @@ func (dec *Decoder) Decode(v interface{}) error {
if dec.isPooled == 1 {
panic(InvalidUsagePooledDecoderError("Invalid usage of pooled decoder"))
}

var err error

switch vt := v.(type) {
case *string:
err = dec.decodeString(vt)
Expand Down Expand Up @@ -312,20 +326,24 @@ func (dec *Decoder) Decode(v interface{}) error {
case **bool:
err = dec.decodeBoolNull(vt)
case UnmarshalerJSONObject:
_, err = dec.decodeObject(vt)
dec.cursor, err = dec.decodeObject(vt)
case UnmarshalerJSONArray:
_, err = dec.decodeArray(vt)
dec.cursor, err = dec.decodeArray(vt)
case *EmbeddedJSON:
err = dec.decodeEmbeddedJSON(vt)
case *interface{}:
err = dec.decodeInterface(vt)
default:
return InvalidUnmarshalError(fmt.Sprintf(invalidUnmarshalErrorMsg, vt))
}
if err != nil {
return err

if err == nil {
err = dec.err
}
return dec.err

dec.reset()

return err
}

// Non exported
Expand Down
7 changes: 6 additions & 1 deletion decode_array.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@ func (dec *Decoder) DecodeArray(v UnmarshalerJSONArray) error {
if dec.isPooled == 1 {
panic(InvalidUsagePooledDecoderError("Invalid usage of pooled decoder"))
}
_, err := dec.decodeArray(v)

var err error
dec.cursor, err = dec.decodeArray(v)

dec.reset()

return err
}
func (dec *Decoder) decodeArray(arr UnmarshalerJSONArray) (int, error) {
Expand Down
6 changes: 5 additions & 1 deletion decode_bool.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ func (dec *Decoder) DecodeBool(v *bool) error {
if dec.isPooled == 1 {
panic(InvalidUsagePooledDecoderError("Invalid usage of pooled decoder"))
}
return dec.decodeBool(v)

err := dec.decodeBool(v)
dec.reset()

return err
}
func (dec *Decoder) decodeBool(v *bool) error {
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
Expand Down
1 change: 1 addition & 0 deletions decode_bool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,7 @@ func TestDecoderBoolDecoderAPI(t *testing.T) {
func TestDecoderBoolPoolError(t *testing.T) {
v := true
dec := NewDecoder(nil)
dec.reset()
dec.Release()
defer func() {
err := recover()
Expand Down
24 changes: 24 additions & 0 deletions decode_embedded_json_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

type Request struct {
Expand Down Expand Up @@ -178,3 +179,26 @@ func TestDecodeEmbeededJSONNil2(t *testing.T) {
assert.NotNil(t, err, `err should not be nil a nil pointer is given`)
assert.IsType(t, InvalidUnmarshalError(""), err, `err should not be of type InvalidUnmarshalError`)
}

func TestDecoderReuse(t *testing.T) {
r := strings.NewReader(`{"foo":"bar"}{"foo":"baz"}{"foo":"world"}`)

dec := NewDecoder(r)
var ej EmbeddedJSON

dec.Decode(&ej)

require.Equal(t, `{"foo":"bar"}`, string(ej))

ej = ej[:0]

dec.Decode(&ej)

assert.Equal(t, `{"foo":"baz"}`, string(ej))

ej = ej[:0]

dec.Decode(&ej)

assert.Equal(t, `{"foo":"world"}`, string(ej))
}
3 changes: 3 additions & 0 deletions decode_interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ func (dec *Decoder) DecodeInterface(i *interface{}) error {
if dec.isPooled == 1 {
panic(InvalidUsagePooledDecoderError("Invalid usage of pooled decoder"))
}

err := dec.decodeInterface(i)
dec.reset()

return err
}

Expand Down
1 change: 1 addition & 0 deletions decode_interface_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,7 @@ func TestUnmarshalInterfaceError(t *testing.T) {
func TestDecodeInterfacePoolError(t *testing.T) {
result := interface{}(1)
dec := NewDecoder(nil)
dec.reset()
dec.Release()
defer func() {
err := recover()
Expand Down
12 changes: 10 additions & 2 deletions decode_number_float.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ func (dec *Decoder) DecodeFloat64(v *float64) error {
if dec.isPooled == 1 {
panic(InvalidUsagePooledDecoderError("Invalid usage of pooled decoder"))
}
return dec.decodeFloat64(v)

err := dec.decodeFloat64(v)
dec.reset()

return err
}
func (dec *Decoder) decodeFloat64(v *float64) error {
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
Expand Down Expand Up @@ -215,7 +219,11 @@ func (dec *Decoder) DecodeFloat32(v *float32) error {
if dec.isPooled == 1 {
panic(InvalidUsagePooledDecoderError("Invalid usage of pooled decoder"))
}
return dec.decodeFloat32(v)

err := dec.decodeFloat32(v)
dec.reset()

return err
}
func (dec *Decoder) decodeFloat32(v *float32) error {
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
Expand Down
2 changes: 2 additions & 0 deletions decode_number_float_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ func TestDecoderFloat64(t *testing.T) {
t.Run("pool-error", func(t *testing.T) {
result := float64(1)
dec := NewDecoder(nil)
dec.reset()
dec.Release()
defer func() {
err := recover()
Expand Down Expand Up @@ -931,6 +932,7 @@ func TestDecoderFloat32(t *testing.T) {
t.Run("pool-error", func(t *testing.T) {
result := float32(1)
dec := NewDecoder(nil)
dec.reset()
dec.Release()
defer func() {
err := recover()
Expand Down
30 changes: 25 additions & 5 deletions decode_number_int.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ func (dec *Decoder) DecodeInt(v *int) error {
if dec.isPooled == 1 {
panic(InvalidUsagePooledDecoderError("Invalid usage of pooled decoder"))
}
return dec.decodeInt(v)

err := dec.decodeInt(v)
dec.reset()

return err
}
func (dec *Decoder) decodeInt(v *int) error {
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
Expand Down Expand Up @@ -119,7 +123,11 @@ func (dec *Decoder) DecodeInt16(v *int16) error {
if dec.isPooled == 1 {
panic(InvalidUsagePooledDecoderError("Invalid usage of pooled decoder"))
}
return dec.decodeInt16(v)

err := dec.decodeInt16(v)
dec.reset()

return err
}
func (dec *Decoder) decodeInt16(v *int16) error {
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
Expand Down Expand Up @@ -351,7 +359,11 @@ func (dec *Decoder) DecodeInt8(v *int8) error {
if dec.isPooled == 1 {
panic(InvalidUsagePooledDecoderError("Invalid usage of pooled decoder"))
}
return dec.decodeInt8(v)

err := dec.decodeInt8(v)
dec.reset()

return err
}
func (dec *Decoder) decodeInt8(v *int8) error {
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
Expand Down Expand Up @@ -582,7 +594,11 @@ func (dec *Decoder) DecodeInt32(v *int32) error {
if dec.isPooled == 1 {
panic(InvalidUsagePooledDecoderError("Invalid usage of pooled decoder"))
}
return dec.decodeInt32(v)

err := dec.decodeInt32(v)
dec.reset()

return err
}
func (dec *Decoder) decodeInt32(v *int32) error {
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
Expand Down Expand Up @@ -812,7 +828,11 @@ func (dec *Decoder) DecodeInt64(v *int64) error {
if dec.isPooled == 1 {
panic(InvalidUsagePooledDecoderError("Invalid usage of pooled decoder"))
}
return dec.decodeInt64(v)

err := dec.decodeInt64(v)
dec.reset()

return err
}

func (dec *Decoder) decodeInt64(v *int64) error {
Expand Down
Loading