mirror of
https://github.com/json-iterator/go.git
synced 2025-03-17 20:47:45 +02:00
expose OptionalEncoder&OptionalDecoder; add attachment to Stream&Iterator for customized decoder/encoder
This commit is contained in:
parent
aed5a81f09
commit
b1b003864e
@ -1,10 +1,10 @@
|
|||||||
package jsoniter
|
package jsoniter
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"reflect"
|
"reflect"
|
||||||
"errors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Any generic object representation.
|
// Any generic object representation.
|
||||||
|
@ -77,6 +77,7 @@ type Iterator struct {
|
|||||||
captureStartedAt int
|
captureStartedAt int
|
||||||
captured []byte
|
captured []byte
|
||||||
Error error
|
Error error
|
||||||
|
Attachment interface{} // open for customized decoder
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewIterator creates an empty Iterator instance
|
// NewIterator creates an empty Iterator instance
|
||||||
|
@ -28,6 +28,7 @@ func (cfg *frozenConfig) BorrowStream(writer io.Writer) *Stream {
|
|||||||
|
|
||||||
func (cfg *frozenConfig) ReturnStream(stream *Stream) {
|
func (cfg *frozenConfig) ReturnStream(stream *Stream) {
|
||||||
stream.Error = nil
|
stream.Error = nil
|
||||||
|
stream.Attachment = nil
|
||||||
select {
|
select {
|
||||||
case cfg.streamPool <- stream:
|
case cfg.streamPool <- stream:
|
||||||
return
|
return
|
||||||
@ -48,6 +49,7 @@ func (cfg *frozenConfig) BorrowIterator(data []byte) *Iterator {
|
|||||||
|
|
||||||
func (cfg *frozenConfig) ReturnIterator(iter *Iterator) {
|
func (cfg *frozenConfig) ReturnIterator(iter *Iterator) {
|
||||||
iter.Error = nil
|
iter.Error = nil
|
||||||
|
iter.Attachment = nil
|
||||||
select {
|
select {
|
||||||
case cfg.iteratorPool <- iter:
|
case cfg.iteratorPool <- iter:
|
||||||
return
|
return
|
||||||
|
@ -72,24 +72,24 @@ func init() {
|
|||||||
textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
|
textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
|
||||||
}
|
}
|
||||||
|
|
||||||
type optionalDecoder struct {
|
type OptionalDecoder struct {
|
||||||
valueType reflect.Type
|
ValueType reflect.Type
|
||||||
valueDecoder ValDecoder
|
ValueDecoder ValDecoder
|
||||||
}
|
}
|
||||||
|
|
||||||
func (decoder *optionalDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
|
func (decoder *OptionalDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||||
if iter.ReadNil() {
|
if iter.ReadNil() {
|
||||||
*((*unsafe.Pointer)(ptr)) = nil
|
*((*unsafe.Pointer)(ptr)) = nil
|
||||||
} else {
|
} else {
|
||||||
if *((*unsafe.Pointer)(ptr)) == nil {
|
if *((*unsafe.Pointer)(ptr)) == nil {
|
||||||
//pointer to null, we have to allocate memory to hold the value
|
//pointer to null, we have to allocate memory to hold the value
|
||||||
value := reflect.New(decoder.valueType)
|
value := reflect.New(decoder.ValueType)
|
||||||
newPtr := extractInterface(value.Interface()).word
|
newPtr := extractInterface(value.Interface()).word
|
||||||
decoder.valueDecoder.Decode(newPtr, iter)
|
decoder.ValueDecoder.Decode(newPtr, iter)
|
||||||
*((*uintptr)(ptr)) = uintptr(newPtr)
|
*((*uintptr)(ptr)) = uintptr(newPtr)
|
||||||
} else {
|
} else {
|
||||||
//reuse existing instance
|
//reuse existing instance
|
||||||
decoder.valueDecoder.Decode(*((*unsafe.Pointer)(ptr)), iter)
|
decoder.ValueDecoder.Decode(*((*unsafe.Pointer)(ptr)), iter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -113,23 +113,23 @@ func (decoder *deferenceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type optionalEncoder struct {
|
type OptionalEncoder struct {
|
||||||
valueEncoder ValEncoder
|
ValueEncoder ValEncoder
|
||||||
}
|
}
|
||||||
|
|
||||||
func (encoder *optionalEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
|
func (encoder *OptionalEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
|
||||||
if *((*unsafe.Pointer)(ptr)) == nil {
|
if *((*unsafe.Pointer)(ptr)) == nil {
|
||||||
stream.WriteNil()
|
stream.WriteNil()
|
||||||
} else {
|
} else {
|
||||||
encoder.valueEncoder.Encode(*((*unsafe.Pointer)(ptr)), stream)
|
encoder.ValueEncoder.Encode(*((*unsafe.Pointer)(ptr)), stream)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (encoder *optionalEncoder) EncodeInterface(val interface{}, stream *Stream) {
|
func (encoder *OptionalEncoder) EncodeInterface(val interface{}, stream *Stream) {
|
||||||
WriteToStream(val, stream, encoder)
|
WriteToStream(val, stream, encoder)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (encoder *optionalEncoder) IsEmpty(ptr unsafe.Pointer) bool {
|
func (encoder *OptionalEncoder) IsEmpty(ptr unsafe.Pointer) bool {
|
||||||
return *((*unsafe.Pointer)(ptr)) == nil
|
return *((*unsafe.Pointer)(ptr)) == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -307,7 +307,7 @@ func createDecoderOfType(cfg *frozenConfig, typ reflect.Type) (ValDecoder, error
|
|||||||
templateInterface := reflect.New(typ).Elem().Interface()
|
templateInterface := reflect.New(typ).Elem().Interface()
|
||||||
var decoder ValDecoder = &unmarshalerDecoder{extractInterface(templateInterface)}
|
var decoder ValDecoder = &unmarshalerDecoder{extractInterface(templateInterface)}
|
||||||
if typ.Kind() == reflect.Ptr {
|
if typ.Kind() == reflect.Ptr {
|
||||||
decoder = &optionalDecoder{typ.Elem(), decoder}
|
decoder = &OptionalDecoder{typ.Elem(), decoder}
|
||||||
}
|
}
|
||||||
return decoder, nil
|
return decoder, nil
|
||||||
}
|
}
|
||||||
@ -320,7 +320,7 @@ func createDecoderOfType(cfg *frozenConfig, typ reflect.Type) (ValDecoder, error
|
|||||||
templateInterface := reflect.New(typ).Elem().Interface()
|
templateInterface := reflect.New(typ).Elem().Interface()
|
||||||
var decoder ValDecoder = &textUnmarshalerDecoder{extractInterface(templateInterface)}
|
var decoder ValDecoder = &textUnmarshalerDecoder{extractInterface(templateInterface)}
|
||||||
if typ.Kind() == reflect.Ptr {
|
if typ.Kind() == reflect.Ptr {
|
||||||
decoder = &optionalDecoder{typ.Elem(), decoder}
|
decoder = &OptionalDecoder{typ.Elem(), decoder}
|
||||||
}
|
}
|
||||||
return decoder, nil
|
return decoder, nil
|
||||||
}
|
}
|
||||||
@ -480,7 +480,7 @@ func createEncoderOfType(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error
|
|||||||
checkIsEmpty: checkIsEmpty,
|
checkIsEmpty: checkIsEmpty,
|
||||||
}
|
}
|
||||||
if typ.Kind() == reflect.Ptr {
|
if typ.Kind() == reflect.Ptr {
|
||||||
encoder = &optionalEncoder{encoder}
|
encoder = &OptionalEncoder{encoder}
|
||||||
}
|
}
|
||||||
return encoder, nil
|
return encoder, nil
|
||||||
}
|
}
|
||||||
@ -507,7 +507,7 @@ func createEncoderOfType(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error
|
|||||||
checkIsEmpty: checkIsEmpty,
|
checkIsEmpty: checkIsEmpty,
|
||||||
}
|
}
|
||||||
if typ.Kind() == reflect.Ptr {
|
if typ.Kind() == reflect.Ptr {
|
||||||
encoder = &optionalEncoder{encoder}
|
encoder = &OptionalEncoder{encoder}
|
||||||
}
|
}
|
||||||
return encoder, nil
|
return encoder, nil
|
||||||
}
|
}
|
||||||
@ -567,7 +567,7 @@ func createCheckIsEmpty(typ reflect.Type) (checkIsEmpty, error) {
|
|||||||
case reflect.Map:
|
case reflect.Map:
|
||||||
return &mapEncoder{}, nil
|
return &mapEncoder{}, nil
|
||||||
case reflect.Ptr:
|
case reflect.Ptr:
|
||||||
return &optionalEncoder{}, nil
|
return &OptionalEncoder{}, nil
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unsupported type: %v", typ)
|
return nil, fmt.Errorf("unsupported type: %v", typ)
|
||||||
}
|
}
|
||||||
@ -678,7 +678,7 @@ func decoderOfOptional(cfg *frozenConfig, typ reflect.Type) (ValDecoder, error)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &optionalDecoder{elemType, decoder}, nil
|
return &OptionalDecoder{elemType, decoder}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func encoderOfOptional(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) {
|
func encoderOfOptional(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) {
|
||||||
@ -687,9 +687,9 @@ func encoderOfOptional(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
encoder := &optionalEncoder{elemEncoder}
|
encoder := &OptionalEncoder{elemEncoder}
|
||||||
if elemType.Kind() == reflect.Map {
|
if elemType.Kind() == reflect.Map {
|
||||||
encoder = &optionalEncoder{encoder}
|
encoder = &OptionalEncoder{encoder}
|
||||||
}
|
}
|
||||||
return encoder, nil
|
return encoder, nil
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ func encoderOfArray(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if typ.Elem().Kind() == reflect.Map {
|
if typ.Elem().Kind() == reflect.Map {
|
||||||
encoder = &optionalEncoder{encoder}
|
encoder = &OptionalEncoder{encoder}
|
||||||
}
|
}
|
||||||
return &arrayEncoder{typ, typ.Elem(), encoder}, nil
|
return &arrayEncoder{typ, typ.Elem(), encoder}, nil
|
||||||
}
|
}
|
||||||
|
@ -185,7 +185,7 @@ func _getTypeDecoderFromExtension(typ reflect.Type) ValDecoder {
|
|||||||
if typ.Kind() == reflect.Ptr {
|
if typ.Kind() == reflect.Ptr {
|
||||||
decoder := typeDecoders[typ.Elem().String()]
|
decoder := typeDecoders[typ.Elem().String()]
|
||||||
if decoder != nil {
|
if decoder != nil {
|
||||||
return &optionalDecoder{typ.Elem(), decoder}
|
return &OptionalDecoder{typ.Elem(), decoder}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -216,7 +216,7 @@ func _getTypeEncoderFromExtension(typ reflect.Type) ValEncoder {
|
|||||||
if typ.Kind() == reflect.Ptr {
|
if typ.Kind() == reflect.Ptr {
|
||||||
encoder := typeEncoders[typ.Elem().String()]
|
encoder := typeEncoders[typ.Elem().String()]
|
||||||
if encoder != nil {
|
if encoder != nil {
|
||||||
return &optionalEncoder{encoder}
|
return &OptionalEncoder{encoder}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -254,7 +254,7 @@ func describeStruct(cfg *frozenConfig, typ reflect.Type) (*StructDescriptor, err
|
|||||||
for _, binding := range structDescriptor.Fields {
|
for _, binding := range structDescriptor.Fields {
|
||||||
binding.levels = append([]int{i}, binding.levels...)
|
binding.levels = append([]int{i}, binding.levels...)
|
||||||
omitempty := binding.Encoder.(*structFieldEncoder).omitempty
|
omitempty := binding.Encoder.(*structFieldEncoder).omitempty
|
||||||
binding.Encoder = &optionalEncoder{binding.Encoder}
|
binding.Encoder = &OptionalEncoder{binding.Encoder}
|
||||||
binding.Encoder = &structFieldEncoder{&field, binding.Encoder, omitempty}
|
binding.Encoder = &structFieldEncoder{&field, binding.Encoder, omitempty}
|
||||||
binding.Decoder = &deferenceDecoder{field.Type.Elem(), binding.Decoder}
|
binding.Decoder = &deferenceDecoder{field.Type.Elem(), binding.Decoder}
|
||||||
binding.Decoder = &structFieldDecoder{&field, binding.Decoder}
|
binding.Decoder = &structFieldDecoder{&field, binding.Decoder}
|
||||||
|
@ -21,7 +21,7 @@ func encoderOfSlice(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if typ.Elem().Kind() == reflect.Map {
|
if typ.Elem().Kind() == reflect.Map {
|
||||||
encoder = &optionalEncoder{encoder}
|
encoder = &OptionalEncoder{encoder}
|
||||||
}
|
}
|
||||||
return &sliceEncoder{typ, typ.Elem(), encoder}, nil
|
return &sliceEncoder{typ, typ.Elem(), encoder}, nil
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Stream is a io.Writer like object, with JSON specific write functions.
|
// stream is a io.Writer like object, with JSON specific write functions.
|
||||||
// Error is not returned as return value, but stored as Error member on this stream instance.
|
// Error is not returned as return value, but stored as Error member on this stream instance.
|
||||||
type Stream struct {
|
type Stream struct {
|
||||||
cfg *frozenConfig
|
cfg *frozenConfig
|
||||||
@ -13,6 +13,7 @@ type Stream struct {
|
|||||||
n int
|
n int
|
||||||
Error error
|
Error error
|
||||||
indention int
|
indention int
|
||||||
|
Attachment interface{} // open for customized encoder
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewStream create new stream instance.
|
// NewStream create new stream instance.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user