You've already forked json-iterator
mirror of
https://github.com/json-iterator/go.git
synced 2025-06-21 23:07:33 +02:00
#27 support json.Marshaler
This commit is contained in:
105
feature_reflect_map.go
Normal file
105
feature_reflect_map.go
Normal file
@ -0,0 +1,105 @@
|
||||
package jsoniter
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type mapDecoder struct {
|
||||
mapType reflect.Type
|
||||
elemType reflect.Type
|
||||
elemDecoder Decoder
|
||||
mapInterface emptyInterface
|
||||
}
|
||||
|
||||
func (decoder *mapDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||
// 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()
|
||||
if realVal.IsNil() {
|
||||
realVal.Set(reflect.MakeMap(realVal.Type()))
|
||||
}
|
||||
for field := iter.ReadObject(); field != ""; field = iter.ReadObject() {
|
||||
elem := reflect.New(decoder.elemType)
|
||||
decoder.elemDecoder.decode(unsafe.Pointer(elem.Pointer()), iter)
|
||||
// to put into map, we have to use reflection
|
||||
realVal.SetMapIndex(reflect.ValueOf(string([]byte(field))), elem.Elem())
|
||||
}
|
||||
}
|
||||
|
||||
type mapEncoder struct {
|
||||
mapType reflect.Type
|
||||
elemType reflect.Type
|
||||
elemEncoder Encoder
|
||||
mapInterface emptyInterface
|
||||
}
|
||||
|
||||
func (encoder *mapEncoder) encode(ptr unsafe.Pointer, stream *Stream) {
|
||||
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()
|
||||
}
|
||||
stream.WriteObjectField(key.String())
|
||||
val := realVal.MapIndex(key).Interface()
|
||||
encoder.elemEncoder.encodeInterface(val, stream)
|
||||
}
|
||||
stream.WriteObjectEnd()
|
||||
}
|
||||
|
||||
func (encoder *mapEncoder) encodeInterface(val interface{}, stream *Stream) {
|
||||
writeToStream(val, stream, encoder)
|
||||
}
|
||||
|
||||
func (encoder *mapEncoder) isEmpty(ptr unsafe.Pointer) bool {
|
||||
mapInterface := encoder.mapInterface
|
||||
mapInterface.word = ptr
|
||||
realInterface := (*interface{})(unsafe.Pointer(&mapInterface))
|
||||
realVal := reflect.ValueOf(*realInterface)
|
||||
return realVal.Len() == 0
|
||||
}
|
||||
|
||||
type mapInterfaceEncoder struct {
|
||||
mapType reflect.Type
|
||||
elemType reflect.Type
|
||||
elemEncoder Encoder
|
||||
mapInterface emptyInterface
|
||||
}
|
||||
|
||||
func (encoder *mapInterfaceEncoder) encode(ptr unsafe.Pointer, stream *Stream) {
|
||||
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()
|
||||
}
|
||||
stream.WriteObjectField(key.String())
|
||||
val := realVal.MapIndex(key).Interface()
|
||||
encoder.elemEncoder.encode(unsafe.Pointer(&val), stream)
|
||||
}
|
||||
stream.WriteObjectEnd()
|
||||
}
|
||||
|
||||
func (encoder *mapInterfaceEncoder) encodeInterface(val interface{}, stream *Stream) {
|
||||
writeToStream(val, stream, encoder)
|
||||
}
|
||||
|
||||
func (encoder *mapInterfaceEncoder) isEmpty(ptr unsafe.Pointer) bool {
|
||||
mapInterface := encoder.mapInterface
|
||||
mapInterface.word = ptr
|
||||
realInterface := (*interface{})(unsafe.Pointer(&mapInterface))
|
||||
realVal := reflect.ValueOf(*realInterface)
|
||||
|
||||
return realVal.Len() == 0
|
||||
}
|
Reference in New Issue
Block a user