Browse Source

#31 support json.RawMessage

Tao Wen 8 years ago
parent
commit
fe9fa8900e
4 changed files with 46 additions and 6 deletions
  1. 3 0
      feature_iter_float.go
  2. 14 6
      feature_reflect.go
  3. 19 0
      feature_reflect_native.go
  4. 10 0
      jsoniter_array_test.go

+ 3 - 0
feature_iter_float.go

@@ -145,6 +145,9 @@ func (iter *Iterator) readNumberAsString() (ret string) {
 	if iter.Error != nil && iter.Error != io.EOF {
 		return
 	}
+	if len(str) == 0 {
+		iter.reportError("readNumberAsString", "invalid number")
+	}
 	return *(*string)(unsafe.Pointer(&str))
 }
 

+ 14 - 6
feature_reflect.go

@@ -73,6 +73,7 @@ var typeEncoders map[string]Encoder
 var fieldEncoders map[string]Encoder
 var extensions []ExtensionFunc
 var jsonNumberType reflect.Type
+var jsonRawMessageType reflect.Type
 var anyType reflect.Type
 var marshalerType reflect.Type
 var unmarshalerType reflect.Type
@@ -86,6 +87,7 @@ func init() {
 	atomic.StorePointer(&DECODERS, unsafe.Pointer(&map[string]Decoder{}))
 	atomic.StorePointer(&ENCODERS, unsafe.Pointer(&map[string]Encoder{}))
 	jsonNumberType = reflect.TypeOf((*json.Number)(nil)).Elem()
+	jsonRawMessageType = reflect.TypeOf((*json.RawMessage)(nil)).Elem()
 	anyType = reflect.TypeOf((*Any)(nil)).Elem()
 	marshalerType = reflect.TypeOf((*json.Marshaler)(nil)).Elem()
 	unmarshalerType = reflect.TypeOf((*json.Unmarshaler)(nil)).Elem()
@@ -335,16 +337,19 @@ func decoderOfType(typ reflect.Type) (Decoder, error) {
 }
 
 func createDecoderOfType(typ reflect.Type) (Decoder, error) {
+	if typ.ConvertibleTo(jsonRawMessageType) {
+		return &jsonRawMessageCodec{}, nil
+	}
 	if typ.ConvertibleTo(jsonNumberType) {
 		return &jsonNumberCodec{}, nil
 	}
-	if typ.ConvertibleTo(anyType) {
-		return &anyCodec{}, nil
-	}
 	if typ.ConvertibleTo(unmarshalerType) {
 		templateInterface := reflect.New(typ).Elem().Interface()
 		return &optionalDecoder{typ, &unmarshalerDecoder{extractInterface(templateInterface)}}, nil
 	}
+	if typ.ConvertibleTo(anyType) {
+		return &anyCodec{}, nil
+	}
 	switch typ.Kind() {
 	case reflect.String:
 		return &stringCodec{}, nil
@@ -419,16 +424,19 @@ func encoderOfType(typ reflect.Type) (Encoder, error) {
 }
 
 func createEncoderOfType(typ reflect.Type) (Encoder, error) {
+	if typ.ConvertibleTo(jsonRawMessageType) {
+		return &jsonRawMessageCodec{}, nil
+	}
 	if typ.ConvertibleTo(jsonNumberType) {
 		return &jsonNumberCodec{}, nil
 	}
-	if typ.ConvertibleTo(anyType) {
-		return &anyCodec{}, nil
-	}
 	if typ.ConvertibleTo(marshalerType) {
 		templateInterface := reflect.New(typ).Elem().Interface()
 		return &marshalerEncoder{extractInterface(templateInterface)}, nil
 	}
+	if typ.ConvertibleTo(anyType) {
+		return &anyCodec{}, nil
+	}
 	kind := typ.Kind()
 	switch kind {
 	case reflect.String:

+ 19 - 0
feature_reflect_native.go

@@ -360,6 +360,25 @@ func (encoder *jsonNumberCodec) isEmpty(ptr unsafe.Pointer) bool {
 	return len(*((*json.Number)(ptr))) == 0
 }
 
+type jsonRawMessageCodec struct {
+}
+
+func (codec *jsonRawMessageCodec) decode(ptr unsafe.Pointer, iter *Iterator) {
+	*((*json.RawMessage)(ptr)) = json.RawMessage(iter.SkipAndReturnBytes())
+}
+
+func (codec *jsonRawMessageCodec) encode(ptr unsafe.Pointer, stream *Stream) {
+	stream.WriteRaw(string(*((*json.RawMessage)(ptr))))
+}
+
+func (encoder *jsonRawMessageCodec) encodeInterface(val interface{}, stream *Stream) {
+	stream.WriteRaw(string(val.(json.RawMessage)))
+}
+
+func (encoder *jsonRawMessageCodec) isEmpty(ptr unsafe.Pointer) bool {
+	return len(*((*json.RawMessage)(ptr))) == 0
+}
+
 type stringNumberDecoder struct {
 	elemDecoder Decoder
 }

+ 10 - 0
jsoniter_array_test.go

@@ -253,6 +253,16 @@ func Test_write_array_of_interface_in_struct(t *testing.T) {
 	should.Equal(`{"Field":[1,2],"Field2":""}`, str)
 }
 
+func Test_json_RawMessage(t *testing.T) {
+	should := require.New(t)
+	var data json.RawMessage
+	should.Nil(Unmarshal([]byte(`[1,2,3]`), &data))
+	should.Equal(`[1,2,3]`, string(data))
+	str, err := MarshalToString(data)
+	should.Nil(err)
+	should.Equal(`[1,2,3]`, str)
+}
+
 func Benchmark_jsoniter_array(b *testing.B) {
 	b.ReportAllocs()
 	input := []byte(`[1,2,3,4,5,6,7,8,9]`)