1
0
mirror of https://github.com/json-iterator/go.git synced 2025-06-15 22:50:24 +02:00

16 Commits
1.1.0 ... 1.1.3

83 changed files with 789 additions and 429 deletions

28
Gopkg.lock generated
View File

@ -2,32 +2,20 @@
[[projects]] [[projects]]
name = "github.com/davecgh/go-spew" name = "github.com/modern-go/concurrent"
packages = ["spew"]
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
version = "v1.1.0"
[[projects]]
branch = "master"
name = "github.com/google/gofuzz"
packages = ["."] packages = ["."]
revision = "24818f796faf91cd76ec7bddd72458fbced7a6c1" revision = "e0a39a4cb4216ea8db28e22a69f4ec25610d513a"
version = "1.0.0"
[[projects]] [[projects]]
name = "github.com/pmezard/go-difflib" name = "github.com/modern-go/reflect2"
packages = ["difflib"] packages = ["."]
revision = "792786c7400a136282c1664665ae0a8db921c6c2" revision = "1df9eeb2bb81f327b96228865c5687bc2194af3f"
version = "v1.0.0" version = "1.0.0"
[[projects]]
name = "github.com/stretchr/testify"
packages = ["assert","require"]
revision = "69483b4bd14f5845b5a1e55bca19e954e827f1d0"
version = "v1.1.4"
[solve-meta] [solve-meta]
analyzer-name = "dep" analyzer-name = "dep"
analyzer-version = 1 analyzer-version = 1
inputs-digest = "f8b7cf3941d3792cbbd570bb53c093adaf774334d1162c651565c97a58dc9d09" inputs-digest = "ac7003b5a981716353a43055ab7d4c5357403cb30a60de2dbdeb446c1544beaa"
solver-name = "gps-cdcl" solver-name = "gps-cdcl"
solver-version = 1 solver-version = 1

View File

@ -19,15 +19,8 @@
# name = "github.com/x/y" # name = "github.com/x/y"
# version = "2.4.0" # version = "2.4.0"
ignored = ["github.com/davecgh/go-spew*","github.com/google/gofuzz*","github.com/stretchr/testify*"]
[[constraint]] [[constraint]]
name = "github.com/davecgh/go-spew" name = "github.com/modern-go/reflect2"
version = "1.1.0" version = "1.0.0"
[[constraint]]
branch = "master"
name = "github.com/google/gofuzz"
[[constraint]]
name = "github.com/stretchr/testify"
version = "1.1.4"

14
any.go
View File

@ -3,10 +3,11 @@ package jsoniter
import ( import (
"errors" "errors"
"fmt" "fmt"
"github.com/modern-go/reflect2"
"io" "io"
"reflect" "reflect"
"strconv"
"unsafe" "unsafe"
"github.com/v2pro/plz/reflect2"
) )
// Any generic object representation. // Any generic object representation.
@ -101,6 +102,9 @@ func Wrap(val interface{}) Any {
case reflect.String: case reflect.String:
return WrapString(val.(string)) return WrapString(val.(string))
case reflect.Int: case reflect.Int:
if strconv.IntSize == 32 {
return WrapInt32(int32(val.(int)))
}
return WrapInt64(int64(val.(int))) return WrapInt64(int64(val.(int)))
case reflect.Int8: case reflect.Int8:
return WrapInt32(int32(val.(int8))) return WrapInt32(int32(val.(int8)))
@ -111,7 +115,15 @@ func Wrap(val interface{}) Any {
case reflect.Int64: case reflect.Int64:
return WrapInt64(val.(int64)) return WrapInt64(val.(int64))
case reflect.Uint: case reflect.Uint:
if strconv.IntSize == 32 {
return WrapUint32(uint32(val.(uint)))
}
return WrapUint64(uint64(val.(uint))) return WrapUint64(uint64(val.(uint)))
case reflect.Uintptr:
if ptrSize == 32 {
return WrapUint32(uint32(val.(uintptr)))
}
return WrapUint64(uint64(val.(uintptr)))
case reflect.Uint8: case reflect.Uint8:
return WrapUint32(uint32(val.(uint8))) return WrapUint32(uint32(val.(uint8)))
case reflect.Uint16: case reflect.Uint16:

View File

@ -3,8 +3,8 @@ package any_tests
import ( import (
"testing" "testing"
"github.com/stretchr/testify/require"
"github.com/json-iterator/go" "github.com/json-iterator/go"
"github.com/stretchr/testify/require"
) )
func Test_read_empty_array_as_any(t *testing.T) { func Test_read_empty_array_as_any(t *testing.T) {

View File

@ -4,8 +4,8 @@ import (
"fmt" "fmt"
"testing" "testing"
"github.com/stretchr/testify/require"
"github.com/json-iterator/go" "github.com/json-iterator/go"
"github.com/stretchr/testify/require"
) )
var boolConvertMap = map[string]bool{ var boolConvertMap = map[string]bool{

View File

@ -3,8 +3,8 @@ package any_tests
import ( import (
"testing" "testing"
"github.com/stretchr/testify/require"
"github.com/json-iterator/go" "github.com/json-iterator/go"
"github.com/stretchr/testify/require"
) )
var floatConvertMap = map[string]float64{ var floatConvertMap = map[string]float64{

View File

@ -4,8 +4,8 @@ import (
"fmt" "fmt"
"testing" "testing"
"github.com/stretchr/testify/require"
"github.com/json-iterator/go" "github.com/json-iterator/go"
"github.com/stretchr/testify/require"
) )
var intConvertMap = map[string]int{ var intConvertMap = map[string]int{

View File

@ -1,9 +1,9 @@
package any_tests package any_tests
import ( import (
"github.com/json-iterator/go"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"testing" "testing"
"github.com/json-iterator/go"
) )
func Test_wrap_map(t *testing.T) { func Test_wrap_map(t *testing.T) {

View File

@ -1,9 +1,9 @@
package any_tests package any_tests
import ( import (
"github.com/json-iterator/go"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"testing" "testing"
"github.com/json-iterator/go"
) )
func Test_read_null_as_any(t *testing.T) { func Test_read_null_as_any(t *testing.T) {

View File

@ -3,8 +3,8 @@ package any_tests
import ( import (
"testing" "testing"
"github.com/stretchr/testify/require"
"github.com/json-iterator/go" "github.com/json-iterator/go"
"github.com/stretchr/testify/require"
) )
func Test_read_object_as_any(t *testing.T) { func Test_read_object_as_any(t *testing.T) {

View File

@ -3,8 +3,8 @@ package any_tests
import ( import (
"testing" "testing"
"github.com/stretchr/testify/require"
"github.com/json-iterator/go" "github.com/json-iterator/go"
"github.com/stretchr/testify/require"
) )
var stringConvertMap = map[string]string{ var stringConvertMap = map[string]string{

View File

@ -3,8 +3,8 @@ package any_tests
import ( import (
"testing" "testing"
"github.com/stretchr/testify/require"
"github.com/json-iterator/go" "github.com/json-iterator/go"
"github.com/stretchr/testify/require"
) )
// if must be valid is useless, just drop this test // if must be valid is useless, just drop this test

View File

@ -3,8 +3,8 @@ package any_tests
import ( import (
"testing" "testing"
"github.com/stretchr/testify/require"
"github.com/json-iterator/go" "github.com/json-iterator/go"
"github.com/stretchr/testify/require"
) )
func Test_wrap_and_valuetype_everything(t *testing.T) { func Test_wrap_and_valuetype_everything(t *testing.T) {

View File

@ -1,10 +1,10 @@
package test package test
import ( import (
"testing"
"github.com/stretchr/testify/require"
"github.com/json-iterator/go"
"encoding/json" "encoding/json"
"github.com/json-iterator/go"
"github.com/stretchr/testify/require"
"testing"
) )
func Test_use_number_for_unmarshal(t *testing.T) { func Test_use_number_for_unmarshal(t *testing.T) {
@ -23,7 +23,6 @@ func Test_customize_float_marshal(t *testing.T) {
should.Equal("1.234568", str) should.Equal("1.234568", str)
} }
func Test_customize_tag_key(t *testing.T) { func Test_customize_tag_key(t *testing.T) {
type TestObject struct { type TestObject struct {

View File

@ -2,11 +2,11 @@ package test
import ( import (
"bytes" "bytes"
"github.com/stretchr/testify/require"
"testing"
"github.com/json-iterator/go"
"io/ioutil"
"encoding/json" "encoding/json"
"github.com/json-iterator/go"
"github.com/stretchr/testify/require"
"io/ioutil"
"testing"
) )
func Test_disallowUnknownFields(t *testing.T) { func Test_disallowUnknownFields(t *testing.T) {
@ -18,7 +18,6 @@ func Test_disallowUnknownFields(t *testing.T) {
should.Error(decoder.Decode(&obj)) should.Error(decoder.Decode(&obj))
} }
func Test_new_decoder(t *testing.T) { func Test_new_decoder(t *testing.T) {
should := require.New(t) should := require.New(t)
decoder1 := json.NewDecoder(bytes.NewBufferString(`[1][2]`)) decoder1 := json.NewDecoder(bytes.NewBufferString(`[1][2]`))

View File

@ -8,8 +8,8 @@ import (
"testing" "testing"
"unicode/utf8" "unicode/utf8"
"github.com/stretchr/testify/require"
"github.com/json-iterator/go" "github.com/json-iterator/go"
"github.com/stretchr/testify/require"
) )
func Test_new_encoder(t *testing.T) { func Test_new_encoder(t *testing.T) {

View File

@ -1,11 +1,11 @@
package test package test
import ( import (
"testing"
"github.com/stretchr/testify/require"
"bytes" "bytes"
"github.com/json-iterator/go"
"encoding/json" "encoding/json"
"github.com/json-iterator/go"
"github.com/stretchr/testify/require"
"testing"
) )
// Standard Encoder has trailing newline. // Standard Encoder has trailing newline.

View File

@ -2,9 +2,9 @@ package test
import ( import (
"encoding/json" "encoding/json"
"github.com/json-iterator/go"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"testing" "testing"
"github.com/json-iterator/go"
) )
func Test_marshal_indent(t *testing.T) { func Test_marshal_indent(t *testing.T) {

View File

@ -2,10 +2,10 @@ package test
import ( import (
"encoding/json" "encoding/json"
"github.com/json-iterator/go"
"io/ioutil" "io/ioutil"
"os" "os"
"testing" "testing"
"github.com/json-iterator/go"
) )
//func Test_large_file(t *testing.T) { //func Test_large_file(t *testing.T) {

View File

@ -2,10 +2,12 @@ package jsoniter
import ( import (
"encoding/json" "encoding/json"
"github.com/modern-go/concurrent"
"github.com/modern-go/reflect2"
"io" "io"
"unsafe" "reflect"
"github.com/v2pro/plz/reflect2"
"sync" "sync"
"unsafe"
) )
// Config customize how the API should behave. // Config customize how the API should behave.
@ -38,6 +40,8 @@ type API interface {
NewDecoder(reader io.Reader) *Decoder NewDecoder(reader io.Reader) *Decoder
Valid(data []byte) bool Valid(data []byte) bool
RegisterExtension(extension Extension) RegisterExtension(extension Extension)
DecoderOf(typ reflect2.Type) ValDecoder
EncoderOf(typ reflect2.Type) ValEncoder
} }
// ConfigDefault the default API // ConfigDefault the default API
@ -59,6 +63,63 @@ var ConfigFastest = Config{
ObjectFieldMustBeSimpleString: true, // do not unescape object field ObjectFieldMustBeSimpleString: true, // do not unescape object field
}.Froze() }.Froze()
type frozenConfig struct {
configBeforeFrozen Config
sortMapKeys bool
indentionStep int
objectFieldMustBeSimpleString bool
onlyTaggedField bool
disallowUnknownFields bool
decoderCache *concurrent.Map
encoderCache *concurrent.Map
extensions []Extension
streamPool *sync.Pool
iteratorPool *sync.Pool
}
func (cfg *frozenConfig) initCache() {
cfg.decoderCache = concurrent.NewMap()
cfg.encoderCache = concurrent.NewMap()
}
func (cfg *frozenConfig) addDecoderToCache(cacheKey uintptr, decoder ValDecoder) {
cfg.decoderCache.Store(cacheKey, decoder)
}
func (cfg *frozenConfig) addEncoderToCache(cacheKey uintptr, encoder ValEncoder) {
cfg.encoderCache.Store(cacheKey, encoder)
}
func (cfg *frozenConfig) getDecoderFromCache(cacheKey uintptr) ValDecoder {
decoder, found := cfg.decoderCache.Load(cacheKey)
if found {
return decoder.(ValDecoder)
}
return nil
}
func (cfg *frozenConfig) getEncoderFromCache(cacheKey uintptr) ValEncoder {
encoder, found := cfg.encoderCache.Load(cacheKey)
if found {
return encoder.(ValEncoder)
}
return nil
}
var cfgCache = concurrent.NewMap()
func getFrozenConfigFromCache(cfg Config) *frozenConfig {
obj, found := cfgCache.Load(cfg)
if found {
return obj.(*frozenConfig)
}
return nil
}
func addFrozenConfigToCache(cfg Config, frozenConfig *frozenConfig) {
cfgCache.Store(cfg, frozenConfig)
}
// Froze forge API from config // Froze forge API from config
func (cfg Config) Froze() API { func (cfg Config) Froze() API {
api := &frozenConfig{ api := &frozenConfig{
@ -133,6 +194,11 @@ func (cfg *frozenConfig) validateJsonRawMessage(extension EncoderExtension) {
func (cfg *frozenConfig) useNumber(extension DecoderExtension) { func (cfg *frozenConfig) useNumber(extension DecoderExtension) {
extension[reflect2.TypeOfPtr((*interface{})(nil)).Elem()] = &funcDecoder{func(ptr unsafe.Pointer, iter *Iterator) { extension[reflect2.TypeOfPtr((*interface{})(nil)).Elem()] = &funcDecoder{func(ptr unsafe.Pointer, iter *Iterator) {
exitingValue := *((*interface{})(ptr))
if exitingValue != nil && reflect.TypeOf(exitingValue).Kind() == reflect.Ptr {
iter.ReadVal(exitingValue)
return
}
if iter.WhatIsNext() == NumberValue { if iter.WhatIsNext() == NumberValue {
*((*interface{})(ptr)) = json.Number(iter.readNumberAsString()) *((*interface{})(ptr)) = json.Number(iter.readNumberAsString())
} else { } else {

View File

@ -1,64 +0,0 @@
//+build go1.9
package jsoniter
import (
"sync"
)
type frozenConfig struct {
configBeforeFrozen Config
sortMapKeys bool
indentionStep int
objectFieldMustBeSimpleString bool
onlyTaggedField bool
disallowUnknownFields bool
decoderCache sync.Map
encoderCache sync.Map
extensions []Extension
streamPool *sync.Pool
iteratorPool *sync.Pool
}
func (cfg *frozenConfig) initCache() {
cfg.decoderCache = sync.Map{}
cfg.encoderCache = sync.Map{}
}
func (cfg *frozenConfig) addDecoderToCache(cacheKey uintptr, decoder ValDecoder) {
cfg.decoderCache.Store(cacheKey, decoder)
}
func (cfg *frozenConfig) addEncoderToCache(cacheKey uintptr, encoder ValEncoder) {
cfg.encoderCache.Store(cacheKey, encoder)
}
func (cfg *frozenConfig) getDecoderFromCache(cacheKey uintptr) ValDecoder {
decoder, found := cfg.decoderCache.Load(cacheKey)
if found {
return decoder.(ValDecoder)
}
return nil
}
func (cfg *frozenConfig) getEncoderFromCache(cacheKey uintptr) ValEncoder {
encoder, found := cfg.encoderCache.Load(cacheKey)
if found {
return encoder.(ValEncoder)
}
return nil
}
var cfgCache = &sync.Map{}
func getFrozenConfigFromCache(cfg Config) *frozenConfig {
obj, found := cfgCache.Load(cfg)
if found {
return obj.(*frozenConfig)
}
return nil
}
func addFrozenConfigToCache(cfg Config, frozenConfig *frozenConfig) {
cfgCache.Store(cfg, frozenConfig)
}

View File

@ -1,70 +0,0 @@
//+build !go1.9
package jsoniter
import (
"sync"
)
type frozenConfig struct {
configBeforeFrozen Config
sortMapKeys bool
indentionStep int
objectFieldMustBeSimpleString bool
onlyTaggedField bool
disallowUnknownFields bool
cacheLock *sync.RWMutex
decoderCache map[uintptr]ValDecoder
encoderCache map[uintptr]ValEncoder
extensions []Extension
streamPool *sync.Pool
iteratorPool *sync.Pool
}
func (cfg *frozenConfig) initCache() {
cfg.cacheLock = &sync.RWMutex{}
cfg.decoderCache = map[uintptr]ValDecoder{}
cfg.encoderCache = map[uintptr]ValEncoder{}
}
func (cfg *frozenConfig) addDecoderToCache(cacheKey uintptr, decoder ValDecoder) {
cfg.cacheLock.Lock()
cfg.decoderCache[cacheKey] = decoder
cfg.cacheLock.Unlock()
}
func (cfg *frozenConfig) addEncoderToCache(cacheKey uintptr, encoder ValEncoder) {
cfg.cacheLock.Lock()
cfg.encoderCache[cacheKey] = encoder
cfg.cacheLock.Unlock()
}
func (cfg *frozenConfig) getDecoderFromCache(cacheKey uintptr) ValDecoder {
cfg.cacheLock.RLock()
decoder, _ := cfg.decoderCache[cacheKey].(ValDecoder)
cfg.cacheLock.RUnlock()
return decoder
}
func (cfg *frozenConfig) getEncoderFromCache(cacheKey uintptr) ValEncoder {
cfg.cacheLock.RLock()
encoder, _ := cfg.encoderCache[cacheKey].(ValEncoder)
cfg.cacheLock.RUnlock()
return encoder
}
var cfgCacheLock = &sync.RWMutex{}
var cfgCache = map[Config]*frozenConfig{}
func getFrozenConfigFromCache(cfg Config) *frozenConfig {
cfgCacheLock.RLock()
frozenConfig := cfgCache[cfg]
cfgCacheLock.RUnlock()
return frozenConfig
}
func addFrozenConfigToCache(cfg Config, frozenConfig *frozenConfig) {
cfgCacheLock.Lock()
cfgCache[cfg] = frozenConfig
cfgCacheLock.Unlock()
}

View File

@ -3,6 +3,7 @@ package jsoniter
import ( import (
"fmt" "fmt"
"os" "os"
"strings"
) )
func ExampleMarshal() { func ExampleMarshal() {
@ -93,3 +94,28 @@ func ExampleGet() {
// Output: // Output:
// Crimson // Crimson
} }
func ExampleMapKey() {
hello := MyKey("hello")
output, _ := Marshal(map[*MyKey]string{&hello: "world"})
fmt.Println(string(output))
obj := map[*MyKey]string{}
Unmarshal(output, &obj)
for k, v := range obj {
fmt.Println(*k, v)
}
// Output:
// {"Hello":"world"}
// Hel world
}
type MyKey string
func (m *MyKey) MarshalText() ([]byte, error) {
return []byte(strings.Replace(string(*m), "h", "H", -1)), nil
}
func (m *MyKey) UnmarshalText(text []byte) error {
*m = MyKey(text[:3])
return nil
}

View File

@ -1,12 +1,12 @@
package test package test
import ( import (
"testing"
"unsafe"
"time"
"github.com/json-iterator/go" "github.com/json-iterator/go"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"strconv" "strconv"
"testing"
"time"
"unsafe"
) )
func Test_customize_type_decoder(t *testing.T) { func Test_customize_type_decoder(t *testing.T) {
@ -61,7 +61,6 @@ func Test_customize_field_decoder(t *testing.T) {
} }
} }
func Test_recursive_empty_interface_customization(t *testing.T) { func Test_recursive_empty_interface_customization(t *testing.T) {
t.Skip() t.Skip()
var obj interface{} var obj interface{}

View File

@ -1,11 +1,13 @@
package test package test
import ( import (
"unsafe" "github.com/json-iterator/go"
"github.com/modern-go/reflect2"
"github.com/stretchr/testify/require"
"reflect"
"strconv" "strconv"
"testing" "testing"
"github.com/stretchr/testify/require" "unsafe"
"github.com/json-iterator/go"
) )
type TestObject1 struct { type TestObject1 struct {
@ -46,6 +48,53 @@ func Test_customize_field_by_extension(t *testing.T) {
should.Equal(`{"field-1":100}`, str) should.Equal(`{"field-1":100}`, str)
} }
func Test_customize_map_key_encoder(t *testing.T) {
should := require.New(t)
cfg := jsoniter.Config{}.Froze()
cfg.RegisterExtension(&testMapKeyExtension{})
m := map[int]int{1: 2}
output, err := cfg.MarshalToString(m)
should.NoError(err)
should.Equal(`{"2":2}`, output)
m = map[int]int{}
should.NoError(cfg.UnmarshalFromString(output, &m))
should.Equal(map[int]int{1: 2}, m)
}
type testMapKeyExtension struct {
jsoniter.DummyExtension
}
func (extension *testMapKeyExtension) CreateMapKeyEncoder(typ reflect2.Type) jsoniter.ValEncoder {
if typ.Kind() == reflect.Int {
return &funcEncoder{
fun: func(ptr unsafe.Pointer, stream *jsoniter.Stream) {
stream.WriteRaw(`"`)
stream.WriteInt(*(*int)(ptr) + 1)
stream.WriteRaw(`"`)
},
}
}
return nil
}
func (extension *testMapKeyExtension) CreateMapKeyDecoder(typ reflect2.Type) jsoniter.ValDecoder {
if typ.Kind() == reflect.Int {
return &funcDecoder{
fun: func(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
i, err := strconv.Atoi(iter.ReadString())
if err != nil {
iter.ReportError("read map key", err.Error())
return
}
i--
*(*int)(ptr) = i
},
}
}
return nil
}
type funcDecoder struct { type funcDecoder struct {
fun jsoniter.DecoderFunc fun jsoniter.DecoderFunc
} }

View File

@ -0,0 +1,238 @@
package extra
import (
"github.com/json-iterator/go"
"github.com/modern-go/reflect2"
"unicode/utf8"
"unsafe"
)
// safeSet holds the value true if the ASCII character with the given array
// position can be represented inside a JSON string without any further
// escaping.
//
// All values are true except for the ASCII control characters (0-31), the
// double quote ("), and the backslash character ("\").
var safeSet = [utf8.RuneSelf]bool{
' ': true,
'!': true,
'"': false,
'#': true,
'$': true,
'%': true,
'&': true,
'\'': true,
'(': true,
')': true,
'*': true,
'+': true,
',': true,
'-': true,
'.': true,
'/': true,
'0': true,
'1': true,
'2': true,
'3': true,
'4': true,
'5': true,
'6': true,
'7': true,
'8': true,
'9': true,
':': true,
';': true,
'<': true,
'=': true,
'>': true,
'?': true,
'@': true,
'A': true,
'B': true,
'C': true,
'D': true,
'E': true,
'F': true,
'G': true,
'H': true,
'I': true,
'J': true,
'K': true,
'L': true,
'M': true,
'N': true,
'O': true,
'P': true,
'Q': true,
'R': true,
'S': true,
'T': true,
'U': true,
'V': true,
'W': true,
'X': true,
'Y': true,
'Z': true,
'[': true,
'\\': false,
']': true,
'^': true,
'_': true,
'`': true,
'a': true,
'b': true,
'c': true,
'd': true,
'e': true,
'f': true,
'g': true,
'h': true,
'i': true,
'j': true,
'k': true,
'l': true,
'm': true,
'n': true,
'o': true,
'p': true,
'q': true,
'r': true,
's': true,
't': true,
'u': true,
'v': true,
'w': true,
'x': true,
'y': true,
'z': true,
'{': true,
'|': true,
'}': true,
'~': true,
'\u007f': true,
}
var binaryType = reflect2.TypeOfPtr((*[]byte)(nil)).Elem()
type BinaryAsStringExtension struct {
jsoniter.DummyExtension
}
func (extension *BinaryAsStringExtension) CreateEncoder(typ reflect2.Type) jsoniter.ValEncoder {
if typ == binaryType {
return &binaryAsStringCodec{}
}
return nil
}
func (extension *BinaryAsStringExtension) CreateDecoder(typ reflect2.Type) jsoniter.ValDecoder {
if typ == binaryType {
return &binaryAsStringCodec{}
}
return nil
}
type binaryAsStringCodec struct {
}
func (codec *binaryAsStringCodec) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
rawBytes := iter.ReadStringAsSlice()
bytes := make([]byte, 0, len(rawBytes))
for i := 0; i < len(rawBytes); i++ {
b := rawBytes[i]
if b == '\\' {
b2 := rawBytes[i+1]
if b2 != '\\' {
iter.ReportError("decode binary as string", `\\x is only supported escape`)
return
}
b3 := rawBytes[i+2]
if b3 != 'x' {
iter.ReportError("decode binary as string", `\\x is only supported escape`)
return
}
b4 := rawBytes[i+3]
b5 := rawBytes[i+4]
i = i + 4
b = readHex(iter, b4, b5)
}
bytes = append(bytes, b)
}
*(*[]byte)(ptr) = bytes
}
func (codec *binaryAsStringCodec) IsEmpty(ptr unsafe.Pointer) bool {
return len(*((*[]byte)(ptr))) == 0
}
func (codec *binaryAsStringCodec) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
newBuffer := writeBytes(stream.Buffer(), *(*[]byte)(ptr))
stream.SetBuffer(newBuffer)
}
func readHex(iter *jsoniter.Iterator, b1, b2 byte) byte {
var ret byte
if b1 >= '0' && b1 <= '9' {
ret = b1 - '0'
} else if b1 >= 'a' && b1 <= 'f' {
ret = b1 - 'a' + 10
} else {
iter.ReportError("read hex", "expects 0~9 or a~f, but found "+string([]byte{b1}))
return 0
}
ret = ret * 16
if b2 >= '0' && b2 <= '9' {
ret = b2 - '0'
} else if b2 >= 'a' && b2 <= 'f' {
ret = b2 - 'a' + 10
} else {
iter.ReportError("read hex", "expects 0~9 or a~f, but found "+string([]byte{b2}))
return 0
}
return ret
}
var hex = "0123456789abcdef"
func writeBytes(space []byte, s []byte) []byte {
space = append(space, '"')
// write string, the fast path, without utf8 and escape support
var i int
var c byte
for i, c = range s {
if c < utf8.RuneSelf && safeSet[c] {
space = append(space, c)
} else {
break
}
}
if i == len(s)-1 {
space = append(space, '"')
return space
}
return writeBytesSlowPath(space, s[i:])
}
func writeBytesSlowPath(space []byte, s []byte) []byte {
start := 0
// for the remaining parts, we process them char by char
var i int
var b byte
for i, b = range s {
if b >= utf8.RuneSelf {
space = append(space, '\\', '\\', 'x', hex[b>>4], hex[b&0xF])
start = i + 1
continue
}
if safeSet[b] {
continue
}
if start < i {
space = append(space, s[start:i]...)
}
space = append(space, '\\', '\\', 'x', hex[b>>4], hex[b&0xF])
start = i + 1
}
if start < len(s) {
space = append(space, s[start:]...)
}
return append(space, '"')
}

View File

@ -0,0 +1,32 @@
package extra
import (
"github.com/json-iterator/go"
"github.com/stretchr/testify/require"
"testing"
)
func init() {
jsoniter.RegisterExtension(&BinaryAsStringExtension{})
}
func TestBinaryAsStringCodec(t *testing.T) {
t.Run("safe set", func(t *testing.T) {
should := require.New(t)
output, err := jsoniter.Marshal([]byte("hello"))
should.NoError(err)
should.Equal(`"hello"`, string(output))
var val []byte
should.NoError(jsoniter.Unmarshal(output, &val))
should.Equal(`hello`, string(val))
})
t.Run("non safe set", func(t *testing.T) {
should := require.New(t)
output, err := jsoniter.Marshal([]byte{1, 2, 3, 15})
should.NoError(err)
should.Equal(`"\\x01\\x02\\x03\\x0f"`, string(output))
var val []byte
should.NoError(jsoniter.Unmarshal(output, &val))
should.Equal([]byte{1, 2, 3, 15}, val)
})
}

View File

@ -9,7 +9,7 @@ import (
"unsafe" "unsafe"
"github.com/json-iterator/go" "github.com/json-iterator/go"
"github.com/v2pro/plz/reflect2" "github.com/modern-go/reflect2"
) )
const maxUint = ^uint(0) const maxUint = ^uint(0)
@ -183,6 +183,9 @@ func (decoder *fuzzyStringDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Ite
*((*string)(ptr)) = string(number) *((*string)(ptr)) = string(number)
case jsoniter.StringValue: case jsoniter.StringValue:
*((*string)(ptr)) = iter.ReadString() *((*string)(ptr)) = iter.ReadString()
case jsoniter.NilValue:
iter.Skip()
*((*string)(ptr)) = ""
default: default:
iter.ReportError("fuzzyStringDecoder", "not number or string") iter.ReportError("fuzzyStringDecoder", "not number or string")
} }
@ -208,6 +211,9 @@ func (decoder *fuzzyIntegerDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.It
} else { } else {
str = "0" str = "0"
} }
case jsoniter.NilValue:
iter.Skip()
str = "0"
default: default:
iter.ReportError("fuzzyIntegerDecoder", "not number or string") iter.ReportError("fuzzyIntegerDecoder", "not number or string")
} }
@ -244,6 +250,9 @@ func (decoder *fuzzyFloat32Decoder) Decode(ptr unsafe.Pointer, iter *jsoniter.It
} else { } else {
*((*float32)(ptr)) = 0 *((*float32)(ptr)) = 0
} }
case jsoniter.NilValue:
iter.Skip()
*((*float32)(ptr)) = 0
default: default:
iter.ReportError("fuzzyFloat32Decoder", "not number or string") iter.ReportError("fuzzyFloat32Decoder", "not number or string")
} }
@ -273,7 +282,10 @@ func (decoder *fuzzyFloat64Decoder) Decode(ptr unsafe.Pointer, iter *jsoniter.It
} else { } else {
*((*float64)(ptr)) = 0 *((*float64)(ptr)) = 0
} }
case jsoniter.NilValue:
iter.Skip()
*((*float64)(ptr)) = 0
default: default:
iter.ReportError("fuzzyFloat32Decoder", "not number or string") iter.ReportError("fuzzyFloat64Decoder", "not number or string")
} }
} }

View File

@ -357,3 +357,35 @@ func Test_bad_case(t *testing.T) {
should := require.New(t) should := require.New(t)
should.Nil(err) should.Nil(err)
} }
func Test_null_to_string(t *testing.T) {
should := require.New(t)
body := []byte(`null`)
var message string
err := jsoniter.Unmarshal(body, &message)
should.NoError(err)
}
func Test_null_to_int(t *testing.T) {
should := require.New(t)
body := []byte(`null`)
var message int
err := jsoniter.Unmarshal(body, &message)
should.NoError(err)
}
func Test_null_to_float32(t *testing.T) {
should := require.New(t)
body := []byte(`null`)
var message float32
err := jsoniter.Unmarshal(body, &message)
should.NoError(err)
}
func Test_null_to_float64(t *testing.T) {
should := require.New(t)
body := []byte(`null`)
var message float64
err := jsoniter.Unmarshal(body, &message)
should.NoError(err)
}

View File

@ -22,11 +22,17 @@ func init() {
// ReadUint read uint // ReadUint read uint
func (iter *Iterator) ReadUint() uint { func (iter *Iterator) ReadUint() uint {
if strconv.IntSize == 32 {
return uint(iter.ReadUint32())
}
return uint(iter.ReadUint64()) return uint(iter.ReadUint64())
} }
// ReadInt read int // ReadInt read int
func (iter *Iterator) ReadInt() int { func (iter *Iterator) ReadInt() int {
if strconv.IntSize == 32 {
return int(iter.ReadInt32())
}
return int(iter.ReadInt64()) return int(iter.ReadInt64())
} }

View File

@ -3,9 +3,9 @@ package misc_tests
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"github.com/json-iterator/go"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"testing" "testing"
"github.com/json-iterator/go"
) )
func Test_empty_array(t *testing.T) { func Test_empty_array(t *testing.T) {

View File

@ -4,8 +4,8 @@ import (
"bytes" "bytes"
"testing" "testing"
"github.com/stretchr/testify/require"
"github.com/json-iterator/go" "github.com/json-iterator/go"
"github.com/stretchr/testify/require"
) )
func Test_true(t *testing.T) { func Test_true(t *testing.T) {

View File

@ -4,8 +4,8 @@ import (
"encoding/json" "encoding/json"
"testing" "testing"
"github.com/stretchr/testify/require"
"github.com/json-iterator/go" "github.com/json-iterator/go"
"github.com/stretchr/testify/require"
) )
func Test_read_big_float(t *testing.T) { func Test_read_big_float(t *testing.T) {

View File

@ -9,8 +9,8 @@ import (
"strconv" "strconv"
"testing" "testing"
"github.com/stretchr/testify/require"
"github.com/json-iterator/go" "github.com/json-iterator/go"
"github.com/stretchr/testify/require"
) )
func Test_read_uint64_invalid(t *testing.T) { func Test_read_uint64_invalid(t *testing.T) {

View File

@ -2,10 +2,10 @@ package misc_tests
import ( import (
"encoding/json" "encoding/json"
"testing"
"github.com/stretchr/testify/require"
"github.com/json-iterator/go" "github.com/json-iterator/go"
"github.com/stretchr/testify/require"
"io" "io"
"testing"
) )
func Test_nil_non_empty_interface(t *testing.T) { func Test_nil_non_empty_interface(t *testing.T) {

View File

@ -7,8 +7,8 @@ import (
"strconv" "strconv"
"testing" "testing"
"github.com/stretchr/testify/require"
"github.com/json-iterator/go" "github.com/json-iterator/go"
"github.com/stretchr/testify/require"
) )
func Test_bad_case(t *testing.T) { func Test_bad_case(t *testing.T) {

View File

@ -5,9 +5,9 @@ import (
"math/big" "math/big"
"testing" "testing"
"github.com/json-iterator/go"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"strings" "strings"
"github.com/json-iterator/go"
) )
func Test_decode_TextMarshaler_key_map(t *testing.T) { func Test_decode_TextMarshaler_key_map(t *testing.T) {
@ -31,3 +31,14 @@ func Test_read_map_with_reader(t *testing.T) {
should.Equal(m2, m1) should.Equal(m2, m1)
should.Equal("1.0.76", m1["note"].(map[string]interface{})["CoreServices"].(map[string]interface{})["version_name"]) should.Equal("1.0.76", m1["note"].(map[string]interface{})["CoreServices"].(map[string]interface{})["version_name"])
} }
func Test_map_eface_of_eface(t *testing.T) {
should := require.New(t)
json := jsoniter.ConfigCompatibleWithStandardLibrary
output, err := json.MarshalToString(map[interface{}]interface{}{
"1": 2,
3: "4",
})
should.NoError(err)
should.Equal(`{"1":2,"3":"4"}`, output)
}

View File

@ -2,9 +2,9 @@ package misc_tests
import ( import (
"encoding/json" "encoding/json"
"github.com/json-iterator/go"
"reflect" "reflect"
"testing" "testing"
"github.com/json-iterator/go"
) )
type Level1 struct { type Level1 struct {

View File

@ -5,8 +5,8 @@ import (
"io" "io"
"testing" "testing"
"github.com/stretchr/testify/require"
"github.com/json-iterator/go" "github.com/json-iterator/go"
"github.com/stretchr/testify/require"
) )
func Test_read_null(t *testing.T) { func Test_read_null(t *testing.T) {

View File

@ -4,10 +4,10 @@ import (
"bytes" "bytes"
"testing" "testing"
"github.com/stretchr/testify/require"
"github.com/json-iterator/go" "github.com/json-iterator/go"
"time" "github.com/stretchr/testify/require"
"strings" "strings"
"time"
) )
func Test_empty_object(t *testing.T) { func Test_empty_object(t *testing.T) {
@ -130,3 +130,20 @@ func Test_reader_and_load_more(t *testing.T) {
obj := TestObject{} obj := TestObject{}
should.Nil(decoder.Decode(&obj)) should.Nil(decoder.Decode(&obj))
} }
func Test_unmarshal_into_existing_value(t *testing.T) {
should := require.New(t)
type TestObject struct {
Field1 int
Field2 interface{}
}
var obj TestObject
m := map[string]interface{}{}
obj.Field2 = &m
cfg := jsoniter.Config{UseNumber: true}.Froze()
err := cfg.Unmarshal([]byte(`{"Field1":1,"Field2":{"k":"v"}}`), &obj)
should.NoError(err)
should.Equal(map[string]interface{}{
"k": "v",
}, m)
}

View File

@ -2,10 +2,10 @@ package misc_tests
import ( import (
"encoding/json" "encoding/json"
"github.com/json-iterator/go"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"strings" "strings"
"testing" "testing"
"github.com/json-iterator/go"
) )
func Test_jsoniter_RawMessage(t *testing.T) { func Test_jsoniter_RawMessage(t *testing.T) {

View File

@ -2,9 +2,9 @@ package jsoniter
import ( import (
"fmt" "fmt"
"github.com/modern-go/reflect2"
"reflect" "reflect"
"unsafe" "unsafe"
"github.com/v2pro/plz/reflect2"
) )
// ValDecoder is an internal type registered to cache as needed. // ValDecoder is an internal type registered to cache as needed.

View File

@ -2,9 +2,9 @@ package jsoniter
import ( import (
"fmt" "fmt"
"github.com/modern-go/reflect2"
"io" "io"
"unsafe" "unsafe"
"github.com/v2pro/plz/reflect2"
) )
func decoderOfArray(ctx *ctx, typ reflect2.Type) ValDecoder { func decoderOfArray(ctx *ctx, typ reflect2.Type) ValDecoder {

View File

@ -1,9 +1,9 @@
package jsoniter package jsoniter
import ( import (
"github.com/v2pro/plz/reflect2" "github.com/modern-go/reflect2"
"unsafe"
"reflect" "reflect"
"unsafe"
) )
type dynamicEncoder struct { type dynamicEncoder struct {

View File

@ -2,12 +2,12 @@ package jsoniter
import ( import (
"fmt" "fmt"
"github.com/modern-go/reflect2"
"reflect" "reflect"
"sort" "sort"
"strings" "strings"
"unicode" "unicode"
"unsafe" "unsafe"
"github.com/v2pro/plz/reflect2"
) )
var typeDecoders = map[string]ValDecoder{} var typeDecoders = map[string]ValDecoder{}
@ -47,6 +47,8 @@ type Binding struct {
// Can also rename fields by UpdateStructDescriptor. // Can also rename fields by UpdateStructDescriptor.
type Extension interface { type Extension interface {
UpdateStructDescriptor(structDescriptor *StructDescriptor) UpdateStructDescriptor(structDescriptor *StructDescriptor)
CreateMapKeyDecoder(typ reflect2.Type) ValDecoder
CreateMapKeyEncoder(typ reflect2.Type) ValEncoder
CreateDecoder(typ reflect2.Type) ValDecoder CreateDecoder(typ reflect2.Type) ValDecoder
CreateEncoder(typ reflect2.Type) ValEncoder CreateEncoder(typ reflect2.Type) ValEncoder
DecorateDecoder(typ reflect2.Type, decoder ValDecoder) ValDecoder DecorateDecoder(typ reflect2.Type, decoder ValDecoder) ValDecoder
@ -61,6 +63,16 @@ type DummyExtension struct {
func (extension *DummyExtension) UpdateStructDescriptor(structDescriptor *StructDescriptor) { func (extension *DummyExtension) UpdateStructDescriptor(structDescriptor *StructDescriptor) {
} }
// CreateMapKeyDecoder No-op
func (extension *DummyExtension) CreateMapKeyDecoder(typ reflect2.Type) ValDecoder {
return nil
}
// CreateMapKeyEncoder No-op
func (extension *DummyExtension) CreateMapKeyEncoder(typ reflect2.Type) ValEncoder {
return nil
}
// CreateDecoder No-op // CreateDecoder No-op
func (extension *DummyExtension) CreateDecoder(typ reflect2.Type) ValDecoder { func (extension *DummyExtension) CreateDecoder(typ reflect2.Type) ValDecoder {
return nil return nil
@ -97,6 +109,16 @@ func (extension EncoderExtension) CreateEncoder(typ reflect2.Type) ValEncoder {
return extension[typ] return extension[typ]
} }
// CreateMapKeyDecoder No-op
func (extension EncoderExtension) CreateMapKeyDecoder(typ reflect2.Type) ValDecoder {
return nil
}
// CreateMapKeyEncoder No-op
func (extension EncoderExtension) CreateMapKeyEncoder(typ reflect2.Type) ValEncoder {
return nil
}
// DecorateDecoder No-op // DecorateDecoder No-op
func (extension EncoderExtension) DecorateDecoder(typ reflect2.Type, decoder ValDecoder) ValDecoder { func (extension EncoderExtension) DecorateDecoder(typ reflect2.Type, decoder ValDecoder) ValDecoder {
return decoder return decoder
@ -113,6 +135,16 @@ type DecoderExtension map[reflect2.Type]ValDecoder
func (extension DecoderExtension) UpdateStructDescriptor(structDescriptor *StructDescriptor) { func (extension DecoderExtension) UpdateStructDescriptor(structDescriptor *StructDescriptor) {
} }
// CreateMapKeyDecoder No-op
func (extension DecoderExtension) CreateMapKeyDecoder(typ reflect2.Type) ValDecoder {
return nil
}
// CreateMapKeyEncoder No-op
func (extension DecoderExtension) CreateMapKeyEncoder(typ reflect2.Type) ValEncoder {
return nil
}
// CreateDecoder get decoder from map // CreateDecoder get decoder from map
func (extension DecoderExtension) CreateDecoder(typ reflect2.Type) ValDecoder { func (extension DecoderExtension) CreateDecoder(typ reflect2.Type) ValDecoder {
return extension[typ] return extension[typ]

View File

@ -2,9 +2,9 @@ package jsoniter
import ( import (
"encoding/json" "encoding/json"
"github.com/modern-go/reflect2"
"strconv" "strconv"
"unsafe" "unsafe"
"github.com/v2pro/plz/reflect2"
) )
type Number string type Number string

View File

@ -1,9 +1,9 @@
package jsoniter package jsoniter
import ( import (
"unsafe"
"encoding/json" "encoding/json"
"github.com/v2pro/plz/reflect2" "github.com/modern-go/reflect2"
"unsafe"
) )
var jsonRawMessageType = reflect2.TypeOfPtr((*json.RawMessage)(nil)).Elem() var jsonRawMessageType = reflect2.TypeOfPtr((*json.RawMessage)(nil)).Elem()

View File

@ -1,11 +1,12 @@
package jsoniter package jsoniter
import ( import (
"fmt"
"github.com/modern-go/reflect2"
"io"
"reflect" "reflect"
"sort" "sort"
"unsafe" "unsafe"
"github.com/v2pro/plz/reflect2"
"fmt"
) )
func decoderOfMap(ctx *ctx, typ reflect2.Type) ValDecoder { func decoderOfMap(ctx *ctx, typ reflect2.Type) ValDecoder {
@ -38,6 +39,12 @@ func encoderOfMap(ctx *ctx, typ reflect2.Type) ValEncoder {
} }
func decoderOfMapKey(ctx *ctx, typ reflect2.Type) ValDecoder { func decoderOfMapKey(ctx *ctx, typ reflect2.Type) ValDecoder {
for _, extension := range ctx.extensions {
decoder := extension.CreateMapKeyDecoder(typ)
if decoder != nil {
return decoder
}
}
switch typ.Kind() { switch typ.Kind() {
case reflect.String: case reflect.String:
return decoderOfType(ctx, reflect2.DefaultTypeOfKind(reflect.String)) return decoderOfType(ctx, reflect2.DefaultTypeOfKind(reflect.String))
@ -70,6 +77,12 @@ func decoderOfMapKey(ctx *ctx, typ reflect2.Type) ValDecoder {
} }
func encoderOfMapKey(ctx *ctx, typ reflect2.Type) ValEncoder { func encoderOfMapKey(ctx *ctx, typ reflect2.Type) ValEncoder {
for _, extension := range ctx.extensions {
encoder := extension.CreateMapKeyEncoder(typ)
if encoder != nil {
return encoder
}
}
switch typ.Kind() { switch typ.Kind() {
case reflect.String: case reflect.String:
return encoderOfType(ctx, reflect2.DefaultTypeOfKind(reflect.String)) return encoderOfType(ctx, reflect2.DefaultTypeOfKind(reflect.String))
@ -95,6 +108,9 @@ func encoderOfMapKey(ctx *ctx, typ reflect2.Type) ValEncoder {
stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")), stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")),
} }
} }
if typ.Kind() == reflect.Interface {
return &dynamicMapKeyEncoder{ctx, typ}
}
return &lazyErrorEncoder{err: fmt.Errorf("unsupported map key type: %v", typ)} return &lazyErrorEncoder{err: fmt.Errorf("unsupported map key type: %v", typ)}
} }
} }
@ -191,6 +207,21 @@ func (encoder *numericMapKeyEncoder) IsEmpty(ptr unsafe.Pointer) bool {
return false return false
} }
type dynamicMapKeyEncoder struct {
ctx *ctx
valType reflect2.Type
}
func (encoder *dynamicMapKeyEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
obj := encoder.valType.UnsafeIndirect(ptr)
encoderOfMapKey(encoder.ctx, reflect2.TypeOf(obj)).Encode(reflect2.PtrOf(obj), stream)
}
func (encoder *dynamicMapKeyEncoder) IsEmpty(ptr unsafe.Pointer) bool {
obj := encoder.valType.UnsafeIndirect(ptr)
return encoderOfMapKey(encoder.ctx, reflect2.TypeOf(obj)).IsEmpty(reflect2.PtrOf(obj))
}
type mapEncoder struct { type mapEncoder struct {
mapType *reflect2.UnsafeMapType mapType *reflect2.UnsafeMapType
keyEncoder ValEncoder keyEncoder ValEncoder
@ -241,6 +272,9 @@ func (encoder *sortKeysMapEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
subStream.buf = make([]byte, 0, 64) subStream.buf = make([]byte, 0, 64)
key, elem := mapIter.UnsafeNext() key, elem := mapIter.UnsafeNext()
encoder.keyEncoder.Encode(key, subStream) encoder.keyEncoder.Encode(key, subStream)
if subStream.Error != nil && subStream.Error != io.EOF && stream.Error == nil {
stream.Error = subStream.Error
}
encodedKey := subStream.Buffer() encodedKey := subStream.Buffer()
subIter.ResetBytes(encodedKey) subIter.ResetBytes(encodedKey)
decodedKey := subIter.ReadString() decodedKey := subIter.ReadString()

View File

@ -1,10 +1,10 @@
package jsoniter package jsoniter
import ( import (
"github.com/v2pro/plz/reflect2"
"unsafe"
"encoding" "encoding"
"encoding/json" "encoding/json"
"github.com/modern-go/reflect2"
"unsafe"
) )
var marshalerType = reflect2.TypeOfPtr((*json.Marshaler)(nil)).Elem() var marshalerType = reflect2.TypeOfPtr((*json.Marshaler)(nil)).Elem()

View File

@ -2,11 +2,14 @@ package jsoniter
import ( import (
"encoding/base64" "encoding/base64"
"github.com/modern-go/reflect2"
"reflect" "reflect"
"strconv"
"unsafe" "unsafe"
"github.com/v2pro/plz/reflect2"
) )
const ptrSize = 32 << uintptr(^uintptr(0)>>63)
func createEncoderOfNative(ctx *ctx, typ reflect2.Type) ValEncoder { func createEncoderOfNative(ctx *ctx, typ reflect2.Type) ValEncoder {
if typ.Kind() == reflect.Slice && typ.(reflect2.SliceType).Elem().Kind() == reflect.Uint8 { if typ.Kind() == reflect.Slice && typ.(reflect2.SliceType).Elem().Kind() == reflect.Uint8 {
sliceDecoder := decoderOfSlice(ctx, typ) sliceDecoder := decoderOfSlice(ctx, typ)
@ -24,7 +27,10 @@ func createEncoderOfNative(ctx *ctx, typ reflect2.Type) ValEncoder {
if typeName != "int" { if typeName != "int" {
return encoderOfType(ctx, reflect2.TypeOfPtr((*int)(nil)).Elem()) return encoderOfType(ctx, reflect2.TypeOfPtr((*int)(nil)).Elem())
} }
return &intCodec{} if strconv.IntSize == 32 {
return &int32Codec{}
}
return &int64Codec{}
case reflect.Int8: case reflect.Int8:
if typeName != "int8" { if typeName != "int8" {
return encoderOfType(ctx, reflect2.TypeOfPtr((*int8)(nil)).Elem()) return encoderOfType(ctx, reflect2.TypeOfPtr((*int8)(nil)).Elem())
@ -49,7 +55,10 @@ func createEncoderOfNative(ctx *ctx, typ reflect2.Type) ValEncoder {
if typeName != "uint" { if typeName != "uint" {
return encoderOfType(ctx, reflect2.TypeOfPtr((*uint)(nil)).Elem()) return encoderOfType(ctx, reflect2.TypeOfPtr((*uint)(nil)).Elem())
} }
return &uintCodec{} if strconv.IntSize == 32 {
return &uint32Codec{}
}
return &uint64Codec{}
case reflect.Uint8: case reflect.Uint8:
if typeName != "uint8" { if typeName != "uint8" {
return encoderOfType(ctx, reflect2.TypeOfPtr((*uint8)(nil)).Elem()) return encoderOfType(ctx, reflect2.TypeOfPtr((*uint8)(nil)).Elem())
@ -69,7 +78,10 @@ func createEncoderOfNative(ctx *ctx, typ reflect2.Type) ValEncoder {
if typeName != "uintptr" { if typeName != "uintptr" {
return encoderOfType(ctx, reflect2.TypeOfPtr((*uintptr)(nil)).Elem()) return encoderOfType(ctx, reflect2.TypeOfPtr((*uintptr)(nil)).Elem())
} }
return &uintptrCodec{} if ptrSize == 32 {
return &uint32Codec{}
}
return &uint64Codec{}
case reflect.Uint64: case reflect.Uint64:
if typeName != "uint64" { if typeName != "uint64" {
return encoderOfType(ctx, reflect2.TypeOfPtr((*uint64)(nil)).Elem()) return encoderOfType(ctx, reflect2.TypeOfPtr((*uint64)(nil)).Elem())
@ -110,7 +122,10 @@ func createDecoderOfNative(ctx *ctx, typ reflect2.Type) ValDecoder {
if typeName != "int" { if typeName != "int" {
return decoderOfType(ctx, reflect2.TypeOfPtr((*int)(nil)).Elem()) return decoderOfType(ctx, reflect2.TypeOfPtr((*int)(nil)).Elem())
} }
return &intCodec{} if strconv.IntSize == 32 {
return &int32Codec{}
}
return &int64Codec{}
case reflect.Int8: case reflect.Int8:
if typeName != "int8" { if typeName != "int8" {
return decoderOfType(ctx, reflect2.TypeOfPtr((*int8)(nil)).Elem()) return decoderOfType(ctx, reflect2.TypeOfPtr((*int8)(nil)).Elem())
@ -135,7 +150,10 @@ func createDecoderOfNative(ctx *ctx, typ reflect2.Type) ValDecoder {
if typeName != "uint" { if typeName != "uint" {
return decoderOfType(ctx, reflect2.TypeOfPtr((*uint)(nil)).Elem()) return decoderOfType(ctx, reflect2.TypeOfPtr((*uint)(nil)).Elem())
} }
return &uintCodec{} if strconv.IntSize == 32 {
return &uint32Codec{}
}
return &uint64Codec{}
case reflect.Uint8: case reflect.Uint8:
if typeName != "uint8" { if typeName != "uint8" {
return decoderOfType(ctx, reflect2.TypeOfPtr((*uint8)(nil)).Elem()) return decoderOfType(ctx, reflect2.TypeOfPtr((*uint8)(nil)).Elem())
@ -155,7 +173,10 @@ func createDecoderOfNative(ctx *ctx, typ reflect2.Type) ValDecoder {
if typeName != "uintptr" { if typeName != "uintptr" {
return decoderOfType(ctx, reflect2.TypeOfPtr((*uintptr)(nil)).Elem()) return decoderOfType(ctx, reflect2.TypeOfPtr((*uintptr)(nil)).Elem())
} }
return &uintptrCodec{} if ptrSize == 32 {
return &uint32Codec{}
}
return &uint64Codec{}
case reflect.Uint64: case reflect.Uint64:
if typeName != "uint64" { if typeName != "uint64" {
return decoderOfType(ctx, reflect2.TypeOfPtr((*uint64)(nil)).Elem()) return decoderOfType(ctx, reflect2.TypeOfPtr((*uint64)(nil)).Elem())
@ -196,40 +217,6 @@ func (codec *stringCodec) IsEmpty(ptr unsafe.Pointer) bool {
return *((*string)(ptr)) == "" return *((*string)(ptr)) == ""
} }
type intCodec struct {
}
func (codec *intCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
if !iter.ReadNil() {
*((*int)(ptr)) = iter.ReadInt()
}
}
func (codec *intCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteInt(*((*int)(ptr)))
}
func (codec *intCodec) IsEmpty(ptr unsafe.Pointer) bool {
return *((*int)(ptr)) == 0
}
type uintptrCodec struct {
}
func (codec *uintptrCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
if !iter.ReadNil() {
*((*uintptr)(ptr)) = uintptr(iter.ReadUint64())
}
}
func (codec *uintptrCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteUint64(uint64(*((*uintptr)(ptr))))
}
func (codec *uintptrCodec) IsEmpty(ptr unsafe.Pointer) bool {
return *((*uintptr)(ptr)) == 0
}
type int8Codec struct { type int8Codec struct {
} }
@ -298,24 +285,6 @@ func (codec *int64Codec) IsEmpty(ptr unsafe.Pointer) bool {
return *((*int64)(ptr)) == 0 return *((*int64)(ptr)) == 0
} }
type uintCodec struct {
}
func (codec *uintCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
if !iter.ReadNil() {
*((*uint)(ptr)) = iter.ReadUint()
return
}
}
func (codec *uintCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteUint(*((*uint)(ptr)))
}
func (codec *uintCodec) IsEmpty(ptr unsafe.Pointer) bool {
return *((*uint)(ptr)) == 0
}
type uint8Codec struct { type uint8Codec struct {
} }
@ -449,7 +418,7 @@ func (codec *base64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) {
case StringValue: case StringValue:
encoding := base64.StdEncoding encoding := base64.StdEncoding
src := iter.SkipAndReturnBytes() src := iter.SkipAndReturnBytes()
src = src[1: len(src)-1] src = src[1 : len(src)-1]
decodedLen := encoding.DecodedLen(len(src)) decodedLen := encoding.DecodedLen(len(src))
dst := make([]byte, decodedLen) dst := make([]byte, decodedLen)
len, err := encoding.Decode(dst, src) len, err := encoding.Decode(dst, src)

View File

@ -1,9 +1,9 @@
package jsoniter package jsoniter
import ( import (
"github.com/modern-go/reflect2"
"reflect" "reflect"
"unsafe" "unsafe"
"github.com/v2pro/plz/reflect2"
) )
func decoderOfOptional(ctx *ctx, typ reflect2.Type) ValDecoder { func decoderOfOptional(ctx *ctx, typ reflect2.Type) ValDecoder {

View File

@ -2,9 +2,9 @@ package jsoniter
import ( import (
"fmt" "fmt"
"github.com/modern-go/reflect2"
"io" "io"
"unsafe" "unsafe"
"github.com/v2pro/plz/reflect2"
) )
func decoderOfSlice(ctx *ctx, typ reflect2.Type) ValDecoder { func decoderOfSlice(ctx *ctx, typ reflect2.Type) ValDecoder {

View File

@ -2,10 +2,10 @@ package jsoniter
import ( import (
"fmt" "fmt"
"github.com/modern-go/reflect2"
"io" "io"
"strings" "strings"
"unsafe" "unsafe"
"github.com/v2pro/plz/reflect2"
) )
func decoderOfStruct(ctx *ctx, typ reflect2.Type) ValDecoder { func decoderOfStruct(ctx *ctx, typ reflect2.Type) ValDecoder {
@ -995,7 +995,7 @@ func (decoder *structFieldDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
fieldPtr := decoder.field.UnsafeGet(ptr) fieldPtr := decoder.field.UnsafeGet(ptr)
decoder.fieldDecoder.Decode(fieldPtr, iter) decoder.fieldDecoder.Decode(fieldPtr, iter)
if iter.Error != nil && iter.Error != io.EOF { if iter.Error != nil && iter.Error != io.EOF {
iter.Error = fmt.Errorf("%s: %s", decoder.field.Name, iter.Error.Error()) iter.Error = fmt.Errorf("%s: %s", decoder.field.Name(), iter.Error.Error())
} }
} }

View File

@ -2,10 +2,10 @@ package jsoniter
import ( import (
"fmt" "fmt"
"github.com/modern-go/reflect2"
"io" "io"
"reflect" "reflect"
"unsafe" "unsafe"
"github.com/v2pro/plz/reflect2"
) )
func encoderOfStruct(ctx *ctx, typ reflect2.Type) ValEncoder { func encoderOfStruct(ctx *ctx, typ reflect2.Type) ValEncoder {
@ -47,38 +47,12 @@ func encoderOfStruct(ctx *ctx, typ reflect2.Type) ValEncoder {
} }
func createCheckIsEmpty(ctx *ctx, typ reflect2.Type) checkIsEmpty { func createCheckIsEmpty(ctx *ctx, typ reflect2.Type) checkIsEmpty {
encoder := createEncoderOfNative(ctx, typ)
if encoder != nil {
return encoder
}
kind := typ.Kind() kind := typ.Kind()
switch kind { switch kind {
case reflect.String:
return &stringCodec{}
case reflect.Int:
return &intCodec{}
case reflect.Int8:
return &int8Codec{}
case reflect.Int16:
return &int16Codec{}
case reflect.Int32:
return &int32Codec{}
case reflect.Int64:
return &int64Codec{}
case reflect.Uint:
return &uintCodec{}
case reflect.Uint8:
return &uint8Codec{}
case reflect.Uint16:
return &uint16Codec{}
case reflect.Uint32:
return &uint32Codec{}
case reflect.Uintptr:
return &uintptrCodec{}
case reflect.Uint64:
return &uint64Codec{}
case reflect.Float32:
return &float32Codec{}
case reflect.Float64:
return &float64Codec{}
case reflect.Bool:
return &boolCodec{}
case reflect.Interface: case reflect.Interface:
return &dynamicEncoder{typ} return &dynamicEncoder{typ}
case reflect.Struct: case reflect.Struct:

View File

@ -5,8 +5,8 @@ import (
"encoding/json" "encoding/json"
"testing" "testing"
"github.com/stretchr/testify/require"
"github.com/json-iterator/go" "github.com/json-iterator/go"
"github.com/stretchr/testify/require"
) )
func Test_skip_number_in_array(t *testing.T) { func Test_skip_number_in_array(t *testing.T) {

View File

@ -6,8 +6,8 @@ import (
"github.com/json-iterator/go" "github.com/json-iterator/go"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"io" "io"
"testing"
"reflect" "reflect"
"testing"
) )
type testCase struct { type testCase struct {

View File

@ -55,6 +55,11 @@ func (stream *Stream) Buffer() []byte {
return stream.buf return stream.buf
} }
// SetBuffer allows to append to the internal buffer directly
func (stream *Stream) SetBuffer(buf []byte) {
stream.buf = buf
}
// Write writes the contents of p into the buffer. // Write writes the contents of p into the buffer.
// It returns the number of bytes written. // It returns the number of bytes written.
// If nn < len(p), it also returns an error explaining // If nn < len(p), it also returns an error explaining

View File

@ -17,16 +17,16 @@ func init() {
func writeFirstBuf(space []byte, v uint32) []byte { func writeFirstBuf(space []byte, v uint32) []byte {
start := v >> 24 start := v >> 24
if start == 0 { if start == 0 {
space = append(space, byte(v >> 16), byte(v >> 8)) space = append(space, byte(v>>16), byte(v>>8))
} else if start == 1 { } else if start == 1 {
space = append(space, byte(v >> 8)) space = append(space, byte(v>>8))
} }
space = append(space, byte(v)) space = append(space, byte(v))
return space return space
} }
func writeBuf(buf []byte, v uint32) []byte { func writeBuf(buf []byte, v uint32) []byte {
return append(buf, byte(v >> 16), byte(v >> 8), byte(v)) return append(buf, byte(v>>16), byte(v>>8), byte(v))
} }
// WriteUint8 write uint8 to stream // WriteUint8 write uint8 to stream
@ -91,7 +91,7 @@ func (stream *Stream) WriteUint32(val uint32) {
stream.buf = writeFirstBuf(stream.buf, digits[q2]) stream.buf = writeFirstBuf(stream.buf, digits[q2])
} else { } else {
r3 := q2 - q3*1000 r3 := q2 - q3*1000
stream.buf = append(stream.buf, byte(q3 + '0')) stream.buf = append(stream.buf, byte(q3+'0'))
stream.buf = writeBuf(stream.buf, digits[r3]) stream.buf = writeBuf(stream.buf, digits[r3])
} }
stream.buf = writeBuf(stream.buf, digits[r2]) stream.buf = writeBuf(stream.buf, digits[r2])

View File

@ -1,8 +1,8 @@
package test package test
import ( import (
"strings"
"encoding" "encoding"
"strings"
) )
func init() { func init() {
@ -26,7 +26,6 @@ func (k *stringKeyType) UnmarshalText(text []byte) error {
var _ encoding.TextMarshaler = stringKeyType("") var _ encoding.TextMarshaler = stringKeyType("")
var _ encoding.TextUnmarshaler = new(stringKeyType) var _ encoding.TextUnmarshaler = new(stringKeyType)
type structKeyType struct { type structKeyType struct {
X string X string
} }

View File

@ -3,8 +3,8 @@ package test
import ( import (
"bytes" "bytes"
"encoding/base64" "encoding/base64"
"strings"
"encoding/json" "encoding/json"
"strings"
) )
type StringMarshaler string type StringMarshaler string

View File

@ -1,10 +1,10 @@
package test package test
import ( import (
"strings"
"encoding/base64"
"bytes" "bytes"
"encoding/base64"
"encoding/json" "encoding/json"
"strings"
) )
type structMarshaler struct { type structMarshaler struct {

View File

@ -91,7 +91,6 @@ func (p *jsonMarshaler) UnmarshalJSON(input []byte) error {
return nil return nil
} }
type jsonMarshalerMap map[int]int type jsonMarshalerMap map[int]int
func (p *jsonMarshalerMap) MarshalJSON() ([]byte, error) { func (p *jsonMarshalerMap) MarshalJSON() ([]byte, error) {
@ -117,7 +116,6 @@ func (p *textMarshaler) UnmarshalText(input []byte) error {
type textMarshalerMap map[int]int type textMarshalerMap map[int]int
func (p *textMarshalerMap) MarshalText() ([]byte, error) { func (p *textMarshalerMap) MarshalText() ([]byte, error) {
return []byte(`{}`), nil return []byte(`{}`), nil
} }

View File

@ -1,10 +1,10 @@
package test package test
import ( import (
"strings"
"encoding"
"bytes" "bytes"
"encoding"
"encoding/base64" "encoding/base64"
"strings"
) )
func init() { func init() {

View File

@ -2,9 +2,9 @@ package test
import ( import (
"bytes" "bytes"
"encoding"
"encoding/base64" "encoding/base64"
"strings" "strings"
"encoding"
) )
func init() { func init() {

View File

@ -1,15 +1,15 @@
package test package test
import ( import (
"testing"
"reflect"
"fmt"
"github.com/google/gofuzz"
"strings"
"github.com/json-iterator/go"
"encoding/json"
"bytes" "bytes"
"encoding/json"
"fmt"
"github.com/davecgh/go-spew/spew" "github.com/davecgh/go-spew/spew"
"github.com/google/gofuzz"
"github.com/json-iterator/go"
"reflect"
"strings"
"testing"
) )
var testCases []interface{} var testCases []interface{}

View File

@ -66,12 +66,12 @@ func init() {
}{"hello"}, }{"hello"},
struct { struct {
Field interface{} Field interface{}
}{struct{ }{struct {
field chan int field chan int
}{}}, }{}},
struct { struct {
Field interface{} Field interface{}
}{struct{ }{struct {
Field *int Field *int
}{pInt(100)}}, }{pInt(100)}},
) )

View File

@ -1,13 +1,13 @@
package test package test
import ( import (
"bytes"
"encoding/json"
"fmt" "fmt"
"testing" "github.com/json-iterator/go"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"strconv" "strconv"
"bytes" "testing"
"github.com/json-iterator/go"
"encoding/json"
) )
func Test_read_float(t *testing.T) { func Test_read_float(t *testing.T) {
@ -50,7 +50,6 @@ func Test_read_float(t *testing.T) {
} }
} }
func Test_write_float32(t *testing.T) { func Test_write_float32(t *testing.T) {
vals := []float32{0, 1, -1, 99, 0xff, 0xfff, 0xffff, 0xfffff, 0xffffff, 0x4ffffff, 0xfffffff, vals := []float32{0, 1, -1, 99, 0xff, 0xfff, 0xffff, 0xfffff, 0xffffff, 0x4ffffff, 0xfffffff,
-0x4ffffff, -0xfffffff, 1.2345, 1.23456, 1.234567, 1.001} -0x4ffffff, -0xfffffff, 1.2345, 1.23456, 1.234567, 1.001}

View File

@ -1,12 +1,12 @@
package test package test
import ( import (
"bytes"
"fmt"
"github.com/json-iterator/go"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"strconv" "strconv"
"fmt"
"testing" "testing"
"bytes"
"github.com/json-iterator/go"
) )
func init() { func init() {
@ -158,7 +158,6 @@ func Test_read_int64(t *testing.T) {
} }
} }
func Test_write_uint8(t *testing.T) { func Test_write_uint8(t *testing.T) {
vals := []uint8{0, 1, 11, 111, 255} vals := []uint8{0, 1, 11, 111, 255}
for _, val := range vals { for _, val := range vals {

View File

@ -3,11 +3,11 @@ package test
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"github.com/json-iterator/go"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"io" "io"
"testing" "testing"
"github.com/json-iterator/go"
) )
func Test_missing_object_end(t *testing.T) { func Test_missing_object_end(t *testing.T) {

View File

@ -1,8 +1,8 @@
package test package test
import ( import (
"math/big"
"encoding/json" "encoding/json"
"math/big"
) )
func init() { func init() {
@ -26,7 +26,7 @@ func init() {
}, },
nilMap, nilMap,
&nilMap, &nilMap,
map[string]*json.RawMessage{"hello":pRawMessage(json.RawMessage("[]"))}, map[string]*json.RawMessage{"hello": pRawMessage(json.RawMessage("[]"))},
) )
unmarshalCases = append(unmarshalCases, unmarshalCase{ unmarshalCases = append(unmarshalCases, unmarshalCase{
ptr: (*map[string]string)(nil), ptr: (*map[string]string)(nil),

View File

@ -1,8 +1,8 @@
package test package test
import ( import (
"encoding/json"
"encoding" "encoding"
"encoding/json"
) )
func init() { func init() {
@ -17,10 +17,10 @@ func init() {
tmOfStructInt{}, tmOfStructInt{},
&tm2, &tm2,
map[tmOfStruct]int{ map[tmOfStruct]int{
tmOfStruct{}: 100, {}: 100,
}, },
map[*tmOfStruct]int{ map[*tmOfStruct]int{
&tmOfStruct{}: 100, {}: 100,
}, },
map[encoding.TextMarshaler]int{ map[encoding.TextMarshaler]int{
tm1: 100, tm1: 100,
@ -47,7 +47,6 @@ func (q *jmOfStruct) UnmarshalJSON(value []byte) error {
return nil return nil
} }
type tmOfStruct struct { type tmOfStruct struct {
F2 chan []byte F2 chan []byte
} }

View File

@ -6,6 +6,7 @@ func init() {
[]interface{}{"hello"}, []interface{}{"hello"},
nilSlice, nilSlice,
&nilSlice, &nilSlice,
[]byte{1, 2, 3},
) )
unmarshalCases = append(unmarshalCases, unmarshalCase{ unmarshalCases = append(unmarshalCases, unmarshalCase{
ptr: (*[]string)(nil), ptr: (*[]string)(nil),
@ -13,5 +14,11 @@ func init() {
}, unmarshalCase{ }, unmarshalCase{
ptr: (*[]string)(nil), ptr: (*[]string)(nil),
input: "[]", input: "[]",
}, unmarshalCase{
ptr: (*[]byte)(nil),
input: "[1,2,3]",
}, unmarshalCase{
ptr: (*[]byte)(nil),
input: `"aGVsbG8="`,
}) })
} }

View File

@ -1,9 +1,9 @@
package test package test
import ( import (
"testing"
"github.com/json-iterator/go"
"encoding/json" "encoding/json"
"github.com/json-iterator/go"
"testing"
"unicode/utf8" "unicode/utf8"
) )

View File

@ -1,9 +1,9 @@
package test package test
import ( import (
"time"
"encoding/json"
"bytes" "bytes"
"encoding/json"
"time"
) )
func init() { func init() {

View File

@ -1,12 +1,12 @@
package test package test
import ( import (
"testing"
"encoding/json" "encoding/json"
"github.com/stretchr/testify/require"
"github.com/json-iterator/go"
"fmt" "fmt"
"github.com/v2pro/plz/reflect2" "github.com/json-iterator/go"
"github.com/modern-go/reflect2"
"github.com/stretchr/testify/require"
"testing"
) )
type unmarshalCase struct { type unmarshalCase struct {