diff --git a/feature_any.go b/feature_any.go index 409e45b..136858f 100644 --- a/feature_any.go +++ b/feature_any.go @@ -185,7 +185,7 @@ func (iter *Iterator) readObjectAny(reusableIter *Iterator) Any { func (iter *Iterator) readArrayAny(reusableIter *Iterator) Any { level := 1 lazyBuf := make([]byte, 1, 32) - lazyBuf[0] = '{' + lazyBuf[0] = '[' for { start := iter.head for i := iter.head; i < iter.tail; i++ { diff --git a/feature_any_array.go b/feature_any_array.go index c451343..fec726d 100644 --- a/feature_any_array.go +++ b/feature_any_array.go @@ -1,5 +1,9 @@ package jsoniter +import ( + "unsafe" +) + type arrayLazyAny struct { baseAny buf []byte @@ -231,3 +235,26 @@ func (any *arrayLazyAny) IterateArray() (func() (Any, bool), bool) { } }, true } + + + +func (any *arrayLazyAny) GetArray() []Any { + any.fillCache() + return any.cache +} + +func (any *arrayLazyAny) SetArray(newList []Any) bool { + any.fillCache() + any.cache = newList + return true +} + +func (any *arrayLazyAny) WriteTo(stream *Stream) { + if len(any.remaining) == len(any.buf) { + // nothing has been parsed yet + stream.WriteRaw(*(*string)(unsafe.Pointer(&any.buf))) + } else { + any.fillCache() + stream.WriteVal(any.cache) + } +} \ No newline at end of file diff --git a/feature_any_int.go b/feature_any_int.go index 684e950..8b325bb 100644 --- a/feature_any_int.go +++ b/feature_any_int.go @@ -67,6 +67,10 @@ func (any *intLazyAny) ToString() string { return *(*string)(unsafe.Pointer(&any.buf)) } +func (any *intLazyAny) WriteTo(stream *Stream) { + stream.WriteRaw(*(*string)(unsafe.Pointer(&any.buf))) +} + type intAny struct { baseAny err error diff --git a/feature_any_object.go b/feature_any_object.go index f5ce013..43e0ddc 100644 --- a/feature_any_object.go +++ b/feature_any_object.go @@ -272,4 +272,14 @@ func (any *objectLazyAny) SetObject(val map[string]Any) bool { any.fillCache() any.cache = val return true +} + +func (any *objectLazyAny) WriteTo(stream *Stream) { + if len(any.remaining) == len(any.buf) { + // nothing has been parsed yet + stream.WriteRaw(*(*string)(unsafe.Pointer(&any.buf))) + } else { + any.fillCache() + stream.WriteVal(any.cache) + } } \ No newline at end of file diff --git a/feature_reflect.go b/feature_reflect.go index 62fc892..a85a58e 100644 --- a/feature_reflect.go +++ b/feature_reflect.go @@ -20,8 +20,19 @@ For a simple struct binding, it will be reflect.Value free and allocation free type Decoder interface { decode(ptr unsafe.Pointer, iter *Iterator) } + type Encoder interface { encode(ptr unsafe.Pointer, stream *Stream) + encodeInterface(val interface{}, stream *Stream) +} + +func WriteToStream(val interface{}, stream *Stream, encoder Encoder) { + e := (*emptyInterface)(unsafe.Pointer(&val)) + if reflect.TypeOf(val).Kind() == reflect.Ptr { + encoder.encode(unsafe.Pointer(&e.word), stream) + } else { + encoder.encode(e.word, stream) + } } type DecoderFunc func(ptr unsafe.Pointer, iter *Iterator) @@ -44,6 +55,10 @@ func (encoder *funcEncoder) encode(ptr unsafe.Pointer, stream *Stream) { encoder.fun(ptr, stream) } +func (encoder *funcEncoder) encodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, encoder) +} + var DECODERS unsafe.Pointer var ENCODERS unsafe.Pointer @@ -52,6 +67,7 @@ var fieldDecoders map[string]Decoder var typeEncoders map[string]Encoder var fieldEncoders map[string]Encoder var extensions []ExtensionFunc +var anyType reflect.Type func init() { typeDecoders = map[string]Decoder{} @@ -61,10 +77,7 @@ func init() { extensions = []ExtensionFunc{} atomic.StorePointer(&DECODERS, unsafe.Pointer(&map[string]Decoder{})) atomic.StorePointer(&ENCODERS, unsafe.Pointer(&map[string]Encoder{})) - RegisterTypeEncoder("*jsoniter.intAny", func(ptr unsafe.Pointer, stream *Stream) { - val := *(**intAny)(ptr) - val.WriteTo(stream) - }) + anyType = reflect.TypeOf((*Any)(nil)).Elem() } func addDecoderToCache(cacheKey reflect.Type, decoder Decoder) { @@ -170,6 +183,10 @@ func (encoder *optionalEncoder) encode(ptr unsafe.Pointer, stream *Stream) { } } +func (encoder *optionalEncoder) encodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, encoder) +} + type mapDecoder struct { mapType reflect.Type elemType reflect.Type @@ -212,12 +229,15 @@ func (encoder *mapEncoder) encode(ptr unsafe.Pointer, stream *Stream) { } stream.WriteObjectField(key.String()) val := realVal.MapIndex(key).Interface() - e := (*emptyInterface)(unsafe.Pointer(&val)) - encoder.elemEncoder.encode(e.word, stream) + encoder.elemEncoder.encodeInterface(val, stream) } stream.WriteObjectEnd() } +func (encoder *mapEncoder) encodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, encoder) +} + type mapInterfaceEncoder struct { mapType reflect.Type elemType reflect.Type @@ -243,6 +263,10 @@ func (encoder *mapInterfaceEncoder) encode(ptr unsafe.Pointer, stream *Stream) { stream.WriteObjectEnd() } +func (encoder *mapInterfaceEncoder) encodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, encoder) +} + // emptyInterface is the header for an interface{} value. type emptyInterface struct { typ *struct{} @@ -285,13 +309,7 @@ func (stream *Stream) WriteVal(val interface{}) { cachedEncoder = encoder addEncoderToCache(cacheKey, encoder) } - - e := (*emptyInterface)(unsafe.Pointer(&val)) - if typ.Kind() == reflect.Ptr { - cachedEncoder.encode(unsafe.Pointer(&e.word), stream) - } else { - cachedEncoder.encode(e.word, stream) - } + cachedEncoder.encodeInterface(val, stream) } type prefix string @@ -365,6 +383,9 @@ func decoderOfType(typ reflect.Type) (Decoder, error) { } func encoderOfType(typ reflect.Type) (Encoder, error) { + if typ.ConvertibleTo(anyType) { + return &anyCodec{}, nil + } typeName := typ.String() typeEncoder := typeEncoders[typeName] if typeEncoder != nil { @@ -442,14 +463,15 @@ func decoderOfMap(typ reflect.Type) (Decoder, error) { } func encoderOfMap(typ reflect.Type) (Encoder, error) { - encoder, err := encoderOfType(typ.Elem()) + elemType := typ.Elem() + encoder, err := encoderOfType(elemType) if err != nil { return nil, err } mapInterface := reflect.New(typ).Elem().Interface() - if typ.Elem().Kind() == reflect.Interface { - return &mapInterfaceEncoder{typ, typ.Elem(), encoder, *((*emptyInterface)(unsafe.Pointer(&mapInterface)))}, nil + if elemType.Kind() == reflect.Interface && elemType.NumMethod() == 0 { + return &mapInterfaceEncoder{typ, elemType, encoder, *((*emptyInterface)(unsafe.Pointer(&mapInterface)))}, nil } else { - return &mapEncoder{typ, typ.Elem(), encoder, *((*emptyInterface)(unsafe.Pointer(&mapInterface)))}, nil + return &mapEncoder{typ, elemType, encoder, *((*emptyInterface)(unsafe.Pointer(&mapInterface)))}, nil } } diff --git a/feature_reflect_array.go b/feature_reflect_array.go index 9227203..c0370f2 100644 --- a/feature_reflect_array.go +++ b/feature_reflect_array.go @@ -49,6 +49,10 @@ func (encoder *sliceEncoder) encode(ptr unsafe.Pointer, stream *Stream) { } } +func (encoder *sliceEncoder) encodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, encoder) +} + type sliceDecoder struct { sliceType reflect.Type elemType reflect.Type diff --git a/feature_reflect_native.go b/feature_reflect_native.go index afb88b4..982e721 100644 --- a/feature_reflect_native.go +++ b/feature_reflect_native.go @@ -15,6 +15,10 @@ func (codec *stringCodec) encode(ptr unsafe.Pointer, stream *Stream) { stream.WriteString(*((*string)(ptr))) } +func (encoder *stringCodec) encodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, encoder) +} + type intCodec struct { } @@ -26,6 +30,10 @@ func (codec *intCodec) encode(ptr unsafe.Pointer, stream *Stream) { stream.WriteInt(*((*int)(ptr))) } +func (encoder *intCodec) encodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, encoder) +} + type int8Codec struct { } @@ -37,6 +45,10 @@ func (codec *int8Codec) encode(ptr unsafe.Pointer, stream *Stream) { stream.WriteInt8(*((*int8)(ptr))) } +func (encoder *int8Codec) encodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, encoder) +} + type int16Codec struct { } @@ -48,6 +60,10 @@ func (codec *int16Codec) encode(ptr unsafe.Pointer, stream *Stream) { stream.WriteInt16(*((*int16)(ptr))) } +func (encoder *int16Codec) encodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, encoder) +} + type int32Codec struct { } @@ -59,6 +75,10 @@ func (codec *int32Codec) encode(ptr unsafe.Pointer, stream *Stream) { stream.WriteInt32(*((*int32)(ptr))) } +func (encoder *int32Codec) encodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, encoder) +} + type int64Codec struct { } @@ -70,6 +90,10 @@ func (codec *int64Codec) encode(ptr unsafe.Pointer, stream *Stream) { stream.WriteInt64(*((*int64)(ptr))) } +func (encoder *int64Codec) encodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, encoder) +} + type uintCodec struct { } @@ -81,6 +105,10 @@ func (codec *uintCodec) encode(ptr unsafe.Pointer, stream *Stream) { stream.WriteUint(*((*uint)(ptr))) } +func (encoder *uintCodec) encodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, encoder) +} + type uint8Codec struct { } @@ -92,6 +120,10 @@ func (codec *uint8Codec) encode(ptr unsafe.Pointer, stream *Stream) { stream.WriteUint8(*((*uint8)(ptr))) } +func (encoder *uint8Codec) encodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, encoder) +} + type uint16Codec struct { } @@ -99,10 +131,14 @@ func (decoder *uint16Codec) decode(ptr unsafe.Pointer, iter *Iterator) { *((*uint16)(ptr)) = iter.ReadUint16() } -func (decoder *uint16Codec) encode(ptr unsafe.Pointer, stream *Stream) { +func (codec *uint16Codec) encode(ptr unsafe.Pointer, stream *Stream) { stream.WriteUint16(*((*uint16)(ptr))) } +func (encoder *uint16Codec) encodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, encoder) +} + type uint32Codec struct { } @@ -114,6 +150,10 @@ func (codec *uint32Codec) encode(ptr unsafe.Pointer, stream *Stream) { stream.WriteUint32(*((*uint32)(ptr))) } +func (encoder *uint32Codec) encodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, encoder) +} + type uint64Codec struct { } @@ -125,6 +165,10 @@ func (codec *uint64Codec) encode(ptr unsafe.Pointer, stream *Stream) { stream.WriteUint64(*((*uint64)(ptr))) } +func (encoder *uint64Codec) encodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, encoder) +} + type float32Codec struct { } @@ -136,6 +180,10 @@ func (codec *float32Codec) encode(ptr unsafe.Pointer, stream *Stream) { stream.WriteFloat32(*((*float32)(ptr))) } +func (encoder *float32Codec) encodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, encoder) +} + type float64Codec struct { } @@ -147,6 +195,10 @@ func (codec *float64Codec) encode(ptr unsafe.Pointer, stream *Stream) { stream.WriteFloat64(*((*float64)(ptr))) } +func (encoder *float64Codec) encodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, encoder) +} + type boolCodec struct { } @@ -158,6 +210,10 @@ func (codec *boolCodec) encode(ptr unsafe.Pointer, stream *Stream) { stream.WriteBool(*((*bool)(ptr))) } +func (encoder *boolCodec) encodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, encoder) +} + type interfaceCodec struct { } @@ -169,6 +225,25 @@ func (codec *interfaceCodec) encode(ptr unsafe.Pointer, stream *Stream) { stream.WriteVal(*((*interface{})(ptr))) } +func (encoder *interfaceCodec) encodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, encoder) +} + +type anyCodec struct { +} + +func (codec *anyCodec) decode(ptr unsafe.Pointer, iter *Iterator) { + *((*Any)(ptr)) = iter.ReadAny() +} + +func (codec *anyCodec) encode(ptr unsafe.Pointer, stream *Stream) { + (*((*Any)(ptr))).WriteTo(stream) +} + +func (encoder *anyCodec) encodeInterface(val interface{}, stream *Stream) { + (val.(Any)).WriteTo(stream) +} + type stringNumberDecoder struct { elemDecoder Decoder } diff --git a/feature_reflect_object.go b/feature_reflect_object.go index bf09b61..a27bfcf 100644 --- a/feature_reflect_object.go +++ b/feature_reflect_object.go @@ -405,6 +405,10 @@ func (encoder *structFieldEncoder) encode(ptr unsafe.Pointer, stream *Stream) { } } +func (encoder *structFieldEncoder) encodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, encoder) +} + type structEncoder struct { firstField *structFieldEncoder @@ -421,9 +425,18 @@ func (encoder *structEncoder) encode(ptr unsafe.Pointer, stream *Stream) { stream.WriteObjectEnd() } +func (encoder *structEncoder) encodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, encoder) +} + + type emptyStructEncoder struct { } func (encoder *emptyStructEncoder) encode(ptr unsafe.Pointer, stream *Stream) { stream.WriteEmptyObject() +} + +func (encoder *emptyStructEncoder) encodeInterface(val interface{}, stream *Stream) { + WriteToStream(val, stream, encoder) } \ No newline at end of file diff --git a/jsoniter_array_test.go b/jsoniter_array_test.go index 50432db..aa5672c 100644 --- a/jsoniter_array_test.go +++ b/jsoniter_array_test.go @@ -82,13 +82,23 @@ func Test_read_array_with_any_iterator(t *testing.T) { should.Equal([]int{1, 2}, elements) } -func Test_array_any_get(t *testing.T) { +func Test_array_lazy_any_get(t *testing.T) { should := require.New(t) any, err := UnmarshalAnyFromString("[1,[2,3],4]") should.Nil(err) should.Equal(3, any.Get(1,1).ToInt()) } +func Test_array_lazy_any_set(t *testing.T) { + should := require.New(t) + any, err := UnmarshalAnyFromString("[1,[2,3],4]") + should.Nil(err) + any.GetArray()[0] = WrapInt64(2) + str, err := MarshalToString(any) + should.Nil(err) + should.Equal("[2,[2,3],4]", str) +} + func Test_invalid_array(t *testing.T) { _, err := UnmarshalAnyFromString("[") if err == nil || err == io.EOF { diff --git a/jsoniter_object_test.go b/jsoniter_object_test.go index 23c2584..3d9b04d 100644 --- a/jsoniter_object_test.go +++ b/jsoniter_object_test.go @@ -152,7 +152,9 @@ func Test_object_lazy_any_set(t *testing.T) { any, err := UnmarshalAnyFromString(`{"a":{"b":{"c":"d"}}}`) should.Nil(err) any.GetObject()["a"] = WrapInt64(1) - should.Equal(`{"a":1}`, any.ToString()) + str, err := MarshalToString(any) + should.Nil(err) + should.Equal(`{"a":1}`, str) } func Test_write_object(t *testing.T) {