Kaynağa Gözat

#76 support TextUnmarshal

Tao Wen 8 yıl önce
ebeveyn
işleme
545a32f2a1
3 değiştirilmiş dosya ile 90 ekleme ve 6 silme
  1. 28 5
      feature_reflect.go
  2. 10 0
      feature_reflect_map.go
  3. 52 1
      feature_reflect_native.go

+ 28 - 5
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()

+ 10 - 0
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:

+ 52 - 1
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())
 	}
 }