1
0
mirror of https://github.com/json-iterator/go.git synced 2025-01-23 18:54:21 +02:00
json-iterator/feature_reflect_map.go

245 lines
7.1 KiB
Go
Raw Normal View History

2017-05-24 14:34:00 +08:00
package jsoniter
import (
2017-06-05 23:01:00 +08:00
"encoding"
2017-06-06 23:27:00 +08:00
"encoding/json"
"reflect"
2017-06-17 21:11:23 +08:00
"sort"
2017-06-05 23:53:48 +08:00
"strconv"
2017-06-06 23:27:00 +08:00
"unsafe"
2017-05-24 14:34:00 +08:00
)
type mapDecoder struct {
mapType reflect.Type
2017-06-05 23:53:48 +08:00
keyType reflect.Type
2017-05-24 14:34:00 +08:00
elemType reflect.Type
elemDecoder ValDecoder
2017-05-24 14:34:00 +08:00
mapInterface emptyInterface
}
2017-06-20 15:11:01 +08:00
func (decoder *mapDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
2017-05-24 14:34:00 +08:00
// dark magic to cast unsafe.Pointer back to interface{} using reflect.Type
mapInterface := decoder.mapInterface
mapInterface.word = ptr
realInterface := (*interface{})(unsafe.Pointer(&mapInterface))
realVal := reflect.ValueOf(*realInterface).Elem()
2017-06-26 10:20:49 +08:00
if iter.ReadNil() {
realVal.Set(reflect.Zero(decoder.mapType))
return
}
2017-05-24 14:34:00 +08:00
if realVal.IsNil() {
realVal.Set(reflect.MakeMap(realVal.Type()))
}
iter.ReadMapCB(func(iter *Iterator, keyStr string) bool {
2017-05-24 14:34:00 +08:00
elem := reflect.New(decoder.elemType)
2017-06-20 15:11:01 +08:00
decoder.elemDecoder.Decode(unsafe.Pointer(elem.Pointer()), iter)
2017-05-24 14:34:00 +08:00
// to put into map, we have to use reflection
2017-06-06 00:09:33 +08:00
keyType := decoder.keyType
2017-06-29 00:14:55 +08:00
// TODO: remove this from loop
2017-06-06 00:09:33 +08:00
switch {
case keyType.Kind() == reflect.String:
2017-06-26 11:52:22 +08:00
realVal.SetMapIndex(reflect.ValueOf(keyStr).Convert(keyType), elem.Elem())
2017-06-06 00:09:33 +08:00
return true
case keyType.Implements(textUnmarshalerType):
textUnmarshaler := reflect.New(keyType.Elem()).Interface().(encoding.TextUnmarshaler)
err := textUnmarshaler.UnmarshalText([]byte(keyStr))
if err != nil {
2017-06-20 15:11:01 +08:00
iter.ReportError("read map key as TextUnmarshaler", err.Error())
2017-06-06 00:09:33 +08:00
return false
2017-06-05 23:53:48 +08:00
}
2017-06-06 00:09:33 +08:00
realVal.SetMapIndex(reflect.ValueOf(textUnmarshaler), elem.Elem())
return true
2017-06-29 00:14:55 +08:00
case reflect.PtrTo(keyType).Implements(textUnmarshalerType):
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())
return true
2017-06-06 00:09:33 +08:00
default:
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) {
2017-06-20 15:11:01 +08:00
iter.ReportError("read map key as int64", "read int64 failed")
2017-06-06 00:09:33 +08:00
return false
}
realVal.SetMapIndex(reflect.ValueOf(n).Convert(keyType), elem.Elem())
return true
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
n, err := strconv.ParseUint(keyStr, 10, 64)
if err != nil || reflect.Zero(keyType).OverflowUint(n) {
2017-06-20 15:11:01 +08:00
iter.ReportError("read map key as uint64", "read uint64 failed")
2017-06-06 00:09:33 +08:00
return false
}
realVal.SetMapIndex(reflect.ValueOf(n).Convert(keyType), elem.Elem())
return true
2017-06-05 23:53:48 +08:00
}
}
2017-06-20 15:11:01 +08:00
iter.ReportError("read map key", "unexpected map key type "+keyType.String())
2017-06-06 00:09:33 +08:00
return true
})
2017-05-24 14:34:00 +08:00
}
type mapEncoder struct {
mapType reflect.Type
elemType reflect.Type
elemEncoder ValEncoder
2017-05-24 14:34:00 +08:00
mapInterface emptyInterface
}
2017-06-20 15:11:01 +08:00
func (encoder *mapEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
2017-05-24 14:34:00 +08:00
mapInterface := encoder.mapInterface
mapInterface.word = ptr
realInterface := (*interface{})(unsafe.Pointer(&mapInterface))
realVal := reflect.ValueOf(*realInterface)
stream.WriteObjectStart()
for i, key := range realVal.MapKeys() {
if i != 0 {
stream.WriteMore()
}
2017-06-05 23:01:00 +08:00
encodeMapKey(key, stream)
if stream.indention > 0 {
stream.writeTwoBytes(byte(':'), byte(' '))
} else {
stream.writeByte(':')
}
2017-05-24 14:34:00 +08:00
val := realVal.MapIndex(key).Interface()
2017-06-20 15:11:01 +08:00
encoder.elemEncoder.EncodeInterface(val, stream)
2017-05-24 14:34:00 +08:00
}
stream.WriteObjectEnd()
}
2017-06-05 23:01:00 +08:00
func encodeMapKey(key reflect.Value, stream *Stream) {
if key.Kind() == reflect.String {
stream.WriteString(key.String())
return
}
if tm, ok := key.Interface().(encoding.TextMarshaler); ok {
buf, err := tm.MarshalText()
if err != nil {
stream.Error = err
return
}
stream.writeByte('"')
stream.Write(buf)
stream.writeByte('"')
return
}
switch key.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
stream.writeByte('"')
stream.WriteInt64(key.Int())
stream.writeByte('"')
return
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
stream.writeByte('"')
stream.WriteUint64(key.Uint())
stream.writeByte('"')
return
}
2017-07-09 11:33:03 +08:00
stream.Error = &json.UnsupportedTypeError{Type: key.Type()}
2017-06-05 23:01:00 +08:00
}
2017-06-20 15:11:01 +08:00
func (encoder *mapEncoder) EncodeInterface(val interface{}, stream *Stream) {
2017-06-20 17:43:47 +08:00
WriteToStream(val, stream, encoder)
2017-05-24 14:34:00 +08:00
}
2017-06-20 15:11:01 +08:00
func (encoder *mapEncoder) IsEmpty(ptr unsafe.Pointer) bool {
2017-05-24 14:34:00 +08:00
mapInterface := encoder.mapInterface
mapInterface.word = ptr
realInterface := (*interface{})(unsafe.Pointer(&mapInterface))
realVal := reflect.ValueOf(*realInterface)
return realVal.Len() == 0
2017-06-06 00:09:33 +08:00
}
2017-06-16 16:46:30 +08:00
type sortKeysMapEncoder struct {
mapType reflect.Type
elemType reflect.Type
elemEncoder ValEncoder
2017-06-16 16:46:30 +08:00
mapInterface emptyInterface
}
2017-06-20 15:11:01 +08:00
func (encoder *sortKeysMapEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
2017-06-16 16:46:30 +08:00
mapInterface := encoder.mapInterface
mapInterface.word = ptr
realInterface := (*interface{})(unsafe.Pointer(&mapInterface))
realVal := reflect.ValueOf(*realInterface)
// Extract and sort the keys.
2017-06-26 10:42:47 +08:00
keys := realVal.MapKeys()
2017-07-02 13:22:55 +08:00
sv := stringValues(make([]reflectWithString, len(keys)))
2017-06-26 10:42:47 +08:00
for i, v := range keys {
sv[i].v = v
if err := sv[i].resolve(); err != nil {
stream.Error = err
return
}
}
2017-07-02 13:22:55 +08:00
sort.Sort(sv)
2017-06-16 16:46:30 +08:00
stream.WriteObjectStart()
for i, key := range sv {
if i != 0 {
stream.WriteMore()
}
2017-06-26 11:52:22 +08:00
stream.WriteVal(key.s) // might need html escape, so can not WriteString directly
if stream.indention > 0 {
stream.writeTwoBytes(byte(':'), byte(' '))
} else {
stream.writeByte(':')
}
2017-06-26 10:42:47 +08:00
val := realVal.MapIndex(key.v).Interface()
2017-06-20 15:11:01 +08:00
encoder.elemEncoder.EncodeInterface(val, stream)
2017-06-16 16:46:30 +08:00
}
stream.WriteObjectEnd()
}
2017-06-17 16:27:19 +08:00
// stringValues is a slice of reflect.Value holding *reflect.StringValue.
// It implements the methods to sort by string.
2017-06-26 10:42:47 +08:00
type stringValues []reflectWithString
type reflectWithString struct {
v reflect.Value
s string
}
func (w *reflectWithString) resolve() error {
if w.v.Kind() == reflect.String {
w.s = w.v.String()
return nil
}
if tm, ok := w.v.Interface().(encoding.TextMarshaler); ok {
buf, err := tm.MarshalText()
w.s = string(buf)
return err
}
switch w.v.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
w.s = strconv.FormatInt(w.v.Int(), 10)
return nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
w.s = strconv.FormatUint(w.v.Uint(), 10)
return nil
}
2017-07-09 11:33:03 +08:00
return &json.UnsupportedTypeError{Type: w.v.Type()}
2017-06-26 10:42:47 +08:00
}
2017-06-16 16:46:30 +08:00
2017-06-17 16:27:19 +08:00
func (sv stringValues) Len() int { return len(sv) }
func (sv stringValues) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] }
2017-06-26 10:42:47 +08:00
func (sv stringValues) Less(i, j int) bool { return sv[i].s < sv[j].s }
2017-06-16 16:46:30 +08:00
2017-06-20 15:11:01 +08:00
func (encoder *sortKeysMapEncoder) EncodeInterface(val interface{}, stream *Stream) {
2017-06-20 17:43:47 +08:00
WriteToStream(val, stream, encoder)
2017-06-16 16:46:30 +08:00
}
2017-06-20 15:11:01 +08:00
func (encoder *sortKeysMapEncoder) IsEmpty(ptr unsafe.Pointer) bool {
2017-06-16 16:46:30 +08:00
mapInterface := encoder.mapInterface
mapInterface.word = ptr
realInterface := (*interface{})(unsafe.Pointer(&mapInterface))
realVal := reflect.ValueOf(*realInterface)
return realVal.Len() == 0
}