Jelajahi Sumber

#97 omit empty behavior should follow the original type

Tao Wen 8 tahun lalu
induk
melakukan
f2c50ef73b
2 mengubah file dengan 32 tambahan dan 26 penghapusan
  1. 27 5
      feature_reflect.go
  2. 5 21
      feature_reflect_native.go

+ 27 - 5
feature_reflect.go

@@ -32,6 +32,10 @@ type ValEncoder interface {
 	EncodeInterface(val interface{}, stream *Stream)
 }
 
+type checkIsEmpty interface {
+	IsEmpty(ptr unsafe.Pointer) bool
+}
+
 func WriteToStream(val interface{}, stream *Stream, encoder ValEncoder) {
 	e := (*emptyInterface)(unsafe.Pointer(&val))
 	if e.word == nil {
@@ -424,7 +428,6 @@ func encoderOfType(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) {
 }
 
 func createEncoderOfType(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) {
-	typeName := typ.String()
 	if typ == jsonRawMessageType {
 		return &jsonRawMessageCodec{}, nil
 	}
@@ -438,17 +441,31 @@ func createEncoderOfType(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error
 		return &base64Codec{typ}, nil
 	}
 	if typ.Implements(marshalerType) {
+		checkIsEmpty, err := createEncoderOfSimpleType(cfg, typ)
+		if err != nil {
+			return nil, err
+		}
 		templateInterface := reflect.New(typ).Elem().Interface()
-		var encoder ValEncoder = &marshalerEncoder{extractInterface(templateInterface)}
-		if typ.Kind() != reflect.Struct {
+		var encoder ValEncoder = &marshalerEncoder{
+			templateInterface: extractInterface(templateInterface),
+			checkIsEmpty:      checkIsEmpty,
+		}
+		if typ.Kind() == reflect.Ptr {
 			encoder = &optionalEncoder{encoder}
 		}
 		return encoder, nil
 	}
 	if typ.Implements(textMarshalerType) {
+		checkIsEmpty, err := createEncoderOfSimpleType(cfg, typ)
+		if err != nil {
+			return nil, err
+		}
 		templateInterface := reflect.New(typ).Elem().Interface()
-		var encoder ValEncoder = &textMarshalerEncoder{extractInterface(templateInterface)}
-		if typ.Kind() != reflect.Struct {
+		var encoder ValEncoder = &textMarshalerEncoder{
+			templateInterface: extractInterface(templateInterface),
+			checkIsEmpty:      checkIsEmpty,
+		}
+		if typ.Kind() == reflect.Ptr {
 			encoder = &optionalEncoder{encoder}
 		}
 		return encoder, nil
@@ -456,6 +473,11 @@ func createEncoderOfType(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error
 	if typ.Implements(anyType) {
 		return &anyCodec{}, nil
 	}
+	return createEncoderOfSimpleType(cfg, typ)
+}
+
+func createEncoderOfSimpleType(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) {
+	typeName := typ.String()
 	kind := typ.Kind()
 	switch kind {
 	case reflect.String:

+ 5 - 21
feature_reflect_native.go

@@ -419,7 +419,7 @@ func (codec *base64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) {
 	}
 	encoding := base64.StdEncoding
 	src := iter.SkipAndReturnBytes()
-	src = src[1 : len(src)-1]
+	src = src[1: len(src)-1]
 	decodedLen := encoding.DecodedLen(len(src))
 	dst := make([]byte, decodedLen)
 	len, err := encoding.Decode(dst, src)
@@ -544,6 +544,7 @@ func (encoder *stringModeStringEncoder) IsEmpty(ptr unsafe.Pointer) bool {
 
 type marshalerEncoder struct {
 	templateInterface emptyInterface
+	checkIsEmpty      checkIsEmpty
 }
 
 func (encoder *marshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
@@ -563,20 +564,12 @@ func (encoder *marshalerEncoder) EncodeInterface(val interface{}, stream *Stream
 }
 
 func (encoder *marshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool {
-	templateInterface := encoder.templateInterface
-	templateInterface.word = ptr
-	realInterface := (*interface{})(unsafe.Pointer(&templateInterface))
-	marshaler := (*realInterface).(json.Marshaler)
-	bytes, err := marshaler.MarshalJSON()
-	if err != nil {
-		return true
-	} else {
-		return len(bytes) > 0
-	}
+	return encoder.checkIsEmpty.IsEmpty(ptr)
 }
 
 type textMarshalerEncoder struct {
 	templateInterface emptyInterface
+	checkIsEmpty checkIsEmpty
 }
 
 func (encoder *textMarshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
@@ -597,16 +590,7 @@ func (encoder *textMarshalerEncoder) EncodeInterface(val interface{}, stream *St
 }
 
 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
-	}
+	return encoder.checkIsEmpty.IsEmpty(ptr)
 }
 
 type unmarshalerDecoder struct {