mirror of
https://github.com/json-iterator/go.git
synced 2024-12-03 08:45:22 +02:00
cd6773e694
we don't need to check if the key is surrounded by quotation. In fact, the key might not be strings if we register an extension to customize the map key encoder/decoder.It may be an integer, float, or even a struct.
347 lines
8.9 KiB
Go
347 lines
8.9 KiB
Go
package jsoniter
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/modern-go/reflect2"
|
|
"io"
|
|
"reflect"
|
|
"sort"
|
|
"unsafe"
|
|
)
|
|
|
|
func decoderOfMap(ctx *ctx, typ reflect2.Type) ValDecoder {
|
|
mapType := typ.(*reflect2.UnsafeMapType)
|
|
keyDecoder := decoderOfMapKey(ctx.append("[mapKey]"), mapType.Key())
|
|
elemDecoder := decoderOfType(ctx.append("[mapElem]"), mapType.Elem())
|
|
return &mapDecoder{
|
|
mapType: mapType,
|
|
keyType: mapType.Key(),
|
|
elemType: mapType.Elem(),
|
|
keyDecoder: keyDecoder,
|
|
elemDecoder: elemDecoder,
|
|
}
|
|
}
|
|
|
|
func encoderOfMap(ctx *ctx, typ reflect2.Type) ValEncoder {
|
|
mapType := typ.(*reflect2.UnsafeMapType)
|
|
if ctx.sortMapKeys {
|
|
return &sortKeysMapEncoder{
|
|
mapType: mapType,
|
|
keyEncoder: encoderOfMapKey(ctx.append("[mapKey]"), mapType.Key()),
|
|
elemEncoder: encoderOfType(ctx.append("[mapElem]"), mapType.Elem()),
|
|
}
|
|
}
|
|
return &mapEncoder{
|
|
mapType: mapType,
|
|
keyEncoder: encoderOfMapKey(ctx.append("[mapKey]"), mapType.Key()),
|
|
elemEncoder: encoderOfType(ctx.append("[mapElem]"), mapType.Elem()),
|
|
}
|
|
}
|
|
|
|
func decoderOfMapKey(ctx *ctx, typ reflect2.Type) ValDecoder {
|
|
decoder := ctx.decoderExtension.CreateMapKeyDecoder(typ)
|
|
if decoder != nil {
|
|
return decoder
|
|
}
|
|
for _, extension := range ctx.extraExtensions {
|
|
decoder := extension.CreateMapKeyDecoder(typ)
|
|
if decoder != nil {
|
|
return decoder
|
|
}
|
|
}
|
|
|
|
ptrType := reflect2.PtrTo(typ)
|
|
if ptrType.Implements(unmarshalerType) {
|
|
return &referenceDecoder{
|
|
&unmarshalerDecoder{
|
|
valType: ptrType,
|
|
},
|
|
}
|
|
}
|
|
if typ.Implements(unmarshalerType) {
|
|
return &unmarshalerDecoder{
|
|
valType: typ,
|
|
}
|
|
}
|
|
if ptrType.Implements(textUnmarshalerType) {
|
|
return &referenceDecoder{
|
|
&textUnmarshalerDecoder{
|
|
valType: ptrType,
|
|
},
|
|
}
|
|
}
|
|
if typ.Implements(textUnmarshalerType) {
|
|
return &textUnmarshalerDecoder{
|
|
valType: typ,
|
|
}
|
|
}
|
|
|
|
switch typ.Kind() {
|
|
case reflect.String:
|
|
return decoderOfType(ctx, reflect2.DefaultTypeOfKind(reflect.String))
|
|
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())
|
|
return &numericMapKeyDecoder{decoderOfType(ctx, typ)}
|
|
default:
|
|
return &lazyErrorDecoder{err: fmt.Errorf("unsupported map key type: %v", typ)}
|
|
}
|
|
}
|
|
|
|
func encoderOfMapKey(ctx *ctx, typ reflect2.Type) ValEncoder {
|
|
encoder := ctx.encoderExtension.CreateMapKeyEncoder(typ)
|
|
if encoder != nil {
|
|
return encoder
|
|
}
|
|
for _, extension := range ctx.extraExtensions {
|
|
encoder := extension.CreateMapKeyEncoder(typ)
|
|
if encoder != nil {
|
|
return encoder
|
|
}
|
|
}
|
|
|
|
if typ == textMarshalerType {
|
|
return &directTextMarshalerEncoder{
|
|
stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")),
|
|
}
|
|
}
|
|
if typ.Implements(textMarshalerType) {
|
|
return &textMarshalerEncoder{
|
|
valType: typ,
|
|
stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")),
|
|
}
|
|
}
|
|
|
|
switch typ.Kind() {
|
|
case reflect.String:
|
|
return encoderOfType(ctx, reflect2.DefaultTypeOfKind(reflect.String))
|
|
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())
|
|
return &numericMapKeyEncoder{encoderOfType(ctx, typ)}
|
|
default:
|
|
if typ.Kind() == reflect.Interface {
|
|
return &dynamicMapKeyEncoder{ctx, typ}
|
|
}
|
|
return &lazyErrorEncoder{err: fmt.Errorf("unsupported map key type: %v", typ)}
|
|
}
|
|
}
|
|
|
|
type mapDecoder struct {
|
|
mapType *reflect2.UnsafeMapType
|
|
keyType reflect2.Type
|
|
elemType reflect2.Type
|
|
keyDecoder ValDecoder
|
|
elemDecoder ValDecoder
|
|
}
|
|
|
|
func (decoder *mapDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
|
|
mapType := decoder.mapType
|
|
c := iter.nextToken()
|
|
if c == 'n' {
|
|
iter.skipThreeBytes('u', 'l', 'l')
|
|
*(*unsafe.Pointer)(ptr) = nil
|
|
mapType.UnsafeSet(ptr, mapType.UnsafeNew())
|
|
return
|
|
}
|
|
if mapType.UnsafeIsNil(ptr) {
|
|
mapType.UnsafeSet(ptr, mapType.UnsafeMakeMap(0))
|
|
}
|
|
if c != '{' {
|
|
iter.ReportError("ReadMapCB", `expect { or n, but found `+string([]byte{c}))
|
|
return
|
|
}
|
|
c = iter.nextToken()
|
|
if c == '}' {
|
|
return
|
|
}
|
|
iter.unreadByte()
|
|
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)
|
|
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}))
|
|
}
|
|
}
|
|
|
|
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 {
|
|
encoder ValEncoder
|
|
}
|
|
|
|
func (encoder *numericMapKeyEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
|
|
stream.writeByte('"')
|
|
encoder.encoder.Encode(ptr, stream)
|
|
stream.writeByte('"')
|
|
}
|
|
|
|
func (encoder *numericMapKeyEncoder) IsEmpty(ptr unsafe.Pointer) bool {
|
|
return false
|
|
}
|
|
|
|
type dynamicMapKeyEncoder struct {
|
|
ctx *ctx
|
|
valType reflect2.Type
|
|
}
|
|
|
|
func (encoder *dynamicMapKeyEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
|
|
obj := encoder.valType.UnsafeIndirect(ptr)
|
|
encoderOfMapKey(encoder.ctx, reflect2.TypeOf(obj)).Encode(reflect2.PtrOf(obj), stream)
|
|
}
|
|
|
|
func (encoder *dynamicMapKeyEncoder) IsEmpty(ptr unsafe.Pointer) bool {
|
|
obj := encoder.valType.UnsafeIndirect(ptr)
|
|
return encoderOfMapKey(encoder.ctx, reflect2.TypeOf(obj)).IsEmpty(reflect2.PtrOf(obj))
|
|
}
|
|
|
|
type mapEncoder struct {
|
|
mapType *reflect2.UnsafeMapType
|
|
keyEncoder ValEncoder
|
|
elemEncoder ValEncoder
|
|
}
|
|
|
|
func (encoder *mapEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
|
|
if *(*unsafe.Pointer)(ptr) == nil {
|
|
stream.WriteNil()
|
|
return
|
|
}
|
|
stream.WriteObjectStart()
|
|
iter := encoder.mapType.UnsafeIterate(ptr)
|
|
for i := 0; iter.HasNext(); i++ {
|
|
if i != 0 {
|
|
stream.WriteMore()
|
|
}
|
|
key, elem := iter.UnsafeNext()
|
|
encoder.keyEncoder.Encode(key, stream)
|
|
if stream.indention > 0 {
|
|
stream.writeTwoBytes(byte(':'), byte(' '))
|
|
} else {
|
|
stream.writeByte(':')
|
|
}
|
|
encoder.elemEncoder.Encode(elem, stream)
|
|
}
|
|
stream.WriteObjectEnd()
|
|
}
|
|
|
|
func (encoder *mapEncoder) IsEmpty(ptr unsafe.Pointer) bool {
|
|
iter := encoder.mapType.UnsafeIterate(ptr)
|
|
return !iter.HasNext()
|
|
}
|
|
|
|
type sortKeysMapEncoder struct {
|
|
mapType *reflect2.UnsafeMapType
|
|
keyEncoder ValEncoder
|
|
elemEncoder ValEncoder
|
|
}
|
|
|
|
func (encoder *sortKeysMapEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
|
|
if *(*unsafe.Pointer)(ptr) == nil {
|
|
stream.WriteNil()
|
|
return
|
|
}
|
|
stream.WriteObjectStart()
|
|
mapIter := encoder.mapType.UnsafeIterate(ptr)
|
|
subStream := stream.cfg.BorrowStream(nil)
|
|
subStream.Attachment = stream.Attachment
|
|
subIter := stream.cfg.BorrowIterator(nil)
|
|
keyValues := encodedKeyValues{}
|
|
for mapIter.HasNext() {
|
|
key, elem := mapIter.UnsafeNext()
|
|
subStreamIndex := subStream.Buffered()
|
|
encoder.keyEncoder.Encode(key, subStream)
|
|
if subStream.Error != nil && subStream.Error != io.EOF && stream.Error == nil {
|
|
stream.Error = subStream.Error
|
|
}
|
|
encodedKey := subStream.Buffer()[subStreamIndex:]
|
|
subIter.ResetBytes(encodedKey)
|
|
decodedKey := subIter.ReadString()
|
|
if stream.indention > 0 {
|
|
subStream.writeTwoBytes(byte(':'), byte(' '))
|
|
} else {
|
|
subStream.writeByte(':')
|
|
}
|
|
encoder.elemEncoder.Encode(elem, subStream)
|
|
keyValues = append(keyValues, encodedKV{
|
|
key: decodedKey,
|
|
keyValue: subStream.Buffer()[subStreamIndex:],
|
|
})
|
|
}
|
|
sort.Sort(keyValues)
|
|
for i, keyValue := range keyValues {
|
|
if i != 0 {
|
|
stream.WriteMore()
|
|
}
|
|
stream.Write(keyValue.keyValue)
|
|
}
|
|
if subStream.Error != nil && stream.Error == nil {
|
|
stream.Error = subStream.Error
|
|
}
|
|
stream.WriteObjectEnd()
|
|
stream.cfg.ReturnStream(subStream)
|
|
stream.cfg.ReturnIterator(subIter)
|
|
}
|
|
|
|
func (encoder *sortKeysMapEncoder) IsEmpty(ptr unsafe.Pointer) bool {
|
|
iter := encoder.mapType.UnsafeIterate(ptr)
|
|
return !iter.HasNext()
|
|
}
|
|
|
|
type encodedKeyValues []encodedKV
|
|
|
|
type encodedKV struct {
|
|
key string
|
|
keyValue []byte
|
|
}
|
|
|
|
func (sv encodedKeyValues) Len() int { return len(sv) }
|
|
func (sv encodedKeyValues) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] }
|
|
func (sv encodedKeyValues) Less(i, j int) bool { return sv[i].key < sv[j].key }
|