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 marshalerType reflect.Type
var unmarshalerType reflect.Type
var textMarshalerType reflect.Type
var textUnmarshalerType reflect.Type
func init() {
@ -63,6 +64,7 @@ func init() {
anyType = reflect.TypeOf((*Any)(nil)).Elem()
marshalerType = reflect.TypeOf((*json.Marshaler)(nil)).Elem()
unmarshalerType = reflect.TypeOf((*json.Unmarshaler)(nil)).Elem()
textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(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 {
return &base64Codec{}, nil
}
if typ.ConvertibleTo(unmarshalerType) {
if typ.Implements(unmarshalerType) {
templateInterface := reflect.New(typ).Elem().Interface()
var decoder ValDecoder = &unmarshalerDecoder{extractInterface(templateInterface)}
if typ.Kind() != reflect.Struct {
@ -267,12 +269,25 @@ func createDecoderOfType(cfg *frozenConfig, typ reflect.Type) (ValDecoder, error
}
return decoder, nil
}
if reflect.PtrTo(typ).ConvertibleTo(unmarshalerType) {
if reflect.PtrTo(typ).Implements(unmarshalerType) {
templateInterface := reflect.New(typ).Interface()
var decoder ValDecoder = &unmarshalerDecoder{extractInterface(templateInterface)}
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
}
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 {
return &base64Codec{typ}, nil
}
if typ.ConvertibleTo(marshalerType) {
if typ.Implements(marshalerType) {
templateInterface := reflect.New(typ).Elem().Interface()
var encoder ValEncoder = &marshalerEncoder{extractInterface(templateInterface)}
if typ.Kind() != reflect.Struct {
@ -410,7 +425,15 @@ func createEncoderOfType(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error
}
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
}
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)
// to put into map, we have to use reflection
keyType := decoder.keyType
// TODO: remove this from loop
switch {
case keyType.Kind() == reflect.String:
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())
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:
switch keyType.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:

View File

@ -5,6 +5,7 @@ import (
"encoding/json"
"unsafe"
"reflect"
"encoding"
)
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 {
templateInterface emptyInterface
}
@ -586,6 +621,22 @@ func (decoder *unmarshalerDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
bytes := iter.SkipAndReturnBytes()
err := unmarshaler.UnmarshalJSON(bytes)
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())
}
}