1
0
mirror of https://github.com/json-iterator/go.git synced 2025-05-13 21:36:29 +02:00

use reflect2 to implement map decoder

This commit is contained in:
Tao Wen 2018-02-19 22:53:42 +08:00
parent d6f02cbd48
commit 08218647c3
5 changed files with 201 additions and 133 deletions

View File

@ -82,19 +82,22 @@ func (stream *Stream) WriteVal(val interface{}) {
encoder.Encode(reflect2.PtrOf(val), stream) encoder.Encode(reflect2.PtrOf(val), stream)
} }
func decoderOfType(cfg *frozenConfig, prefix string, typ reflect.Type) ValDecoder { func (cfg *frozenConfig) DecoderOf(typ reflect.Type) ValDecoder {
cacheKey := typ cacheKey := typ
decoder := cfg.getDecoderFromCache(cacheKey) decoder := cfg.getDecoderFromCache(cacheKey)
if decoder != nil { if decoder != nil {
return decoder return decoder
} }
decoder = getTypeDecoderFromExtension(cfg, typ) decoder = decoderOfType(cfg, "", typ)
if decoder != nil {
cfg.addDecoderToCache(cacheKey, decoder) cfg.addDecoderToCache(cacheKey, decoder)
return decoder return decoder
} }
decoder = &placeholderDecoder{cfg: cfg, cacheKey: cacheKey}
cfg.addDecoderToCache(cacheKey, decoder) func decoderOfType(cfg *frozenConfig, prefix string, typ reflect.Type) ValDecoder {
decoder := getTypeDecoderFromExtension(cfg, typ)
if decoder != nil {
return decoder
}
decoder = createDecoderOfType(cfg, prefix, typ) decoder = createDecoderOfType(cfg, prefix, typ)
for _, extension := range extensions { for _, extension := range extensions {
decoder = extension.DecorateDecoder(typ, decoder) decoder = extension.DecorateDecoder(typ, decoder)
@ -102,7 +105,6 @@ func decoderOfType(cfg *frozenConfig, prefix string, typ reflect.Type) ValDecode
for _, extension := range cfg.extensions { for _, extension := range cfg.extensions {
decoder = extension.DecorateDecoder(typ, decoder) decoder = extension.DecorateDecoder(typ, decoder)
} }
cfg.addDecoderToCache(cacheKey, decoder)
return decoder return decoder
} }
@ -120,30 +122,8 @@ func createDecoderOfType(cfg *frozenConfig, prefix string, typ reflect.Type) Val
if typ.AssignableTo(jsoniterNumberType) { if typ.AssignableTo(jsoniterNumberType) {
return &jsoniterNumberCodec{} return &jsoniterNumberCodec{}
} }
if typ.Implements(unmarshalerType) { decoder := createDecoderOfMarshaler(cfg, prefix, typ)
templateInterface := reflect.New(typ).Elem().Interface() if decoder != nil {
var decoder ValDecoder = &unmarshalerDecoder{extractInterface(templateInterface)}
if typ.Kind() == reflect.Ptr {
decoder = &OptionalDecoder{typ.Elem(), decoder}
}
return decoder
}
if reflect.PtrTo(typ).Implements(unmarshalerType) {
templateInterface := reflect.New(typ).Interface()
var decoder ValDecoder = &unmarshalerDecoder{extractInterface(templateInterface)}
return decoder
}
if typ.Implements(textUnmarshalerType) {
templateInterface := reflect.New(typ).Elem().Interface()
var decoder ValDecoder = &textUnmarshalerDecoder{extractInterface(templateInterface)}
if typ.Kind() == reflect.Ptr {
decoder = &OptionalDecoder{typ.Elem(), decoder}
}
return decoder
}
if reflect.PtrTo(typ).Implements(textUnmarshalerType) {
templateInterface := reflect.New(typ).Interface()
var decoder ValDecoder = &textUnmarshalerDecoder{extractInterface(templateInterface)}
return decoder return decoder
} }
if typ.Kind() == reflect.Slice && typ.Elem().Kind() == reflect.Uint8 { if typ.Kind() == reflect.Slice && typ.Elem().Kind() == reflect.Uint8 {

View File

@ -1,19 +1,24 @@
package jsoniter package jsoniter
import ( import (
"encoding"
"reflect" "reflect"
"sort" "sort"
"strconv"
"unsafe" "unsafe"
"github.com/v2pro/plz/reflect2" "github.com/v2pro/plz/reflect2"
"fmt" "fmt"
) )
func decoderOfMap(cfg *frozenConfig, prefix string, typ reflect.Type) ValDecoder { func decoderOfMap(cfg *frozenConfig, prefix string, typ reflect.Type) ValDecoder {
decoder := decoderOfType(cfg, prefix+"[map]->", typ.Elem()) keyDecoder := decoderOfMapKey(cfg, prefix+" [mapKey]", typ.Key())
mapInterface := reflect.New(typ).Interface() elemDecoder := decoderOfType(cfg, prefix+" [mapElem]", typ.Elem())
return &mapDecoder{typ, typ.Key(), typ.Elem(), decoder, extractInterface(mapInterface)} mapType := reflect2.Type2(typ).(*reflect2.UnsafeMapType)
return &mapDecoder{
mapType: mapType,
keyType: mapType.Key(),
elemType: mapType.Elem(),
keyDecoder: keyDecoder,
elemDecoder: elemDecoder,
}
} }
func encoderOfMap(cfg *frozenConfig, prefix string, typ reflect.Type) ValEncoder { func encoderOfMap(cfg *frozenConfig, prefix string, typ reflect.Type) ValEncoder {
@ -31,6 +36,38 @@ func encoderOfMap(cfg *frozenConfig, prefix string, typ reflect.Type) ValEncoder
} }
} }
func decoderOfMapKey(cfg *frozenConfig, prefix string, typ reflect.Type) ValDecoder {
switch typ.Kind() {
case reflect.String:
return decoderOfType(cfg, prefix, reflect2.DefaultTypeOfKind(reflect.String).Type1())
case reflect.Bool,
reflect.Uint8, reflect.Int8,
reflect.Uint16, reflect.Int16,
reflect.Uint32, reflect.Int32,
reflect.Uint64, reflect.Int64,
reflect.Uint, reflect.Int,
reflect.Float32, reflect.Float64,
reflect.Uintptr:
typ = reflect2.DefaultTypeOfKind(typ.Kind()).Type1()
return &numericMapKeyDecoder{decoderOfType(cfg, prefix, typ)}
default:
ptrType := reflect.PtrTo(typ)
if ptrType.Implements(textMarshalerType) {
return &referenceDecoder{
&textUnmarshalerDecoder{
valType: reflect2.Type2(ptrType),
},
}
}
if typ.Implements(textMarshalerType) {
return &textUnmarshalerDecoder{
valType: reflect2.Type2(typ),
}
}
return &lazyErrorDecoder{err: fmt.Errorf("unsupported map key type: %v", typ)}
}
}
func encoderOfMapKey(cfg *frozenConfig, prefix string, typ reflect.Type) ValEncoder { func encoderOfMapKey(cfg *frozenConfig, prefix string, typ reflect.Type) ValEncoder {
switch typ.Kind() { switch typ.Kind() {
case reflect.String: case reflect.String:
@ -62,77 +99,81 @@ func encoderOfMapKey(cfg *frozenConfig, prefix string, typ reflect.Type) ValEnco
} }
type mapDecoder struct { type mapDecoder struct {
mapType reflect.Type mapType *reflect2.UnsafeMapType
keyType reflect.Type keyType reflect2.Type
elemType reflect.Type elemType reflect2.Type
keyDecoder ValDecoder
elemDecoder ValDecoder elemDecoder ValDecoder
mapInterface emptyInterface
} }
func (decoder *mapDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { func (decoder *mapDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
// dark magic to cast unsafe.Pointer back to interface{} using reflect.Type mapType := decoder.mapType
mapInterface := decoder.mapInterface c := iter.nextToken()
mapInterface.word = ptr if c == 'n' {
realInterface := (*interface{})(unsafe.Pointer(&mapInterface)) iter.skipThreeBytes('u', 'l', 'l')
realVal := reflect.ValueOf(*realInterface).Elem() *(*unsafe.Pointer)(ptr) = nil
if iter.ReadNil() { mapType.UnsafeSet(ptr, mapType.UnsafeNew())
realVal.Set(reflect.Zero(decoder.mapType))
return return
} }
if realVal.IsNil() { if mapType.UnsafeIsNil(ptr) {
realVal.Set(reflect.MakeMap(realVal.Type())) mapType.UnsafeSet(ptr, mapType.UnsafeMakeMap(0))
} }
iter.ReadMapCB(func(iter *Iterator, keyStr string) bool { if c != '{' {
elem := reflect.New(decoder.elemType) iter.ReportError("ReadMapCB", `expect { or n, but found `+string([]byte{c}))
decoder.elemDecoder.Decode(extractInterface(elem.Interface()).word, iter) return
// to put into map, we have to use reflection
keyType := decoder.keyType
// TODO: remove this from loop
switch {
case keyType.Kind() == reflect.String:
realVal.SetMapIndex(reflect.ValueOf(keyStr).Convert(keyType), elem.Elem())
return true
case keyType.Implements(textUnmarshalerType):
textUnmarshaler := reflect.New(keyType.Elem()).Interface().(encoding.TextUnmarshaler)
err := textUnmarshaler.UnmarshalText([]byte(keyStr))
if err != nil {
iter.ReportError("read map key as TextUnmarshaler", err.Error())
return false
} }
realVal.SetMapIndex(reflect.ValueOf(textUnmarshaler), elem.Elem()) c = iter.nextToken()
return true if c == '}' {
case reflect.PtrTo(keyType).Implements(textUnmarshalerType): return
textUnmarshaler := reflect.New(keyType).Interface().(encoding.TextUnmarshaler)
err := textUnmarshaler.UnmarshalText([]byte(keyStr))
if err != nil {
iter.ReportError("read map key as TextUnmarshaler", err.Error())
return false
} }
realVal.SetMapIndex(reflect.ValueOf(textUnmarshaler).Elem(), elem.Elem()) if c != '"' {
return true iter.ReportError("ReadMapCB", `expect " after }, but found `+string([]byte{c}))
default: return
switch keyType.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
n, err := strconv.ParseInt(keyStr, 10, 64)
if err != nil || reflect.Zero(keyType).OverflowInt(n) {
iter.ReportError("read map key as int64", "read int64 failed")
return false
} }
realVal.SetMapIndex(reflect.ValueOf(n).Convert(keyType), elem.Elem()) iter.unreadByte()
return true key := decoder.keyType.UnsafeNew()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: decoder.keyDecoder.Decode(key, iter)
n, err := strconv.ParseUint(keyStr, 10, 64) c = iter.nextToken()
if err != nil || reflect.Zero(keyType).OverflowUint(n) { if c != ':' {
iter.ReportError("read map key as uint64", "read uint64 failed") iter.ReportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c}))
return false return
} }
realVal.SetMapIndex(reflect.ValueOf(n).Convert(keyType), elem.Elem()) elem := decoder.elemType.UnsafeNew()
return true decoder.elemDecoder.Decode(elem, iter)
decoder.mapType.UnsafeSetIndex(ptr, key, elem)
for c = iter.nextToken(); c == ','; c = iter.nextToken() {
key := decoder.keyType.UnsafeNew()
decoder.keyDecoder.Decode(key, iter)
c = iter.nextToken()
if c != ':' {
iter.ReportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c}))
return
}
elem := decoder.elemType.UnsafeNew()
decoder.elemDecoder.Decode(elem, iter)
decoder.mapType.UnsafeSetIndex(ptr, key, elem)
}
if c != '}' {
iter.ReportError("ReadMapCB", `expect }, but found `+string([]byte{c}))
} }
} }
iter.ReportError("read map key", "unexpected map key type "+keyType.String())
return true type numericMapKeyDecoder struct {
}) decoder ValDecoder
}
func (decoder *numericMapKeyDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
c := iter.nextToken()
if c != '"' {
iter.ReportError("ReadMapCB", `expect ", but found `+string([]byte{c}))
return
}
decoder.decoder.Decode(ptr, iter)
c = iter.nextToken()
if c != '"' {
iter.ReportError("ReadMapCB", `expect ", but found `+string([]byte{c}))
return
}
} }
type numericMapKeyEncoder struct { type numericMapKeyEncoder struct {

View File

@ -8,6 +8,21 @@ import (
"reflect" "reflect"
) )
func createDecoderOfMarshaler(cfg *frozenConfig, prefix string, typ reflect.Type) ValDecoder {
ptrType := reflect.PtrTo(typ)
if ptrType.Implements(unmarshalerType) {
return &referenceDecoder{
&unmarshalerDecoder{reflect2.Type2(ptrType)},
}
}
if ptrType.Implements(textUnmarshalerType) {
return &referenceDecoder{
&textUnmarshalerDecoder{reflect2.Type2(ptrType)},
}
}
return nil
}
func createEncoderOfMarshaler(cfg *frozenConfig, prefix string, typ reflect.Type) ValEncoder { func createEncoderOfMarshaler(cfg *frozenConfig, prefix string, typ reflect.Type) ValEncoder {
if typ == marshalerType { if typ == marshalerType {
checkIsEmpty := createCheckIsEmpty(cfg, typ) checkIsEmpty := createCheckIsEmpty(cfg, typ)
@ -160,14 +175,13 @@ func (encoder *directTextMarshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool {
} }
type unmarshalerDecoder struct { type unmarshalerDecoder struct {
templateInterface emptyInterface valType reflect2.Type
} }
func (decoder *unmarshalerDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { func (decoder *unmarshalerDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
templateInterface := decoder.templateInterface valType := decoder.valType
templateInterface.word = ptr obj := valType.UnsafeIndirect(ptr)
realInterface := (*interface{})(unsafe.Pointer(&templateInterface)) unmarshaler := obj.(json.Unmarshaler)
unmarshaler := (*realInterface).(json.Unmarshaler)
iter.nextToken() iter.nextToken()
iter.unreadByte() // skip spaces iter.unreadByte() // skip spaces
bytes := iter.SkipAndReturnBytes() bytes := iter.SkipAndReturnBytes()
@ -178,14 +192,20 @@ func (decoder *unmarshalerDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
} }
type textUnmarshalerDecoder struct { type textUnmarshalerDecoder struct {
templateInterface emptyInterface valType reflect2.Type
} }
func (decoder *textUnmarshalerDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { func (decoder *textUnmarshalerDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
templateInterface := decoder.templateInterface valType := decoder.valType
templateInterface.word = ptr obj := valType.UnsafeIndirect(ptr)
realInterface := (*interface{})(unsafe.Pointer(&templateInterface)) if reflect2.IsNil(obj) {
unmarshaler := (*realInterface).(encoding.TextUnmarshaler) ptrType := valType.(*reflect2.UnsafePtrType)
elemType := ptrType.Elem()
elem := elemType.UnsafeNew()
ptrType.UnsafeSet(ptr, unsafe.Pointer(&elem))
obj = valType.UnsafeIndirect(ptr)
}
unmarshaler := (obj).(encoding.TextUnmarshaler)
str := iter.ReadString() str := iter.ReadString()
err := unmarshaler.UnmarshalText([]byte(str)) err := unmarshaler.UnmarshalText([]byte(str))
if err != nil { if err != nil {

View File

@ -119,3 +119,11 @@ func (encoder *referenceEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
func (encoder *referenceEncoder) IsEmpty(ptr unsafe.Pointer) bool { func (encoder *referenceEncoder) IsEmpty(ptr unsafe.Pointer) bool {
return encoder.encoder.IsEmpty(unsafe.Pointer(&ptr)) return encoder.encoder.IsEmpty(unsafe.Pointer(&ptr))
} }
type referenceDecoder struct {
decoder ValDecoder
}
func (decoder *referenceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
decoder.decoder.Decode(unsafe.Pointer(&ptr), iter)
}

View File

@ -6,61 +6,80 @@ import (
) )
func init() { func init() {
jsonMarshaler := json.Marshaler(fakeJsonMarshaler{}) jm := json.Marshaler(jmOfStruct{})
textMarshaler := encoding.TextMarshaler(fakeTextMarshaler{}) tm1 := encoding.TextMarshaler(tmOfStruct{})
textMarshaler2 := encoding.TextMarshaler(&fakeTextMarshaler2{}) tm2 := encoding.TextMarshaler(&tmOfStructInt{})
marshalCases = append(marshalCases, marshalCases = append(marshalCases,
fakeJsonMarshaler{}, jmOfStruct{},
&jsonMarshaler, &jm,
fakeTextMarshaler{}, tmOfStruct{},
&textMarshaler, &tm1,
fakeTextMarshaler2{}, tmOfStructInt{},
&textMarshaler2, &tm2,
map[fakeTextMarshaler]int{ map[tmOfStruct]int{
fakeTextMarshaler{}: 100, tmOfStruct{}: 100,
}, },
map[*fakeTextMarshaler]int{ map[*tmOfStruct]int{
&fakeTextMarshaler{}: 100, &tmOfStruct{}: 100,
}, },
map[encoding.TextMarshaler]int{ map[encoding.TextMarshaler]int{
textMarshaler: 100, tm1: 100,
}, },
) )
unmarshalCases = append(unmarshalCases, unmarshalCase{
ptr: (*tmOfMap)(nil),
input: `"{1:2}"`,
}, unmarshalCase{
ptr: (*tmOfMapPtr)(nil),
input: `"{1:2}"`,
})
} }
type fakeJsonMarshaler struct { type jmOfStruct struct {
F2 chan []byte F2 chan []byte
} }
func (q fakeJsonMarshaler) MarshalJSON() ([]byte, error) { func (q jmOfStruct) MarshalJSON() ([]byte, error) {
return []byte(`""`), nil return []byte(`""`), nil
} }
func (q *fakeJsonMarshaler) UnmarshalJSON(value []byte) error { func (q *jmOfStruct) UnmarshalJSON(value []byte) error {
return nil return nil
} }
type fakeTextMarshaler struct { type tmOfStruct struct {
F2 chan []byte F2 chan []byte
} }
func (q fakeTextMarshaler) MarshalText() ([]byte, error) { func (q tmOfStruct) MarshalText() ([]byte, error) {
return []byte(`""`), nil return []byte(`""`), nil
} }
func (q *fakeTextMarshaler) UnmarshalText(value []byte) error { func (q *tmOfStruct) UnmarshalText(value []byte) error {
return nil return nil
} }
type fakeTextMarshaler2 struct { type tmOfStructInt struct {
Field2 int Field2 int
} }
func (q *fakeTextMarshaler2) MarshalText() ([]byte, error) { func (q *tmOfStructInt) MarshalText() ([]byte, error) {
return []byte(`"abc"`), nil return []byte(`"abc"`), nil
} }
func (q *fakeTextMarshaler2) UnmarshalText(value []byte) error { func (q *tmOfStructInt) UnmarshalText(value []byte) error {
return nil
}
type tmOfMap map[int]int
func (q tmOfMap) UnmarshalText(value []byte) error {
return nil
}
type tmOfMapPtr map[int]int
func (q *tmOfMapPtr) UnmarshalText(value []byte) error {
return nil return nil
} }