diff --git a/any_test.go b/any_test.go index 52fc9d4..3cd4f55 100644 --- a/any_test.go +++ b/any_test.go @@ -1,7 +1,6 @@ package jx import ( - "bytes" hexEnc "encoding/hex" "encoding/json" "fmt" @@ -132,7 +131,7 @@ func (v *Any) Read(d *Decoder) error { v.Type = AnyBool case Object: v.Type = AnyObj - if err := d.Object(func(r *Decoder, s string) error { + if err := d.Obj(func(r *Decoder, s string) error { var elem Any if err := elem.Read(r); err != nil { return xerrors.Errorf("elem: %w", err) @@ -147,7 +146,7 @@ func (v *Any) Read(d *Decoder) error { return nil case Array: v.Type = AnyArr - if err := d.Array(func(r *Decoder) error { + if err := d.Arr(func(r *Decoder) error { var elem Any if err := elem.Read(r); err != nil { return xerrors.Errorf("elem: %w", err) @@ -171,7 +170,7 @@ func (v Any) Write(w *Encoder) error { } switch v.Type { case AnyStr: - w.String(v.Str) + w.Str(v.Str) case AnyFloat: if err := w.Float64(v.Float); err != nil { return err @@ -256,18 +255,16 @@ func (v Any) String() string { } func TestAny_Read(t *testing.T) { - t.Run("Object", func(t *testing.T) { + t.Run("Obj", func(t *testing.T) { var v Any const input = `{"foo":{"bar":1,"baz":[1,2,3.14],"200":null}}` - r := DecodeString(input) + r := DecodeStr(input) assert.NoError(t, v.Read(r)) assert.Equal(t, `{foo: {bar: 1, baz: [1, 2, f3.14], 200: null}}`, v.String()) - buf := new(bytes.Buffer) - w := NewEncoder(buf, 1024) - require.NoError(t, w.Any(v)) - require.NoError(t, w.Flush()) - require.Equal(t, input, buf.String(), "encoded value should equal to input") + e := NewEncoder() + require.NoError(t, e.Any(v)) + require.Equal(t, input, e.String(), "encoded value should equal to input") }) t.Run("Inputs", func(t *testing.T) { for _, tt := range []struct { @@ -282,19 +279,17 @@ func TestAny_Read(t *testing.T) { r := DecodeBytes(input) require.NoError(t, v.Read(r)) - buf := new(bytes.Buffer) - s := NewEncoder(buf, 1024) - require.NoError(t, v.Write(s)) - require.NoError(t, s.Flush()) - require.Equal(t, tt.Input, buf.String(), "encoded value should equal to input") + e := NewEncoder() + require.NoError(t, v.Write(e)) + require.Equal(t, tt.Input, e.String(), "encoded value should equal to input") var otherValue Any - r.ResetBytes(buf.Bytes()) + r.ResetBytes(e.Bytes()) if err := otherValue.Read(r); err != nil { t.Error(err) t.Log(hexEnc.Dump(input)) - t.Log(hexEnc.Dump(buf.Bytes())) + t.Log(hexEnc.Dump(e.Bytes())) } }) } diff --git a/bench_test.go b/bench_test.go index 9c8586a..9314956 100644 --- a/bench_test.go +++ b/bench_test.go @@ -19,7 +19,7 @@ func Benchmark_large_file(b *testing.B) { for n := 0; n < b.N; n++ { iter.ResetBytes(data) - if err := iter.Array(func(iter *Decoder) error { + if err := iter.Arr(func(iter *Decoder) error { return iter.Skip() }); err != nil { b.Fatal(err) diff --git a/bool_test.go b/bool_test.go index 908c7b2..37247f9 100644 --- a/bool_test.go +++ b/bool_test.go @@ -1,7 +1,6 @@ package jx import ( - "bytes" "testing" "github.com/stretchr/testify/require" @@ -9,23 +8,21 @@ import ( func Test_true(t *testing.T) { should := require.New(t) - iter := DecodeString(`true`) + iter := DecodeStr(`true`) should.True(iter.Bool()) } func Test_false(t *testing.T) { should := require.New(t) - iter := DecodeString(`false`) + iter := DecodeStr(`false`) should.False(iter.Bool()) } func Test_write_true_false(t *testing.T) { should := require.New(t) - buf := &bytes.Buffer{} - w := NewEncoder(buf, 4096) + w := NewEncoder() w.True() w.False() w.Bool(false) - should.NoError(w.Flush()) - should.Equal("truefalsefalse", buf.String()) + should.Equal("truefalsefalse", string(w.Bytes())) } diff --git a/dec.go b/dec.go index b57213b..f246fc8 100644 --- a/dec.go +++ b/dec.go @@ -127,8 +127,8 @@ func DecodeBytes(input []byte) *Decoder { } } -// DecodeString creates a Decoder that reads string as json. -func DecodeString(input string) *Decoder { +// DecodeStr creates a Decoder that reads string as json. +func DecodeStr(input string) *Decoder { return DecodeBytes([]byte(input)) } @@ -222,7 +222,7 @@ func (d *Decoder) unread() { d.head-- } // limit maximum depth of nesting, as allowed by https://tools.ietf.org/html/rfc7159#section-9 const maxDepth = 10000 -func (d *Decoder) incrementDepth() error { +func (d *Decoder) incDepth() error { d.depth++ if d.depth > maxDepth { return xerrors.New("max depth") @@ -230,7 +230,7 @@ func (d *Decoder) incrementDepth() error { return nil } -func (d *Decoder) decrementDepth() error { +func (d *Decoder) decDepth() error { d.depth-- if d.depth < 0 { return xerrors.New("negative depth") diff --git a/dec_arr.go b/dec_arr.go index 9bd8268..b2849a8 100644 --- a/dec_arr.go +++ b/dec_arr.go @@ -33,12 +33,12 @@ func (d *Decoder) Elem() (ok bool, err error) { } } -// Array reads array and calls f on each array element. -func (d *Decoder) Array(f func(d *Decoder) error) error { +// Arr reads array and calls f on each array element. +func (d *Decoder) Arr(f func(d *Decoder) error) error { if err := d.expectNext('['); err != nil { return xerrors.Errorf("start: %w", err) } - if err := d.incrementDepth(); err != nil { + if err := d.incDepth(); err != nil { return xerrors.Errorf("inc: %w", err) } c, err := d.next() @@ -49,7 +49,7 @@ func (d *Decoder) Array(f func(d *Decoder) error) error { return err } if c == ']' { - return d.decrementDepth() + return d.decDepth() } d.unread() if err := f(d); err != nil { @@ -74,5 +74,5 @@ func (d *Decoder) Array(f func(d *Decoder) error) error { if c != ']' { return xerrors.Errorf("end: %w", badToken(c)) } - return d.decrementDepth() + return d.decDepth() } diff --git a/dec_capture_test.go b/dec_capture_test.go index 04891f6..cfd1b65 100644 --- a/dec_capture_test.go +++ b/dec_capture_test.go @@ -22,12 +22,12 @@ func TestIterator_Capture(t *testing.T) { }` i := GetDecoder() i.ResetBytes([]byte(input)) - err := i.Object(func(i *Decoder, key string) error { - return i.Array(func(i *Decoder) error { + err := i.Obj(func(i *Decoder, key string) error { + return i.Arr(func(i *Decoder) error { // Reading "type" field value first. var typ string if err := i.Capture(func(i *Decoder) error { - return i.Object(func(i *Decoder, key string) error { + return i.Obj(func(i *Decoder, key string) error { switch key { case "type": s, err := i.String() @@ -44,7 +44,7 @@ func TestIterator_Capture(t *testing.T) { return err } // Reading objects depending on type. - return i.Object(func(i *Decoder, key string) error { + return i.Obj(func(i *Decoder, key string) error { if key == "type" { s, err := i.String() if err != nil { @@ -83,10 +83,10 @@ func BenchmarkIterator_Skip(b *testing.B) { } func TestDecoder_Capture(t *testing.T) { - i := DecodeString(`["foo", "bar", "baz"]`) + i := DecodeStr(`["foo", "bar", "baz"]`) var elems int if err := i.Capture(func(i *Decoder) error { - return i.Array(func(i *Decoder) error { + return i.Arr(func(i *Decoder) error { elems++ return i.Skip() }) diff --git a/dec_obj.go b/dec_obj.go index c400c2a..33e83ff 100644 --- a/dec_obj.go +++ b/dec_obj.go @@ -6,14 +6,14 @@ import ( "golang.org/x/xerrors" ) -// ObjectBytes calls f for every key in object, using byte slice as key. +// ObjBytes calls f for every key in object, using byte slice as key. // // The key value is valid only until f is not returned. -func (d *Decoder) ObjectBytes(f func(d *Decoder, key []byte) error) error { +func (d *Decoder) ObjBytes(f func(d *Decoder, key []byte) error) error { if err := d.expectNext('{'); err != nil { return xerrors.Errorf("start: %w", err) } - if err := d.incrementDepth(); err != nil { + if err := d.incDepth(); err != nil { return xerrors.Errorf("inc: %w", err) } c, err := d.next() @@ -21,7 +21,7 @@ func (d *Decoder) ObjectBytes(f func(d *Decoder, key []byte) error) error { return xerrors.Errorf("next: %w", err) } if c == '}' { - return d.decrementDepth() + return d.decDepth() } d.unread() @@ -61,14 +61,14 @@ func (d *Decoder) ObjectBytes(f func(d *Decoder, key []byte) error) error { if c != '}' { return xerrors.Errorf("end: %w", badToken(c)) } - return d.decrementDepth() + return d.decDepth() } -// Object reads json object, calling f on each field. +// Obj reads json object, calling f on each field. // -// Use ObjectBytes to reduce heap allocations for keys. -func (d *Decoder) Object(f func(d *Decoder, key string) error) error { - return d.ObjectBytes(func(d *Decoder, key []byte) error { +// Use ObjBytes to reduce heap allocations for keys. +func (d *Decoder) Obj(f func(d *Decoder, key string) error) error { + return d.ObjBytes(func(d *Decoder, key []byte) error { return f(d, string(key)) }) } diff --git a/dec_obj_test.go b/dec_obj_test.go index 7195267..57d93ec 100644 --- a/dec_obj_test.go +++ b/dec_obj_test.go @@ -8,9 +8,9 @@ import ( ) func TestDecoder_ObjectBytes(t *testing.T) { - i := DecodeString(`{"id":1,"randomNumber":10}`) + i := DecodeStr(`{"id":1,"randomNumber":10}`) met := map[string]struct{}{} - require.NoError(t, i.ObjectBytes(func(i *Decoder, key []byte) error { + require.NoError(t, i.ObjBytes(func(i *Decoder, key []byte) error { switch string(key) { case "id": v, err := i.Int64() diff --git a/dec_skip.go b/dec_skip.go index dec77af..16494c1 100644 --- a/dec_skip.go +++ b/dec_skip.go @@ -175,14 +175,14 @@ func (d *Decoder) strFastSkip() (ok bool, err error) { func (d *Decoder) skipObject() error { d.unread() - return d.ObjectBytes(func(iter *Decoder, _ []byte) error { + return d.ObjBytes(func(iter *Decoder, _ []byte) error { return iter.Skip() }) } func (d *Decoder) skipArray() error { d.unread() - return d.Array(func(iter *Decoder) error { + return d.Arr(func(iter *Decoder) error { return iter.Skip() }) } diff --git a/dec_skip_bench_test.go b/dec_skip_bench_test.go index 55c2052..b6a4782 100644 --- a/dec_skip_bench_test.go +++ b/dec_skip_bench_test.go @@ -37,7 +37,7 @@ func Benchmark_skip(b *testing.B) { for n := 0; n < b.N; n++ { result := TestResp{} iter := DecodeBytes(input) - if err := iter.ObjectBytes(func(i *Decoder, key []byte) error { + if err := iter.ObjBytes(func(i *Decoder, key []byte) error { switch string(key) { case "code": v, err := iter.Uint64() diff --git a/dec_skip_cases_test.go b/dec_skip_cases_test.go index e86ca84..988a8f5 100644 --- a/dec_skip_cases_test.go +++ b/dec_skip_cases_test.go @@ -78,7 +78,7 @@ func Test_skip(t *testing.T) { should := require.New(t) ptrVal := reflect.New(valType) stdErr := json.Unmarshal([]byte(input), ptrVal.Interface()) - iter := DecodeString(input) + iter := DecodeStr(input) if stdErr == nil { should.NoError(iter.Skip()) should.ErrorIs(iter.Null(), io.ErrUnexpectedEOF) diff --git a/dec_skip_test.go b/dec_skip_test.go index 8378a7c..2b93544 100644 --- a/dec_skip_test.go +++ b/dec_skip_test.go @@ -7,7 +7,7 @@ import ( ) func Test_skip_number_in_array(t *testing.T) { - iter := DecodeString(`[-0.12, "stream"]`) + iter := DecodeStr(`[-0.12, "stream"]`) iter.Elem() iter.Skip() iter.Elem() @@ -17,7 +17,7 @@ func Test_skip_number_in_array(t *testing.T) { } func Test_skip_string_in_array(t *testing.T) { - iter := DecodeString(`["hello", "stream"]`) + iter := DecodeStr(`["hello", "stream"]`) iter.Elem() iter.Skip() iter.Elem() @@ -27,7 +27,7 @@ func Test_skip_string_in_array(t *testing.T) { } func Test_skip_null(t *testing.T) { - iter := DecodeString(`[null , "stream"]`) + iter := DecodeStr(`[null , "stream"]`) iter.Elem() iter.Skip() iter.Elem() @@ -37,7 +37,7 @@ func Test_skip_null(t *testing.T) { } func Test_skip_true(t *testing.T) { - iter := DecodeString(`[true , "stream"]`) + iter := DecodeStr(`[true , "stream"]`) iter.Elem() iter.Skip() iter.Elem() @@ -47,7 +47,7 @@ func Test_skip_true(t *testing.T) { } func Test_skip_false(t *testing.T) { - iter := DecodeString(`[false , "stream"]`) + iter := DecodeStr(`[false , "stream"]`) iter.Elem() iter.Skip() iter.Elem() @@ -57,7 +57,7 @@ func Test_skip_false(t *testing.T) { } func Test_skip_array(t *testing.T) { - iter := DecodeString(`[[1, [2, [3], 4]], "stream"]`) + iter := DecodeStr(`[[1, [2, [3], 4]], "stream"]`) iter.Elem() iter.Skip() iter.Elem() @@ -67,7 +67,7 @@ func Test_skip_array(t *testing.T) { } func Test_skip_empty_array(t *testing.T) { - iter := DecodeString(`[ [ ], "stream"]`) + iter := DecodeStr(`[ [ ], "stream"]`) iter.Elem() iter.Skip() iter.Elem() @@ -77,7 +77,7 @@ func Test_skip_empty_array(t *testing.T) { } func Test_skip_nested(t *testing.T) { - iter := DecodeString(`[ {"a" : [{"stream": "c"}], "d": 102 }, "stream"]`) + iter := DecodeStr(`[ {"a" : [{"stream": "c"}], "d": 102 }, "stream"]`) if _, err := iter.Elem(); err != nil { t.Fatal(err) } @@ -91,6 +91,6 @@ func Test_skip_nested(t *testing.T) { } func Test_skip_simple_nested(t *testing.T) { - iter := DecodeString(`["foo", "bar", "baz"]`) + iter := DecodeStr(`["foo", "bar", "baz"]`) require.NoError(t, iter.Skip()) } diff --git a/enc.go b/enc.go index 22c1bcf..f2d5499 100644 --- a/enc.go +++ b/enc.go @@ -4,41 +4,48 @@ import ( "io" ) -// Encoder encodes json to internal buffer and flushes to io.Writer if set. -// -// Call Flush to write buffer to io.Writer. +// Encoder encodes json to underlying buffer. type Encoder struct { - out io.Writer - buf []byte - + buf []byte ident int curIdent int } +// WriteTo implements io.WriterTo. +func (e *Encoder) WriteTo(w io.Writer) (n int64, err error) { + wrote, err := w.Write(e.buf) + return int64(wrote), err +} + // SetIdent sets length of single indentation step. func (e *Encoder) SetIdent(n int) { e.ident = n } -// NewEncoder create new encoder instance. -func NewEncoder(out io.Writer, bufSize int) *Encoder { +// String returns string of underlying buffer. +func (e *Encoder) String() string { + return string(e.Bytes()) +} + +// NewEncoder creates new encoder. +func NewEncoder() *Encoder { + const defaultBuf = 256 + return &Encoder{ - out: out, - buf: make([]byte, 0, bufSize), + buf: make([]byte, 0, defaultBuf), } } -// Reset reuse this stream instance by assign a new writer -func (e *Encoder) Reset(out io.Writer) { - e.out = out +// Reset resets underlying buffer. +func (e *Encoder) Reset() { e.buf = e.buf[:0] } // Bytes returns underlying buffer. func (e *Encoder) Bytes() []byte { return e.buf } -// SetBuf allows to set the internal buffer directly. -func (e *Encoder) SetBuf(buf []byte) { e.buf = buf } +// SetBytes sets underlying buffer. +func (e *Encoder) SetBytes(buf []byte) { e.buf = buf } // byte writes a single byte. func (e *Encoder) byte(c byte) { @@ -61,24 +68,12 @@ func (e *Encoder) fiveBytes(c1, c2, c3, c4, c5 byte) { e.buf = append(e.buf, c1, c2, c3, c4, c5) } -// Flush writes any buffered data to the underlying io.Writer. -func (e *Encoder) Flush() error { - if e.out == nil { - return nil - } - if _, err := e.out.Write(e.buf); err != nil { - return err - } - e.buf = e.buf[:0] - return nil -} - -// Raw writes raw json. +// Raw writes string as raw json. func (e *Encoder) Raw(v string) { e.buf = append(e.buf, v...) } -// RawBytes writes raw json. +// RawBytes writes byte slice as raw json. func (e *Encoder) RawBytes(b []byte) { e.buf = append(e.buf, b...) } @@ -116,7 +111,7 @@ func (e *Encoder) ObjStart() { // ObjField write "field": with possible indention. func (e *Encoder) ObjField(field string) { - e.String(field) + e.Str(field) if e.curIdent > 0 { e.twoBytes(':', ' ') } else { diff --git a/enc_bench_test.go b/enc_bench_test.go index 8a0eb3d..4ee4f44 100644 --- a/enc_bench_test.go +++ b/enc_bench_test.go @@ -1,18 +1,17 @@ package jx import ( - "bytes" "strconv" "testing" ) func Benchmark_stream_encode_big_object(b *testing.B) { - var buf bytes.Buffer - var stream = NewEncoder(&buf, 100) + b.ReportAllocs() + + e := GetEncoder() for i := 0; i < b.N; i++ { - buf.Reset() - stream.Reset(&buf) - if err := encodeObject(stream); err != nil { + e.Reset() + if err := encodeObject(e); err != nil { b.Fatal(err) } } @@ -26,7 +25,7 @@ func encodeObject(w *Encoder) error { w.More() w.ObjField("name") - w.String("Jane Doe") + w.Str("Jane Doe") w.More() w.ObjField("address") @@ -36,7 +35,7 @@ func encodeObject(w *Encoder) error { w.More() } w.ObjField(field.key) - w.String(field.val) + w.Str(field.val) } w.More() @@ -63,7 +62,7 @@ func encodeObject(w *Encoder) error { if i != 0 { w.More() } - w.String(s) + w.Str(s) } w.ArrEnd() @@ -73,7 +72,7 @@ func encodeObject(w *Encoder) error { w.More() } w.ObjField("longText" + strconv.Itoa(i)) - w.String(text) + w.Str(text) } for i := 0; i < 25; i++ { diff --git a/enc_str.go b/enc_str.go index 8635763..16ebec1 100644 --- a/enc_str.go +++ b/enc_str.go @@ -217,8 +217,8 @@ var safeSet = [utf8.RuneSelf]bool{ const hex = "0123456789abcdef" -// StringEscape encodes string with html special characters escaping. -func (e *Encoder) StringEscape(v string) { +// StrEscape encodes string with html special characters escaping. +func (e *Encoder) StrEscape(v string) { length := len(v) e.buf = append(e.buf, '"') // Fast path, probably does not require escaping. @@ -307,8 +307,8 @@ func (e *Encoder) strEscape(i int, v string, valLen int) { e.byte('"') } -// String write string to stream without html escape -func (e *Encoder) String(v string) { +// Str write string to stream without html escape +func (e *Encoder) Str(v string) { length := len(v) e.buf = append(e.buf, '"') // write string, the fast path, without utf8 and escape support diff --git a/enc_str_test.go b/enc_str_test.go index 8827a94..0d3ffec 100644 --- a/enc_str_test.go +++ b/enc_str_test.go @@ -7,20 +7,18 @@ import ( ) func TestEncoder_StringEscape(t *testing.T) { - s := NewEncoder(nil, 0) + s := NewEncoder() const data = `Hello\\\n\r\\` + "\n\rWorld\u2028" - s.StringEscape(data) - require.NoError(t, s.Flush()) + s.StrEscape(data) requireCompat(t, s.Bytes(), data) const expected = `"\u003chtml\u003eHello\\\\\\n\\r\\\\\n\rWorld\u2028\u003c/html\u003e"` require.Equal(t, expected, string(s.Bytes())) } func TestEncoder_String(t *testing.T) { - s := NewEncoder(nil, 0) + s := NewEncoder() const data = `\nH\tel\tl\ro\\World\r` + "\n\rHello\r\tHi" - s.String(data) - require.NoError(t, s.Flush()) + s.Str(data) const expected = `"\\nH\\tel\\tl\\ro\\\\World\\r\n\rHello\r\tHi"` require.Equal(t, expected, string(s.Bytes())) requireCompat(t, s.Bytes(), data) diff --git a/enc_test.go b/enc_test.go index 9134d52..a248500 100644 --- a/enc_test.go +++ b/enc_test.go @@ -8,73 +8,39 @@ import ( func TestEncoder_byte_should_grow_buffer(t *testing.T) { should := require.New(t) - stream := NewEncoder(nil, 1) - stream.byte('1') - should.Equal("1", string(stream.Bytes())) - should.Equal(1, len(stream.buf)) - stream.byte('2') - should.Equal("12", string(stream.Bytes())) - should.Equal(2, len(stream.buf)) - stream.threeBytes('3', '4', '5') - should.Equal("12345", string(stream.Bytes())) + e := NewEncoder() + e.byte('1') + should.Equal("1", string(e.Bytes())) + should.Equal(1, len(e.buf)) + e.byte('2') + should.Equal("12", string(e.Bytes())) + should.Equal(2, len(e.buf)) + e.threeBytes('3', '4', '5') + should.Equal("12345", string(e.Bytes())) } func TestEncoder_Raw_should_grow_buffer(t *testing.T) { should := require.New(t) - stream := NewEncoder(nil, 1) - stream.Raw("123") - should.NoError(stream.Flush()) - should.Equal("123", string(stream.Bytes())) + e := NewEncoder() + e.Raw("123") + should.Equal("123", string(e.Bytes())) } func TestEncoder_Str_should_grow_buffer(t *testing.T) { should := require.New(t) - stream := NewEncoder(nil, 0) - stream.String("123") - should.NoError(stream.Flush()) - should.Equal(`"123"`, string(stream.Bytes())) -} - -type NopWriter struct { - bufferSize int -} - -func (w *NopWriter) Write(p []byte) (n int, err error) { - w.bufferSize = cap(p) - return len(p), nil -} - -func TestEncoder_Flush_should_stop_grow_buffer(t *testing.T) { - // GetEncoder an array of a zillion zeros. - writer := new(NopWriter) - stream := NewEncoder(writer, 512) - stream.ArrStart() - for i := 0; i < 10000000; i++ { - stream.Int(0) - stream.More() - _ = stream.Flush() - } - stream.Int(0) - stream.ArrEnd() - - // Confirm that the buffer didn't have to grow. - should := require.New(t) - - // 512 is the internal buffer size set in NewEncoder - // - // Flush is called after each array element, so only the first 8 bytes of it - // is ever used, and it is never extended. Capacity remains 512. - should.Equal(512, writer.bufferSize) + e := NewEncoder() + e.Str("123") + should.Equal(`"123"`, string(e.Bytes())) } func TestEncoder_ArrEmpty(t *testing.T) { - s := NewEncoder(nil, 0) - s.ArrEmpty() - require.Equal(t, "[]", string(s.Bytes())) + e := NewEncoder() + e.ArrEmpty() + require.Equal(t, "[]", string(e.Bytes())) } func TestEncoder_ObjEmpty(t *testing.T) { - s := NewEncoder(nil, 0) - s.ObjEmpty() - require.Equal(t, "{}", string(s.Bytes())) + e := NewEncoder() + e.ObjEmpty() + require.Equal(t, "{}", string(e.Bytes())) } diff --git a/float_test.go b/float_test.go index a47a8e4..998fab3 100644 --- a/float_test.go +++ b/float_test.go @@ -14,7 +14,7 @@ import ( func Test_read_big_float(t *testing.T) { should := require.New(t) - r := DecodeString(`12.3`) + r := DecodeStr(`12.3`) val, err := r.BigFloat() should.NoError(err) val64, _ := val.Float64() @@ -23,7 +23,7 @@ func Test_read_big_float(t *testing.T) { func Test_read_big_int(t *testing.T) { should := require.New(t) - iter := DecodeString(`92233720368547758079223372036854775807`) + iter := DecodeStr(`92233720368547758079223372036854775807`) val, err := iter.BigInt() should.NoError(err) should.NotNil(val) @@ -32,7 +32,7 @@ func Test_read_big_int(t *testing.T) { func Test_read_number(t *testing.T) { should := require.New(t) - iter := DecodeString(`92233720368547758079223372036854775807`) + iter := DecodeStr(`92233720368547758079223372036854775807`) val, err := iter.Number() should.NoError(err) should.Equal(`92233720368547758079223372036854775807`, string(val)) @@ -67,7 +67,7 @@ func Test_read_float(t *testing.T) { // non-streaming t.Run(fmt.Sprintf("%v", input), func(t *testing.T) { should := require.New(t) - r := DecodeString(input + ",") + r := DecodeStr(input + ",") expected, err := strconv.ParseFloat(input, 32) should.NoError(err) got, err := r.Float32() @@ -76,7 +76,7 @@ func Test_read_float(t *testing.T) { }) t.Run(fmt.Sprintf("%v", input), func(t *testing.T) { should := require.New(t) - r := DecodeString(input + ",") + r := DecodeStr(input + ",") expected, err := strconv.ParseFloat(input, 64) should.NoError(err) got, err := r.Float64() @@ -112,24 +112,20 @@ func Test_write_float32(t *testing.T) { for _, val := range vals { t.Run(fmt.Sprintf("%v", val), func(t *testing.T) { should := require.New(t) - buf := &bytes.Buffer{} - w := NewEncoder(buf, 4096) + w := NewEncoder() should.NoError(w.Float32Lossy(val)) - should.NoError(w.Flush()) output, err := json.Marshal(val) should.Nil(err) - should.Equal(string(output), buf.String()) + should.Equal(output, w.Bytes()) }) } should := require.New(t) - buf := &bytes.Buffer{} - w := NewEncoder(buf, 10) + w := NewEncoder() w.Raw("abcdefg") should.NoError(w.Float32Lossy(1.123456)) - should.NoError(w.Flush()) - should.Equal("abcdefg1.123456", buf.String()) + should.Equal("abcdefg1.123456", string(w.Bytes())) - w = NewEncoder(nil, 0) + w = NewEncoder() should.NoError(w.WriteFloat32(float32(0.0000001))) should.Equal("1e-07", string(w.Bytes())) } @@ -140,26 +136,22 @@ func Test_write_float64(t *testing.T) { for _, val := range vals { t.Run(fmt.Sprintf("%v", val), func(t *testing.T) { should := require.New(t) - buf := &bytes.Buffer{} - w := NewEncoder(buf, 4096) + w := NewEncoder() should.NoError(w.Float64(val)) - should.NoError(w.Flush()) s := strconv.FormatFloat(val, 'f', -1, 64) if !strings.Contains(s, ".") { s += ".0" } - should.Equal(s, buf.String()) + should.Equal(s, string(w.Bytes())) }) } should := require.New(t) - buf := &bytes.Buffer{} - w := NewEncoder(buf, 10) - w.Raw("abcdefg") - should.NoError(w.Float64Lossy(1.123456)) - should.NoError(w.Flush()) - should.Equal("abcdefg1.123456", buf.String()) + e := NewEncoder() + e.Raw("abcdefg") + should.NoError(e.Float64Lossy(1.123456)) + should.Equal("abcdefg1.123456", e.String()) - w = NewEncoder(nil, 0) - should.NoError(w.Float64(0.0000001)) - should.Equal("1e-07", string(w.Bytes())) + e.Reset() + should.NoError(e.Float64(0.0000001)) + should.Equal("1e-07", e.String()) } diff --git a/fuzz_test.go b/fuzz_test.go index 2a0a3c4..2f26709 100644 --- a/fuzz_test.go +++ b/fuzz_test.go @@ -39,38 +39,29 @@ func FuzzDecEnc(f *testing.F) { if v.Type == AnyInvalid { t.Skip() } - var buf bytes.Buffer w := GetEncoder() - w.Reset(&buf) if err := w.Any(v); err != nil { t.Fatal(err) } - if err := w.Flush(); err != nil { - t.Fatal(err) - } // Parsing from buf to new value. - r.ResetBytes(buf.Bytes()) + r.ResetBytes(w.Bytes()) parsed, err := r.Any() if err != nil { t.Fatalf("%v:\nBuf: %s\nValue: %s\nData: %s", - err, buf.Bytes(), v, data) + err, w.Bytes(), v, data) } if !reflect.DeepEqual(parsed, v) { t.Fatalf("%v:\nBuf: %s\nValue: %s != %s \nData: %s", - nil, buf.Bytes(), parsed, v, data) + nil, w.Bytes(), parsed, v, data) } - // Writing parsed value to newBuf. - var newBuf bytes.Buffer - w.Reset(&newBuf) + b := w.Bytes() + w.SetBytes(nil) if err := parsed.Write(w); err != nil { t.Fatal(err) } - if err := w.Flush(); err != nil { - t.Fatal(err) - } - if !bytes.Equal(newBuf.Bytes(), buf.Bytes()) { - t.Fatalf("%s != %s", &newBuf, &buf) + if !bytes.Equal(w.Bytes(), b) { + t.Fatalf("%s != %s", w, b) } }) } @@ -79,28 +70,22 @@ func FuzzValues(f *testing.F) { f.Add(int64(1), "hello") f.Add(int64(1534564316421), " привет ") f.Fuzz(func(t *testing.T, n int64, str string) { - buf := new(bytes.Buffer) w := GetEncoder() - w.Reset(buf) defer PutEncoder(w) w.ArrStart() w.Int64(n) w.More() - w.String(str) + w.Str(str) w.ArrEnd() - if err := w.Flush(); err != nil { - t.Fatal(err) - } - i := GetDecoder() - i.ResetBytes(buf.Bytes()) + i.ResetBytes(w.Bytes()) var ( nGot int64 sGot string ) - if err := i.Array(func(i *Decoder) error { + if err := i.Arr(func(i *Decoder) error { var err error switch i.Next() { case Number: @@ -112,16 +97,16 @@ func FuzzValues(f *testing.F) { } return err }); err != nil { - t.Fatalf("'%s': %v", buf, err) + t.Fatalf("'%s': %v", w, err) } if nGot != n { t.Fatalf("'%s': %d (got) != %d (expected)", - buf, nGot, n, + w, nGot, n, ) } if sGot != str { t.Fatalf("'%s': %q (got) != %q (expected)", - buf, sGot, str, + w, sGot, str, ) } }) diff --git a/int_bench_test.go b/int_bench_test.go index 8900eeb..bd1f4ae 100644 --- a/int_bench_test.go +++ b/int_bench_test.go @@ -2,16 +2,15 @@ package jx import ( "encoding/json" - "io/ioutil" "strconv" "testing" ) func Benchmark_encode_int(b *testing.B) { - stream := NewEncoder(ioutil.Discard, 64) + e := NewEncoder() for n := 0; n < b.N; n++ { - stream.Reset(nil) - stream.Uint64(0xffffffff) + e.Reset() + e.Uint64(0xffffffff) } } diff --git a/int_test.go b/int_test.go index 04127fc..18e6ca2 100644 --- a/int_test.go +++ b/int_test.go @@ -11,7 +11,7 @@ import ( func Test_read_uint64_invalid(t *testing.T) { should := require.New(t) - iter := DecodeString(",") + iter := DecodeStr(",") _, err := iter.Uint64() should.Error(err) } @@ -21,7 +21,7 @@ func Test_read_int32(t *testing.T) { for _, input := range inputs { t.Run(fmt.Sprintf("%v", input), func(t *testing.T) { should := require.New(t) - iter := DecodeString(input) + iter := DecodeStr(input) expected, err := strconv.ParseInt(input, 10, 32) should.NoError(err) v, err := iter.Int32() @@ -44,11 +44,11 @@ func Test_read_int_overflow(t *testing.T) { for _, s := range []string{"1234232323232323235678912", "-1234567892323232323212"} { t.Run(s, func(t *testing.T) { should := require.New(t) - iter := DecodeString(s) + iter := DecodeStr(s) _, err := iter.Int32() should.Error(err) - iterUint := DecodeString(s) + iterUint := DecodeStr(s) _, err = iterUint.Uint32() should.Error(err) }) @@ -57,11 +57,11 @@ func Test_read_int_overflow(t *testing.T) { for _, s := range []string{"123456789232323232321545111111111111111111111111111111145454545445", "-1234567892323232323212"} { t.Run(s, func(t *testing.T) { should := require.New(t) - iter := DecodeString(s) + iter := DecodeStr(s) v, err := iter.Int64() should.Error(err, "%v", v) - iterUint := DecodeString(s) + iterUint := DecodeStr(s) vu, err := iterUint.Uint64() should.Error(err, "%v", vu) }) @@ -70,7 +70,7 @@ func Test_read_int_overflow(t *testing.T) { func Test_read_int64_overflow(t *testing.T) { s := `123456789232323232321545111111111111111111111111111111145454545445` - iter := DecodeString(s) + iter := DecodeStr(s) _, err := iter.Int64() require.Error(t, err) } @@ -80,7 +80,7 @@ func Test_read_int64(t *testing.T) { for _, input := range inputs { t.Run(fmt.Sprintf("%v", input), func(t *testing.T) { should := require.New(t) - iter := DecodeString(input) + iter := DecodeStr(input) expected, err := strconv.ParseInt(input, 10, 64) should.NoError(err) v, err := iter.Int64() @@ -104,20 +104,16 @@ func Test_write_uint32(t *testing.T) { for _, val := range vals { t.Run(fmt.Sprintf("%v", val), func(t *testing.T) { should := require.New(t) - buf := &bytes.Buffer{} - stream := NewEncoder(buf, 4096) - stream.Uint32(val) - should.NoError(stream.Flush()) - should.Equal(strconv.FormatUint(uint64(val), 10), buf.String()) + e := NewEncoder() + e.Uint32(val) + should.Equal(strconv.FormatUint(uint64(val), 10), e.String()) }) } should := require.New(t) - buf := &bytes.Buffer{} - stream := NewEncoder(buf, 10) - stream.Raw("a") - stream.Uint32(0xffffffff) // should clear buffer - should.NoError(stream.Flush()) - should.Equal("a4294967295", buf.String()) + e := NewEncoder() + e.Raw("a") + e.Uint32(0xffffffff) // should clear buffer + should.Equal("a4294967295", e.String()) } func Test_write_int32(t *testing.T) { @@ -125,20 +121,16 @@ func Test_write_int32(t *testing.T) { for _, val := range vals { t.Run(fmt.Sprintf("%v", val), func(t *testing.T) { should := require.New(t) - buf := &bytes.Buffer{} - stream := NewEncoder(buf, 4096) - stream.Int32(val) - should.NoError(stream.Flush()) - should.Equal(strconv.FormatInt(int64(val), 10), buf.String()) + e := NewEncoder() + e.Int32(val) + should.Equal(strconv.FormatInt(int64(val), 10), e.String()) }) } should := require.New(t) - buf := &bytes.Buffer{} - stream := NewEncoder(buf, 11) - stream.Raw("a") - stream.Int32(-0x7fffffff) // should clear buffer - should.NoError(stream.Flush()) - should.Equal("a-2147483647", buf.String()) + e := NewEncoder() + e.Raw("a") + e.Int32(-0x7fffffff) // should clear buffer + should.Equal("a-2147483647", e.String()) } func Test_write_uint64(t *testing.T) { @@ -148,20 +140,16 @@ func Test_write_uint64(t *testing.T) { for _, val := range vals { t.Run(fmt.Sprintf("%v", val), func(t *testing.T) { should := require.New(t) - buf := &bytes.Buffer{} - stream := NewEncoder(buf, 4096) - stream.Uint64(val) - should.NoError(stream.Flush()) - should.Equal(strconv.FormatUint(val, 10), buf.String()) + e := NewEncoder() + e.Uint64(val) + should.Equal(strconv.FormatUint(val, 10), e.String()) }) } should := require.New(t) - buf := &bytes.Buffer{} - stream := NewEncoder(buf, 10) - stream.Raw("a") - stream.Uint64(0xffffffff) // should clear buffer - should.NoError(stream.Flush()) - should.Equal("a4294967295", buf.String()) + e := NewEncoder() + e.Raw("a") + e.Uint64(0xffffffff) // should clear buffer + should.Equal("a4294967295", e.String()) } func Test_write_int64(t *testing.T) { @@ -171,20 +159,16 @@ func Test_write_int64(t *testing.T) { for _, val := range vals { t.Run(fmt.Sprintf("%v", val), func(t *testing.T) { should := require.New(t) - buf := &bytes.Buffer{} - stream := NewEncoder(buf, 4096) - stream.Int64(val) - should.NoError(stream.Flush()) - should.Equal(strconv.FormatInt(val, 10), buf.String()) + e := NewEncoder() + e.Int64(val) + should.Equal(strconv.FormatInt(val, 10), e.String()) }) } should := require.New(t) - buf := &bytes.Buffer{} - stream := NewEncoder(buf, 10) - stream.Raw("a") - stream.Int64(0xffffffff) // should clear buffer - should.NoError(stream.Flush()) - should.Equal("a4294967295", buf.String()) + e := NewEncoder() + e.Raw("a") + e.Int64(0xffffffff) // should clear buffer + should.Equal("a4294967295", e.String()) } func intPow(n, m int64) int64 { diff --git a/invalid_test.go b/invalid_test.go index f4e6465..a83d772 100644 --- a/invalid_test.go +++ b/invalid_test.go @@ -19,12 +19,12 @@ func Test_invalid_float(t *testing.T) { for _, input := range inputs { t.Run(input, func(t *testing.T) { should := require.New(t) - iter := DecodeString(input + ",") + iter := DecodeStr(input + ",") should.Error(iter.Skip()) - iter = DecodeString(input + ",") + iter = DecodeStr(input + ",") _, err := iter.Float64() should.Error(err) - iter = DecodeString(input + ",") + iter = DecodeStr(input + ",") _, err = iter.Float32() should.Error(err) }) diff --git a/jx.go b/jx.go index 708ed28..b77dc40 100644 --- a/jx.go +++ b/jx.go @@ -17,7 +17,7 @@ func Valid(data []byte) bool { var ( encPool = &sync.Pool{ New: func() interface{} { - return NewEncoder(nil, 256) + return NewEncoder() }, } decPool = &sync.Pool{ @@ -45,8 +45,7 @@ func GetEncoder() *Encoder { // PutEncoder puts *Encoder to pool func PutEncoder(e *Encoder) { - e.Reset(nil) + e.Reset() e.SetIdent(0) - e.buf = e.buf[:0] encPool.Put(e) } diff --git a/null_test.go b/null_test.go index fc820d0..c763e31 100644 --- a/null_test.go +++ b/null_test.go @@ -1,7 +1,6 @@ package jx import ( - "bytes" "testing" "github.com/stretchr/testify/require" @@ -9,16 +8,14 @@ import ( func Test_write_null(t *testing.T) { should := require.New(t) - buf := &bytes.Buffer{} - stream := NewEncoder(buf, 4096) - stream.Null() - should.NoError(stream.Flush()) - should.Equal("null", buf.String()) + e := NewEncoder() + e.Null() + should.Equal("null", e.String()) } func Test_decode_null_array_element(t *testing.T) { should := require.New(t) - iter := DecodeString(`[null,"a"]`) + iter := DecodeStr(`[null,"a"]`) should.True(iter.Elem()) should.NoError(iter.Null()) should.True(iter.Elem()) @@ -29,7 +26,7 @@ func Test_decode_null_array_element(t *testing.T) { func Test_decode_null_string(t *testing.T) { should := require.New(t) - iter := DecodeString(`[null,"a"]`) + iter := DecodeStr(`[null,"a"]`) should.True(iter.Elem()) should.NoError(iter.Null()) should.True(iter.Elem()) @@ -39,7 +36,7 @@ func Test_decode_null_string(t *testing.T) { } func Test_decode_null_skip(t *testing.T) { - iter := DecodeString(`[null,"a"]`) + iter := DecodeStr(`[null,"a"]`) iter.Elem() iter.Skip() iter.Elem() diff --git a/obj_test.go b/obj_test.go index 83f6ba6..2d133d2 100644 --- a/obj_test.go +++ b/obj_test.go @@ -1,15 +1,14 @@ package jx import ( - "bytes" "testing" "github.com/stretchr/testify/require" ) func Test_empty_object(t *testing.T) { - iter := DecodeString(`{}`) - require.NoError(t, iter.Object(func(iter *Decoder, field string) error { + iter := DecodeStr(`{}`) + require.NoError(t, iter.Obj(func(iter *Decoder, field string) error { t.Error("should not call") return nil })) @@ -17,8 +16,8 @@ func Test_empty_object(t *testing.T) { func Test_one_field(t *testing.T) { should := require.New(t) - iter := DecodeString(`{"a": "stream"}`) - should.NoError(iter.Object(func(iter *Decoder, field string) error { + d := DecodeStr(`{"a": "stream"}`) + should.NoError(d.Obj(func(iter *Decoder, field string) error { should.Equal("a", field) return iter.Skip() })) @@ -26,16 +25,14 @@ func Test_one_field(t *testing.T) { func Test_write_object(t *testing.T) { should := require.New(t) - buf := &bytes.Buffer{} - s := NewEncoder(buf, 4096) - s.SetIdent(2) - s.ObjStart() - s.ObjField("hello") - s.Int(1) - s.More() - s.ObjField("world") - s.Int(2) - s.ObjEnd() - should.NoError(s.Flush()) - should.Equal("{\n \"hello\": 1,\n \"world\": 2\n}", buf.String()) + e := NewEncoder() + e.SetIdent(2) + e.ObjStart() + e.ObjField("hello") + e.Int(1) + e.More() + e.ObjField("world") + e.Int(2) + e.ObjEnd() + should.Equal("{\n \"hello\": 1,\n \"world\": 2\n}", e.String()) } diff --git a/string_test.go b/string_test.go index 5bc0783..d6eab39 100644 --- a/string_test.go +++ b/string_test.go @@ -1,7 +1,6 @@ package jx import ( - "bytes" hexEnc "encoding/hex" "encoding/json" "testing" @@ -27,7 +26,7 @@ func Test_read_string(t *testing.T) { } for _, input := range badInputs { - i := DecodeString(input) + i := DecodeStr(input) _, err := i.String() assert.Error(t, err, "input: %q", input) } @@ -62,7 +61,7 @@ func Test_read_string(t *testing.T) { for _, tc := range goodInputs { testReadString(t, tc.input, tc.expectValue, false, "json.Unmarshal", json.Unmarshal) - i := DecodeString(tc.input) + i := DecodeStr(tc.input) s, err := i.String() assert.NoError(t, err) assert.Equal(t, tc.expectValue, s) @@ -92,24 +91,21 @@ func TestDecoder_Str(t *testing.T) { {Name: "\\x00TrailingSpace", Input: "\x00 "}, } { t.Run(tt.Name, func(t *testing.T) { - buf := new(bytes.Buffer) - s := NewEncoder(buf, 128) + s := NewEncoder() t.Logf("%v", []rune(tt.Input)) - s.String(tt.Input) - require.NoError(t, s.Flush()) - t.Logf("%v", []rune(buf.String())) + s.Str(tt.Input) + t.Logf("%v", []rune(s.String())) // Check `encoding/json` compatibility. var gotStd string - requireCompat(t, buf.Bytes(), tt.Input) - require.NoError(t, json.Unmarshal(buf.Bytes(), &gotStd)) + require.NoError(t, json.Unmarshal(s.Bytes(), &gotStd)) require.Equal(t, tt.Input, gotStd) - i := DecodeBytes(buf.Bytes()) + i := DecodeBytes(s.Bytes()) got, err := i.String() require.NoError(t, err) - require.Equal(t, tt.Input, got, "%s\n%s", buf, hexEnc.Dump(buf.Bytes())) + require.Equal(t, tt.Input, got, "%s\n%s", s, hexEnc.Dump(s.Bytes())) }) } }