Tao Wen 8 лет назад
Родитель
Сommit
d1aa59e34e
5 измененных файлов с 150 добавлено и 10 удалено
  1. 30 0
      feature_reflect.go
  2. 5 0
      feature_reflect_array.go
  3. 64 0
      feature_reflect_native.go
  4. 38 10
      feature_reflect_object.go
  5. 13 0
      jsoniter_reflect_struct_test.go

+ 30 - 0
feature_reflect.go

@@ -22,6 +22,7 @@ type Decoder interface {
 }
 
 type Encoder interface {
+	isEmpty(ptr unsafe.Pointer) bool
 	encode(ptr unsafe.Pointer, stream *Stream)
 	encodeInterface(val interface{}, stream *Stream)
 }
@@ -59,6 +60,10 @@ func (encoder *funcEncoder) encodeInterface(val interface{}, stream *Stream) {
 	WriteToStream(val, stream, encoder)
 }
 
+func (encoder *funcEncoder) isEmpty(ptr unsafe.Pointer) bool {
+	return false
+}
+
 var DECODERS unsafe.Pointer
 var ENCODERS unsafe.Pointer
 
@@ -187,6 +192,14 @@ func (encoder *optionalEncoder) encodeInterface(val interface{}, stream *Stream)
 	WriteToStream(val, stream, encoder)
 }
 
+func (encoder *optionalEncoder) isEmpty(ptr unsafe.Pointer) bool {
+	if *((*unsafe.Pointer)(ptr)) == nil {
+		return true
+	} else {
+		return encoder.valueEncoder.isEmpty(*((*unsafe.Pointer)(ptr)))
+	}
+}
+
 type mapDecoder struct {
 	mapType      reflect.Type
 	elemType     reflect.Type
@@ -240,6 +253,14 @@ func (encoder *mapEncoder) encodeInterface(val interface{}, stream *Stream) {
 	WriteToStream(val, stream, encoder)
 }
 
+func (encoder *mapEncoder) isEmpty(ptr unsafe.Pointer) bool {
+	mapInterface := encoder.mapInterface
+	mapInterface.word = ptr
+	realInterface := (*interface{})(unsafe.Pointer(&mapInterface))
+	realVal := reflect.ValueOf(*realInterface)
+	return realVal.Len() == 0
+}
+
 type mapInterfaceEncoder struct {
 	mapType      reflect.Type
 	elemType     reflect.Type
@@ -269,6 +290,15 @@ func (encoder *mapInterfaceEncoder) encodeInterface(val interface{}, stream *Str
 	WriteToStream(val, stream, encoder)
 }
 
+func (encoder *mapInterfaceEncoder) isEmpty(ptr unsafe.Pointer) bool {
+	mapInterface := encoder.mapInterface
+	mapInterface.word = ptr
+	realInterface := (*interface{})(unsafe.Pointer(&mapInterface))
+	realVal := reflect.ValueOf(*realInterface)
+
+	return realVal.Len() == 0
+}
+
 // emptyInterface is the header for an interface{} value.
 type emptyInterface struct {
 	typ  *struct{}

+ 5 - 0
feature_reflect_array.go

@@ -53,6 +53,11 @@ func (encoder *sliceEncoder) encodeInterface(val interface{}, stream *Stream) {
 	WriteToStream(val, stream, encoder)
 }
 
+func (encoder *sliceEncoder) isEmpty(ptr unsafe.Pointer) bool {
+	slice := (*sliceHeader)(ptr)
+	return slice.Len == 0
+}
+
 type sliceDecoder struct {
 	sliceType   reflect.Type
 	elemType    reflect.Type

+ 64 - 0
feature_reflect_native.go

@@ -19,6 +19,10 @@ func (encoder *stringCodec) encodeInterface(val interface{}, stream *Stream) {
 	WriteToStream(val, stream, encoder)
 }
 
+func (codec *stringCodec) isEmpty(ptr unsafe.Pointer) bool {
+	return *((*string)(ptr)) == ""
+}
+
 type intCodec struct {
 }
 
@@ -34,6 +38,10 @@ func (encoder *intCodec) encodeInterface(val interface{}, stream *Stream) {
 	WriteToStream(val, stream, encoder)
 }
 
+func (codec *intCodec) isEmpty(ptr unsafe.Pointer) bool {
+	return *((*int)(ptr)) == 0
+}
+
 type int8Codec struct {
 }
 
@@ -49,6 +57,10 @@ func (encoder *int8Codec) encodeInterface(val interface{}, stream *Stream) {
 	WriteToStream(val, stream, encoder)
 }
 
+func (codec *int8Codec) isEmpty(ptr unsafe.Pointer) bool {
+	return *((*int8)(ptr)) == 0
+}
+
 type int16Codec struct {
 }
 
@@ -64,6 +76,10 @@ func (encoder *int16Codec) encodeInterface(val interface{}, stream *Stream) {
 	WriteToStream(val, stream, encoder)
 }
 
+func (codec *int16Codec) isEmpty(ptr unsafe.Pointer) bool {
+	return *((*int16)(ptr)) == 0
+}
+
 type int32Codec struct {
 }
 
@@ -79,6 +95,10 @@ func (encoder *int32Codec) encodeInterface(val interface{}, stream *Stream) {
 	WriteToStream(val, stream, encoder)
 }
 
+func (codec *int32Codec) isEmpty(ptr unsafe.Pointer) bool {
+	return *((*int32)(ptr)) == 0
+}
+
 type int64Codec struct {
 }
 
@@ -94,6 +114,10 @@ func (encoder *int64Codec) encodeInterface(val interface{}, stream *Stream) {
 	WriteToStream(val, stream, encoder)
 }
 
+func (codec *int64Codec) isEmpty(ptr unsafe.Pointer) bool {
+	return *((*int64)(ptr)) == 0
+}
+
 type uintCodec struct {
 }
 
@@ -109,6 +133,10 @@ func (encoder *uintCodec) encodeInterface(val interface{}, stream *Stream) {
 	WriteToStream(val, stream, encoder)
 }
 
+func (codec *uintCodec) isEmpty(ptr unsafe.Pointer) bool {
+	return *((*uint)(ptr)) == 0
+}
+
 type uint8Codec struct {
 }
 
@@ -124,6 +152,10 @@ func (encoder *uint8Codec) encodeInterface(val interface{}, stream *Stream) {
 	WriteToStream(val, stream, encoder)
 }
 
+func (codec *uint8Codec) isEmpty(ptr unsafe.Pointer) bool {
+	return *((*uint8)(ptr)) == 0
+}
+
 type uint16Codec struct {
 }
 
@@ -139,6 +171,10 @@ func (encoder *uint16Codec) encodeInterface(val interface{}, stream *Stream) {
 	WriteToStream(val, stream, encoder)
 }
 
+func (codec *uint16Codec) isEmpty(ptr unsafe.Pointer) bool {
+	return *((*uint16)(ptr)) == 0
+}
+
 type uint32Codec struct {
 }
 
@@ -154,6 +190,10 @@ func (encoder *uint32Codec) encodeInterface(val interface{}, stream *Stream) {
 	WriteToStream(val, stream, encoder)
 }
 
+func (codec *uint32Codec) isEmpty(ptr unsafe.Pointer) bool {
+	return *((*uint32)(ptr)) == 0
+}
+
 type uint64Codec struct {
 }
 
@@ -169,6 +209,10 @@ func (encoder *uint64Codec) encodeInterface(val interface{}, stream *Stream) {
 	WriteToStream(val, stream, encoder)
 }
 
+func (codec *uint64Codec) isEmpty(ptr unsafe.Pointer) bool {
+	return *((*uint64)(ptr)) == 0
+}
+
 type float32Codec struct {
 }
 
@@ -184,6 +228,10 @@ func (encoder *float32Codec) encodeInterface(val interface{}, stream *Stream) {
 	WriteToStream(val, stream, encoder)
 }
 
+func (codec *float32Codec) isEmpty(ptr unsafe.Pointer) bool {
+	return *((*float32)(ptr)) == 0
+}
+
 type float64Codec struct {
 }
 
@@ -199,6 +247,10 @@ func (encoder *float64Codec) encodeInterface(val interface{}, stream *Stream) {
 	WriteToStream(val, stream, encoder)
 }
 
+func (codec *float64Codec) isEmpty(ptr unsafe.Pointer) bool {
+	return *((*float64)(ptr)) == 0
+}
+
 type boolCodec struct {
 }
 
@@ -214,6 +266,10 @@ func (encoder *boolCodec) encodeInterface(val interface{}, stream *Stream) {
 	WriteToStream(val, stream, encoder)
 }
 
+func (codec *boolCodec) isEmpty(ptr unsafe.Pointer) bool {
+	return !(*((*bool)(ptr)))
+}
+
 type interfaceCodec struct {
 }
 
@@ -229,6 +285,10 @@ func (encoder *interfaceCodec) encodeInterface(val interface{}, stream *Stream)
 	stream.WriteVal(val)
 }
 
+func (codec *interfaceCodec) isEmpty(ptr unsafe.Pointer) bool {
+	return ptr == nil
+}
+
 type anyCodec struct {
 }
 
@@ -244,6 +304,10 @@ func (encoder *anyCodec) encodeInterface(val interface{}, stream *Stream) {
 	(val.(Any)).WriteTo(stream)
 }
 
+func (encoder *anyCodec) isEmpty(ptr unsafe.Pointer) bool {
+	return (*((*Any)(ptr))).Size() == 0
+}
+
 type stringNumberDecoder struct {
 	elemDecoder Decoder
 }

+ 38 - 10
feature_reflect_object.go

@@ -33,9 +33,16 @@ func encoderOfStruct(typ reflect.Type) (Encoder, error) {
 				fieldNames = []string{tagParts[0]}
 			}
 		}
+		omitempty := false
+		for _, tagPart := range tagParts {
+			if tagPart == "omitempty" {
+				omitempty = true
+			}
+		}
 		var encoder Encoder
+		var err error
 		if len(fieldNames) > 0 {
-			encoder, err := encoderOfType(field.Type)
+			encoder, err = encoderOfType(field.Type)
 			if err != nil {
 				return prefix(fmt.Sprintf("{%s}", field.Name)).addToEncoder(encoder, err)
 			}
@@ -46,14 +53,11 @@ func encoderOfStruct(typ reflect.Type) (Encoder, error) {
 			}
 		}
 		for _, fieldName := range fieldNames {
-			if structEncoder_.firstField == nil {
-				structEncoder_.firstField = &structFieldEncoder{&field, fieldName, encoder}
-			} else {
-				structEncoder_.fields = append(structEncoder_.fields, &structFieldEncoder{&field, fieldName, encoder})
-			}
+			structEncoder_.fields = append(structEncoder_.fields,
+				&structFieldEncoder{&field, fieldName, encoder, omitempty})
 		}
 	}
-	if structEncoder_.firstField == nil {
+	if len(structEncoder_.fields) == 0 {
 		return &emptyStructEncoder{}, nil
 	}
 	return structEncoder_, nil
@@ -1024,6 +1028,7 @@ type structFieldEncoder struct {
 	field        *reflect.StructField
 	fieldName    string
 	fieldEncoder Encoder
+	omitempty    bool
 }
 
 func (encoder *structFieldEncoder) encode(ptr unsafe.Pointer, stream *Stream) {
@@ -1039,18 +1044,28 @@ func (encoder *structFieldEncoder) encodeInterface(val interface{}, stream *Stre
 	WriteToStream(val, stream, encoder)
 }
 
+func (encoder *structFieldEncoder) isEmpty(ptr unsafe.Pointer) bool {
+	fieldPtr := uintptr(ptr) + encoder.field.Offset
+	return encoder.fieldEncoder.isEmpty(unsafe.Pointer(fieldPtr))
+}
+
 
 type structEncoder struct {
-	firstField *structFieldEncoder
 	fields []*structFieldEncoder
 }
 
 func (encoder *structEncoder) encode(ptr unsafe.Pointer, stream *Stream) {
 	stream.WriteObjectStart()
-	encoder.firstField.encode(ptr, stream)
+	isNotFirst := false
 	for _, field := range encoder.fields {
-		stream.WriteMore()
+		if isNotFirst {
+			stream.WriteMore()
+		}
+		if field.omitempty && field.isEmpty(ptr) {
+			continue
+		}
 		field.encode(ptr, stream)
+		isNotFirst = true
 	}
 	stream.WriteObjectEnd()
 }
@@ -1059,6 +1074,15 @@ func (encoder *structEncoder) encodeInterface(val interface{}, stream *Stream) {
 	WriteToStream(val, stream, encoder)
 }
 
+func (encoder *structEncoder) isEmpty(ptr unsafe.Pointer) bool {
+	for _, field := range encoder.fields {
+		if !field.isEmpty(ptr) {
+			return false
+		}
+	}
+	return true
+}
+
 
 type emptyStructEncoder struct {
 }
@@ -1069,4 +1093,8 @@ func (encoder *emptyStructEncoder) encode(ptr unsafe.Pointer, stream *Stream) {
 
 func (encoder *emptyStructEncoder) encodeInterface(val interface{}, stream *Stream) {
 	WriteToStream(val, stream, encoder)
+}
+
+func (encoder *emptyStructEncoder) isEmpty(ptr unsafe.Pointer) bool {
+	return true
 }

+ 13 - 0
jsoniter_reflect_struct_test.go

@@ -158,4 +158,17 @@ func Test_mixed(t *testing.T) {
 	should.Nil(err)
 	should.Equal(1, aa.ID)
 	should.Equal("123", aa.Payload["account"])
+}
+
+func Test_omit_empty(t *testing.T) {
+	should := require.New(t)
+	type TestObject struct {
+		Field1 string `json:"field-1,omitempty"`
+		Field2 string `json:"field-2,omitempty"`
+	}
+	obj := TestObject{}
+	obj.Field2 = "hello"
+	str, err := MarshalToString(&obj)
+	should.Nil(err)
+	should.Equal(`{"field-2":"hello"}`, str)
 }