From 545a32f2a1db95039b1a8192458b7efa8f9b64f2 Mon Sep 17 00:00:00 2001 From: Tao Wen Date: Thu, 29 Jun 2017 00:14:55 +0800 Subject: [PATCH] #76 support TextUnmarshal --- feature_reflect.go | 33 ++++++++++++++++++++---- feature_reflect_map.go | 10 ++++++++ feature_reflect_native.go | 53 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 90 insertions(+), 6 deletions(-) diff --git a/feature_reflect.go b/feature_reflect.go index f4e80f4..055f699 100644 --- a/feature_reflect.go +++ b/feature_reflect.go @@ -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() diff --git a/feature_reflect_map.go b/feature_reflect_map.go index 576c13d..a1c7fd0 100644 --- a/feature_reflect_map.go +++ b/feature_reflect_map.go @@ -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: diff --git a/feature_reflect_native.go b/feature_reflect_native.go index ab9844f..6211e16 100644 --- a/feature_reflect_native.go +++ b/feature_reflect_native.go @@ -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()) } }