mirror of
https://github.com/json-iterator/go.git
synced 2025-05-19 21:53:05 +02:00
split files
This commit is contained in:
parent
c78023531e
commit
5af8cc4b09
@ -6,7 +6,6 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
@ -25,6 +24,71 @@ type Decoder interface {
|
|||||||
decode(ptr unsafe.Pointer, iter *Iterator)
|
decode(ptr unsafe.Pointer, iter *Iterator)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DecoderFunc func(ptr unsafe.Pointer, iter *Iterator)
|
||||||
|
type ExtensionFunc func(typ reflect.Type, field *reflect.StructField) ([]string, DecoderFunc)
|
||||||
|
|
||||||
|
type funcDecoder struct {
|
||||||
|
fun DecoderFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (decoder *funcDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||||
|
decoder.fun(ptr, iter)
|
||||||
|
}
|
||||||
|
|
||||||
|
var DECODERS unsafe.Pointer
|
||||||
|
|
||||||
|
var typeDecoders map[string]Decoder
|
||||||
|
var fieldDecoders map[string]Decoder
|
||||||
|
var extensions []ExtensionFunc
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
typeDecoders = map[string]Decoder{}
|
||||||
|
fieldDecoders = map[string]Decoder{}
|
||||||
|
extensions = []ExtensionFunc{}
|
||||||
|
atomic.StorePointer(&DECODERS, unsafe.Pointer(&map[string]Decoder{}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func addDecoderToCache(cacheKey reflect.Type, decoder Decoder) {
|
||||||
|
retry := true
|
||||||
|
for retry {
|
||||||
|
ptr := atomic.LoadPointer(&DECODERS)
|
||||||
|
cache := *(*map[reflect.Type]Decoder)(ptr)
|
||||||
|
copy := map[reflect.Type]Decoder{}
|
||||||
|
for k, v := range cache {
|
||||||
|
copy[k] = v
|
||||||
|
}
|
||||||
|
copy[cacheKey] = decoder
|
||||||
|
retry = !atomic.CompareAndSwapPointer(&DECODERS, ptr, unsafe.Pointer(©))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getDecoderFromCache(cacheKey reflect.Type) Decoder {
|
||||||
|
ptr := atomic.LoadPointer(&DECODERS)
|
||||||
|
cache := *(*map[reflect.Type]Decoder)(ptr)
|
||||||
|
return cache[cacheKey]
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterTypeDecoder can register a type for json object
|
||||||
|
func RegisterTypeDecoder(typ string, fun DecoderFunc) {
|
||||||
|
typeDecoders[typ] = &funcDecoder{fun}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterFieldDecoder can register a type for json field
|
||||||
|
func RegisterFieldDecoder(typ string, field string, fun DecoderFunc) {
|
||||||
|
fieldDecoders[fmt.Sprintf("%s/%s", typ, field)] = &funcDecoder{fun}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterExtension can register a custom extension
|
||||||
|
func RegisterExtension(extension ExtensionFunc) {
|
||||||
|
extensions = append(extensions, extension)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CleanDecoders cleans decoders registered
|
||||||
|
func CleanDecoders() {
|
||||||
|
typeDecoders = map[string]Decoder{}
|
||||||
|
fieldDecoders = map[string]Decoder{}
|
||||||
|
}
|
||||||
|
|
||||||
type optionalDecoder struct {
|
type optionalDecoder struct {
|
||||||
valueType reflect.Type
|
valueType reflect.Type
|
||||||
valueDecoder Decoder
|
valueDecoder Decoder
|
||||||
@ -46,218 +110,6 @@ func (decoder *optionalDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type generalStructDecoder struct {
|
|
||||||
typ reflect.Type
|
|
||||||
fields map[string]*structFieldDecoder
|
|
||||||
}
|
|
||||||
|
|
||||||
func (decoder *generalStructDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
|
||||||
if !iter.readObjectStart() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
field := iter.readObjectField()
|
|
||||||
fieldDecoder := decoder.fields[field]
|
|
||||||
if fieldDecoder == nil {
|
|
||||||
iter.Skip()
|
|
||||||
} else {
|
|
||||||
fieldDecoder.decode(ptr, iter)
|
|
||||||
}
|
|
||||||
for iter.nextToken() == ',' {
|
|
||||||
field = iter.readObjectField()
|
|
||||||
fieldDecoder = decoder.fields[field]
|
|
||||||
if fieldDecoder == nil {
|
|
||||||
iter.Skip()
|
|
||||||
} else {
|
|
||||||
fieldDecoder.decode(ptr, iter)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if iter.Error != nil && iter.Error != io.EOF {
|
|
||||||
iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type skipDecoder struct {
|
|
||||||
typ reflect.Type
|
|
||||||
}
|
|
||||||
|
|
||||||
func (decoder *skipDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
|
||||||
iter.Skip()
|
|
||||||
if iter.Error != nil && iter.Error != io.EOF {
|
|
||||||
iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type oneFieldStructDecoder struct {
|
|
||||||
typ reflect.Type
|
|
||||||
fieldName string
|
|
||||||
fieldDecoder *structFieldDecoder
|
|
||||||
}
|
|
||||||
|
|
||||||
func (decoder *oneFieldStructDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
|
||||||
if !iter.readObjectStart() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
field := iter.readObjectField()
|
|
||||||
if field == decoder.fieldName {
|
|
||||||
decoder.fieldDecoder.decode(ptr, iter)
|
|
||||||
} else {
|
|
||||||
iter.Skip()
|
|
||||||
}
|
|
||||||
for iter.nextToken() == ',' {
|
|
||||||
field = iter.readObjectField()
|
|
||||||
if field == decoder.fieldName {
|
|
||||||
decoder.fieldDecoder.decode(ptr, iter)
|
|
||||||
} else {
|
|
||||||
iter.Skip()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if iter.Error != nil && iter.Error != io.EOF {
|
|
||||||
iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type twoFieldsStructDecoder struct {
|
|
||||||
typ reflect.Type
|
|
||||||
fieldName1 string
|
|
||||||
fieldDecoder1 *structFieldDecoder
|
|
||||||
fieldName2 string
|
|
||||||
fieldDecoder2 *structFieldDecoder
|
|
||||||
}
|
|
||||||
|
|
||||||
func (decoder *twoFieldsStructDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
|
||||||
if !iter.readObjectStart() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
field := iter.readObjectField()
|
|
||||||
switch field {
|
|
||||||
case decoder.fieldName1:
|
|
||||||
decoder.fieldDecoder1.decode(ptr, iter)
|
|
||||||
case decoder.fieldName2:
|
|
||||||
decoder.fieldDecoder2.decode(ptr, iter)
|
|
||||||
default:
|
|
||||||
iter.Skip()
|
|
||||||
}
|
|
||||||
for iter.nextToken() == ',' {
|
|
||||||
field = iter.readObjectField()
|
|
||||||
switch field {
|
|
||||||
case decoder.fieldName1:
|
|
||||||
decoder.fieldDecoder1.decode(ptr, iter)
|
|
||||||
case decoder.fieldName2:
|
|
||||||
decoder.fieldDecoder2.decode(ptr, iter)
|
|
||||||
default:
|
|
||||||
iter.Skip()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if iter.Error != nil && iter.Error != io.EOF {
|
|
||||||
iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type threeFieldsStructDecoder struct {
|
|
||||||
typ reflect.Type
|
|
||||||
fieldName1 string
|
|
||||||
fieldDecoder1 *structFieldDecoder
|
|
||||||
fieldName2 string
|
|
||||||
fieldDecoder2 *structFieldDecoder
|
|
||||||
fieldName3 string
|
|
||||||
fieldDecoder3 *structFieldDecoder
|
|
||||||
}
|
|
||||||
|
|
||||||
func (decoder *threeFieldsStructDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
|
||||||
if !iter.readObjectStart() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
field := iter.readObjectField()
|
|
||||||
switch field {
|
|
||||||
case decoder.fieldName1:
|
|
||||||
decoder.fieldDecoder1.decode(ptr, iter)
|
|
||||||
case decoder.fieldName2:
|
|
||||||
decoder.fieldDecoder2.decode(ptr, iter)
|
|
||||||
case decoder.fieldName3:
|
|
||||||
decoder.fieldDecoder3.decode(ptr, iter)
|
|
||||||
default:
|
|
||||||
iter.Skip()
|
|
||||||
}
|
|
||||||
for iter.nextToken() == ',' {
|
|
||||||
field = iter.readObjectField()
|
|
||||||
switch field {
|
|
||||||
case decoder.fieldName1:
|
|
||||||
decoder.fieldDecoder1.decode(ptr, iter)
|
|
||||||
case decoder.fieldName2:
|
|
||||||
decoder.fieldDecoder2.decode(ptr, iter)
|
|
||||||
case decoder.fieldName3:
|
|
||||||
decoder.fieldDecoder3.decode(ptr, iter)
|
|
||||||
default:
|
|
||||||
iter.Skip()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if iter.Error != nil && iter.Error != io.EOF {
|
|
||||||
iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type fourFieldsStructDecoder struct {
|
|
||||||
typ reflect.Type
|
|
||||||
fieldName1 string
|
|
||||||
fieldDecoder1 *structFieldDecoder
|
|
||||||
fieldName2 string
|
|
||||||
fieldDecoder2 *structFieldDecoder
|
|
||||||
fieldName3 string
|
|
||||||
fieldDecoder3 *structFieldDecoder
|
|
||||||
fieldName4 string
|
|
||||||
fieldDecoder4 *structFieldDecoder
|
|
||||||
}
|
|
||||||
|
|
||||||
func (decoder *fourFieldsStructDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
|
||||||
if !iter.readObjectStart() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
field := iter.readObjectField()
|
|
||||||
switch field {
|
|
||||||
case decoder.fieldName1:
|
|
||||||
decoder.fieldDecoder1.decode(ptr, iter)
|
|
||||||
case decoder.fieldName2:
|
|
||||||
decoder.fieldDecoder2.decode(ptr, iter)
|
|
||||||
case decoder.fieldName3:
|
|
||||||
decoder.fieldDecoder3.decode(ptr, iter)
|
|
||||||
case decoder.fieldName4:
|
|
||||||
decoder.fieldDecoder4.decode(ptr, iter)
|
|
||||||
default:
|
|
||||||
iter.Skip()
|
|
||||||
}
|
|
||||||
for iter.nextToken() == ',' {
|
|
||||||
field = iter.readObjectField()
|
|
||||||
switch field {
|
|
||||||
case decoder.fieldName1:
|
|
||||||
decoder.fieldDecoder1.decode(ptr, iter)
|
|
||||||
case decoder.fieldName2:
|
|
||||||
decoder.fieldDecoder2.decode(ptr, iter)
|
|
||||||
case decoder.fieldName3:
|
|
||||||
decoder.fieldDecoder3.decode(ptr, iter)
|
|
||||||
case decoder.fieldName4:
|
|
||||||
decoder.fieldDecoder4.decode(ptr, iter)
|
|
||||||
default:
|
|
||||||
iter.Skip()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if iter.Error != nil && iter.Error != io.EOF {
|
|
||||||
iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type structFieldDecoder struct {
|
|
||||||
field *reflect.StructField
|
|
||||||
fieldDecoder Decoder
|
|
||||||
}
|
|
||||||
|
|
||||||
func (decoder *structFieldDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
|
||||||
fieldPtr := uintptr(ptr) + decoder.field.Offset
|
|
||||||
decoder.fieldDecoder.decode(unsafe.Pointer(fieldPtr), iter)
|
|
||||||
if iter.Error != nil && iter.Error != io.EOF {
|
|
||||||
iter.Error = fmt.Errorf("%s: %s", decoder.field.Name, iter.Error.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type mapDecoder struct {
|
type mapDecoder struct {
|
||||||
mapType reflect.Type
|
mapType reflect.Type
|
||||||
elemType reflect.Type
|
elemType reflect.Type
|
||||||
@ -280,167 +132,6 @@ func (decoder *mapDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type sliceDecoder struct {
|
|
||||||
sliceType reflect.Type
|
|
||||||
elemType reflect.Type
|
|
||||||
elemDecoder Decoder
|
|
||||||
}
|
|
||||||
|
|
||||||
// sliceHeader is a safe version of SliceHeader used within this package.
|
|
||||||
type sliceHeader struct {
|
|
||||||
Data unsafe.Pointer
|
|
||||||
Len int
|
|
||||||
Cap int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (decoder *sliceDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
|
||||||
decoder.doDecode(ptr, iter)
|
|
||||||
if iter.Error != nil && iter.Error != io.EOF {
|
|
||||||
iter.Error = fmt.Errorf("%v: %s", decoder.sliceType, iter.Error.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (decoder *sliceDecoder) doDecode(ptr unsafe.Pointer, iter *Iterator) {
|
|
||||||
slice := (*sliceHeader)(ptr)
|
|
||||||
reuseSlice(slice, decoder.sliceType, 4)
|
|
||||||
if !iter.ReadArray() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
offset := uintptr(0)
|
|
||||||
decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data) + offset), iter)
|
|
||||||
if !iter.ReadArray() {
|
|
||||||
slice.Len = 1
|
|
||||||
return
|
|
||||||
}
|
|
||||||
offset += decoder.elemType.Size()
|
|
||||||
decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data) + offset), iter)
|
|
||||||
if !iter.ReadArray() {
|
|
||||||
slice.Len = 2
|
|
||||||
return
|
|
||||||
}
|
|
||||||
offset += decoder.elemType.Size()
|
|
||||||
decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data) + offset), iter)
|
|
||||||
if !iter.ReadArray() {
|
|
||||||
slice.Len = 3
|
|
||||||
return
|
|
||||||
}
|
|
||||||
offset += decoder.elemType.Size()
|
|
||||||
decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data) + offset), iter)
|
|
||||||
slice.Len = 4
|
|
||||||
for iter.ReadArray() {
|
|
||||||
growOne(slice, decoder.sliceType, decoder.elemType)
|
|
||||||
offset += decoder.elemType.Size()
|
|
||||||
decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data) + offset), iter)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// grow grows the slice s so that it can hold extra more values, allocating
|
|
||||||
// more capacity if needed. It also returns the old and new slice lengths.
|
|
||||||
func growOne(slice *sliceHeader, sliceType reflect.Type, elementType reflect.Type) {
|
|
||||||
newLen := slice.Len + 1
|
|
||||||
if newLen <= slice.Cap {
|
|
||||||
slice.Len = newLen
|
|
||||||
return
|
|
||||||
}
|
|
||||||
newCap := slice.Cap
|
|
||||||
if newCap == 0 {
|
|
||||||
newCap = 1
|
|
||||||
} else {
|
|
||||||
for newCap < newLen {
|
|
||||||
if slice.Len < 1024 {
|
|
||||||
newCap += newCap
|
|
||||||
} else {
|
|
||||||
newCap += newCap / 4
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dst := unsafe.Pointer(reflect.MakeSlice(sliceType, newLen, newCap).Pointer())
|
|
||||||
// copy old array into new array
|
|
||||||
originalBytesCount := uintptr(slice.Len) * elementType.Size()
|
|
||||||
srcPtr := (*[1 << 30]byte)(slice.Data)
|
|
||||||
dstPtr := (*[1 << 30]byte)(dst)
|
|
||||||
for i := uintptr(0); i < originalBytesCount; i++ {
|
|
||||||
dstPtr[i] = srcPtr[i]
|
|
||||||
}
|
|
||||||
slice.Len = newLen
|
|
||||||
slice.Cap = newCap
|
|
||||||
slice.Data = dst
|
|
||||||
}
|
|
||||||
|
|
||||||
func reuseSlice(slice *sliceHeader, sliceType reflect.Type, expectedCap int) {
|
|
||||||
if expectedCap <= slice.Cap {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
dst := unsafe.Pointer(reflect.MakeSlice(sliceType, 0, expectedCap).Pointer())
|
|
||||||
slice.Cap = expectedCap
|
|
||||||
slice.Data = dst
|
|
||||||
}
|
|
||||||
|
|
||||||
var DECODERS unsafe.Pointer
|
|
||||||
|
|
||||||
func addDecoderToCache(cacheKey reflect.Type, decoder Decoder) {
|
|
||||||
retry := true
|
|
||||||
for retry {
|
|
||||||
ptr := atomic.LoadPointer(&DECODERS)
|
|
||||||
cache := *(*map[reflect.Type]Decoder)(ptr)
|
|
||||||
copy := map[reflect.Type]Decoder{}
|
|
||||||
for k, v := range cache {
|
|
||||||
copy[k] = v
|
|
||||||
}
|
|
||||||
copy[cacheKey] = decoder
|
|
||||||
retry = !atomic.CompareAndSwapPointer(&DECODERS, ptr, unsafe.Pointer(©))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getDecoderFromCache(cacheKey reflect.Type) Decoder {
|
|
||||||
ptr := atomic.LoadPointer(&DECODERS)
|
|
||||||
cache := *(*map[reflect.Type]Decoder)(ptr)
|
|
||||||
return cache[cacheKey]
|
|
||||||
}
|
|
||||||
|
|
||||||
var typeDecoders map[string]Decoder
|
|
||||||
var fieldDecoders map[string]Decoder
|
|
||||||
var extensions []ExtensionFunc
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
typeDecoders = map[string]Decoder{}
|
|
||||||
fieldDecoders = map[string]Decoder{}
|
|
||||||
extensions = []ExtensionFunc{}
|
|
||||||
atomic.StorePointer(&DECODERS, unsafe.Pointer(&map[string]Decoder{}))
|
|
||||||
}
|
|
||||||
|
|
||||||
type DecoderFunc func(ptr unsafe.Pointer, iter *Iterator)
|
|
||||||
type ExtensionFunc func(typ reflect.Type, field *reflect.StructField) ([]string, DecoderFunc)
|
|
||||||
|
|
||||||
type funcDecoder struct {
|
|
||||||
fun DecoderFunc
|
|
||||||
}
|
|
||||||
|
|
||||||
func (decoder *funcDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
|
||||||
decoder.fun(ptr, iter)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterTypeDecoder can register a type for json object
|
|
||||||
func RegisterTypeDecoder(typ string, fun DecoderFunc) {
|
|
||||||
typeDecoders[typ] = &funcDecoder{fun}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterFieldDecoder can register a type for json field
|
|
||||||
func RegisterFieldDecoder(typ string, field string, fun DecoderFunc) {
|
|
||||||
fieldDecoders[fmt.Sprintf("%s/%s", typ, field)] = &funcDecoder{fun}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterExtension can register a custom extension
|
|
||||||
func RegisterExtension(extension ExtensionFunc) {
|
|
||||||
extensions = append(extensions, extension)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CleanDecoders cleans decoders registered
|
|
||||||
func CleanDecoders() {
|
|
||||||
typeDecoders = map[string]Decoder{}
|
|
||||||
fieldDecoders = map[string]Decoder{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// emptyInterface is the header for an interface{} value.
|
// emptyInterface is the header for an interface{} value.
|
||||||
type emptyInterface struct {
|
type emptyInterface struct {
|
||||||
typ *struct{}
|
typ *struct{}
|
||||||
@ -646,123 +337,6 @@ func decoderOfOptional(typ reflect.Type) (Decoder, error) {
|
|||||||
return &optionalDecoder{typ, decoder}, nil
|
return &optionalDecoder{typ, decoder}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func decoderOfStruct(typ reflect.Type) (Decoder, error) {
|
|
||||||
fields := map[string]*structFieldDecoder{}
|
|
||||||
for i := 0; i < typ.NumField(); i++ {
|
|
||||||
field := typ.Field(i)
|
|
||||||
fieldDecoderKey := fmt.Sprintf("%s/%s", typ.String(), field.Name)
|
|
||||||
var fieldNames []string
|
|
||||||
for _, extension := range extensions {
|
|
||||||
alternativeFieldNames, fun := extension(typ, &field)
|
|
||||||
if alternativeFieldNames != nil {
|
|
||||||
fieldNames = alternativeFieldNames
|
|
||||||
}
|
|
||||||
if fun != nil {
|
|
||||||
fieldDecoders[fieldDecoderKey] = &funcDecoder{fun}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
decoder := fieldDecoders[fieldDecoderKey]
|
|
||||||
tagParts := strings.Split(field.Tag.Get("json"), ",")
|
|
||||||
// if fieldNames set by extension, use theirs, otherwise try tags
|
|
||||||
if fieldNames == nil {
|
|
||||||
/// tagParts[0] always present, even if no tags
|
|
||||||
switch tagParts[0] {
|
|
||||||
case "":
|
|
||||||
fieldNames = []string{field.Name}
|
|
||||||
case "-":
|
|
||||||
fieldNames = []string{}
|
|
||||||
default:
|
|
||||||
fieldNames = []string{tagParts[0]}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if decoder == nil {
|
|
||||||
var err error
|
|
||||||
decoder, err = decoderOfPtr(field.Type)
|
|
||||||
if err != nil {
|
|
||||||
return prefix(fmt.Sprintf("{%s}", field.Name)).addTo(decoder, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(tagParts) > 1 && tagParts[1] == "string" {
|
|
||||||
decoder = &stringNumberDecoder{decoder}
|
|
||||||
}
|
|
||||||
for _, fieldName := range fieldNames {
|
|
||||||
fields[fieldName] = &structFieldDecoder{&field, decoder}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch len(fields) {
|
|
||||||
case 0:
|
|
||||||
return &skipDecoder{typ}, nil
|
|
||||||
case 1:
|
|
||||||
for fieldName, fieldDecoder := range fields {
|
|
||||||
return &oneFieldStructDecoder{typ, fieldName, fieldDecoder}, nil
|
|
||||||
}
|
|
||||||
case 2:
|
|
||||||
var fieldName1 string
|
|
||||||
var fieldName2 string
|
|
||||||
var fieldDecoder1 *structFieldDecoder
|
|
||||||
var fieldDecoder2 *structFieldDecoder
|
|
||||||
for fieldName, fieldDecoder := range fields {
|
|
||||||
if fieldName1 == "" {
|
|
||||||
fieldName1 = fieldName
|
|
||||||
fieldDecoder1 = fieldDecoder
|
|
||||||
} else {
|
|
||||||
fieldName2 = fieldName
|
|
||||||
fieldDecoder2 = fieldDecoder
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &twoFieldsStructDecoder{typ, fieldName1, fieldDecoder1, fieldName2, fieldDecoder2}, nil
|
|
||||||
case 3:
|
|
||||||
var fieldName1 string
|
|
||||||
var fieldName2 string
|
|
||||||
var fieldName3 string
|
|
||||||
var fieldDecoder1 *structFieldDecoder
|
|
||||||
var fieldDecoder2 *structFieldDecoder
|
|
||||||
var fieldDecoder3 *structFieldDecoder
|
|
||||||
for fieldName, fieldDecoder := range fields {
|
|
||||||
if fieldName1 == "" {
|
|
||||||
fieldName1 = fieldName
|
|
||||||
fieldDecoder1 = fieldDecoder
|
|
||||||
} else if fieldName2 == "" {
|
|
||||||
fieldName2 = fieldName
|
|
||||||
fieldDecoder2 = fieldDecoder
|
|
||||||
} else {
|
|
||||||
fieldName3 = fieldName
|
|
||||||
fieldDecoder3 = fieldDecoder
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &threeFieldsStructDecoder{typ,
|
|
||||||
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3}, nil
|
|
||||||
case 4:
|
|
||||||
var fieldName1 string
|
|
||||||
var fieldName2 string
|
|
||||||
var fieldName3 string
|
|
||||||
var fieldName4 string
|
|
||||||
var fieldDecoder1 *structFieldDecoder
|
|
||||||
var fieldDecoder2 *structFieldDecoder
|
|
||||||
var fieldDecoder3 *structFieldDecoder
|
|
||||||
var fieldDecoder4 *structFieldDecoder
|
|
||||||
for fieldName, fieldDecoder := range fields {
|
|
||||||
if fieldName1 == "" {
|
|
||||||
fieldName1 = fieldName
|
|
||||||
fieldDecoder1 = fieldDecoder
|
|
||||||
} else if fieldName2 == "" {
|
|
||||||
fieldName2 = fieldName
|
|
||||||
fieldDecoder2 = fieldDecoder
|
|
||||||
} else if fieldName3 == "" {
|
|
||||||
fieldName3 = fieldName
|
|
||||||
fieldDecoder3 = fieldDecoder
|
|
||||||
} else {
|
|
||||||
fieldName4 = fieldName
|
|
||||||
fieldDecoder4 = fieldDecoder
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &fourFieldsStructDecoder{typ,
|
|
||||||
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
|
|
||||||
fieldName4, fieldDecoder4}, nil
|
|
||||||
}
|
|
||||||
return &generalStructDecoder{typ, fields}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func decoderOfSlice(typ reflect.Type) (Decoder, error) {
|
func decoderOfSlice(typ reflect.Type) (Decoder, error) {
|
||||||
decoder, err := decoderOfPtr(typ.Elem())
|
decoder, err := decoderOfPtr(typ.Elem())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
104
feature_reflect_array.go
Normal file
104
feature_reflect_array.go
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
package jsoniter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
"reflect"
|
||||||
|
"io"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type sliceDecoder struct {
|
||||||
|
sliceType reflect.Type
|
||||||
|
elemType reflect.Type
|
||||||
|
elemDecoder Decoder
|
||||||
|
}
|
||||||
|
|
||||||
|
// sliceHeader is a safe version of SliceHeader used within this package.
|
||||||
|
type sliceHeader struct {
|
||||||
|
Data unsafe.Pointer
|
||||||
|
Len int
|
||||||
|
Cap int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (decoder *sliceDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||||
|
decoder.doDecode(ptr, iter)
|
||||||
|
if iter.Error != nil && iter.Error != io.EOF {
|
||||||
|
iter.Error = fmt.Errorf("%v: %s", decoder.sliceType, iter.Error.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (decoder *sliceDecoder) doDecode(ptr unsafe.Pointer, iter *Iterator) {
|
||||||
|
slice := (*sliceHeader)(ptr)
|
||||||
|
reuseSlice(slice, decoder.sliceType, 4)
|
||||||
|
if !iter.ReadArray() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
offset := uintptr(0)
|
||||||
|
decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data) + offset), iter)
|
||||||
|
if !iter.ReadArray() {
|
||||||
|
slice.Len = 1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
offset += decoder.elemType.Size()
|
||||||
|
decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data) + offset), iter)
|
||||||
|
if !iter.ReadArray() {
|
||||||
|
slice.Len = 2
|
||||||
|
return
|
||||||
|
}
|
||||||
|
offset += decoder.elemType.Size()
|
||||||
|
decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data) + offset), iter)
|
||||||
|
if !iter.ReadArray() {
|
||||||
|
slice.Len = 3
|
||||||
|
return
|
||||||
|
}
|
||||||
|
offset += decoder.elemType.Size()
|
||||||
|
decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data) + offset), iter)
|
||||||
|
slice.Len = 4
|
||||||
|
for iter.ReadArray() {
|
||||||
|
growOne(slice, decoder.sliceType, decoder.elemType)
|
||||||
|
offset += decoder.elemType.Size()
|
||||||
|
decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data) + offset), iter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// grow grows the slice s so that it can hold extra more values, allocating
|
||||||
|
// more capacity if needed. It also returns the old and new slice lengths.
|
||||||
|
func growOne(slice *sliceHeader, sliceType reflect.Type, elementType reflect.Type) {
|
||||||
|
newLen := slice.Len + 1
|
||||||
|
if newLen <= slice.Cap {
|
||||||
|
slice.Len = newLen
|
||||||
|
return
|
||||||
|
}
|
||||||
|
newCap := slice.Cap
|
||||||
|
if newCap == 0 {
|
||||||
|
newCap = 1
|
||||||
|
} else {
|
||||||
|
for newCap < newLen {
|
||||||
|
if slice.Len < 1024 {
|
||||||
|
newCap += newCap
|
||||||
|
} else {
|
||||||
|
newCap += newCap / 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dst := unsafe.Pointer(reflect.MakeSlice(sliceType, newLen, newCap).Pointer())
|
||||||
|
// copy old array into new array
|
||||||
|
originalBytesCount := uintptr(slice.Len) * elementType.Size()
|
||||||
|
srcPtr := (*[1 << 30]byte)(slice.Data)
|
||||||
|
dstPtr := (*[1 << 30]byte)(dst)
|
||||||
|
for i := uintptr(0); i < originalBytesCount; i++ {
|
||||||
|
dstPtr[i] = srcPtr[i]
|
||||||
|
}
|
||||||
|
slice.Len = newLen
|
||||||
|
slice.Cap = newCap
|
||||||
|
slice.Data = dst
|
||||||
|
}
|
||||||
|
|
||||||
|
func reuseSlice(slice *sliceHeader, sliceType reflect.Type, expectedCap int) {
|
||||||
|
if expectedCap <= slice.Cap {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dst := unsafe.Pointer(reflect.MakeSlice(sliceType, 0, expectedCap).Pointer())
|
||||||
|
slice.Cap = expectedCap
|
||||||
|
slice.Data = dst
|
||||||
|
}
|
338
feature_reflect_object.go
Normal file
338
feature_reflect_object.go
Normal file
@ -0,0 +1,338 @@
|
|||||||
|
package jsoniter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func decoderOfStruct(typ reflect.Type) (Decoder, error) {
|
||||||
|
fields := map[string]*structFieldDecoder{}
|
||||||
|
for i := 0; i < typ.NumField(); i++ {
|
||||||
|
field := typ.Field(i)
|
||||||
|
fieldDecoderKey := fmt.Sprintf("%s/%s", typ.String(), field.Name)
|
||||||
|
var fieldNames []string
|
||||||
|
for _, extension := range extensions {
|
||||||
|
alternativeFieldNames, fun := extension(typ, &field)
|
||||||
|
if alternativeFieldNames != nil {
|
||||||
|
fieldNames = alternativeFieldNames
|
||||||
|
}
|
||||||
|
if fun != nil {
|
||||||
|
fieldDecoders[fieldDecoderKey] = &funcDecoder{fun}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
decoder := fieldDecoders[fieldDecoderKey]
|
||||||
|
tagParts := strings.Split(field.Tag.Get("json"), ",")
|
||||||
|
// if fieldNames set by extension, use theirs, otherwise try tags
|
||||||
|
if fieldNames == nil {
|
||||||
|
/// tagParts[0] always present, even if no tags
|
||||||
|
switch tagParts[0] {
|
||||||
|
case "":
|
||||||
|
fieldNames = []string{field.Name}
|
||||||
|
case "-":
|
||||||
|
fieldNames = []string{}
|
||||||
|
default:
|
||||||
|
fieldNames = []string{tagParts[0]}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if decoder == nil {
|
||||||
|
var err error
|
||||||
|
decoder, err = decoderOfPtr(field.Type)
|
||||||
|
if err != nil {
|
||||||
|
return prefix(fmt.Sprintf("{%s}", field.Name)).addTo(decoder, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(tagParts) > 1 && tagParts[1] == "string" {
|
||||||
|
decoder = &stringNumberDecoder{decoder}
|
||||||
|
}
|
||||||
|
for _, fieldName := range fieldNames {
|
||||||
|
fields[fieldName] = &structFieldDecoder{&field, decoder}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch len(fields) {
|
||||||
|
case 0:
|
||||||
|
return &skipDecoder{typ}, nil
|
||||||
|
case 1:
|
||||||
|
for fieldName, fieldDecoder := range fields {
|
||||||
|
return &oneFieldStructDecoder{typ, fieldName, fieldDecoder}, nil
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
var fieldName1 string
|
||||||
|
var fieldName2 string
|
||||||
|
var fieldDecoder1 *structFieldDecoder
|
||||||
|
var fieldDecoder2 *structFieldDecoder
|
||||||
|
for fieldName, fieldDecoder := range fields {
|
||||||
|
if fieldName1 == "" {
|
||||||
|
fieldName1 = fieldName
|
||||||
|
fieldDecoder1 = fieldDecoder
|
||||||
|
} else {
|
||||||
|
fieldName2 = fieldName
|
||||||
|
fieldDecoder2 = fieldDecoder
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &twoFieldsStructDecoder{typ, fieldName1, fieldDecoder1, fieldName2, fieldDecoder2}, nil
|
||||||
|
case 3:
|
||||||
|
var fieldName1 string
|
||||||
|
var fieldName2 string
|
||||||
|
var fieldName3 string
|
||||||
|
var fieldDecoder1 *structFieldDecoder
|
||||||
|
var fieldDecoder2 *structFieldDecoder
|
||||||
|
var fieldDecoder3 *structFieldDecoder
|
||||||
|
for fieldName, fieldDecoder := range fields {
|
||||||
|
if fieldName1 == "" {
|
||||||
|
fieldName1 = fieldName
|
||||||
|
fieldDecoder1 = fieldDecoder
|
||||||
|
} else if fieldName2 == "" {
|
||||||
|
fieldName2 = fieldName
|
||||||
|
fieldDecoder2 = fieldDecoder
|
||||||
|
} else {
|
||||||
|
fieldName3 = fieldName
|
||||||
|
fieldDecoder3 = fieldDecoder
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &threeFieldsStructDecoder{typ,
|
||||||
|
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3}, nil
|
||||||
|
case 4:
|
||||||
|
var fieldName1 string
|
||||||
|
var fieldName2 string
|
||||||
|
var fieldName3 string
|
||||||
|
var fieldName4 string
|
||||||
|
var fieldDecoder1 *structFieldDecoder
|
||||||
|
var fieldDecoder2 *structFieldDecoder
|
||||||
|
var fieldDecoder3 *structFieldDecoder
|
||||||
|
var fieldDecoder4 *structFieldDecoder
|
||||||
|
for fieldName, fieldDecoder := range fields {
|
||||||
|
if fieldName1 == "" {
|
||||||
|
fieldName1 = fieldName
|
||||||
|
fieldDecoder1 = fieldDecoder
|
||||||
|
} else if fieldName2 == "" {
|
||||||
|
fieldName2 = fieldName
|
||||||
|
fieldDecoder2 = fieldDecoder
|
||||||
|
} else if fieldName3 == "" {
|
||||||
|
fieldName3 = fieldName
|
||||||
|
fieldDecoder3 = fieldDecoder
|
||||||
|
} else {
|
||||||
|
fieldName4 = fieldName
|
||||||
|
fieldDecoder4 = fieldDecoder
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &fourFieldsStructDecoder{typ,
|
||||||
|
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
|
||||||
|
fieldName4, fieldDecoder4}, nil
|
||||||
|
}
|
||||||
|
return &generalStructDecoder{typ, fields}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type generalStructDecoder struct {
|
||||||
|
typ reflect.Type
|
||||||
|
fields map[string]*structFieldDecoder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (decoder *generalStructDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||||
|
if !iter.readObjectStart() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
field := iter.readObjectField()
|
||||||
|
fieldDecoder := decoder.fields[field]
|
||||||
|
if fieldDecoder == nil {
|
||||||
|
iter.Skip()
|
||||||
|
} else {
|
||||||
|
fieldDecoder.decode(ptr, iter)
|
||||||
|
}
|
||||||
|
for iter.nextToken() == ',' {
|
||||||
|
field = iter.readObjectField()
|
||||||
|
fieldDecoder = decoder.fields[field]
|
||||||
|
if fieldDecoder == nil {
|
||||||
|
iter.Skip()
|
||||||
|
} else {
|
||||||
|
fieldDecoder.decode(ptr, iter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if iter.Error != nil && iter.Error != io.EOF {
|
||||||
|
iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type skipDecoder struct {
|
||||||
|
typ reflect.Type
|
||||||
|
}
|
||||||
|
|
||||||
|
func (decoder *skipDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||||
|
iter.Skip()
|
||||||
|
if iter.Error != nil && iter.Error != io.EOF {
|
||||||
|
iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type oneFieldStructDecoder struct {
|
||||||
|
typ reflect.Type
|
||||||
|
fieldName string
|
||||||
|
fieldDecoder *structFieldDecoder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (decoder *oneFieldStructDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||||
|
if !iter.readObjectStart() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
field := iter.readObjectField()
|
||||||
|
if field == decoder.fieldName {
|
||||||
|
decoder.fieldDecoder.decode(ptr, iter)
|
||||||
|
} else {
|
||||||
|
iter.Skip()
|
||||||
|
}
|
||||||
|
for iter.nextToken() == ',' {
|
||||||
|
field = iter.readObjectField()
|
||||||
|
if field == decoder.fieldName {
|
||||||
|
decoder.fieldDecoder.decode(ptr, iter)
|
||||||
|
} else {
|
||||||
|
iter.Skip()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if iter.Error != nil && iter.Error != io.EOF {
|
||||||
|
iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type twoFieldsStructDecoder struct {
|
||||||
|
typ reflect.Type
|
||||||
|
fieldName1 string
|
||||||
|
fieldDecoder1 *structFieldDecoder
|
||||||
|
fieldName2 string
|
||||||
|
fieldDecoder2 *structFieldDecoder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (decoder *twoFieldsStructDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||||
|
if !iter.readObjectStart() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
field := iter.readObjectField()
|
||||||
|
switch field {
|
||||||
|
case decoder.fieldName1:
|
||||||
|
decoder.fieldDecoder1.decode(ptr, iter)
|
||||||
|
case decoder.fieldName2:
|
||||||
|
decoder.fieldDecoder2.decode(ptr, iter)
|
||||||
|
default:
|
||||||
|
iter.Skip()
|
||||||
|
}
|
||||||
|
for iter.nextToken() == ',' {
|
||||||
|
field = iter.readObjectField()
|
||||||
|
switch field {
|
||||||
|
case decoder.fieldName1:
|
||||||
|
decoder.fieldDecoder1.decode(ptr, iter)
|
||||||
|
case decoder.fieldName2:
|
||||||
|
decoder.fieldDecoder2.decode(ptr, iter)
|
||||||
|
default:
|
||||||
|
iter.Skip()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if iter.Error != nil && iter.Error != io.EOF {
|
||||||
|
iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type threeFieldsStructDecoder struct {
|
||||||
|
typ reflect.Type
|
||||||
|
fieldName1 string
|
||||||
|
fieldDecoder1 *structFieldDecoder
|
||||||
|
fieldName2 string
|
||||||
|
fieldDecoder2 *structFieldDecoder
|
||||||
|
fieldName3 string
|
||||||
|
fieldDecoder3 *structFieldDecoder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (decoder *threeFieldsStructDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||||
|
if !iter.readObjectStart() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
field := iter.readObjectField()
|
||||||
|
switch field {
|
||||||
|
case decoder.fieldName1:
|
||||||
|
decoder.fieldDecoder1.decode(ptr, iter)
|
||||||
|
case decoder.fieldName2:
|
||||||
|
decoder.fieldDecoder2.decode(ptr, iter)
|
||||||
|
case decoder.fieldName3:
|
||||||
|
decoder.fieldDecoder3.decode(ptr, iter)
|
||||||
|
default:
|
||||||
|
iter.Skip()
|
||||||
|
}
|
||||||
|
for iter.nextToken() == ',' {
|
||||||
|
field = iter.readObjectField()
|
||||||
|
switch field {
|
||||||
|
case decoder.fieldName1:
|
||||||
|
decoder.fieldDecoder1.decode(ptr, iter)
|
||||||
|
case decoder.fieldName2:
|
||||||
|
decoder.fieldDecoder2.decode(ptr, iter)
|
||||||
|
case decoder.fieldName3:
|
||||||
|
decoder.fieldDecoder3.decode(ptr, iter)
|
||||||
|
default:
|
||||||
|
iter.Skip()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if iter.Error != nil && iter.Error != io.EOF {
|
||||||
|
iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type fourFieldsStructDecoder struct {
|
||||||
|
typ reflect.Type
|
||||||
|
fieldName1 string
|
||||||
|
fieldDecoder1 *structFieldDecoder
|
||||||
|
fieldName2 string
|
||||||
|
fieldDecoder2 *structFieldDecoder
|
||||||
|
fieldName3 string
|
||||||
|
fieldDecoder3 *structFieldDecoder
|
||||||
|
fieldName4 string
|
||||||
|
fieldDecoder4 *structFieldDecoder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (decoder *fourFieldsStructDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||||
|
if !iter.readObjectStart() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
field := iter.readObjectField()
|
||||||
|
switch field {
|
||||||
|
case decoder.fieldName1:
|
||||||
|
decoder.fieldDecoder1.decode(ptr, iter)
|
||||||
|
case decoder.fieldName2:
|
||||||
|
decoder.fieldDecoder2.decode(ptr, iter)
|
||||||
|
case decoder.fieldName3:
|
||||||
|
decoder.fieldDecoder3.decode(ptr, iter)
|
||||||
|
case decoder.fieldName4:
|
||||||
|
decoder.fieldDecoder4.decode(ptr, iter)
|
||||||
|
default:
|
||||||
|
iter.Skip()
|
||||||
|
}
|
||||||
|
for iter.nextToken() == ',' {
|
||||||
|
field = iter.readObjectField()
|
||||||
|
switch field {
|
||||||
|
case decoder.fieldName1:
|
||||||
|
decoder.fieldDecoder1.decode(ptr, iter)
|
||||||
|
case decoder.fieldName2:
|
||||||
|
decoder.fieldDecoder2.decode(ptr, iter)
|
||||||
|
case decoder.fieldName3:
|
||||||
|
decoder.fieldDecoder3.decode(ptr, iter)
|
||||||
|
case decoder.fieldName4:
|
||||||
|
decoder.fieldDecoder4.decode(ptr, iter)
|
||||||
|
default:
|
||||||
|
iter.Skip()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if iter.Error != nil && iter.Error != io.EOF {
|
||||||
|
iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type structFieldDecoder struct {
|
||||||
|
field *reflect.StructField
|
||||||
|
fieldDecoder Decoder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (decoder *structFieldDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||||
|
fieldPtr := uintptr(ptr) + decoder.field.Offset
|
||||||
|
decoder.fieldDecoder.decode(unsafe.Pointer(fieldPtr), iter)
|
||||||
|
if iter.Error != nil && iter.Error != io.EOF {
|
||||||
|
iter.Error = fmt.Errorf("%s: %s", decoder.field.Name, iter.Error.Error())
|
||||||
|
}
|
||||||
|
}
|
112
jsoniter_reflect_struct_test.go
Normal file
112
jsoniter_reflect_struct_test.go
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
package jsoniter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"github.com/json-iterator/go/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_decode_one_field_struct(t *testing.T) {
|
||||||
|
should := require.New(t)
|
||||||
|
type TestObject struct {
|
||||||
|
field1 string
|
||||||
|
}
|
||||||
|
obj := TestObject{}
|
||||||
|
should.Nil(UnmarshalString(`{}`, &obj))
|
||||||
|
should.Equal("", obj.field1)
|
||||||
|
should.Nil(UnmarshalString(`{"field1": "hello"}`, &obj))
|
||||||
|
should.Equal("hello", obj.field1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_decode_two_fields_struct(t *testing.T) {
|
||||||
|
should := require.New(t)
|
||||||
|
type TestObject struct {
|
||||||
|
field1 string
|
||||||
|
field2 string
|
||||||
|
}
|
||||||
|
obj := TestObject{}
|
||||||
|
should.Nil(UnmarshalString(`{}`, &obj))
|
||||||
|
should.Equal("", obj.field1)
|
||||||
|
should.Nil(UnmarshalString(`{"field1": "a", "field2": "b"}`, &obj))
|
||||||
|
should.Equal("a", obj.field1)
|
||||||
|
should.Equal("b", obj.field2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_decode_three_fields_struct(t *testing.T) {
|
||||||
|
should := require.New(t)
|
||||||
|
type TestObject struct {
|
||||||
|
field1 string
|
||||||
|
field2 string
|
||||||
|
field3 string
|
||||||
|
}
|
||||||
|
obj := TestObject{}
|
||||||
|
should.Nil(UnmarshalString(`{}`, &obj))
|
||||||
|
should.Equal("", obj.field1)
|
||||||
|
should.Nil(UnmarshalString(`{"field1": "a", "field2": "b", "field3": "c"}`, &obj))
|
||||||
|
should.Equal("a", obj.field1)
|
||||||
|
should.Equal("b", obj.field2)
|
||||||
|
should.Equal("c", obj.field3)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_decode_four_fields_struct(t *testing.T) {
|
||||||
|
should := require.New(t)
|
||||||
|
type TestObject struct {
|
||||||
|
field1 string
|
||||||
|
field2 string
|
||||||
|
field3 string
|
||||||
|
field4 string
|
||||||
|
}
|
||||||
|
obj := TestObject{}
|
||||||
|
should.Nil(UnmarshalString(`{}`, &obj))
|
||||||
|
should.Equal("", obj.field1)
|
||||||
|
should.Nil(UnmarshalString(`{"field1": "a", "field2": "b", "field3": "c", "field4": "d"}`, &obj))
|
||||||
|
should.Equal("a", obj.field1)
|
||||||
|
should.Equal("b", obj.field2)
|
||||||
|
should.Equal("c", obj.field3)
|
||||||
|
should.Equal("d", obj.field4)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_decode_five_fields_struct(t *testing.T) {
|
||||||
|
should := require.New(t)
|
||||||
|
type TestObject struct {
|
||||||
|
field1 string
|
||||||
|
field2 string
|
||||||
|
field3 string
|
||||||
|
field4 string
|
||||||
|
field5 string
|
||||||
|
}
|
||||||
|
obj := TestObject{}
|
||||||
|
should.Nil(UnmarshalString(`{}`, &obj))
|
||||||
|
should.Equal("", obj.field1)
|
||||||
|
should.Nil(UnmarshalString(`{"field1": "a", "field2": "b", "field3": "c", "field4": "d", "field5": "e"}`, &obj))
|
||||||
|
should.Equal("a", obj.field1)
|
||||||
|
should.Equal("b", obj.field2)
|
||||||
|
should.Equal("c", obj.field3)
|
||||||
|
should.Equal("d", obj.field4)
|
||||||
|
should.Equal("e", obj.field5)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_decode_struct_with_optional_field(t *testing.T) {
|
||||||
|
should := require.New(t)
|
||||||
|
type TestObject struct {
|
||||||
|
field1 *string
|
||||||
|
field2 *string
|
||||||
|
}
|
||||||
|
obj := TestObject{}
|
||||||
|
UnmarshalString(`{"field1": null, "field2": "world"}`, &obj)
|
||||||
|
should.Nil(obj.field1)
|
||||||
|
should.Equal("world", *obj.field2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_decode_struct_field_with_tag(t *testing.T) {
|
||||||
|
should := require.New(t)
|
||||||
|
type TestObject struct {
|
||||||
|
Field1 string `json:"field-1"`
|
||||||
|
Field2 string `json:"-"`
|
||||||
|
Field3 int `json:",string"`
|
||||||
|
}
|
||||||
|
obj := TestObject{Field2: "world"}
|
||||||
|
UnmarshalString(`{"field-1": "hello", "field2": "", "Field3": "100"}`, &obj)
|
||||||
|
should.Equal("hello", obj.Field1)
|
||||||
|
should.Equal("world", obj.Field2)
|
||||||
|
should.Equal(100, obj.Field3)
|
||||||
|
}
|
@ -8,159 +8,21 @@ import (
|
|||||||
"github.com/json-iterator/go/require"
|
"github.com/json-iterator/go/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_reflect_one_field_struct(t *testing.T) {
|
func Test_decode_slice(t *testing.T) {
|
||||||
should := require.New(t)
|
should := require.New(t)
|
||||||
type TestObject struct {
|
|
||||||
field1 string
|
|
||||||
}
|
|
||||||
obj := TestObject{}
|
|
||||||
should.Nil(UnmarshalString(`{}`, &obj))
|
|
||||||
should.Equal("", obj.field1)
|
|
||||||
should.Nil(UnmarshalString(`{"field1": "hello"}`, &obj))
|
|
||||||
should.Equal("hello", obj.field1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_reflect_two_fields_struct(t *testing.T) {
|
|
||||||
should := require.New(t)
|
|
||||||
type TestObject struct {
|
|
||||||
field1 string
|
|
||||||
field2 string
|
|
||||||
}
|
|
||||||
obj := TestObject{}
|
|
||||||
should.Nil(UnmarshalString(`{}`, &obj))
|
|
||||||
should.Equal("", obj.field1)
|
|
||||||
should.Nil(UnmarshalString(`{"field1": "a", "field2": "b"}`, &obj))
|
|
||||||
should.Equal("a", obj.field1)
|
|
||||||
should.Equal("b", obj.field2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_reflect_three_fields_struct(t *testing.T) {
|
|
||||||
should := require.New(t)
|
|
||||||
type TestObject struct {
|
|
||||||
field1 string
|
|
||||||
field2 string
|
|
||||||
field3 string
|
|
||||||
}
|
|
||||||
obj := TestObject{}
|
|
||||||
should.Nil(UnmarshalString(`{}`, &obj))
|
|
||||||
should.Equal("", obj.field1)
|
|
||||||
should.Nil(UnmarshalString(`{"field1": "a", "field2": "b", "field3": "c"}`, &obj))
|
|
||||||
should.Equal("a", obj.field1)
|
|
||||||
should.Equal("b", obj.field2)
|
|
||||||
should.Equal("c", obj.field3)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_reflect_four_fields_struct(t *testing.T) {
|
|
||||||
should := require.New(t)
|
|
||||||
type TestObject struct {
|
|
||||||
field1 string
|
|
||||||
field2 string
|
|
||||||
field3 string
|
|
||||||
field4 string
|
|
||||||
}
|
|
||||||
obj := TestObject{}
|
|
||||||
should.Nil(UnmarshalString(`{}`, &obj))
|
|
||||||
should.Equal("", obj.field1)
|
|
||||||
should.Nil(UnmarshalString(`{"field1": "a", "field2": "b", "field3": "c", "field4": "d"}`, &obj))
|
|
||||||
should.Equal("a", obj.field1)
|
|
||||||
should.Equal("b", obj.field2)
|
|
||||||
should.Equal("c", obj.field3)
|
|
||||||
should.Equal("d", obj.field4)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_reflect_five_fields_struct(t *testing.T) {
|
|
||||||
should := require.New(t)
|
|
||||||
type TestObject struct {
|
|
||||||
field1 string
|
|
||||||
field2 string
|
|
||||||
field3 string
|
|
||||||
field4 string
|
|
||||||
field5 string
|
|
||||||
}
|
|
||||||
obj := TestObject{}
|
|
||||||
should.Nil(UnmarshalString(`{}`, &obj))
|
|
||||||
should.Equal("", obj.field1)
|
|
||||||
should.Nil(UnmarshalString(`{"field1": "a", "field2": "b", "field3": "c", "field4": "d", "field5": "e"}`, &obj))
|
|
||||||
should.Equal("a", obj.field1)
|
|
||||||
should.Equal("b", obj.field2)
|
|
||||||
should.Equal("c", obj.field3)
|
|
||||||
should.Equal("d", obj.field4)
|
|
||||||
should.Equal("e", obj.field5)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_struct_with_optional_field(t *testing.T) {
|
|
||||||
should := require.New(t)
|
|
||||||
type TestObject struct {
|
|
||||||
field1 *string
|
|
||||||
field2 *string
|
|
||||||
}
|
|
||||||
obj := TestObject{}
|
|
||||||
UnmarshalString(`{"field1": null, "field2": "world"}`, &obj)
|
|
||||||
should.Nil(obj.field1)
|
|
||||||
should.Equal("world", *obj.field2)
|
|
||||||
}
|
|
||||||
|
|
||||||
type StructOfTag struct {
|
|
||||||
Field1 string `json:"field-1"`
|
|
||||||
Field2 string `json:"-"`
|
|
||||||
Field3 int `json:",string"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_reflect_struct_tag_field(t *testing.T) {
|
|
||||||
iter := ParseString(`{"field-1": "hello", "field2": "", "Field3": "100"}`)
|
|
||||||
Struct := StructOfTag{Field2: "world"}
|
|
||||||
iter.Read(&Struct)
|
|
||||||
if Struct.Field1 != "hello" {
|
|
||||||
fmt.Println(iter.Error)
|
|
||||||
t.Fatal(Struct.Field1)
|
|
||||||
}
|
|
||||||
if Struct.Field2 != "world" {
|
|
||||||
fmt.Println(iter.Error)
|
|
||||||
t.Fatal(Struct.Field2)
|
|
||||||
}
|
|
||||||
if Struct.Field3 != 100 {
|
|
||||||
fmt.Println(iter.Error)
|
|
||||||
t.Fatal(Struct.Field3)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_reflect_slice(t *testing.T) {
|
|
||||||
iter := ParseString(`["hello", "world"]`)
|
|
||||||
slice := make([]string, 0, 5)
|
slice := make([]string, 0, 5)
|
||||||
iter.Read(&slice)
|
UnmarshalString(`["hello", "world"]`, &slice)
|
||||||
if len(slice) != 2 {
|
should.Equal([]string{"hello", "world"}, slice)
|
||||||
fmt.Println(iter.Error)
|
|
||||||
t.Fatal(len(slice))
|
|
||||||
}
|
|
||||||
if slice[0] != "hello" {
|
|
||||||
fmt.Println(iter.Error)
|
|
||||||
t.Fatal(slice[0])
|
|
||||||
}
|
|
||||||
if slice[1] != "world" {
|
|
||||||
fmt.Println(iter.Error)
|
|
||||||
t.Fatal(slice[1])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_reflect_large_slice(t *testing.T) {
|
func Test_decode_large_slice(t *testing.T) {
|
||||||
iter := ParseString(`[1,2,3,4,5,6,7,8,9]`)
|
should := require.New(t)
|
||||||
slice := make([]int, 0, 1)
|
slice := make([]int, 0, 1)
|
||||||
iter.Read(&slice)
|
UnmarshalString(`[1,2,3,4,5,6,7,8,9]`, &slice)
|
||||||
if len(slice) != 9 {
|
should.Equal([]int{1, 2, 3, 4, 5, 6, 7, 8, 9}, slice)
|
||||||
fmt.Println(iter.Error)
|
|
||||||
t.Fatal(len(slice))
|
|
||||||
}
|
|
||||||
if slice[0] != 1 {
|
|
||||||
fmt.Println(iter.Error)
|
|
||||||
t.Fatal(slice[0])
|
|
||||||
}
|
|
||||||
if slice[8] != 9 {
|
|
||||||
fmt.Println(iter.Error)
|
|
||||||
t.Fatal(slice[8])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_reflect_nested(t *testing.T) {
|
func Test_decode_nested(t *testing.T) {
|
||||||
type StructOfString struct {
|
type StructOfString struct {
|
||||||
field1 string
|
field1 string
|
||||||
field2 string
|
field2 string
|
||||||
@ -186,7 +48,7 @@ func Test_reflect_nested(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_reflect_base64(t *testing.T) {
|
func Test_decode_base64(t *testing.T) {
|
||||||
iter := ParseString(`"YWJj"`)
|
iter := ParseString(`"YWJj"`)
|
||||||
val := []byte{}
|
val := []byte{}
|
||||||
RegisterTypeDecoder("[]uint8", func(ptr unsafe.Pointer, iter *Iterator) {
|
RegisterTypeDecoder("[]uint8", func(ptr unsafe.Pointer, iter *Iterator) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user