Merge branch 'master' into golangci-lint

This commit is contained in:
Daisuke Maki 2021-02-02 07:54:20 +09:00
commit 5f9f30fc8e
25 changed files with 184 additions and 478 deletions

View File

@ -1,4 +1,7 @@
run:
skip-files:
- encode_optype.go
- ".*_test\\.go$"
linters-settings:
govet:
@ -9,6 +12,7 @@ linters-settings:
linters:
enable-all: true
disable:
- dogsled
- dupl
- exhaustive
- exhaustivestruct
@ -35,6 +39,12 @@ linters:
- testpackage
- thelper
- wrapcheck
- interfacer
- lll
- nakedret
- nestif
- nlreturn
- testpackage
- wsl
issues:
@ -48,10 +58,12 @@ issues:
text: "don't use an underscore in package name"
linters:
- golint
- path: rtype.go
linters:
- golint
# Maximum issues count per one linter. Set to 0 to disable. Default is 50.
max-issues-per-linter: 0
# Maximum count of issues with the same text. Set to 0 to disable. Default is 3.
max-same-issues: 0

View File

@ -21,9 +21,8 @@ type decoder interface {
}
type Decoder struct {
s *stream
disallowUnknownFields bool
structTypeToDecoder map[uintptr]decoder
s *stream
structTypeToDecoder map[uintptr]decoder
}
type decoderMap struct {
@ -240,11 +239,12 @@ func (d *Decoder) Token() (Token, error) {
if s.read() {
continue
}
return nil, io.EOF
goto END
default:
return nil, errInvalidCharacter(s.char(), "token", s.totalOffset())
}
}
END:
return nil, io.EOF
}

View File

@ -147,7 +147,6 @@ func (d *bytesDecoder) decodeBinary(buf []byte, cursor int64, p unsafe.Pointer)
}
cursor++
}
return nil, 0, errUnexpectedEndOfJSON("[]byte", cursor)
case '[':
if d.sliceDecoder == nil {
return nil, 0, &UnmarshalTypeError{

View File

@ -309,7 +309,7 @@ func (d *Decoder) compileStruct(typ *rtype, structName, fieldName string) (decod
// recursive definition
continue
}
d.removeConflictFields(fieldMap, conflictedMap, stDec, uintptr(field.Offset))
d.removeConflictFields(fieldMap, conflictedMap, stDec, field.Offset)
} else if pdec, ok := dec.(*ptrDecoder); ok {
contentDec := pdec.contentDecoder()
if pdec.typ == typ {
@ -326,7 +326,7 @@ func (d *Decoder) compileStruct(typ *rtype, structName, fieldName string) (decod
if !exists {
fieldSet := &structFieldSet{
dec: newAnonymousFieldDecoder(pdec.typ, v.offset, v.dec),
offset: uintptr(field.Offset),
offset: field.Offset,
isTaggedKey: v.isTaggedKey,
}
fieldMap[k] = fieldSet
@ -347,7 +347,7 @@ func (d *Decoder) compileStruct(typ *rtype, structName, fieldName string) (decod
if v.isTaggedKey {
fieldSet := &structFieldSet{
dec: newAnonymousFieldDecoder(pdec.typ, v.offset, v.dec),
offset: uintptr(field.Offset),
offset: field.Offset,
isTaggedKey: v.isTaggedKey,
}
fieldMap[k] = fieldSet

View File

@ -142,5 +142,4 @@ func skipValue(buf []byte, cursor int64) (int64, error) {
}
cursor++
}
return cursor, errUnexpectedEndOfJSON("value of object", cursor)
}

View File

@ -149,7 +149,6 @@ func (d *intDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, error)
return nil, 0, d.typeError([]byte{buf[cursor]}, cursor)
}
}
return nil, 0, errUnexpectedEndOfJSON("number(integer)", cursor)
}
func (d *intDecoder) decodeStream(s *stream, p unsafe.Pointer) error {

View File

@ -143,7 +143,6 @@ func (d *interfaceDecoder) decodeStream(s *stream, p unsafe.Pointer) error {
}
s.cursor++
}
return errUnexpectedEndOfJSON("string", s.totalOffset())
case 't':
if err := trueBytes(s); err != nil {
return err
@ -229,7 +228,6 @@ func (d *interfaceDecoder) decode(buf []byte, cursor int64, p unsafe.Pointer) (i
}
cursor++
}
return 0, errUnexpectedEndOfJSON("string", cursor)
case 't':
if cursor+3 >= int64(len(buf)) {
return 0, errUnexpectedEndOfJSON("bool(true)", cursor)

View File

@ -94,7 +94,6 @@ func (d *mapDecoder) decodeStream(s *stream, p unsafe.Pointer) error {
return errExpected("comma after object value", s.totalOffset())
}
}
return nil
}
func (d *mapDecoder) decode(buf []byte, cursor int64, p unsafe.Pointer) (int64, error) {
@ -151,7 +150,6 @@ func (d *mapDecoder) decode(buf []byte, cursor int64, p unsafe.Pointer) (int64,
if err != nil {
return 0, err
}
cursor = valueCursor
mapassign(d.mapType, mapValue, unsafe.Pointer(&key), unsafe.Pointer(&value))
cursor = skipWhiteSpace(buf, valueCursor)
if buf[cursor] == '}' {

View File

@ -28,6 +28,7 @@ func (d *ptrDecoder) contentDecoder() decoder {
return dec.contentDecoder()
}
//nolint:golint
//go:linkname unsafe_New reflect.unsafe_New
func unsafe_New(*rtype) unsafe.Pointer

View File

@ -16,7 +16,6 @@ type stream struct {
r io.Reader
offset int64
cursor int64
readPos int64
allRead bool
useNumber bool
disallowUnknownFields bool
@ -200,5 +199,4 @@ func (s *stream) skipValue() error {
}
s.cursor++
}
return errUnexpectedEndOfJSON("value of object", s.offset)
}

View File

@ -150,6 +150,7 @@ RETRY:
return nil
}
//nolint:deadcode,unused
func appendCoerceInvalidUTF8(b []byte, s []byte) []byte {
c := [4]byte{}
@ -298,7 +299,6 @@ func (d *stringDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, err
}
cursor++
}
return nil, 0, errUnexpectedEndOfJSON("string", cursor)
case 'n':
buflen := int64(len(buf))
if cursor+3 >= buflen {

View File

@ -93,7 +93,6 @@ func (d *structDecoder) decodeStream(s *stream, p unsafe.Pointer) error {
}
s.cursor++
}
return nil
}
func (d *structDecoder) decode(buf []byte, cursor int64, p unsafe.Pointer) (int64, error) {

View File

@ -70,12 +70,12 @@ func (d *uintDecoder) decodeStreamByte(s *stream) ([]byte, error) {
}
num := s.buf[start:s.cursor]
return num, nil
default:
return nil, d.typeError([]byte{s.char()}, s.totalOffset())
case nul:
if s.read() {
continue
}
default:
return nil, d.typeError([]byte{s.char()}, s.totalOffset())
}
break
}

View File

@ -128,7 +128,7 @@ func (e *Encoder) SetIndent(prefix, indent string) {
func marshal(v interface{}, opt EncodeOption) ([]byte, error) {
ctx := takeEncodeRuntimeContext()
buf, err := encode(ctx, v, EncodeOptionHTMLEscape)
buf, err := encode(ctx, v, opt|EncodeOptionHTMLEscape)
if err != nil {
releaseEncodeRuntimeContext(ctx)
return nil, err
@ -149,7 +149,7 @@ func marshal(v interface{}, opt EncodeOption) ([]byte, error) {
func marshalNoEscape(v interface{}, opt EncodeOption) ([]byte, error) {
ctx := takeEncodeRuntimeContext()
buf, err := encodeNoEscape(ctx, v, EncodeOptionHTMLEscape)
buf, err := encodeNoEscape(ctx, v, opt|EncodeOptionHTMLEscape)
if err != nil {
releaseEncodeRuntimeContext(ctx)
return nil, err
@ -170,7 +170,7 @@ func marshalNoEscape(v interface{}, opt EncodeOption) ([]byte, error) {
func marshalIndent(v interface{}, prefix, indent string, opt EncodeOption) ([]byte, error) {
ctx := takeEncodeRuntimeContext()
buf, err := encodeIndent(ctx, v, prefix, indent, EncodeOptionHTMLEscape)
buf, err := encodeIndent(ctx, v, prefix, indent, opt|EncodeOptionHTMLEscape)
if err != nil {
releaseEncodeRuntimeContext(ctx)
return nil, err
@ -320,10 +320,6 @@ func encodeBool(b []byte, v bool) []byte {
return append(b, "false"...)
}
func encodeBytes(dst []byte, src []byte) []byte {
return append(dst, src...)
}
func encodeNull(b []byte) []byte {
return append(b, "null"...)
}

View File

@ -22,11 +22,12 @@ type opcodeSet struct {
}
var (
marshalJSONType = reflect.TypeOf((*Marshaler)(nil)).Elem()
marshalTextType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
cachedOpcode unsafe.Pointer // map[uintptr]*opcodeSet
baseTypeAddr uintptr
cachedOpcodeSets []*opcodeSet
marshalJSONType = reflect.TypeOf((*Marshaler)(nil)).Elem()
marshalTextType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
cachedOpcode unsafe.Pointer // map[uintptr]*opcodeSet
baseTypeAddr uintptr
cachedOpcodeSets []*opcodeSet
existsCachedOpcodeSets bool
)
const (
@ -72,7 +73,7 @@ func setupOpcodeSets() error {
}
}
}
addrRange := uintptr(max) - uintptr(min)
addrRange := max - min
if addrRange == 0 {
return fmt.Errorf("failed to get address range of types")
}
@ -80,43 +81,13 @@ func setupOpcodeSets() error {
return fmt.Errorf("too big address range %d", addrRange)
}
cachedOpcodeSets = make([]*opcodeSet, addrRange)
existsCachedOpcodeSets = true
baseTypeAddr = min
return nil
}
func init() {
if err := setupOpcodeSets(); err != nil {
// fallback to slow path
}
}
func encodeCompileToGetCodeSet(typeptr uintptr) (*opcodeSet, error) {
if cachedOpcodeSets == nil {
return encodeCompileToGetCodeSetSlowPath(typeptr)
}
if codeSet := cachedOpcodeSets[typeptr-baseTypeAddr]; codeSet != nil {
return codeSet, nil
}
// noescape trick for header.typ ( reflect.*rtype )
copiedType := *(**rtype)(unsafe.Pointer(&typeptr))
code, err := encodeCompileHead(&encodeCompileContext{
typ: copiedType,
root: true,
structTypeToCompiledCode: map[uintptr]*compiledCode{},
})
if err != nil {
return nil, err
}
code = copyOpcode(code)
codeLength := code.totalLength()
codeSet := &opcodeSet{
code: code,
codeLength: codeLength,
}
cachedOpcodeSets[int(typeptr-baseTypeAddr)] = codeSet
return codeSet, nil
_ = setupOpcodeSets()
}
func encodeCompileToGetCodeSetSlowPath(typeptr uintptr) (*opcodeSet, error) {
@ -799,6 +770,7 @@ func encodeTypeToHeaderType(ctx *encodeCompileContext, code *opcode) opType {
ptrNum++
code = code.next
ctx.decIndex()
continue
}
break
}
@ -923,6 +895,7 @@ func encodeTypeToFieldType(ctx *encodeCompileContext, code *opcode) opType {
ptrNum++
code = code.next
ctx.decIndex()
continue
}
break
}
@ -1182,7 +1155,7 @@ type structFieldPair struct {
linked bool
}
func encodeAnonymousStructFieldPairMap(typ *rtype, tags structTags, named string, valueCode *opcode) map[string][]structFieldPair {
func encodeAnonymousStructFieldPairMap(tags structTags, named string, valueCode *opcode) map[string][]structFieldPair {
anonymousFields := map[string][]structFieldPair{}
f := valueCode
var prevAnonymousField *opcode
@ -1224,7 +1197,7 @@ func encodeAnonymousStructFieldPairMap(typ *rtype, tags structTags, named string
isTaggedKey: f.isTaggedKey,
})
if f.next != nil && f.nextField != f.next && f.next.op.codeType() == codeStructField {
for k, v := range encodeAnonymousStructFieldPairMap(typ, tags, named, f.next) {
for k, v := range encodeAnonymousStructFieldPairMap(tags, named, f.next) {
anonymousFields[k] = append(anonymousFields[k], v...)
}
}
@ -1350,7 +1323,7 @@ func encodeCompileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode, error)
if tag.isTaggedKey {
tagKey = tag.key
}
for k, v := range encodeAnonymousStructFieldPairMap(typ, tags, tagKey, valueCode) {
for k, v := range encodeAnonymousStructFieldPairMap(tags, tagKey, valueCode) {
anonymousFields[k] = append(anonymousFields[k], v...)
}
}

34
encode_compile_norace.go Normal file
View File

@ -0,0 +1,34 @@
// +build !race
package json
import "unsafe"
func encodeCompileToGetCodeSet(typeptr uintptr) (*opcodeSet, error) {
if !existsCachedOpcodeSets {
return encodeCompileToGetCodeSetSlowPath(typeptr)
}
if codeSet := cachedOpcodeSets[typeptr-baseTypeAddr]; codeSet != nil {
return codeSet, nil
}
// noescape trick for header.typ ( reflect.*rtype )
copiedType := *(**rtype)(unsafe.Pointer(&typeptr))
code, err := encodeCompileHead(&encodeCompileContext{
typ: copiedType,
root: true,
structTypeToCompiledCode: map[uintptr]*compiledCode{},
})
if err != nil {
return nil, err
}
code = copyOpcode(code)
codeLength := code.totalLength()
codeSet := &opcodeSet{
code: code,
codeLength: codeLength,
}
cachedOpcodeSets[int(typeptr-baseTypeAddr)] = codeSet
return codeSet, nil
}

44
encode_compile_race.go Normal file
View File

@ -0,0 +1,44 @@
// +build race
package json
import (
"sync"
"unsafe"
)
var setsMu sync.RWMutex
func encodeCompileToGetCodeSet(typeptr uintptr) (*opcodeSet, error) {
if !existsCachedOpcodeSets {
return encodeCompileToGetCodeSetSlowPath(typeptr)
}
setsMu.RLock()
if codeSet := cachedOpcodeSets[typeptr-baseTypeAddr]; codeSet != nil {
setsMu.RUnlock()
return codeSet, nil
}
setsMu.RUnlock()
// noescape trick for header.typ ( reflect.*rtype )
copiedType := *(**rtype)(unsafe.Pointer(&typeptr))
code, err := encodeCompileHead(&encodeCompileContext{
typ: copiedType,
root: true,
structTypeToCompiledCode: map[uintptr]*compiledCode{},
})
if err != nil {
return nil, err
}
code = copyOpcode(code)
codeLength := code.totalLength()
codeSet := &opcodeSet{
code: code,
codeLength: codeLength,
}
setsMu.Lock()
cachedOpcodeSets[int(typeptr-baseTypeAddr)] = codeSet
setsMu.Unlock()
return codeSet, nil
}

View File

@ -28,7 +28,6 @@ func (m *mapslice) Swap(i, j int) {
}
type encodeMapContext struct {
iter unsafe.Pointer
pos []int
slice *mapslice
buf []byte

View File

@ -124,7 +124,6 @@ func (c *opcode) beforeLastCode() *opcode {
}
code = nextCode
}
return nil
}
func (c *opcode) totalLength() int {

18
encode_opcode_test.go Normal file
View File

@ -0,0 +1,18 @@
package json
import (
"testing"
"unsafe"
)
func TestDumpOpcode(t *testing.T) {
var v interface{} = 1
header := (*interfaceHeader)(unsafe.Pointer(&v))
typ := header.typ
typeptr := uintptr(unsafe.Pointer(typ))
codeSet, err := encodeCompileToGetCodeSet(typeptr)
if err != nil {
t.Fatal(err)
}
codeSet.code.dump()
}

View File

@ -347,345 +347,6 @@ var needEscape = [256]bool{
0xff: true,
}
// htmlSafeSet holds the value true if the ASCII character with the given
// array position can be safely represented inside a JSON string, embedded
// inside of HTML <script> tags, without any additional escaping.
//
// All values are true except for the ASCII control characters (0-31), the
// double quote ("), the backslash character ("\"), HTML opening and closing
// tags ("<" and ">"), and the ampersand ("&").
var htmlSafeSet = [256]bool{
' ': true,
'!': true,
'"': false,
'#': true,
'$': true,
'%': true,
'&': false,
'\'': true,
'(': true,
')': true,
'*': true,
'+': true,
',': true,
'-': true,
'.': true,
'/': true,
'0': true,
'1': true,
'2': true,
'3': true,
'4': true,
'5': true,
'6': true,
'7': true,
'8': true,
'9': true,
':': true,
';': true,
'<': false,
'=': true,
'>': false,
'?': true,
'@': true,
'A': true,
'B': true,
'C': true,
'D': true,
'E': true,
'F': true,
'G': true,
'H': true,
'I': true,
'J': true,
'K': true,
'L': true,
'M': true,
'N': true,
'O': true,
'P': true,
'Q': true,
'R': true,
'S': true,
'T': true,
'U': true,
'V': true,
'W': true,
'X': true,
'Y': true,
'Z': true,
'[': true,
'\\': false,
']': true,
'^': true,
'_': true,
'`': true,
'a': true,
'b': true,
'c': true,
'd': true,
'e': true,
'f': true,
'g': true,
'h': true,
'i': true,
'j': true,
'k': true,
'l': true,
'm': true,
'n': true,
'o': true,
'p': true,
'q': true,
'r': true,
's': true,
't': true,
'u': true,
'v': true,
'w': true,
'x': true,
'y': true,
'z': true,
'{': true,
'|': true,
'}': true,
'~': true,
'\u007f': true,
0x80: false,
0x81: false,
0x82: false,
0x83: false,
0x84: false,
0x85: false,
0x86: false,
0x87: false,
0x88: false,
0x89: false,
0x8a: false,
0x8b: false,
0x8c: false,
0x8d: false,
0x8e: false,
0x8f: false,
0x90: false,
0x91: false,
0x92: false,
0x93: false,
0x94: false,
0x95: false,
0x96: false,
0x97: false,
0x98: false,
0x99: false,
0x9a: false,
0x9b: false,
0x9c: false,
0x9d: false,
0x9e: false,
0x9f: false,
0xa0: false,
0xa1: false,
0xa2: false,
0xa3: false,
0xa4: false,
0xa5: false,
0xa6: false,
0xa7: false,
0xa8: false,
0xa9: false,
0xaa: false,
0xab: false,
0xac: false,
0xad: false,
0xae: false,
0xaf: false,
0xb0: false,
0xb1: false,
0xb2: false,
0xb3: false,
0xb4: false,
0xb5: false,
0xb6: false,
0xb7: false,
0xb8: false,
0xb9: false,
0xba: false,
0xbb: false,
0xbc: false,
0xbd: false,
0xbe: false,
0xbf: false,
0xc0: false,
0xc1: false,
0xc2: false,
0xc3: false,
0xc4: false,
0xc5: false,
0xc6: false,
0xc7: false,
0xc8: false,
0xc9: false,
0xca: false,
0xcb: false,
0xcc: false,
0xcd: false,
0xce: false,
0xcf: false,
0xd0: false,
0xd1: false,
0xd2: false,
0xd3: false,
0xd4: false,
0xd5: false,
0xd6: false,
0xd7: false,
0xd8: false,
0xd9: false,
0xda: false,
0xdb: false,
0xdc: false,
0xdd: false,
0xde: false,
0xdf: false,
0xe0: false,
0xe1: false,
0xe2: false,
0xe3: false,
0xe4: false,
0xe5: false,
0xe6: false,
0xe7: false,
0xe8: false,
0xe9: false,
0xea: false,
0xeb: false,
0xec: false,
0xed: false,
0xee: false,
0xef: false,
0xf0: false,
0xf1: false,
0xf2: false,
0xf3: false,
0xf4: false,
0xf5: false,
0xf6: false,
0xf7: false,
0xf8: false,
0xf9: false,
0xfa: false,
0xfb: false,
0xfc: false,
0xfd: false,
0xfe: false,
0xff: false,
}
// safeSet holds the value true if the ASCII character with the given array
// position can be represented inside a JSON string without any further
// escaping.
//
// All values are true except for the ASCII control characters (0-31), the
// double quote ("), and the backslash character ("\").
var safeSet = [utf8.RuneSelf]bool{
' ': true,
'!': true,
'"': false,
'#': true,
'$': true,
'%': true,
'&': true,
'\'': true,
'(': true,
')': true,
'*': true,
'+': true,
',': true,
'-': true,
'.': true,
'/': true,
'0': true,
'1': true,
'2': true,
'3': true,
'4': true,
'5': true,
'6': true,
'7': true,
'8': true,
'9': true,
':': true,
';': true,
'<': true,
'=': true,
'>': true,
'?': true,
'@': true,
'A': true,
'B': true,
'C': true,
'D': true,
'E': true,
'F': true,
'G': true,
'H': true,
'I': true,
'J': true,
'K': true,
'L': true,
'M': true,
'N': true,
'O': true,
'P': true,
'Q': true,
'R': true,
'S': true,
'T': true,
'U': true,
'V': true,
'W': true,
'X': true,
'Y': true,
'Z': true,
'[': true,
'\\': false,
']': true,
'^': true,
'_': true,
'`': true,
'a': true,
'b': true,
'c': true,
'd': true,
'e': true,
'f': true,
'g': true,
'h': true,
'i': true,
'j': true,
'k': true,
'l': true,
'm': true,
'n': true,
'o': true,
'p': true,
'q': true,
'r': true,
's': true,
't': true,
'u': true,
'v': true,
'w': true,
'x': true,
'y': true,
'z': true,
'{': true,
'|': true,
'}': true,
'~': true,
'\u007f': true,
}
var hex = "0123456789abcdef"
// escapeIndex finds the index of the first char in `s` that requires escaping.
@ -714,38 +375,6 @@ func escapeIndex(s string) int {
return -1
}
// escapeIndex finds the index of the first char in `s` that requires escaping.
// A char requires escaping if it's outside of the range of [0x20, 0x7F] or if
// it includes a double quote or backslash.
// Also, the chars <, > and & require escaping.
// If no chars in `s` require escaping, the return value is -1.
func escapeIndexWithHTMLEscape(s string) int {
chunks := stringToUint64Slice(s)
for _, n := range chunks {
// combine masks before checking for the MSB of each byte. We include
// `n` in the mask to check whether any of the *input* byte MSBs were
// set (i.e. the byte was outside the ASCII range).
mask := n | (n - (lsb * 0x20)) |
((n ^ (lsb * '"')) - lsb) |
((n ^ (lsb * '\\')) - lsb) |
((n ^ (lsb * '<')) - lsb) |
((n ^ (lsb * '>')) - lsb) |
((n ^ (lsb * '&')) - lsb)
if (mask & msb) != 0 {
return bits.TrailingZeros64(mask&msb) / 8
}
}
valLen := len(s)
for i := len(chunks) * 8; i < valLen; i++ {
if needEscapeWithHTML[s[i]] {
return i
}
}
return -1
}
// below return a mask that can be used to determine if any of the bytes
// in `n` are below `b`. If a byte's MSB is set in the mask then that byte was
// below `b`. The result is only valid if `b`, and each byte in `n`, is below

View File

@ -37,7 +37,6 @@ func ptrToUint64(p uintptr) uint64 { return **(**uint64)(unsafe.Pointer(&p)
func ptrToFloat32(p uintptr) float32 { return **(**float32)(unsafe.Pointer(&p)) }
func ptrToFloat64(p uintptr) float64 { return **(**float64)(unsafe.Pointer(&p)) }
func ptrToBool(p uintptr) bool { return **(**bool)(unsafe.Pointer(&p)) }
func ptrToByte(p uintptr) byte { return **(**byte)(unsafe.Pointer(&p)) }
func ptrToBytes(p uintptr) []byte { return **(**[]byte)(unsafe.Pointer(&p)) }
func ptrToString(p uintptr) string { return **(**string)(unsafe.Pointer(&p)) }
func ptrToSlice(p uintptr) *sliceHeader { return *(**sliceHeader)(unsafe.Pointer(&p)) }
@ -7637,7 +7636,7 @@ func encodeRun(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt Enco
ptr := load(ctxptr, code.headIdx)
b = append(b, code.key...)
b = append(b, '"')
b = appendUint(b, uint64(ptrToUint64(ptr+code.offset)))
b = appendUint(b, ptrToUint64(ptr+code.offset))
b = append(b, '"')
b = encodeComma(b)
code = code.next

View File

@ -7588,7 +7588,7 @@ func encodeRunEscaped(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, o
ptr := load(ctxptr, code.headIdx)
b = append(b, code.escapedKey...)
b = append(b, '"')
b = appendUint(b, uint64(ptrToUint64(ptr+code.offset)))
b = appendUint(b, ptrToUint64(ptr+code.offset))
b = append(b, '"')
b = encodeComma(b)
code = code.next
@ -7801,6 +7801,15 @@ func encodeRunEscaped(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, o
ptr := load(ctxptr, code.headIdx)
b = append(b, code.escapedKey...)
p := ptr + code.offset
if code.typ.Kind() == reflect.Ptr {
p = ptrToPtr(p)
}
if p == 0 {
b = encodeNull(b)
b = encodeComma(b)
code = code.next
break
}
v := ptrToInterface(code, p)
bb, err := v.(Marshaler).MarshalJSON()
if err != nil {
@ -7816,23 +7825,25 @@ func encodeRunEscaped(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, o
case opStructFieldOmitEmptyMarshalJSON:
ptr := load(ctxptr, code.headIdx)
p := ptr + code.offset
if code.typ.Kind() == reflect.Ptr && code.typ.Elem().Implements(marshalJSONType) {
if code.typ.Kind() == reflect.Ptr {
p = ptrToPtr(p)
}
v := ptrToInterface(code, p)
if v != nil && p != 0 {
bb, err := v.(Marshaler).MarshalJSON()
if err != nil {
return nil, errMarshaler(code, err)
}
b = append(b, code.escapedKey...)
buf := bytes.NewBuffer(b)
if err := compact(buf, bb, true); err != nil {
return nil, err
}
b = buf.Bytes()
b = encodeComma(b)
if p == 0 {
code = code.next
break
}
v := ptrToInterface(code, p)
bb, err := v.(Marshaler).MarshalJSON()
if err != nil {
return nil, errMarshaler(code, err)
}
b = append(b, code.escapedKey...)
buf := bytes.NewBuffer(b)
if err := compact(buf, bb, true); err != nil {
return nil, err
}
b = buf.Bytes()
b = encodeComma(b)
code = code.next
case opStructFieldStringTagMarshalJSON:
ptr := load(ctxptr, code.headIdx)
@ -9256,20 +9267,10 @@ func encodeRunEscaped(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, o
case opStructEndOmitEmptyMarshalJSON:
ptr := load(ctxptr, code.headIdx)
p := ptr + code.offset
v := ptrToInterface(code, p)
if v != nil && (code.typ.Kind() != reflect.Ptr || ptrToPtr(p) != 0) {
bb, err := v.(Marshaler).MarshalJSON()
if err != nil {
return nil, errMarshaler(code, err)
}
b = append(b, code.escapedKey...)
buf := bytes.NewBuffer(b)
if err := compact(buf, bb, true); err != nil {
return nil, err
}
b = buf.Bytes()
b = appendStructEnd(b)
} else {
if code.typ.Kind() == reflect.Ptr {
p = ptrToPtr(p)
}
if p == 0 {
last := len(b) - 1
if b[last] == ',' {
b[last] = '}'
@ -9277,7 +9278,21 @@ func encodeRunEscaped(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, o
} else {
b = appendStructEnd(b)
}
code = code.next
break
}
v := ptrToInterface(code, p)
bb, err := v.(Marshaler).MarshalJSON()
if err != nil {
return nil, errMarshaler(code, err)
}
b = append(b, code.escapedKey...)
buf := bytes.NewBuffer(b)
if err := compact(buf, bb, true); err != nil {
return nil, err
}
b = buf.Bytes()
b = appendStructEnd(b)
code = code.next
case opStructEndStringTagMarshalJSON:
ptr := load(ctxptr, code.headIdx)

View File

@ -29,7 +29,7 @@ func encodeWithIndent(dst *bytes.Buffer, src []byte, prefix, indentStr string) e
case '"':
goto LOOP_END
case nul:
return errUnexpectedEndOfJSON("string", int64(length))
return errUnexpectedEndOfJSON("string", length)
}
}
case '{':

View File

@ -22,10 +22,7 @@ func isIgnoredStructField(field reflect.StructField) bool {
}
}
tag := getTag(field)
if tag == "-" {
return true
}
return false
return tag == "-"
}
type structTag struct {