1
0
mirror of https://github.com/json-iterator/go.git synced 2025-03-20 20:54:55 +02:00

#76 support TextUnmarshal

This commit is contained in:
Tao Wen 2017-06-29 00:14:55 +08:00
parent 08dbc98040
commit 545a32f2a1
3 changed files with 90 additions and 6 deletions

View File

@ -54,6 +54,7 @@ var jsoniterRawMessageType reflect.Type
var anyType reflect.Type var anyType reflect.Type
var marshalerType reflect.Type var marshalerType reflect.Type
var unmarshalerType reflect.Type var unmarshalerType reflect.Type
var textMarshalerType reflect.Type
var textUnmarshalerType reflect.Type var textUnmarshalerType reflect.Type
func init() { func init() {
@ -63,6 +64,7 @@ func init() {
anyType = reflect.TypeOf((*Any)(nil)).Elem() anyType = reflect.TypeOf((*Any)(nil)).Elem()
marshalerType = reflect.TypeOf((*json.Marshaler)(nil)).Elem() marshalerType = reflect.TypeOf((*json.Marshaler)(nil)).Elem()
unmarshalerType = reflect.TypeOf((*json.Unmarshaler)(nil)).Elem() unmarshalerType = reflect.TypeOf((*json.Unmarshaler)(nil)).Elem()
textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
} }
@ -259,7 +261,7 @@ func createDecoderOfType(cfg *frozenConfig, typ reflect.Type) (ValDecoder, error
if typ.Kind() == reflect.Slice && typ.Elem().Kind() == reflect.Uint8 { if typ.Kind() == reflect.Slice && typ.Elem().Kind() == reflect.Uint8 {
return &base64Codec{}, nil return &base64Codec{}, nil
} }
if typ.ConvertibleTo(unmarshalerType) { if typ.Implements(unmarshalerType) {
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.Struct { if typ.Kind() != reflect.Struct {
@ -267,12 +269,25 @@ func createDecoderOfType(cfg *frozenConfig, typ reflect.Type) (ValDecoder, error
} }
return decoder, nil return decoder, nil
} }
if reflect.PtrTo(typ).ConvertibleTo(unmarshalerType) { if reflect.PtrTo(typ).Implements(unmarshalerType) {
templateInterface := reflect.New(typ).Interface() templateInterface := reflect.New(typ).Interface()
var decoder ValDecoder = &unmarshalerDecoder{extractInterface(templateInterface)} var decoder ValDecoder = &unmarshalerDecoder{extractInterface(templateInterface)}
return decoder, nil return decoder, nil
} }
if typ.ConvertibleTo(anyType) { if typ.Implements(textUnmarshalerType) {
templateInterface := reflect.New(typ).Elem().Interface()
var decoder ValDecoder = &textUnmarshalerDecoder{extractInterface(templateInterface)}
if typ.Kind() != reflect.Struct {
decoder = &optionalDecoder{typ, decoder}
}
return decoder, nil
}
if reflect.PtrTo(typ).Implements(textUnmarshalerType) {
templateInterface := reflect.New(typ).Interface()
var decoder ValDecoder = &textUnmarshalerDecoder{extractInterface(templateInterface)}
return decoder, nil
}
if typ.Implements(anyType) {
return &anyCodec{}, nil return &anyCodec{}, nil
} }
switch typ.Kind() { switch typ.Kind() {
@ -402,7 +417,7 @@ func createEncoderOfType(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error
if typ.Kind() == reflect.Slice && typ.Elem().Kind() == reflect.Uint8 { if typ.Kind() == reflect.Slice && typ.Elem().Kind() == reflect.Uint8 {
return &base64Codec{typ}, nil return &base64Codec{typ}, nil
} }
if typ.ConvertibleTo(marshalerType) { if typ.Implements(marshalerType) {
templateInterface := reflect.New(typ).Elem().Interface() templateInterface := reflect.New(typ).Elem().Interface()
var encoder ValEncoder = &marshalerEncoder{extractInterface(templateInterface)} var encoder ValEncoder = &marshalerEncoder{extractInterface(templateInterface)}
if typ.Kind() != reflect.Struct { if typ.Kind() != reflect.Struct {
@ -410,7 +425,15 @@ func createEncoderOfType(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error
} }
return encoder, nil return encoder, nil
} }
if typ.ConvertibleTo(anyType) { if typ.Implements(textMarshalerType) {
templateInterface := reflect.New(typ).Elem().Interface()
var encoder ValEncoder = &textMarshalerEncoder{extractInterface(templateInterface)}
if typ.Kind() != reflect.Struct {
encoder = &optionalEncoder{encoder}
}
return encoder, nil
}
if typ.Implements(anyType) {
return &anyCodec{}, nil return &anyCodec{}, nil
} }
kind := typ.Kind() kind := typ.Kind()

View File

@ -35,6 +35,7 @@ func (decoder *mapDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
decoder.elemDecoder.Decode(unsafe.Pointer(elem.Pointer()), iter) decoder.elemDecoder.Decode(unsafe.Pointer(elem.Pointer()), iter)
// to put into map, we have to use reflection // to put into map, we have to use reflection
keyType := decoder.keyType keyType := decoder.keyType
// TODO: remove this from loop
switch { switch {
case keyType.Kind() == reflect.String: case keyType.Kind() == reflect.String:
realVal.SetMapIndex(reflect.ValueOf(keyStr).Convert(keyType), elem.Elem()) realVal.SetMapIndex(reflect.ValueOf(keyStr).Convert(keyType), elem.Elem())
@ -48,6 +49,15 @@ func (decoder *mapDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
} }
realVal.SetMapIndex(reflect.ValueOf(textUnmarshaler), elem.Elem()) realVal.SetMapIndex(reflect.ValueOf(textUnmarshaler), elem.Elem())
return true return true
case reflect.PtrTo(keyType).Implements(textUnmarshalerType):
textUnmarshaler := reflect.New(keyType).Interface().(encoding.TextUnmarshaler)
err := textUnmarshaler.UnmarshalText([]byte(keyStr))
if err != nil {
iter.ReportError("read map key as TextUnmarshaler", err.Error())
return false
}
realVal.SetMapIndex(reflect.ValueOf(textUnmarshaler).Elem(), elem.Elem())
return true
default: default:
switch keyType.Kind() { switch keyType.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:

View File

@ -5,6 +5,7 @@ import (
"encoding/json" "encoding/json"
"unsafe" "unsafe"
"reflect" "reflect"
"encoding"
) )
type stringCodec struct { type stringCodec struct {
@ -574,6 +575,40 @@ func (encoder *marshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool {
} }
} }
type textMarshalerEncoder struct {
templateInterface emptyInterface
}
func (encoder *textMarshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
templateInterface := encoder.templateInterface
templateInterface.word = ptr
realInterface := (*interface{})(unsafe.Pointer(&templateInterface))
marshaler := (*realInterface).(encoding.TextMarshaler)
bytes, err := marshaler.MarshalText()
if err != nil {
stream.Error = err
} else {
stream.WriteString(string(bytes))
}
}
func (encoder *textMarshalerEncoder) EncodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, encoder)
}
func (encoder *textMarshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool {
templateInterface := encoder.templateInterface
templateInterface.word = ptr
realInterface := (*interface{})(unsafe.Pointer(&templateInterface))
marshaler := (*realInterface).(encoding.TextMarshaler)
bytes, err := marshaler.MarshalText()
if err != nil {
return true
} else {
return len(bytes) > 0
}
}
type unmarshalerDecoder struct { type unmarshalerDecoder struct {
templateInterface emptyInterface templateInterface emptyInterface
} }
@ -586,6 +621,22 @@ func (decoder *unmarshalerDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
bytes := iter.SkipAndReturnBytes() bytes := iter.SkipAndReturnBytes()
err := unmarshaler.UnmarshalJSON(bytes) err := unmarshaler.UnmarshalJSON(bytes)
if err != nil { if err != nil {
iter.ReportError("unmarshaler", err.Error()) iter.ReportError("unmarshalerDecoder", err.Error())
}
}
type textUnmarshalerDecoder struct {
templateInterface emptyInterface
}
func (decoder *textUnmarshalerDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
templateInterface := decoder.templateInterface
templateInterface.word = ptr
realInterface := (*interface{})(unsafe.Pointer(&templateInterface))
unmarshaler := (*realInterface).(encoding.TextUnmarshaler)
str := iter.ReadString()
err := unmarshaler.UnmarshalText([]byte(str))
if err != nil {
iter.ReportError("textUnmarshalerDecoder", err.Error())
} }
} }