diff --git a/jsoniter_reflect.go b/jsoniter_reflect.go index e8f71c4..d3ed95e 100644 --- a/jsoniter_reflect.go +++ b/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(©)) + } +} + +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(©)) - } +func decoderOfSlice(type_ reflect.Type) (Decoder, error) { + fmt.Println(type_.Elem()) + return nil, errors.New("n/a") } - -func getStructDecoderFromCache(cacheKey string) *structDecoder { - ptr := atomic.LoadPointer(&DECODERS_STRUCT) - cache := *(*map[string]*structDecoder)(ptr) - return cache[cacheKey] -} - diff --git a/jsoniter_reflect_test.go b/jsoniter_reflect_test.go index 3a743df..b9346cf 100644 --- a/jsoniter_reflect_test.go +++ b/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++ {