Skip to content

Commit

Permalink
fix quoting value even when not applicable
Browse files Browse the repository at this point in the history
  • Loading branch information
ngicks committed Feb 23, 2023
1 parent b661cd9 commit c186b73
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 11 deletions.
23 changes: 17 additions & 6 deletions reflect_extension.go
Expand Up @@ -2,12 +2,13 @@ package jsoniter

import (
"fmt"
"github.com/modern-go/reflect2"
"reflect"
"sort"
"strings"
"unicode"
"unsafe"

"github.com/modern-go/reflect2"
)

var typeDecoders = map[string]ValDecoder{}
Expand Down Expand Up @@ -448,12 +449,22 @@ func processTags(structDescriptor *StructDescriptor, cfg *frozenConfig) {
if tagPart == "omitempty" {
shouldOmitEmpty = true
} else if tagPart == "string" {
if binding.Field.Type().Kind() == reflect.String {
binding.Decoder = &stringModeStringDecoder{binding.Decoder, cfg}
binding.Encoder = &stringModeStringEncoder{binding.Encoder, cfg}
} else {
fieldType := binding.Field.Type()
isPointer := false
if fieldType.Kind() == reflect.Pointer {
isPointer = true
fieldType = reflect2.Type2(fieldType.Type1().Elem())
}
switch fieldType.Kind() {
case reflect.String:
binding.Decoder = &stringModeStringDecoder{isPointer, binding.Decoder, cfg}
binding.Encoder = &stringModeStringEncoder{isPointer, binding.Encoder, cfg}
case reflect.Float32, reflect.Float64,
reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
reflect.Bool:
binding.Decoder = &stringModeNumberDecoder{binding.Decoder}
binding.Encoder = &stringModeNumberEncoder{binding.Encoder}
binding.Encoder = &stringModeNumberEncoder{isPointer, binding.Encoder}
}
}
}
Expand Down
47 changes: 45 additions & 2 deletions reflect_struct_decoder.go
Expand Up @@ -1058,16 +1058,59 @@ func (decoder *structFieldDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
}

type stringModeStringDecoder struct {
isPointer bool // true indicates *string field type.
elemDecoder ValDecoder
cfg *frozenConfig
}

func (decoder *stringModeStringDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
decoder.elemDecoder.Decode(ptr, iter)
str := *((*string)(ptr))

if iter.Error != nil {
return
}

var str string
if decoder.isPointer {
if *((**string)(ptr)) == nil {
return
}
str = **((**string)(ptr))
} else {
str = *((*string)(ptr))
}

if len(str) < 2 {
iter.ReportError(
"stringModeStringDecoder",
`expect len(s) >= 2, but found `+str,
)
return
}
if str[0] != '"' || str[len(str)-1] != '"' {
var idx int
if str[0] == '"' {
idx = len(str) - 1
}
iter.ReportError(
"stringModeStringDecoder",
`expect ", but found `+string(str[idx]),
)
return
}

tempIter := decoder.cfg.BorrowIterator([]byte(str))
defer decoder.cfg.ReturnIterator(tempIter)
*((*string)(ptr)) = tempIter.ReadString()

if decoder.isPointer {
**((**string)(ptr)) = tempIter.ReadString()
} else {
*((*string)(ptr)) = tempIter.ReadString()
}

if tempIter.Error != nil {
iter.Error = tempIter.Error
}
}

type stringModeNumberDecoder struct {
Expand Down
22 changes: 19 additions & 3 deletions reflect_struct_encoder.go
Expand Up @@ -2,10 +2,11 @@ package jsoniter

import (
"fmt"
"github.com/modern-go/reflect2"
"io"
"reflect"
"unsafe"

"github.com/modern-go/reflect2"
)

func encoderOfStruct(ctx *ctx, typ reflect2.Type) ValEncoder {
Expand Down Expand Up @@ -180,25 +181,40 @@ func (encoder *emptyStructEncoder) IsEmpty(ptr unsafe.Pointer) bool {
}

type stringModeNumberEncoder struct {
isPointer bool
elemEncoder ValEncoder
}

func (encoder *stringModeNumberEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
stream.writeByte('"')
shouldQuote := true
if encoder.isPointer && ((*reflect2.UnsafePtrType)(nil)).UnsafeIsNil(ptr) {
shouldQuote = false
}
if shouldQuote {
stream.writeByte('"')
}
encoder.elemEncoder.Encode(ptr, stream)
stream.writeByte('"')
if shouldQuote {
stream.writeByte('"')
}
}

func (encoder *stringModeNumberEncoder) IsEmpty(ptr unsafe.Pointer) bool {
return encoder.elemEncoder.IsEmpty(ptr)
}

type stringModeStringEncoder struct {
isPointer bool
elemEncoder ValEncoder
cfg *frozenConfig
}

func (encoder *stringModeStringEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
if encoder.isPointer && ((*reflect2.UnsafePtrType)(nil)).UnsafeIsNil(ptr) {
encoder.elemEncoder.Encode(ptr, stream)
return
}

tempStream := encoder.cfg.BorrowStream(nil)
tempStream.Attachment = stream.Attachment
defer encoder.cfg.ReturnStream(tempStream)
Expand Down

0 comments on commit c186b73

Please sign in to comment.