Permalink
Browse files

add stream

  • Loading branch information...
1 parent 5af8cc4 commit 6f57d414615cb05e79da8b884f2c898f7f864613 @taowen taowen committed Jan 7, 2017
Showing with 394 additions and 43 deletions.
  1. +21 −1 feature_adapter.go
  2. +9 −9 jsoniter.go → iterator.go
  3. +79 −7 jsoniter_int_test.go
  4. +24 −5 jsoniter_null_test.go
  5. +12 −12 jsoniter_reflect_struct_test.go
  6. +2 −2 jsoniter_reflect_test.go
  7. +18 −7 jsoniter_string_test.go
  8. +229 −0 stream.go
View
@@ -3,6 +3,7 @@ package jsoniter
import (
"io"
"unsafe"
+ "bytes"
)
// Unmarshal adapts to json/encoding APIs
@@ -15,7 +16,8 @@ func Unmarshal(data []byte, v interface{}) error {
return iter.Error
}
-func UnmarshalString(str string, v interface{}) error {
+func UnmarshalFromString(str string, v interface{}) error {
+ // safe to do the unsafe cast here, as str is always referenced in this scope
data := *(*[]byte)(unsafe.Pointer(&str))
iter := ParseBytes(data)
iter.Read(v)
@@ -24,3 +26,21 @@ func UnmarshalString(str string, v interface{}) error {
}
return iter.Error
}
+
+func Marshal(v interface{}) ([]byte, error) {
+ buf := &bytes.Buffer{}
+ stream := NewStream(buf, 4096)
+ stream.WriteVal(v)
+ if stream.Error != nil {
+ return nil, stream.Error
+ }
+ return buf.Bytes(), nil
+}
+
+func MarshalToString(v interface{}) (string, error) {
+ buf, err := Marshal(v)
+ if err != nil {
+ return "", err
+ }
+ return string(buf), nil
+}
@@ -21,22 +21,22 @@ const (
Object
)
-var digits []byte
+var atoiDigits []byte
var valueTypes []ValueType
func init() {
- digits = make([]byte, 256)
- for i := 0; i < len(digits); i++ {
- digits[i] = 255
+ atoiDigits = make([]byte, 256)
+ for i := 0; i < len(atoiDigits); i++ {
+ atoiDigits[i] = 255
}
for i := '0'; i <= '9'; i++ {
- digits[i] = byte(i - '0')
+ atoiDigits[i] = byte(i - '0')
}
for i := 'a'; i <= 'f'; i++ {
- digits[i] = byte((i - 'a') + 10)
+ atoiDigits[i] = byte((i - 'a') + 10)
}
for i := 'A'; i <= 'F'; i++ {
- digits[i] = byte((i - 'A') + 10)
+ atoiDigits[i] = byte((i - 'A') + 10)
}
valueTypes = make([]ValueType, 256)
for i := 0; i < len(valueTypes); i++ {
@@ -278,7 +278,7 @@ func (iter *Iterator) ReadUint32() (ret uint32) {
// ReadUint64 reads a json object as Uint64
func (iter *Iterator) ReadUint64() (ret uint64) {
c := iter.nextToken()
- v := digits[c]
+ v := atoiDigits[c]
if v == 0 {
return 0 // single zero
}
@@ -293,7 +293,7 @@ func (iter *Iterator) ReadUint64() (ret uint64) {
}
ret = ret*10 + uint64(v)
c = iter.readByte()
- v = digits[c]
+ v = atoiDigits[c]
if v == 255 {
iter.unreadByte()
break
View
@@ -4,9 +4,12 @@ import (
"bytes"
"encoding/json"
"testing"
+ "github.com/json-iterator/go/require"
+ "fmt"
+ "strconv"
)
-func Test_uint64_0(t *testing.T) {
+func Test_decode_decode_uint64_0(t *testing.T) {
iter := Parse(bytes.NewBufferString("0"), 4096)
val := iter.ReadUint64()
if iter.Error != nil {
@@ -17,23 +20,23 @@ func Test_uint64_0(t *testing.T) {
}
}
-func Test_uint64_1(t *testing.T) {
+func Test_decode_uint64_1(t *testing.T) {
iter := Parse(bytes.NewBufferString("1"), 4096)
val := iter.ReadUint64()
if val != 1 {
t.Fatal(val)
}
}
-func Test_uint64_100(t *testing.T) {
+func Test_decode_uint64_100(t *testing.T) {
iter := Parse(bytes.NewBufferString("100"), 4096)
val := iter.ReadUint64()
if val != 100 {
t.Fatal(val)
}
}
-func Test_uint64_100_comma(t *testing.T) {
+func Test_decode_uint64_100_comma(t *testing.T) {
iter := Parse(bytes.NewBufferString("100,"), 4096)
val := iter.ReadUint64()
if iter.Error != nil {
@@ -44,30 +47,99 @@ func Test_uint64_100_comma(t *testing.T) {
}
}
-func Test_uint64_invalid(t *testing.T) {
+func Test_decode_uint64_invalid(t *testing.T) {
iter := Parse(bytes.NewBufferString(","), 4096)
iter.ReadUint64()
if iter.Error == nil {
t.FailNow()
}
}
-func Test_int64_100(t *testing.T) {
+func Test_decode_int64_100(t *testing.T) {
iter := Parse(bytes.NewBufferString("100"), 4096)
val := iter.ReadInt64()
if val != 100 {
t.Fatal(val)
}
}
-func Test_int64_minus_100(t *testing.T) {
+func Test_decode_int64_minus_100(t *testing.T) {
iter := Parse(bytes.NewBufferString("-100"), 4096)
val := iter.ReadInt64()
if val != -100 {
t.Fatal(val)
}
}
+func Test_write_uint8(t *testing.T) {
+ vals := []uint8{0, 1, 11, 111, 255}
+ for _, val := range vals {
+ t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
+ should := require.New(t)
+ buf := &bytes.Buffer{}
+ stream := NewStream(buf, 4096)
+ stream.WriteUint8(val)
+ stream.Flush()
+ should.Nil(stream.Error)
+ should.Equal(strconv.Itoa(int(val)), buf.String())
+ })
+ }
+ should := require.New(t)
+ buf := &bytes.Buffer{}
+ stream := NewStream(buf, 3)
+ stream.WriteString("a")
+ stream.WriteUint8(100) // should clear buffer
+ stream.Flush()
+ should.Nil(stream.Error)
+ should.Equal("a100", buf.String())
+}
+
+func Test_write_int8(t *testing.T) {
+ vals := []int8{0, 1, -1, 99, 0x7f, -0x7f}
+ for _, val := range vals {
+ t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
+ should := require.New(t)
+ buf := &bytes.Buffer{}
+ stream := NewStream(buf, 4096)
+ stream.WriteInt8(val)
+ stream.Flush()
+ should.Nil(stream.Error)
+ should.Equal(strconv.Itoa(int(val)), buf.String())
+ })
+ }
+ should := require.New(t)
+ buf := &bytes.Buffer{}
+ stream := NewStream(buf, 4)
+ stream.WriteString("a")
+ stream.WriteInt8(-100) // should clear buffer
+ stream.Flush()
+ should.Nil(stream.Error)
+ should.Equal("a-100", buf.String())
+}
+
+func Test_write_uint16(t *testing.T) {
+ vals := []uint16{0, 1, 11, 111, 255, 0xfff, 0xffff}
+ for _, val := range vals {
+ t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
+ should := require.New(t)
+ buf := &bytes.Buffer{}
+ stream := NewStream(buf, 4096)
+ stream.WriteUint16(val)
+ stream.Flush()
+ should.Nil(stream.Error)
+ should.Equal(strconv.Itoa(int(val)), buf.String())
+ })
+ }
+ should := require.New(t)
+ buf := &bytes.Buffer{}
+ stream := NewStream(buf, 5)
+ stream.WriteString("a")
+ stream.WriteUint16(10000) // should clear buffer
+ stream.Flush()
+ should.Nil(stream.Error)
+ should.Equal("a10000", buf.String())
+}
+
func Benchmark_jsoniter_int(b *testing.B) {
for n := 0; n < b.N; n++ {
iter := ParseString(`-100`)
View
@@ -2,16 +2,35 @@ package jsoniter
import (
"testing"
+ "github.com/json-iterator/go/require"
+ "bytes"
)
-func Test_null(t *testing.T) {
+func Test_decode_null(t *testing.T) {
iter := ParseString(`null`)
if iter.ReadNil() != true {
t.FailNow()
}
}
-func Test_null_object(t *testing.T) {
+func Test_write_null(t *testing.T) {
+ should := require.New(t)
+ buf := &bytes.Buffer{}
+ stream := NewStream(buf, 4096)
+ stream.WriteNull()
+ stream.Flush()
+ should.Nil(stream.Error)
+ should.Equal("null", buf.String())
+}
+
+func Test_encode_null(t *testing.T) {
+ should := require.New(t)
+ str, err := MarshalToString(nil)
+ should.Nil(err)
+ should.Equal("null", str)
+}
+
+func Test_decode_null_object(t *testing.T) {
iter := ParseString(`[null,"a"]`)
iter.ReadArray()
if iter.ReadObject() != "" {
@@ -23,7 +42,7 @@ func Test_null_object(t *testing.T) {
}
}
-func Test_null_array(t *testing.T) {
+func Test_decode_null_array(t *testing.T) {
iter := ParseString(`[null,"a"]`)
iter.ReadArray()
if iter.ReadArray() != false {
@@ -35,7 +54,7 @@ func Test_null_array(t *testing.T) {
}
}
-func Test_null_string(t *testing.T) {
+func Test_decode_null_string(t *testing.T) {
iter := ParseString(`[null,"a"]`)
iter.ReadArray()
if iter.ReadString() != "" {
@@ -47,7 +66,7 @@ func Test_null_string(t *testing.T) {
}
}
-func Test_null_skip(t *testing.T) {
+func Test_decode_null_skip(t *testing.T) {
iter := ParseString(`[null,"a"]`)
iter.ReadArray()
iter.Skip()
@@ -11,9 +11,9 @@ func Test_decode_one_field_struct(t *testing.T) {
field1 string
}
obj := TestObject{}
- should.Nil(UnmarshalString(`{}`, &obj))
+ should.Nil(UnmarshalFromString(`{}`, &obj))
should.Equal("", obj.field1)
- should.Nil(UnmarshalString(`{"field1": "hello"}`, &obj))
+ should.Nil(UnmarshalFromString(`{"field1": "hello"}`, &obj))
should.Equal("hello", obj.field1)
}
@@ -24,9 +24,9 @@ func Test_decode_two_fields_struct(t *testing.T) {
field2 string
}
obj := TestObject{}
- should.Nil(UnmarshalString(`{}`, &obj))
+ should.Nil(UnmarshalFromString(`{}`, &obj))
should.Equal("", obj.field1)
- should.Nil(UnmarshalString(`{"field1": "a", "field2": "b"}`, &obj))
+ should.Nil(UnmarshalFromString(`{"field1": "a", "field2": "b"}`, &obj))
should.Equal("a", obj.field1)
should.Equal("b", obj.field2)
}
@@ -39,9 +39,9 @@ func Test_decode_three_fields_struct(t *testing.T) {
field3 string
}
obj := TestObject{}
- should.Nil(UnmarshalString(`{}`, &obj))
+ should.Nil(UnmarshalFromString(`{}`, &obj))
should.Equal("", obj.field1)
- should.Nil(UnmarshalString(`{"field1": "a", "field2": "b", "field3": "c"}`, &obj))
+ should.Nil(UnmarshalFromString(`{"field1": "a", "field2": "b", "field3": "c"}`, &obj))
should.Equal("a", obj.field1)
should.Equal("b", obj.field2)
should.Equal("c", obj.field3)
@@ -56,9 +56,9 @@ func Test_decode_four_fields_struct(t *testing.T) {
field4 string
}
obj := TestObject{}
- should.Nil(UnmarshalString(`{}`, &obj))
+ should.Nil(UnmarshalFromString(`{}`, &obj))
should.Equal("", obj.field1)
- should.Nil(UnmarshalString(`{"field1": "a", "field2": "b", "field3": "c", "field4": "d"}`, &obj))
+ should.Nil(UnmarshalFromString(`{"field1": "a", "field2": "b", "field3": "c", "field4": "d"}`, &obj))
should.Equal("a", obj.field1)
should.Equal("b", obj.field2)
should.Equal("c", obj.field3)
@@ -75,9 +75,9 @@ func Test_decode_five_fields_struct(t *testing.T) {
field5 string
}
obj := TestObject{}
- should.Nil(UnmarshalString(`{}`, &obj))
+ should.Nil(UnmarshalFromString(`{}`, &obj))
should.Equal("", obj.field1)
- should.Nil(UnmarshalString(`{"field1": "a", "field2": "b", "field3": "c", "field4": "d", "field5": "e"}`, &obj))
+ should.Nil(UnmarshalFromString(`{"field1": "a", "field2": "b", "field3": "c", "field4": "d", "field5": "e"}`, &obj))
should.Equal("a", obj.field1)
should.Equal("b", obj.field2)
should.Equal("c", obj.field3)
@@ -92,7 +92,7 @@ func Test_decode_struct_with_optional_field(t *testing.T) {
field2 *string
}
obj := TestObject{}
- UnmarshalString(`{"field1": null, "field2": "world"}`, &obj)
+ UnmarshalFromString(`{"field1": null, "field2": "world"}`, &obj)
should.Nil(obj.field1)
should.Equal("world", *obj.field2)
}
@@ -105,7 +105,7 @@ func Test_decode_struct_field_with_tag(t *testing.T) {
Field3 int `json:",string"`
}
obj := TestObject{Field2: "world"}
- UnmarshalString(`{"field-1": "hello", "field2": "", "Field3": "100"}`, &obj)
+ UnmarshalFromString(`{"field-1": "hello", "field2": "", "Field3": "100"}`, &obj)
should.Equal("hello", obj.Field1)
should.Equal("world", obj.Field2)
should.Equal(100, obj.Field3)
@@ -11,14 +11,14 @@ import (
func Test_decode_slice(t *testing.T) {
should := require.New(t)
slice := make([]string, 0, 5)
- UnmarshalString(`["hello", "world"]`, &slice)
+ UnmarshalFromString(`["hello", "world"]`, &slice)
should.Equal([]string{"hello", "world"}, slice)
}
func Test_decode_large_slice(t *testing.T) {
should := require.New(t)
slice := make([]int, 0, 1)
- UnmarshalString(`[1,2,3,4,5,6,7,8,9]`, &slice)
+ UnmarshalFromString(`[1,2,3,4,5,6,7,8,9]`, &slice)
should.Equal([]int{1, 2, 3, 4, 5, 6, 7, 8, 9}, slice)
}
Oops, something went wrong.

0 comments on commit 6f57d41

Please sign in to comment.