Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
116 lines (99 sloc) 2.77 KB
// Copyright 2019-present Facebook Inc. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package graphson
import (
"unsafe"
"github.com/json-iterator/go"
"github.com/modern-go/reflect2"
)
// EncoderOfMap returns a value encoder of a map type.
func (ext encodeExtension) EncoderOfMap(typ reflect2.Type) jsoniter.ValEncoder {
mapType := typ.(reflect2.MapType)
return &mapEncoder{
mapType: mapType,
keyEnc: ext.LazyEncoderOf(mapType.Key()),
elemEnc: ext.LazyEncoderOf(mapType.Elem()),
}
}
// DecoratorOfMap decorates a value encoder of a map type.
func (encodeExtension) DecoratorOfMap(enc jsoniter.ValEncoder) jsoniter.ValEncoder {
return typeEncoder{enc, mapType}
}
type mapEncoder struct {
mapType reflect2.MapType
keyEnc jsoniter.ValEncoder
elemEnc jsoniter.ValEncoder
}
func (enc *mapEncoder) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
iter := enc.mapType.UnsafeIterate(ptr)
if !iter.HasNext() {
stream.WriteEmptyArray()
return
}
stream.WriteArrayStart()
for {
key, elem := iter.UnsafeNext()
enc.keyEnc.Encode(key, stream)
stream.WriteMore()
enc.elemEnc.Encode(elem, stream)
if !iter.HasNext() {
break
}
stream.WriteMore()
}
stream.WriteArrayEnd()
}
func (enc *mapEncoder) IsEmpty(ptr unsafe.Pointer) bool {
return !enc.mapType.UnsafeIterate(ptr).HasNext()
}
// DecoderOfMap returns a value decoder of a map type.
func (ext decodeExtension) DecoderOfMap(typ reflect2.Type) jsoniter.ValDecoder {
mapType := typ.(reflect2.MapType)
keyType, elemType := mapType.Key(), mapType.Elem()
return &mapDecoder{
mapType: mapType,
keyType: keyType,
elemType: elemType,
keyDec: ext.LazyDecoderOf(keyType),
elemDec: ext.LazyDecoderOf(elemType),
}
}
// DecoratorOfMap decorates a value decoder of a map type.
func (decodeExtension) DecoratorOfMap(dec jsoniter.ValDecoder) jsoniter.ValDecoder {
return typeDecoder{dec, mapType}
}
type mapDecoder struct {
mapType reflect2.MapType
keyType reflect2.Type
elemType reflect2.Type
keyDec jsoniter.ValDecoder
elemDec jsoniter.ValDecoder
}
func (dec *mapDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
mapType := dec.mapType
if mapType.UnsafeIsNil(ptr) {
mapType.UnsafeSet(ptr, mapType.UnsafeMakeMap(0))
}
var key unsafe.Pointer
if !iter.ReadArrayCB(func(iter *jsoniter.Iterator) bool {
if key == nil {
key = dec.keyType.UnsafeNew()
dec.keyDec.Decode(key, iter)
return iter.Error == nil
}
elem := dec.elemType.UnsafeNew()
dec.elemDec.Decode(elem, iter)
if iter.Error != nil {
return false
}
mapType.UnsafeSetIndex(ptr, key, elem)
key = nil
return true
}) {
return
}
if key != nil {
iter.ReportError("decode map", "odd number of map items")
}
}
You can’t perform that action at this time.