mirror of
https://github.com/json-iterator/go.git
synced 2024-11-27 08:30:57 +02:00
split files
This commit is contained in:
parent
c78023531e
commit
5af8cc4b09
@ -6,7 +6,6 @@ import (
|
||||
"io"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"unsafe"
|
||||
)
|
||||
@ -25,6 +24,71 @@ type Decoder interface {
|
||||
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 {
|
||||
valueType reflect.Type
|
||||
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 {
|
||||
mapType 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.
|
||||
type emptyInterface struct {
|
||||
typ *struct{}
|
||||
@ -646,123 +337,6 @@ func decoderOfOptional(typ reflect.Type) (Decoder, error) {
|
||||
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) {
|
||||
decoder, err := decoderOfPtr(typ.Elem())
|
||||
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"
|
||||
)
|
||||
|
||||
func Test_reflect_one_field_struct(t *testing.T) {
|
||||
func Test_decode_slice(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_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)
|
||||
iter.Read(&slice)
|
||||
if len(slice) != 2 {
|
||||
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])
|
||||
}
|
||||
UnmarshalString(`["hello", "world"]`, &slice)
|
||||
should.Equal([]string{"hello", "world"}, slice)
|
||||
}
|
||||
|
||||
func Test_reflect_large_slice(t *testing.T) {
|
||||
iter := ParseString(`[1,2,3,4,5,6,7,8,9]`)
|
||||
func Test_decode_large_slice(t *testing.T) {
|
||||
should := require.New(t)
|
||||
slice := make([]int, 0, 1)
|
||||
iter.Read(&slice)
|
||||
if len(slice) != 9 {
|
||||
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])
|
||||
}
|
||||
UnmarshalString(`[1,2,3,4,5,6,7,8,9]`, &slice)
|
||||
should.Equal([]int{1, 2, 3, 4, 5, 6, 7, 8, 9}, slice)
|
||||
}
|
||||
|
||||
func Test_reflect_nested(t *testing.T) {
|
||||
func Test_decode_nested(t *testing.T) {
|
||||
type StructOfString struct {
|
||||
field1 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"`)
|
||||
val := []byte{}
|
||||
RegisterTypeDecoder("[]uint8", func(ptr unsafe.Pointer, iter *Iterator) {
|
||||
|
Loading…
Reference in New Issue
Block a user