mirror of
https://github.com/json-iterator/go.git
synced 2025-04-20 11:28:49 +02:00
support map of interface{}
This commit is contained in:
parent
94ae645ab9
commit
f1c4dbde29
@ -14,9 +14,14 @@ type Any interface {
|
|||||||
Keys() []string
|
Keys() []string
|
||||||
IterateObject() (func() (string, Any, bool), bool)
|
IterateObject() (func() (string, Any, bool), bool)
|
||||||
IterateArray() (func() (Any, bool), bool)
|
IterateArray() (func() (Any, bool), bool)
|
||||||
|
GetArray() []Any
|
||||||
|
SetArray(newList []Any) bool
|
||||||
|
GetObject() map[string]Any
|
||||||
|
SetObject(map[string]Any) bool
|
||||||
|
WriteTo(stream *Stream)
|
||||||
}
|
}
|
||||||
|
|
||||||
type baseAny struct {}
|
type baseAny struct{}
|
||||||
|
|
||||||
func (any *baseAny) Get(path ...interface{}) Any {
|
func (any *baseAny) Get(path ...interface{}) Any {
|
||||||
return &invalidAny{}
|
return &invalidAny{}
|
||||||
@ -38,6 +43,29 @@ func (any *baseAny) IterateArray() (func() (Any, bool), bool) {
|
|||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (any *baseAny) GetArray() []Any {
|
||||||
|
return []Any{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (any *baseAny) SetArray(newList []Any) bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (any *baseAny) GetObject() map[string]Any {
|
||||||
|
return map[string]Any{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (any *baseAny) SetObject(map[string]Any) bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (any *baseAny) WriteTo(stream *Stream) {
|
||||||
|
}
|
||||||
|
|
||||||
|
func WrapInt64(val int64) Any {
|
||||||
|
return &intAny{baseAny{}, nil, val}
|
||||||
|
}
|
||||||
|
|
||||||
func (iter *Iterator) ReadAny() Any {
|
func (iter *Iterator) ReadAny() Any {
|
||||||
return iter.readAny(nil)
|
return iter.readAny(nil)
|
||||||
}
|
}
|
||||||
@ -81,7 +109,7 @@ func (iter *Iterator) readNumberAny(reusableIter *Iterator) Any {
|
|||||||
lazyBuf = append(lazyBuf, iter.buf[iter.head:i]...)
|
lazyBuf = append(lazyBuf, iter.buf[iter.head:i]...)
|
||||||
iter.head = i
|
iter.head = i
|
||||||
if dotFound {
|
if dotFound {
|
||||||
return &floatLazyAny{baseAny{},lazyBuf, reusableIter, nil, 0}
|
return &floatLazyAny{baseAny{}, lazyBuf, reusableIter, nil, 0}
|
||||||
} else {
|
} else {
|
||||||
return &intLazyAny{baseAny{}, lazyBuf, reusableIter, nil, 0}
|
return &intLazyAny{baseAny{}, lazyBuf, reusableIter, nil, 0}
|
||||||
}
|
}
|
||||||
@ -175,7 +203,7 @@ func (iter *Iterator) readArrayAny(reusableIter *Iterator) Any {
|
|||||||
if level == 0 {
|
if level == 0 {
|
||||||
iter.head = i + 1
|
iter.head = i + 1
|
||||||
lazyBuf = append(lazyBuf, iter.buf[start:iter.head]...)
|
lazyBuf = append(lazyBuf, iter.buf[start:iter.head]...)
|
||||||
return &arrayLazyAny{baseAny{},lazyBuf, reusableIter, nil, nil, lazyBuf}
|
return &arrayLazyAny{baseAny{}, lazyBuf, reusableIter, nil, nil, lazyBuf}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package jsoniter
|
|||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
type intLazyAny struct {
|
type intLazyAny struct {
|
||||||
@ -64,4 +65,46 @@ func (any *intLazyAny) ToFloat64() float64 {
|
|||||||
|
|
||||||
func (any *intLazyAny) ToString() string {
|
func (any *intLazyAny) ToString() string {
|
||||||
return *(*string)(unsafe.Pointer(&any.buf))
|
return *(*string)(unsafe.Pointer(&any.buf))
|
||||||
|
}
|
||||||
|
|
||||||
|
type intAny struct {
|
||||||
|
baseAny
|
||||||
|
err error
|
||||||
|
val int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (any *intAny) LastError() error {
|
||||||
|
return any.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (any *intAny) ToBool() bool {
|
||||||
|
return any.ToInt64() != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (any *intAny) ToInt() int {
|
||||||
|
return int(any.val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (any *intAny) ToInt32() int32 {
|
||||||
|
return int32(any.val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (any *intAny) ToInt64() int64 {
|
||||||
|
return any.val
|
||||||
|
}
|
||||||
|
|
||||||
|
func (any *intAny) ToFloat32() float32 {
|
||||||
|
return float32(any.val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (any *intAny) ToFloat64() float64 {
|
||||||
|
return float64(any.val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (any *intAny) ToString() string {
|
||||||
|
return strconv.FormatInt(any.val, 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (any *intAny) WriteTo(stream *Stream) {
|
||||||
|
stream.WriteInt64(any.val)
|
||||||
}
|
}
|
@ -161,8 +161,10 @@ func (any *objectLazyAny) ToString() string {
|
|||||||
// nothing has been parsed yet
|
// nothing has been parsed yet
|
||||||
return *(*string)(unsafe.Pointer(&any.buf))
|
return *(*string)(unsafe.Pointer(&any.buf))
|
||||||
} else {
|
} else {
|
||||||
// TODO: serialize the cache
|
any.fillCache()
|
||||||
return ""
|
str, err := MarshalToString(any.cache)
|
||||||
|
any.err = err
|
||||||
|
return str
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,3 +263,13 @@ func (any *objectLazyAny) IterateObject() (func() (string, Any, bool), bool) {
|
|||||||
}, true
|
}, true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (any *objectLazyAny) GetObject() map[string]Any {
|
||||||
|
any.fillCache()
|
||||||
|
return any.cache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (any *objectLazyAny) SetObject(val map[string]Any) bool {
|
||||||
|
any.fillCache()
|
||||||
|
any.cache = val
|
||||||
|
return true
|
||||||
|
}
|
@ -24,6 +24,7 @@ type Encoder interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type DecoderFunc func(ptr unsafe.Pointer, iter *Iterator)
|
type DecoderFunc func(ptr unsafe.Pointer, iter *Iterator)
|
||||||
|
type EncoderFunc func(ptr unsafe.Pointer, stream *Stream)
|
||||||
type ExtensionFunc func(typ reflect.Type, field *reflect.StructField) ([]string, DecoderFunc)
|
type ExtensionFunc func(typ reflect.Type, field *reflect.StructField) ([]string, DecoderFunc)
|
||||||
|
|
||||||
type funcDecoder struct {
|
type funcDecoder struct {
|
||||||
@ -34,19 +35,35 @@ func (decoder *funcDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
|||||||
decoder.fun(ptr, iter)
|
decoder.fun(ptr, iter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type funcEncoder struct {
|
||||||
|
fun EncoderFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (encoder *funcEncoder) encode(ptr unsafe.Pointer, stream *Stream) {
|
||||||
|
encoder.fun(ptr, stream)
|
||||||
|
}
|
||||||
|
|
||||||
var DECODERS unsafe.Pointer
|
var DECODERS unsafe.Pointer
|
||||||
var ENCODERS unsafe.Pointer
|
var ENCODERS unsafe.Pointer
|
||||||
|
|
||||||
var typeDecoders map[string]Decoder
|
var typeDecoders map[string]Decoder
|
||||||
var fieldDecoders map[string]Decoder
|
var fieldDecoders map[string]Decoder
|
||||||
|
var typeEncoders map[string]Encoder
|
||||||
|
var fieldEncoders map[string]Encoder
|
||||||
var extensions []ExtensionFunc
|
var extensions []ExtensionFunc
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
typeDecoders = map[string]Decoder{}
|
typeDecoders = map[string]Decoder{}
|
||||||
fieldDecoders = map[string]Decoder{}
|
fieldDecoders = map[string]Decoder{}
|
||||||
|
typeEncoders = map[string]Encoder{}
|
||||||
|
fieldEncoders = map[string]Encoder{}
|
||||||
extensions = []ExtensionFunc{}
|
extensions = []ExtensionFunc{}
|
||||||
atomic.StorePointer(&DECODERS, unsafe.Pointer(&map[string]Decoder{}))
|
atomic.StorePointer(&DECODERS, unsafe.Pointer(&map[string]Decoder{}))
|
||||||
atomic.StorePointer(&ENCODERS, unsafe.Pointer(&map[string]Encoder{}))
|
atomic.StorePointer(&ENCODERS, unsafe.Pointer(&map[string]Encoder{}))
|
||||||
|
RegisterTypeEncoder("*jsoniter.intAny", func(ptr unsafe.Pointer, stream *Stream) {
|
||||||
|
val := *(**intAny)(ptr)
|
||||||
|
val.WriteTo(stream)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func addDecoderToCache(cacheKey reflect.Type, decoder Decoder) {
|
func addDecoderToCache(cacheKey reflect.Type, decoder Decoder) {
|
||||||
@ -99,6 +116,14 @@ func RegisterFieldDecoder(typ string, field string, fun DecoderFunc) {
|
|||||||
fieldDecoders[fmt.Sprintf("%s/%s", typ, field)] = &funcDecoder{fun}
|
fieldDecoders[fmt.Sprintf("%s/%s", typ, field)] = &funcDecoder{fun}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RegisterTypeEncoder(typ string, fun EncoderFunc) {
|
||||||
|
typeEncoders[typ] = &funcEncoder{fun}
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterFieldEncoder(typ string, field string, fun EncoderFunc) {
|
||||||
|
fieldEncoders[fmt.Sprintf("%s/%s", typ, field)] = &funcEncoder{fun}
|
||||||
|
}
|
||||||
|
|
||||||
// RegisterExtension can register a custom extension
|
// RegisterExtension can register a custom extension
|
||||||
func RegisterExtension(extension ExtensionFunc) {
|
func RegisterExtension(extension ExtensionFunc) {
|
||||||
extensions = append(extensions, extension)
|
extensions = append(extensions, extension)
|
||||||
@ -192,6 +217,31 @@ func (encoder *mapEncoder) encode(ptr unsafe.Pointer, stream *Stream) {
|
|||||||
stream.WriteObjectEnd()
|
stream.WriteObjectEnd()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
// emptyInterface is the header for an interface{} value.
|
// emptyInterface is the header for an interface{} value.
|
||||||
type emptyInterface struct {
|
type emptyInterface struct {
|
||||||
typ *struct{}
|
typ *struct{}
|
||||||
@ -311,6 +361,10 @@ func decoderOfType(typ reflect.Type) (Decoder, error) {
|
|||||||
|
|
||||||
func encoderOfType(typ reflect.Type) (Encoder, error) {
|
func encoderOfType(typ reflect.Type) (Encoder, error) {
|
||||||
typeName := typ.String()
|
typeName := typ.String()
|
||||||
|
typeEncoder := typeEncoders[typeName]
|
||||||
|
if typeEncoder != nil {
|
||||||
|
return typeEncoder, nil
|
||||||
|
}
|
||||||
switch typ.Kind() {
|
switch typ.Kind() {
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
return &stringCodec{}, nil
|
return &stringCodec{}, nil
|
||||||
@ -388,5 +442,9 @@ func encoderOfMap(typ reflect.Type) (Encoder, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
mapInterface := reflect.New(typ).Elem().Interface()
|
mapInterface := reflect.New(typ).Elem().Interface()
|
||||||
return &mapEncoder{typ, typ.Elem(), encoder, *((*emptyInterface)(unsafe.Pointer(&mapInterface)))}, nil
|
if typ.Elem().Kind() == reflect.Interface {
|
||||||
|
return &mapInterfaceEncoder{typ, typ.Elem(), encoder, *((*emptyInterface)(unsafe.Pointer(&mapInterface)))}, nil
|
||||||
|
} else {
|
||||||
|
return &mapEncoder{typ, typ.Elem(), encoder, *((*emptyInterface)(unsafe.Pointer(&mapInterface)))}, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package jsoniter
|
package jsoniter
|
||||||
|
|
||||||
import "unsafe"
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
type stringCodec struct {
|
type stringCodec struct {
|
||||||
}
|
}
|
||||||
|
@ -110,6 +110,13 @@ func Test_read_int64_as_any(t *testing.T) {
|
|||||||
should.True(any.ToBool())
|
should.True(any.ToBool())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_wrap_int(t *testing.T) {
|
||||||
|
should := require.New(t)
|
||||||
|
str, err := MarshalToString(WrapInt64(100))
|
||||||
|
should.Nil(err)
|
||||||
|
should.Equal("100", str)
|
||||||
|
}
|
||||||
|
|
||||||
func Test_write_uint8(t *testing.T) {
|
func Test_write_uint8(t *testing.T) {
|
||||||
vals := []uint8{0, 1, 11, 111, 255}
|
vals := []uint8{0, 1, 11, 111, 255}
|
||||||
for _, val := range vals {
|
for _, val := range vals {
|
||||||
|
@ -11,4 +11,32 @@ func Test_write_array_of_interface(t *testing.T) {
|
|||||||
str, err := MarshalToString(array)
|
str, err := MarshalToString(array)
|
||||||
should.Nil(err)
|
should.Nil(err)
|
||||||
should.Equal(`["hello"]`, str)
|
should.Equal(`["hello"]`, str)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_write_map_of_interface(t *testing.T) {
|
||||||
|
should := require.New(t)
|
||||||
|
val := map[string]interface{}{"hello":"world"}
|
||||||
|
str, err := MarshalToString(val)
|
||||||
|
should.Nil(err)
|
||||||
|
should.Equal(`{"hello":"world"}`, str)
|
||||||
|
}
|
||||||
|
|
||||||
|
type MyInterface interface {
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_write_map_of_custom_interface(t *testing.T) {
|
||||||
|
should := require.New(t)
|
||||||
|
val := map[string]MyInterface{"hello":"world"}
|
||||||
|
str, err := MarshalToString(val)
|
||||||
|
should.Nil(err)
|
||||||
|
should.Equal(`{"hello":"world"}`, str)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_write_interface(t *testing.T) {
|
||||||
|
should := require.New(t)
|
||||||
|
var val interface{}
|
||||||
|
val = "hello"
|
||||||
|
str, err := MarshalToString(val)
|
||||||
|
should.Nil(err)
|
||||||
|
should.Equal(`"hello"`, str)
|
||||||
}
|
}
|
@ -147,6 +147,14 @@ func Test_object_lazy_any_get(t *testing.T) {
|
|||||||
should.Equal("d", any.Get("a", "b", "c").ToString())
|
should.Equal("d", any.Get("a", "b", "c").ToString())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_object_lazy_any_set(t *testing.T) {
|
||||||
|
should := require.New(t)
|
||||||
|
any, err := UnmarshalAnyFromString(`{"a":{"b":{"c":"d"}}}`)
|
||||||
|
should.Nil(err)
|
||||||
|
any.GetObject()["a"] = WrapInt64(1)
|
||||||
|
should.Equal(`{"a":1}`, any.ToString())
|
||||||
|
}
|
||||||
|
|
||||||
func Test_write_object(t *testing.T) {
|
func Test_write_object(t *testing.T) {
|
||||||
should := require.New(t)
|
should := require.New(t)
|
||||||
buf := &bytes.Buffer{}
|
buf := &bytes.Buffer{}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user