Bläddra i källkod

support optional string

Tao Wen 9 år sedan
förälder
incheckning
33e3df45dd
2 ändrade filer med 89 tillägg och 20 borttagningar
  1. 51 19
      jsoniter_reflect.go
  2. 38 1
      jsoniter_reflect_test.go

+ 51 - 19
jsoniter_reflect.go

@@ -19,6 +19,18 @@ func (decoder *stringDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
 	*((*string)(ptr)) = iter.ReadString()
 }
 
+type stringOptionalDecoder struct {
+}
+
+func (decoder *stringOptionalDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
+	if iter.ReadNull() {
+		*((**string)(ptr)) = nil
+	} else {
+		result := iter.ReadString()
+		*((**string)(ptr)) = &result
+	}
+}
+
 type structDecoder struct {
 	fields map[string]Decoder
 }
@@ -45,10 +57,32 @@ func (decoder *structFieldDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
 }
 
 var DECODER_STRING *stringDecoder
+var DECODER_OPTIONAL_STRING *stringOptionalDecoder
 var DECODERS_STRUCT unsafe.Pointer
 
+func addStructDecoderToCache(cacheKey string, decoder *structDecoder) {
+	retry := true
+	for retry {
+		ptr := atomic.LoadPointer(&DECODERS_STRUCT)
+		cache := *(*map[string]*structDecoder)(ptr)
+		copy := map[string]*structDecoder{}
+		for k, v := range cache {
+			copy[k] = v
+		}
+		copy[cacheKey] = decoder
+		retry = !atomic.CompareAndSwapPointer(&DECODERS_STRUCT, ptr, unsafe.Pointer(&copy))
+	}
+}
+
+func getStructDecoderFromCache(cacheKey string) *structDecoder {
+	ptr := atomic.LoadPointer(&DECODERS_STRUCT)
+	cache := *(*map[string]*structDecoder)(ptr)
+	return cache[cacheKey]
+}
+
 func init() {
 	DECODER_STRING = &stringDecoder{}
+	DECODER_OPTIONAL_STRING = &stringOptionalDecoder{}
 	atomic.StorePointer(&DECODERS_STRUCT, unsafe.Pointer(&map[string]*structDecoder{}))
 }
 
@@ -93,11 +127,25 @@ func decoderOfPtr(type_ reflect.Type) (Decoder, error) {
 		return DECODER_STRING, nil
 	case reflect.Struct:
 		return decoderOfStruct(type_)
+	case reflect.Slice:
+		return decoderOfSlice(type_)
+	case reflect.Ptr:
+		return prefix("optional").addTo(decoderOfOptional(type_.Elem()))
+	default:
+		return nil, errors.New("expect string, struct, slice")
+	}
+}
+
+func decoderOfOptional(type_ reflect.Type) (Decoder, error) {
+	switch type_.Kind() {
+	case reflect.String:
+		return DECODER_OPTIONAL_STRING, nil
 	default:
 		return nil, errors.New("expect string")
 	}
 }
 
+
 func decoderOfStruct(type_ reflect.Type) (Decoder, error) {
 	cacheKey := type_.String()
 	cachedDecoder := getStructDecoderFromCache(cacheKey)
@@ -117,23 +165,7 @@ func decoderOfStruct(type_ reflect.Type) (Decoder, error) {
 	return cachedDecoder, nil
 }
 
-func addStructDecoderToCache(cacheKey string, decoder *structDecoder) {
-	retry := true
-	for retry {
-		ptr := atomic.LoadPointer(&DECODERS_STRUCT)
-		cache := *(*map[string]*structDecoder)(ptr)
-		copy := map[string]*structDecoder{}
-		for k, v := range cache {
-			copy[k] = v
-		}
-		copy[cacheKey] = decoder
-		retry = !atomic.CompareAndSwapPointer(&DECODERS_STRUCT, ptr, unsafe.Pointer(&copy))
-	}
-}
-
-func getStructDecoderFromCache(cacheKey string) *structDecoder {
-	ptr := atomic.LoadPointer(&DECODERS_STRUCT)
-	cache := *(*map[string]*structDecoder)(ptr)
-	return cache[cacheKey]
+func decoderOfSlice(type_ reflect.Type) (Decoder, error) {
+	fmt.Println(type_.Elem())
+	return nil, errors.New("n/a")
 }
-

+ 38 - 1
jsoniter_reflect_test.go

@@ -20,7 +20,7 @@ type StructOfString struct {
 	field2 string
 }
 
-func Test_reflect_struct(t *testing.T) {
+func Test_reflect_struct_string(t *testing.T) {
 	iter := ParseString(`{"field1": "hello", "field2": "world"}`)
 	struct_ := StructOfString{}
 	iter.Read(&struct_)
@@ -34,6 +34,43 @@ func Test_reflect_struct(t *testing.T) {
 	}
 }
 
+type StructOfStringPtr struct {
+	field1 *string
+	field2 *string
+}
+
+func Test_reflect_struct_string_ptr(t *testing.T) {
+	iter := ParseString(`{"field1": null, "field2": "world"}`)
+	struct_ := StructOfStringPtr{}
+	iter.Read(&struct_)
+	if struct_.field1 != nil {
+		fmt.Println(iter.Error)
+		t.Fatal(struct_.field1)
+	}
+	if *struct_.field2 != "world" {
+		fmt.Println(iter.Error)
+		t.Fatal(struct_.field1)
+	}
+}
+
+func Test_reflect_array(t *testing.T) {
+	iter := ParseString(`{"hello", "world"}`)
+	array := []string{}
+	iter.Read(&array)
+	if len(array) != 2 {
+		fmt.Println(iter.Error)
+		t.Fatal(len(array))
+	}
+	if array[0] != "hello" {
+		fmt.Println(iter.Error)
+		t.Fatal(array[0])
+	}
+	if array[1] != "world" {
+		fmt.Println(iter.Error)
+		t.Fatal(array[1])
+	}
+}
+
 func Benchmark_jsoniter_reflect(b *testing.B) {
 	b.ReportAllocs()
 	for n := 0; n < b.N; n++ {