You've already forked json-iterator
mirror of
https://github.com/json-iterator/go.git
synced 2025-06-15 22:50:24 +02:00
Compare commits
25 Commits
Author | SHA1 | Date | |
---|---|---|---|
6240e1e798 | |||
0149a5cf4a | |||
5068c8baaf | |||
16f78601b5 | |||
8f50a91be2 | |||
73c7bc881e | |||
4de15a3a87 | |||
14b28b2226 | |||
abe3c4016b | |||
dbb1ef3f63 | |||
46b20bbbec | |||
fdfe0b9a69 | |||
faa3dcf46a | |||
1f58120d43 | |||
6ed27152e0 | |||
3c298d8a76 | |||
9f6e5962a9 | |||
c463aa12c4 | |||
b5d2607a6d | |||
48cc4d965a | |||
c59c42fda0 | |||
8324374402 | |||
2017f3866b | |||
ddc5af4512 | |||
2f7e5c8dd7 |
10
README.md
10
README.md
@ -44,7 +44,9 @@ with
|
||||
|
||||
```go
|
||||
import "github.com/json-iterator/go"
|
||||
jsoniter.Marshal(&data)
|
||||
|
||||
var json = jsoniter.ConfigCompatibleWithStandardLibrary
|
||||
json.Marshal(&data)
|
||||
```
|
||||
|
||||
Replace
|
||||
@ -58,7 +60,9 @@ with
|
||||
|
||||
```go
|
||||
import "github.com/json-iterator/go"
|
||||
jsoniter.Unmarshal(input, &data)
|
||||
|
||||
var json = jsoniter.ConfigCompatibleWithStandardLibrary
|
||||
json.Unmarshal(input, &data)
|
||||
```
|
||||
|
||||
[More documentation](http://jsoniter.com/migrate-from-go-std.html)
|
||||
@ -76,5 +80,7 @@ Contributors
|
||||
* [thockin](https://github.com/thockin)
|
||||
* [mattn](https://github.com/mattn)
|
||||
* [cch123](https://github.com/cch123)
|
||||
* [Oleg Shaldybin](https://github.com/olegshaldybin)
|
||||
* [Jason Toffaletti](https://github.com/toffaletti)
|
||||
|
||||
Report issue or pull request, or email taowen@gmail.com, or [](https://gitter.im/json-iterator/Lobby)
|
||||
|
@ -125,3 +125,8 @@ func (adapter *Encoder) SetEscapeHTML(escapeHTML bool) {
|
||||
config.EscapeHTML = escapeHTML
|
||||
adapter.stream.cfg = config.Froze().(*frozenConfig)
|
||||
}
|
||||
|
||||
// Valid reports whether data is a valid JSON encoding.
|
||||
func Valid(data []byte) bool {
|
||||
return ConfigDefault.Valid(data)
|
||||
}
|
||||
|
@ -45,6 +45,7 @@ type API interface {
|
||||
Get(data []byte, path ...interface{}) Any
|
||||
NewEncoder(writer io.Writer) *Encoder
|
||||
NewDecoder(reader io.Reader) *Decoder
|
||||
Valid(data []byte) bool
|
||||
}
|
||||
|
||||
// ConfigDefault the default API
|
||||
@ -333,3 +334,10 @@ func (cfg *frozenConfig) NewDecoder(reader io.Reader) *Decoder {
|
||||
iter := Parse(cfg, reader, 512)
|
||||
return &Decoder{iter}
|
||||
}
|
||||
|
||||
func (cfg *frozenConfig) Valid(data []byte) bool {
|
||||
iter := cfg.BorrowIterator(data)
|
||||
defer cfg.ReturnIterator(iter)
|
||||
iter.Skip()
|
||||
return iter.Error == nil
|
||||
}
|
||||
|
@ -200,8 +200,22 @@ func (iter *Iterator) ReportError(operation string, msg string) {
|
||||
if peekStart < 0 {
|
||||
peekStart = 0
|
||||
}
|
||||
iter.Error = fmt.Errorf("%s: %s, parsing %v ...%s... at %s", operation, msg, iter.head,
|
||||
string(iter.buf[peekStart:iter.head]), string(iter.buf[0:iter.tail]))
|
||||
peekEnd := iter.head + 10
|
||||
if peekEnd > iter.tail {
|
||||
peekEnd = iter.tail
|
||||
}
|
||||
parsing := string(iter.buf[peekStart:peekEnd])
|
||||
contextStart := iter.head - 50
|
||||
if contextStart < 0 {
|
||||
contextStart = 0
|
||||
}
|
||||
contextEnd := iter.head + 50
|
||||
if contextEnd > iter.tail {
|
||||
contextEnd = iter.tail
|
||||
}
|
||||
context := string(iter.buf[contextStart:contextEnd])
|
||||
iter.Error = fmt.Errorf("%s: %s, error found in #%v byte of ...|%s|..., bigger context ...|%s|...",
|
||||
operation, msg, iter.head-peekStart, parsing, context)
|
||||
}
|
||||
|
||||
// CurrentBuffer gets current buffer as string for debugging purpose
|
||||
@ -210,7 +224,7 @@ func (iter *Iterator) CurrentBuffer() string {
|
||||
if peekStart < 0 {
|
||||
peekStart = 0
|
||||
}
|
||||
return fmt.Sprintf("parsing %v ...|%s|... at %s", iter.head,
|
||||
return fmt.Sprintf("parsing #%v byte, around ...|%s|..., whole buffer ...|%s|...", iter.head,
|
||||
string(iter.buf[peekStart:iter.head]), string(iter.buf[0:iter.tail]))
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@ func (iter *Iterator) ReadArray() (ret bool) {
|
||||
case ',':
|
||||
return true
|
||||
default:
|
||||
iter.ReportError("ReadArray", "expect [ or , or ] or n, but found: "+string([]byte{c}))
|
||||
iter.ReportError("ReadArray", "expect [ or , or ] or n, but found "+string([]byte{c}))
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -42,7 +42,7 @@ func (iter *Iterator) ReadArrayCB(callback func(*Iterator) bool) (ret bool) {
|
||||
c = iter.nextToken()
|
||||
}
|
||||
if c != ']' {
|
||||
iter.ReportError("ReadArrayCB", "expect ] in the end")
|
||||
iter.ReportError("ReadArrayCB", "expect ] in the end, but found "+string([]byte{c}))
|
||||
return false
|
||||
}
|
||||
return true
|
||||
@ -53,6 +53,6 @@ func (iter *Iterator) ReadArrayCB(callback func(*Iterator) bool) (ret bool) {
|
||||
iter.skipThreeBytes('u', 'l', 'l')
|
||||
return true // null
|
||||
}
|
||||
iter.ReportError("ReadArrayCB", "expect [ or n, but found: "+string([]byte{c}))
|
||||
iter.ReportError("ReadArrayCB", "expect [ or n, but found "+string([]byte{c}))
|
||||
return false
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ func (iter *Iterator) ReadObject() (ret string) {
|
||||
if c == '}' {
|
||||
return "" // end of object
|
||||
}
|
||||
iter.ReportError("ReadObject", `expect " after {`)
|
||||
iter.ReportError("ReadObject", `expect " after {, but found `+string([]byte{c}))
|
||||
return
|
||||
case ',':
|
||||
return string(iter.readObjectFieldAsBytes())
|
||||
@ -105,14 +105,14 @@ func (iter *Iterator) ReadObjectCB(callback func(*Iterator, string) bool) bool {
|
||||
if c == '}' {
|
||||
return true
|
||||
}
|
||||
iter.ReportError("ReadObjectCB", `expect " after }`)
|
||||
iter.ReportError("ReadObjectCB", `expect " after }, but found `+string([]byte{c}))
|
||||
return false
|
||||
}
|
||||
if c == 'n' {
|
||||
iter.skipThreeBytes('u', 'l', 'l')
|
||||
return true // null
|
||||
}
|
||||
iter.ReportError("ReadObjectCB", `expect { or n`)
|
||||
iter.ReportError("ReadObjectCB", `expect { or n, but found `+string([]byte{c}))
|
||||
return false
|
||||
}
|
||||
|
||||
@ -125,7 +125,7 @@ func (iter *Iterator) ReadMapCB(callback func(*Iterator, string) bool) bool {
|
||||
iter.unreadByte()
|
||||
field := iter.ReadString()
|
||||
if iter.nextToken() != ':' {
|
||||
iter.ReportError("ReadMapCB", "expect : after object field")
|
||||
iter.ReportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c}))
|
||||
return false
|
||||
}
|
||||
if !callback(iter, field) {
|
||||
@ -135,7 +135,7 @@ func (iter *Iterator) ReadMapCB(callback func(*Iterator, string) bool) bool {
|
||||
for c == ',' {
|
||||
field = iter.ReadString()
|
||||
if iter.nextToken() != ':' {
|
||||
iter.ReportError("ReadMapCB", "expect : after object field")
|
||||
iter.ReportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c}))
|
||||
return false
|
||||
}
|
||||
if !callback(iter, field) {
|
||||
@ -152,14 +152,14 @@ func (iter *Iterator) ReadMapCB(callback func(*Iterator, string) bool) bool {
|
||||
if c == '}' {
|
||||
return true
|
||||
}
|
||||
iter.ReportError("ReadMapCB", `expect " after }`)
|
||||
iter.ReportError("ReadMapCB", `expect " after }, but found `+string([]byte{c}))
|
||||
return false
|
||||
}
|
||||
if c == 'n' {
|
||||
iter.skipThreeBytes('u', 'l', 'l')
|
||||
return true // null
|
||||
}
|
||||
iter.ReportError("ReadMapCB", `expect { or n`)
|
||||
iter.ReportError("ReadMapCB", `expect { or n, but found `+string([]byte{c}))
|
||||
return false
|
||||
}
|
||||
|
||||
@ -176,7 +176,7 @@ func (iter *Iterator) readObjectStart() bool {
|
||||
iter.skipThreeBytes('u', 'l', 'l')
|
||||
return false
|
||||
}
|
||||
iter.ReportError("readObjectStart", "expect { or n")
|
||||
iter.ReportError("readObjectStart", "expect { or n, but found "+string([]byte{c}))
|
||||
return false
|
||||
}
|
||||
|
||||
@ -192,7 +192,7 @@ func (iter *Iterator) readObjectFieldAsBytes() (ret []byte) {
|
||||
}
|
||||
}
|
||||
if iter.buf[iter.head] != ':' {
|
||||
iter.ReportError("readObjectFieldAsBytes", "expect : after object field")
|
||||
iter.ReportError("readObjectFieldAsBytes", "expect : after object field, but found "+string([]byte{iter.buf[iter.head]}))
|
||||
return
|
||||
}
|
||||
iter.head++
|
||||
|
@ -25,7 +25,7 @@ func (iter *Iterator) ReadBool() (ret bool) {
|
||||
iter.skipFourBytes('a', 'l', 's', 'e')
|
||||
return false
|
||||
}
|
||||
iter.ReportError("ReadBool", "expect t or f")
|
||||
iter.ReportError("ReadBool", "expect t or f, but found "+string([]byte{c}))
|
||||
return
|
||||
}
|
||||
|
||||
@ -59,7 +59,9 @@ func (iter *Iterator) stopCapture() []byte {
|
||||
iter.captureStartedAt = -1
|
||||
iter.captured = nil
|
||||
if len(captured) == 0 {
|
||||
return remaining
|
||||
copied := make([]byte, len(remaining))
|
||||
copy(copied, remaining)
|
||||
return copied
|
||||
}
|
||||
captured = append(captured, remaining...)
|
||||
return captured
|
||||
|
@ -28,7 +28,7 @@ func (iter *Iterator) ReadString() (ret string) {
|
||||
iter.skipThreeBytes('u', 'l', 'l')
|
||||
return ""
|
||||
}
|
||||
iter.ReportError("ReadString", `expects " or n`)
|
||||
iter.ReportError("ReadString", `expects " or n, but found `+string([]byte{c}))
|
||||
return
|
||||
}
|
||||
|
||||
@ -139,7 +139,7 @@ func (iter *Iterator) ReadStringAsSlice() (ret []byte) {
|
||||
}
|
||||
return copied
|
||||
}
|
||||
iter.ReportError("ReadStringAsSlice", `expects " or n`)
|
||||
iter.ReportError("ReadStringAsSlice", `expects " or n, but found `+string([]byte{c}))
|
||||
return
|
||||
}
|
||||
|
||||
@ -156,7 +156,7 @@ func (iter *Iterator) readU4() (ret rune) {
|
||||
} else if c >= 'A' && c <= 'F' {
|
||||
ret = ret*16 + rune(c-'A'+10)
|
||||
} else {
|
||||
iter.ReportError("readU4", "expects 0~9 or a~f")
|
||||
iter.ReportError("readU4", "expects 0~9 or a~f, but found "+string([]byte{c}))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,25 @@
|
||||
package jsoniter
|
||||
|
||||
import "encoding/json"
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Number string
|
||||
|
||||
// String returns the literal text of the number.
|
||||
func (n Number) String() string { return string(n) }
|
||||
|
||||
// Float64 returns the number as a float64.
|
||||
func (n Number) Float64() (float64, error) {
|
||||
return strconv.ParseFloat(string(n), 64)
|
||||
}
|
||||
|
||||
// Int64 returns the number as an int64.
|
||||
func (n Number) Int64() (int64, error) {
|
||||
return strconv.ParseInt(string(n), 10, 64)
|
||||
}
|
||||
|
||||
func CastJsonNumber(val interface{}) (string, bool) {
|
||||
switch typedVal := val.(type) {
|
||||
case json.Number:
|
||||
|
@ -269,7 +269,7 @@ func describeStruct(cfg *frozenConfig, typ reflect.Type) (*StructDescriptor, err
|
||||
if decoder == nil {
|
||||
var err error
|
||||
decoder, err = decoderOfType(cfg, field.Type)
|
||||
if err != nil {
|
||||
if len(fieldNames) > 0 && err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@ -277,11 +277,11 @@ func describeStruct(cfg *frozenConfig, typ reflect.Type) (*StructDescriptor, err
|
||||
if encoder == nil {
|
||||
var err error
|
||||
encoder, err = encoderOfType(cfg, field.Type)
|
||||
if err != nil {
|
||||
if len(fieldNames) > 0 && err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// map is stored as pointer in the struct
|
||||
if field.Type.Kind() == reflect.Map {
|
||||
if encoder != nil && field.Type.Kind() == reflect.Map {
|
||||
encoder = &optionalEncoder{encoder}
|
||||
}
|
||||
}
|
||||
|
@ -32,11 +32,9 @@ type intCodec struct {
|
||||
}
|
||||
|
||||
func (codec *intCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||
if iter.ReadNil() {
|
||||
*((*int)(ptr)) = 0
|
||||
return
|
||||
if !iter.ReadNil() {
|
||||
*((*int)(ptr)) = iter.ReadInt()
|
||||
}
|
||||
*((*int)(ptr)) = iter.ReadInt()
|
||||
}
|
||||
|
||||
func (codec *intCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
|
||||
@ -55,11 +53,9 @@ type uintptrCodec struct {
|
||||
}
|
||||
|
||||
func (codec *uintptrCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||
if iter.ReadNil() {
|
||||
*((*uintptr)(ptr)) = 0
|
||||
return
|
||||
if !iter.ReadNil() {
|
||||
*((*uintptr)(ptr)) = uintptr(iter.ReadUint64())
|
||||
}
|
||||
*((*uintptr)(ptr)) = uintptr(iter.ReadUint64())
|
||||
}
|
||||
|
||||
func (codec *uintptrCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
|
||||
@ -78,11 +74,9 @@ type int8Codec struct {
|
||||
}
|
||||
|
||||
func (codec *int8Codec) Decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||
if iter.ReadNil() {
|
||||
*((*uint8)(ptr)) = 0
|
||||
return
|
||||
if !iter.ReadNil() {
|
||||
*((*int8)(ptr)) = iter.ReadInt8()
|
||||
}
|
||||
*((*int8)(ptr)) = iter.ReadInt8()
|
||||
}
|
||||
|
||||
func (codec *int8Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
|
||||
@ -101,11 +95,9 @@ type int16Codec struct {
|
||||
}
|
||||
|
||||
func (codec *int16Codec) Decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||
if iter.ReadNil() {
|
||||
*((*int16)(ptr)) = 0
|
||||
return
|
||||
if !iter.ReadNil() {
|
||||
*((*int16)(ptr)) = iter.ReadInt16()
|
||||
}
|
||||
*((*int16)(ptr)) = iter.ReadInt16()
|
||||
}
|
||||
|
||||
func (codec *int16Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
|
||||
@ -124,11 +116,9 @@ type int32Codec struct {
|
||||
}
|
||||
|
||||
func (codec *int32Codec) Decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||
if iter.ReadNil() {
|
||||
*((*int32)(ptr)) = 0
|
||||
return
|
||||
if !iter.ReadNil() {
|
||||
*((*int32)(ptr)) = iter.ReadInt32()
|
||||
}
|
||||
*((*int32)(ptr)) = iter.ReadInt32()
|
||||
}
|
||||
|
||||
func (codec *int32Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
|
||||
@ -147,11 +137,9 @@ type int64Codec struct {
|
||||
}
|
||||
|
||||
func (codec *int64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||
if iter.ReadNil() {
|
||||
*((*int64)(ptr)) = 0
|
||||
return
|
||||
if !iter.ReadNil() {
|
||||
*((*int64)(ptr)) = iter.ReadInt64()
|
||||
}
|
||||
*((*int64)(ptr)) = iter.ReadInt64()
|
||||
}
|
||||
|
||||
func (codec *int64Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
|
||||
@ -170,11 +158,10 @@ type uintCodec struct {
|
||||
}
|
||||
|
||||
func (codec *uintCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||
if iter.ReadNil() {
|
||||
*((*uint)(ptr)) = 0
|
||||
if !iter.ReadNil() {
|
||||
*((*uint)(ptr)) = iter.ReadUint()
|
||||
return
|
||||
}
|
||||
*((*uint)(ptr)) = iter.ReadUint()
|
||||
}
|
||||
|
||||
func (codec *uintCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
|
||||
@ -193,11 +180,9 @@ type uint8Codec struct {
|
||||
}
|
||||
|
||||
func (codec *uint8Codec) Decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||
if iter.ReadNil() {
|
||||
*((*uint8)(ptr)) = 0
|
||||
return
|
||||
if !iter.ReadNil() {
|
||||
*((*uint8)(ptr)) = iter.ReadUint8()
|
||||
}
|
||||
*((*uint8)(ptr)) = iter.ReadUint8()
|
||||
}
|
||||
|
||||
func (codec *uint8Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
|
||||
@ -216,11 +201,9 @@ type uint16Codec struct {
|
||||
}
|
||||
|
||||
func (codec *uint16Codec) Decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||
if iter.ReadNil() {
|
||||
*((*uint16)(ptr)) = 0
|
||||
return
|
||||
if !iter.ReadNil() {
|
||||
*((*uint16)(ptr)) = iter.ReadUint16()
|
||||
}
|
||||
*((*uint16)(ptr)) = iter.ReadUint16()
|
||||
}
|
||||
|
||||
func (codec *uint16Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
|
||||
@ -239,11 +222,9 @@ type uint32Codec struct {
|
||||
}
|
||||
|
||||
func (codec *uint32Codec) Decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||
if iter.ReadNil() {
|
||||
*((*uint32)(ptr)) = 0
|
||||
return
|
||||
if !iter.ReadNil() {
|
||||
*((*uint32)(ptr)) = iter.ReadUint32()
|
||||
}
|
||||
*((*uint32)(ptr)) = iter.ReadUint32()
|
||||
}
|
||||
|
||||
func (codec *uint32Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
|
||||
@ -262,11 +243,9 @@ type uint64Codec struct {
|
||||
}
|
||||
|
||||
func (codec *uint64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||
if iter.ReadNil() {
|
||||
*((*uint64)(ptr)) = 0
|
||||
return
|
||||
if !iter.ReadNil() {
|
||||
*((*uint64)(ptr)) = iter.ReadUint64()
|
||||
}
|
||||
*((*uint64)(ptr)) = iter.ReadUint64()
|
||||
}
|
||||
|
||||
func (codec *uint64Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
|
||||
@ -285,11 +264,9 @@ type float32Codec struct {
|
||||
}
|
||||
|
||||
func (codec *float32Codec) Decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||
if iter.ReadNil() {
|
||||
*((*float32)(ptr)) = 0
|
||||
return
|
||||
if !iter.ReadNil() {
|
||||
*((*float32)(ptr)) = iter.ReadFloat32()
|
||||
}
|
||||
*((*float32)(ptr)) = iter.ReadFloat32()
|
||||
}
|
||||
|
||||
func (codec *float32Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
|
||||
@ -308,11 +285,9 @@ type float64Codec struct {
|
||||
}
|
||||
|
||||
func (codec *float64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||
if iter.ReadNil() {
|
||||
*((*float64)(ptr)) = 0
|
||||
return
|
||||
if !iter.ReadNil() {
|
||||
*((*float64)(ptr)) = iter.ReadFloat64()
|
||||
}
|
||||
*((*float64)(ptr)) = iter.ReadFloat64()
|
||||
}
|
||||
|
||||
func (codec *float64Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
|
||||
@ -352,13 +327,39 @@ type emptyInterfaceCodec struct {
|
||||
}
|
||||
|
||||
func (codec *emptyInterfaceCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||
if iter.ReadNil() {
|
||||
*((*interface{})(ptr)) = nil
|
||||
existing := *((*interface{})(ptr))
|
||||
|
||||
// Checking for both typed and untyped nil pointers.
|
||||
if existing != nil &&
|
||||
reflect.TypeOf(existing).Kind() == reflect.Ptr &&
|
||||
!reflect.ValueOf(existing).IsNil() {
|
||||
|
||||
var ptrToExisting interface{}
|
||||
for {
|
||||
elem := reflect.ValueOf(existing).Elem()
|
||||
if elem.Kind() != reflect.Ptr || elem.IsNil() {
|
||||
break
|
||||
}
|
||||
ptrToExisting = existing
|
||||
existing = elem.Interface()
|
||||
}
|
||||
|
||||
if iter.ReadNil() {
|
||||
if ptrToExisting != nil {
|
||||
nilPtr := reflect.Zero(reflect.TypeOf(ptrToExisting).Elem())
|
||||
reflect.ValueOf(ptrToExisting).Elem().Set(nilPtr)
|
||||
} else {
|
||||
*((*interface{})(ptr)) = nil
|
||||
}
|
||||
} else {
|
||||
iter.ReadVal(existing)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
existing := *((*interface{})(ptr))
|
||||
if existing != nil && reflect.TypeOf(existing).Kind() == reflect.Ptr {
|
||||
iter.ReadVal(existing)
|
||||
|
||||
if iter.ReadNil() {
|
||||
*((*interface{})(ptr)) = nil
|
||||
} else {
|
||||
*((*interface{})(ptr)) = iter.Read()
|
||||
}
|
||||
@ -391,15 +392,20 @@ func (codec *nonEmptyInterfaceCodec) Decode(ptr unsafe.Pointer, iter *Iterator)
|
||||
e.typ = nonEmptyInterface.itab.typ
|
||||
e.word = nonEmptyInterface.word
|
||||
iter.ReadVal(&i)
|
||||
if e.word == nil {
|
||||
nonEmptyInterface.itab = nil
|
||||
}
|
||||
nonEmptyInterface.word = e.word
|
||||
}
|
||||
|
||||
func (codec *nonEmptyInterfaceCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
|
||||
nonEmptyInterface := (*nonEmptyInterface)(ptr)
|
||||
var i interface{}
|
||||
e := (*emptyInterface)(unsafe.Pointer(&i))
|
||||
e.typ = nonEmptyInterface.itab.typ
|
||||
e.word = nonEmptyInterface.word
|
||||
if nonEmptyInterface.itab != nil {
|
||||
e := (*emptyInterface)(unsafe.Pointer(&i))
|
||||
e.typ = nonEmptyInterface.itab.typ
|
||||
e.word = nonEmptyInterface.word
|
||||
}
|
||||
stream.WriteVal(i)
|
||||
}
|
||||
|
||||
@ -435,7 +441,15 @@ type jsonNumberCodec struct {
|
||||
}
|
||||
|
||||
func (codec *jsonNumberCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||
*((*json.Number)(ptr)) = json.Number([]byte(iter.readNumberAsString()))
|
||||
switch iter.WhatIsNext() {
|
||||
case StringValue:
|
||||
*((*json.Number)(ptr)) = json.Number(iter.ReadString())
|
||||
case NilValue:
|
||||
iter.skipFourBytes('n', 'u', 'l', 'l')
|
||||
*((*json.Number)(ptr)) = ""
|
||||
default:
|
||||
*((*json.Number)(ptr)) = json.Number([]byte(iter.readNumberAsString()))
|
||||
}
|
||||
}
|
||||
|
||||
func (codec *jsonNumberCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
|
||||
@ -454,7 +468,15 @@ type jsoniterNumberCodec struct {
|
||||
}
|
||||
|
||||
func (codec *jsoniterNumberCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||
*((*Number)(ptr)) = Number([]byte(iter.readNumberAsString()))
|
||||
switch iter.WhatIsNext() {
|
||||
case StringValue:
|
||||
*((*Number)(ptr)) = Number(iter.ReadString())
|
||||
case NilValue:
|
||||
iter.skipFourBytes('n', 'u', 'l', 'l')
|
||||
*((*Number)(ptr)) = ""
|
||||
default:
|
||||
*((*Number)(ptr)) = Number([]byte(iter.readNumberAsString()))
|
||||
}
|
||||
}
|
||||
|
||||
func (codec *jsoniterNumberCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
|
||||
@ -586,7 +608,7 @@ type stringModeNumberDecoder struct {
|
||||
func (decoder *stringModeNumberDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||
c := iter.nextToken()
|
||||
if c != '"' {
|
||||
iter.ReportError("stringModeNumberDecoder", `expect "`)
|
||||
iter.ReportError("stringModeNumberDecoder", `expect ", but found `+string([]byte{c}))
|
||||
return
|
||||
}
|
||||
decoder.elemDecoder.Decode(ptr, iter)
|
||||
@ -595,7 +617,7 @@ func (decoder *stringModeNumberDecoder) Decode(ptr unsafe.Pointer, iter *Iterato
|
||||
}
|
||||
c = iter.readByte()
|
||||
if c != '"' {
|
||||
iter.ReportError("stringModeNumberDecoder", `expect "`)
|
||||
iter.ReportError("stringModeNumberDecoder", `expect ", but found `+string([]byte{c}))
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -660,7 +682,11 @@ func (encoder *marshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
|
||||
templateInterface := encoder.templateInterface
|
||||
templateInterface.word = ptr
|
||||
realInterface := (*interface{})(unsafe.Pointer(&templateInterface))
|
||||
marshaler := (*realInterface).(json.Marshaler)
|
||||
marshaler, ok := (*realInterface).(json.Marshaler)
|
||||
if !ok {
|
||||
stream.WriteVal(nil)
|
||||
return
|
||||
}
|
||||
|
||||
bytes, err := marshaler.MarshalJSON()
|
||||
if err != nil {
|
||||
|
@ -191,6 +191,9 @@ func (stream *Stream) ensure(minimal int) {
|
||||
func (stream *Stream) growAtLeast(minimal int) {
|
||||
if stream.out != nil {
|
||||
stream.Flush()
|
||||
if stream.Available() >= minimal {
|
||||
return
|
||||
}
|
||||
}
|
||||
toGrow := len(stream.buf)
|
||||
if toGrow < minimal {
|
||||
@ -280,8 +283,7 @@ func (stream *Stream) WriteArrayStart() {
|
||||
|
||||
// WriteEmptyArray write []
|
||||
func (stream *Stream) WriteEmptyArray() {
|
||||
stream.writeByte('[')
|
||||
stream.writeByte(']')
|
||||
stream.writeTwoBytes('[', ']')
|
||||
}
|
||||
|
||||
// WriteArrayEnd write ] with possible indention
|
||||
|
@ -92,22 +92,22 @@ func Test_bool_can_be_null(t *testing.T) {
|
||||
obj := TestData{}
|
||||
data1 := []byte(`{"field": true}`)
|
||||
err := Unmarshal(data1, &obj)
|
||||
should.Equal(nil, err)
|
||||
should.NoError(err)
|
||||
should.Equal(true, obj.Field)
|
||||
|
||||
data2 := []byte(`{"field": null}`)
|
||||
err = Unmarshal(data2, &obj)
|
||||
should.Equal(nil, err)
|
||||
should.NoError(err)
|
||||
// Same behavior as stdlib, not touching the existing value.
|
||||
should.Equal(true, obj.Field)
|
||||
|
||||
// Checking stdlib behavior as well
|
||||
obj2 := TestData{}
|
||||
err = json.Unmarshal(data1, &obj2)
|
||||
should.Equal(nil, err)
|
||||
should.NoError(err)
|
||||
should.Equal(true, obj2.Field)
|
||||
|
||||
err = json.Unmarshal(data2, &obj2)
|
||||
should.Equal(nil, err)
|
||||
should.NoError(err)
|
||||
should.Equal(true, obj2.Field)
|
||||
}
|
||||
|
@ -2,11 +2,12 @@ package jsoniter
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/stretchr/testify/require"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func Test_customize_type_decoder(t *testing.T) {
|
||||
@ -82,7 +83,7 @@ func Test_customize_field_decoder(t *testing.T) {
|
||||
}
|
||||
|
||||
type TestObject1 struct {
|
||||
field1 string
|
||||
Field1 string
|
||||
}
|
||||
|
||||
type testExtension struct {
|
||||
@ -93,7 +94,7 @@ func (extension *testExtension) UpdateStructDescriptor(structDescriptor *StructD
|
||||
if structDescriptor.Type.String() != "jsoniter.TestObject1" {
|
||||
return
|
||||
}
|
||||
binding := structDescriptor.GetField("field1")
|
||||
binding := structDescriptor.GetField("Field1")
|
||||
binding.Encoder = &funcEncoder{fun: func(ptr unsafe.Pointer, stream *Stream) {
|
||||
str := *((*string)(ptr))
|
||||
val, _ := strconv.Atoi(str)
|
||||
@ -112,7 +113,7 @@ func Test_customize_field_by_extension(t *testing.T) {
|
||||
obj := TestObject1{}
|
||||
err := UnmarshalFromString(`{"field-1": 100}`, &obj)
|
||||
should.Nil(err)
|
||||
should.Equal("100", obj.field1)
|
||||
should.Equal("100", obj.Field1)
|
||||
str, err := MarshalToString(obj)
|
||||
should.Nil(err)
|
||||
should.Equal(`{"field-1":100}`, str)
|
||||
|
@ -40,11 +40,11 @@ func Test_custom_marshaler_on_enum(t *testing.T) {
|
||||
w := Wrapper{Payload: MyEnumB}
|
||||
|
||||
jb, err := Marshal(w)
|
||||
should.Equal(nil, err)
|
||||
should.NoError(err)
|
||||
should.Equal(`{"Payload":"foo-1"}`, string(jb))
|
||||
|
||||
var w2 Wrapper2
|
||||
err = Unmarshal(jb, &w2)
|
||||
should.Equal(nil, err)
|
||||
should.NoError(err)
|
||||
should.Equal(MyEnumB, w2.Payload)
|
||||
}
|
||||
|
@ -506,6 +506,30 @@ func Test_jsoniter_number(t *testing.T) {
|
||||
should.Equal("1", str)
|
||||
}
|
||||
|
||||
func Test_non_numeric_as_number(t *testing.T) {
|
||||
should := require.New(t)
|
||||
var v1 json.Number
|
||||
err := Unmarshal([]byte(`"500"`), &v1)
|
||||
should.Nil(err)
|
||||
should.Equal("500", string(v1))
|
||||
var v2 Number
|
||||
err = Unmarshal([]byte(`"500"`), &v2)
|
||||
should.Nil(err)
|
||||
should.Equal("500", string(v2))
|
||||
}
|
||||
|
||||
func Test_null_as_number(t *testing.T) {
|
||||
should := require.New(t)
|
||||
var v1 json.Number
|
||||
err := json.Unmarshal([]byte(`null`), &v1)
|
||||
should.Nil(err)
|
||||
should.Equal("", string(v1))
|
||||
var v2 Number
|
||||
err = Unmarshal([]byte(`null`), &v2)
|
||||
should.Nil(err)
|
||||
should.Equal("", string(v2))
|
||||
}
|
||||
|
||||
func Benchmark_jsoniter_encode_int(b *testing.B) {
|
||||
stream := NewStream(ConfigDefault, ioutil.Discard, 64)
|
||||
for n := 0; n < b.N; n++ {
|
||||
|
@ -329,13 +329,13 @@ func Test_nil_out_null_interface(t *testing.T) {
|
||||
data1 := []byte(`{"field": true}`)
|
||||
|
||||
err := Unmarshal(data1, &obj)
|
||||
should.Equal(nil, err)
|
||||
should.NoError(err)
|
||||
should.Equal(true, *(obj.Field.(*bool)))
|
||||
|
||||
data2 := []byte(`{"field": null}`)
|
||||
|
||||
err = Unmarshal(data2, &obj)
|
||||
should.Equal(nil, err)
|
||||
should.NoError(err)
|
||||
should.Equal(nil, obj.Field)
|
||||
|
||||
// Checking stdlib behavior matches.
|
||||
@ -344,11 +344,11 @@ func Test_nil_out_null_interface(t *testing.T) {
|
||||
}
|
||||
|
||||
err = json.Unmarshal(data1, &obj2)
|
||||
should.Equal(nil, err)
|
||||
should.NoError(err)
|
||||
should.Equal(true, *(obj2.Field.(*bool)))
|
||||
|
||||
err = json.Unmarshal(data2, &obj2)
|
||||
should.Equal(nil, err)
|
||||
should.NoError(err)
|
||||
should.Equal(nil, obj2.Field)
|
||||
}
|
||||
|
||||
@ -363,10 +363,198 @@ func Test_omitempty_nil_interface(t *testing.T) {
|
||||
}
|
||||
|
||||
js, err := json.Marshal(obj)
|
||||
should.Equal(nil, err)
|
||||
should.NoError(err)
|
||||
should.Equal("{}", string(js))
|
||||
|
||||
str, err := MarshalToString(obj)
|
||||
should.Equal(nil, err)
|
||||
should.NoError(err)
|
||||
should.Equal(string(js), str)
|
||||
}
|
||||
|
||||
func Test_omitempty_nil_nonempty_interface(t *testing.T) {
|
||||
type TestData struct {
|
||||
Field MyInterface `json:"field,omitempty"`
|
||||
}
|
||||
should := require.New(t)
|
||||
|
||||
obj := TestData{
|
||||
Field: nil,
|
||||
}
|
||||
|
||||
js, err := json.Marshal(obj)
|
||||
should.NoError(err)
|
||||
should.Equal("{}", string(js))
|
||||
|
||||
str, err := MarshalToString(obj)
|
||||
should.NoError(err)
|
||||
should.Equal(string(js), str)
|
||||
|
||||
obj.Field = MyString("hello")
|
||||
err = UnmarshalFromString(`{"field":null}`, &obj)
|
||||
should.NoError(err)
|
||||
should.Equal(nil, obj.Field)
|
||||
}
|
||||
|
||||
func Test_marshal_nil_marshaler_interface(t *testing.T) {
|
||||
type TestData struct {
|
||||
Field json.Marshaler `json:"field"`
|
||||
}
|
||||
should := require.New(t)
|
||||
|
||||
obj := TestData{
|
||||
Field: nil,
|
||||
}
|
||||
|
||||
js, err := json.Marshal(obj)
|
||||
should.NoError(err)
|
||||
should.Equal(`{"field":null}`, string(js))
|
||||
|
||||
str, err := MarshalToString(obj)
|
||||
should.NoError(err)
|
||||
should.Equal(string(js), str)
|
||||
}
|
||||
|
||||
func Test_marshal_nil_nonempty_interface(t *testing.T) {
|
||||
type TestData struct {
|
||||
Field MyInterface `json:"field"`
|
||||
}
|
||||
should := require.New(t)
|
||||
|
||||
obj := TestData{
|
||||
Field: nil,
|
||||
}
|
||||
|
||||
js, err := json.Marshal(obj)
|
||||
should.NoError(err)
|
||||
should.Equal(`{"field":null}`, string(js))
|
||||
|
||||
str, err := MarshalToString(obj)
|
||||
should.NoError(err)
|
||||
should.Equal(string(js), str)
|
||||
|
||||
obj.Field = MyString("hello")
|
||||
err = Unmarshal(js, &obj)
|
||||
should.NoError(err)
|
||||
should.Equal(nil, obj.Field)
|
||||
}
|
||||
|
||||
func Test_overwrite_interface_ptr_value_with_nil(t *testing.T) {
|
||||
type Wrapper struct {
|
||||
Payload interface{} `json:"payload,omitempty"`
|
||||
}
|
||||
type Payload struct {
|
||||
Value int `json:"val,omitempty"`
|
||||
}
|
||||
|
||||
should := require.New(t)
|
||||
|
||||
payload := &Payload{}
|
||||
wrapper := &Wrapper{
|
||||
Payload: &payload,
|
||||
}
|
||||
|
||||
err := json.Unmarshal([]byte(`{"payload": {"val": 42}}`), &wrapper)
|
||||
should.Equal(nil, err)
|
||||
should.Equal(&payload, wrapper.Payload)
|
||||
should.Equal(42, (*(wrapper.Payload.(**Payload))).Value)
|
||||
|
||||
err = json.Unmarshal([]byte(`{"payload": null}`), &wrapper)
|
||||
should.Equal(nil, err)
|
||||
should.Equal(&payload, wrapper.Payload)
|
||||
should.Equal((*Payload)(nil), payload)
|
||||
|
||||
payload = &Payload{}
|
||||
wrapper = &Wrapper{
|
||||
Payload: &payload,
|
||||
}
|
||||
|
||||
err = Unmarshal([]byte(`{"payload": {"val": 42}}`), &wrapper)
|
||||
should.Equal(nil, err)
|
||||
should.Equal(&payload, wrapper.Payload)
|
||||
should.Equal(42, (*(wrapper.Payload.(**Payload))).Value)
|
||||
|
||||
err = Unmarshal([]byte(`{"payload": null}`), &wrapper)
|
||||
should.Equal(nil, err)
|
||||
should.Equal(&payload, wrapper.Payload)
|
||||
should.Equal((*Payload)(nil), payload)
|
||||
}
|
||||
|
||||
func Test_overwrite_interface_value_with_nil(t *testing.T) {
|
||||
type Wrapper struct {
|
||||
Payload interface{} `json:"payload,omitempty"`
|
||||
}
|
||||
type Payload struct {
|
||||
Value int `json:"val,omitempty"`
|
||||
}
|
||||
|
||||
should := require.New(t)
|
||||
|
||||
payload := &Payload{}
|
||||
wrapper := &Wrapper{
|
||||
Payload: payload,
|
||||
}
|
||||
|
||||
err := json.Unmarshal([]byte(`{"payload": {"val": 42}}`), &wrapper)
|
||||
should.Equal(nil, err)
|
||||
should.Equal(42, (*(wrapper.Payload.(*Payload))).Value)
|
||||
|
||||
err = json.Unmarshal([]byte(`{"payload": null}`), &wrapper)
|
||||
should.Equal(nil, err)
|
||||
should.Equal(nil, wrapper.Payload)
|
||||
should.Equal(42, payload.Value)
|
||||
|
||||
payload = &Payload{}
|
||||
wrapper = &Wrapper{
|
||||
Payload: payload,
|
||||
}
|
||||
|
||||
err = Unmarshal([]byte(`{"payload": {"val": 42}}`), &wrapper)
|
||||
should.Equal(nil, err)
|
||||
should.Equal(42, (*(wrapper.Payload.(*Payload))).Value)
|
||||
|
||||
err = Unmarshal([]byte(`{"payload": null}`), &wrapper)
|
||||
should.Equal(nil, err)
|
||||
should.Equal(nil, wrapper.Payload)
|
||||
should.Equal(42, payload.Value)
|
||||
}
|
||||
|
||||
func Test_unmarshal_into_nil(t *testing.T) {
|
||||
type Payload struct {
|
||||
Value int `json:"val,omitempty"`
|
||||
}
|
||||
type Wrapper struct {
|
||||
Payload interface{} `json:"payload,omitempty"`
|
||||
}
|
||||
|
||||
should := require.New(t)
|
||||
|
||||
var payload *Payload
|
||||
wrapper := &Wrapper{
|
||||
Payload: payload,
|
||||
}
|
||||
|
||||
err := json.Unmarshal([]byte(`{"payload": {"val": 42}}`), &wrapper)
|
||||
should.Nil(err)
|
||||
should.NotNil(wrapper.Payload)
|
||||
should.Nil(payload)
|
||||
|
||||
err = json.Unmarshal([]byte(`{"payload": null}`), &wrapper)
|
||||
should.Nil(err)
|
||||
should.Nil(wrapper.Payload)
|
||||
should.Nil(payload)
|
||||
|
||||
payload = nil
|
||||
wrapper = &Wrapper{
|
||||
Payload: payload,
|
||||
}
|
||||
|
||||
err = Unmarshal([]byte(`{"payload": {"val": 42}}`), &wrapper)
|
||||
should.Nil(err)
|
||||
should.NotNil(wrapper.Payload)
|
||||
should.Nil(payload)
|
||||
|
||||
err = Unmarshal([]byte(`{"payload": null}`), &wrapper)
|
||||
should.Nil(err)
|
||||
should.Nil(wrapper.Payload)
|
||||
should.Nil(payload)
|
||||
}
|
||||
|
@ -130,3 +130,9 @@ func Test_invalid_number(t *testing.T) {
|
||||
should.Nil(err)
|
||||
should.Equal(string(result2), string(result))
|
||||
}
|
||||
|
||||
func Test_valid(t *testing.T) {
|
||||
should := require.New(t)
|
||||
should.True(Valid([]byte(`{}`)))
|
||||
should.False(Valid([]byte(`{`)))
|
||||
}
|
||||
|
@ -3,9 +3,10 @@ package jsoniter
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"github.com/stretchr/testify/require"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func Test_read_null(t *testing.T) {
|
||||
@ -135,3 +136,33 @@ func Test_encode_nil_array(t *testing.T) {
|
||||
should.Nil(err)
|
||||
should.Equal("null", string(output))
|
||||
}
|
||||
|
||||
func Test_decode_nil_num(t *testing.T) {
|
||||
type TestData struct {
|
||||
Field int `json:"field"`
|
||||
}
|
||||
should := require.New(t)
|
||||
|
||||
data1 := []byte(`{"field": 42}`)
|
||||
data2 := []byte(`{"field": null}`)
|
||||
|
||||
// Checking stdlib behavior as well
|
||||
obj2 := TestData{}
|
||||
err := json.Unmarshal(data1, &obj2)
|
||||
should.Equal(nil, err)
|
||||
should.Equal(42, obj2.Field)
|
||||
|
||||
err = json.Unmarshal(data2, &obj2)
|
||||
should.Equal(nil, err)
|
||||
should.Equal(42, obj2.Field)
|
||||
|
||||
obj := TestData{}
|
||||
|
||||
err = Unmarshal(data1, &obj)
|
||||
should.Equal(nil, err)
|
||||
should.Equal(42, obj.Field)
|
||||
|
||||
err = Unmarshal(data2, &obj)
|
||||
should.Equal(nil, err)
|
||||
should.Equal(42, obj.Field)
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package jsoniter
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/stretchr/testify/require"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@ -86,3 +87,28 @@ func Test_marshal_invalid_json_raw_message(t *testing.T) {
|
||||
should.Equal(`{"raw":null}`, string(aout))
|
||||
should.Nil(aouterr)
|
||||
}
|
||||
|
||||
func Test_raw_message_memory_not_copied_issue(t *testing.T) {
|
||||
jsonStream := `{"name":"xxxxx","bundle_id":"com.zonst.majiang","app_platform":"ios","app_category":"100103", "budget_day":1000,"bidding_min":1,"bidding_max":2,"bidding_type":"CPM", "freq":{"open":true,"type":"day","num":100},"speed":1, "targeting":{"vendor":{"open":true,"list":["zonst"]}, "geo_code":{"open":true,"list":["156110100"]},"app_category":{"open":true,"list":["100101"]}, "day_parting":{"open":true,"list":["100409","100410"]},"device_type":{"open":true,"list":["ipad"]}, "os_version":{"open":true,"list":[10]},"carrier":{"open":true,"list":["mobile"]}, "network":{"open":true,"list":["4G"]}},"url":{"tracking_imp_url":"http://www.baidu.com", "tracking_clk_url":"http://www.baidu.com","jump_url":"http://www.baidu.com","deep_link_url":"http://www.baidu.com"}}`
|
||||
type IteratorObject struct {
|
||||
Name *string `json:"name"`
|
||||
BundleId *string `json:"bundle_id"`
|
||||
AppCategory *string `json:"app_category"`
|
||||
AppPlatform *string `json:"app_platform"`
|
||||
BudgetDay *float32 `json:"budget_day"`
|
||||
BiddingMax *float32 `json:"bidding_max"`
|
||||
BiddingMin *float32 `json:"bidding_min"`
|
||||
BiddingType *string `json:"bidding_type"`
|
||||
Freq *RawMessage `json:"freq"`
|
||||
Targeting *RawMessage `json:"targeting"`
|
||||
Url *RawMessage `json:"url"`
|
||||
Speed *int `json:"speed" db:"speed"`
|
||||
}
|
||||
|
||||
obj := &IteratorObject{}
|
||||
decoder := NewDecoder(strings.NewReader(jsonStream))
|
||||
err := decoder.Decode(obj)
|
||||
should := require.New(t)
|
||||
should.Nil(err)
|
||||
should.Equal(`{"open":true,"type":"day","num":100}`, string(*obj.Freq))
|
||||
}
|
||||
|
@ -51,3 +51,19 @@ func Test_writeString_should_grow_buffer(t *testing.T) {
|
||||
should.Nil(stream.Error)
|
||||
should.Equal(`"123"`, string(stream.Buffer()))
|
||||
}
|
||||
|
||||
type NopWriter struct {
|
||||
bufferSize int
|
||||
}
|
||||
|
||||
func (w *NopWriter) Write(p []byte) (n int, err error) {
|
||||
w.bufferSize = cap(p)
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func Test_flush_buffer_should_stop_grow_buffer(t *testing.T) {
|
||||
writer := new(NopWriter)
|
||||
NewEncoder(writer).Encode(make([]int, 10000000))
|
||||
should := require.New(t)
|
||||
should.Equal(512, writer.bufferSize)
|
||||
}
|
||||
|
52
jsoniter_struct_encoder_test.go
Normal file
52
jsoniter_struct_encoder_test.go
Normal file
@ -0,0 +1,52 @@
|
||||
package jsoniter
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func Test_encode_unexported_field(t *testing.T) {
|
||||
type TestData struct {
|
||||
a int
|
||||
b <-chan int
|
||||
C int
|
||||
d *time.Timer
|
||||
}
|
||||
|
||||
should := require.New(t)
|
||||
|
||||
testChan := make(<-chan int, 10)
|
||||
testTimer := time.NewTimer(10 * time.Second)
|
||||
|
||||
obj := &TestData{
|
||||
a: 42,
|
||||
b: testChan,
|
||||
C: 21,
|
||||
d: testTimer,
|
||||
}
|
||||
|
||||
jb, err := json.Marshal(obj)
|
||||
should.NoError(err)
|
||||
should.Equal([]byte(`{"C":21}`), jb)
|
||||
|
||||
err = json.Unmarshal([]byte(`{"a": 444, "b":"bad", "C":55, "d":{"not": "a timer"}}`), obj)
|
||||
should.NoError(err)
|
||||
should.Equal(42, obj.a)
|
||||
should.Equal(testChan, obj.b)
|
||||
should.Equal(55, obj.C)
|
||||
should.Equal(testTimer, obj.d)
|
||||
|
||||
jb, err = Marshal(obj)
|
||||
should.NoError(err)
|
||||
should.Equal(jb, []byte(`{"C":55}`))
|
||||
|
||||
err = Unmarshal([]byte(`{"a": 444, "b":"bad", "C":256, "d":{"not":"a timer"}}`), obj)
|
||||
should.NoError(err)
|
||||
should.Equal(42, obj.a)
|
||||
should.Equal(testChan, obj.b)
|
||||
should.Equal(256, obj.C)
|
||||
should.Equal(testTimer, obj.d)
|
||||
}
|
Reference in New Issue
Block a user