Add slice test

This commit is contained in:
Masaaki Goshima 2021-03-03 14:54:40 +09:00
parent 83122027f5
commit 2a2a19319d
7 changed files with 3080 additions and 956 deletions

View File

@ -281,6 +281,7 @@ func (t opType) fieldToStringTagField() opType {
"array", "map", "mapLoad", "slice", "struct", "MarshalJSON", "MarshalText", "recursive", "array", "map", "mapLoad", "slice", "struct", "MarshalJSON", "MarshalText", "recursive",
"intString", "uintString", "intString", "uintString",
"intPtr", "uintPtr", "float32Ptr", "float64Ptr", "boolPtr", "stringPtr", "bytesPtr", "intPtr", "uintPtr", "float32Ptr", "float64Ptr", "boolPtr", "stringPtr", "bytesPtr",
"arrayPtr", "slicePtr", "mapPtr",
"intNPtr", "uintNPtr", "float32NPtr", "float64NPtr", "boolNPtr", "stringNPtr", "bytesNPtr", "intNPtr", "uintNPtr", "float32NPtr", "float64NPtr", "boolNPtr", "stringNPtr", "bytesNPtr",
} }
primitiveTypesUpper := []string{} primitiveTypesUpper := []string{}

View File

@ -19,6 +19,7 @@ func float32ptr(v float32) *float32 { return &v }
func float64ptr(v float64) *float64 { return &v } func float64ptr(v float64) *float64 { return &v }
func stringptr(v string) *string { return &v } func stringptr(v string) *string { return &v }
func boolptr(v bool) *bool { return &v } func boolptr(v bool) *bool { return &v }
func sliceptr(v []int) *[]int { return &v }
func encodeByEncodingJSON(data interface{}, indent, escape bool) string { func encodeByEncodingJSON(data interface{}, indent, escape bool) string {
var buf bytes.Buffer var buf bytes.Buffer

1807
cover_slice_test.go Normal file

File diff suppressed because it is too large Load Diff

View File

@ -2,9 +2,12 @@ package json
import ( import (
"bytes" "bytes"
"encoding"
"encoding/base64" "encoding/base64"
"fmt"
"io" "io"
"math" "math"
"reflect"
"strconv" "strconv"
"sync" "sync"
"unsafe" "unsafe"
@ -362,3 +365,32 @@ func appendIndent(ctx *encodeRuntimeContext, b []byte, indent int) []byte {
b = append(b, ctx.prefix...) b = append(b, ctx.prefix...)
return append(b, bytes.Repeat(ctx.indentStr, ctx.baseIndent+indent)...) return append(b, bytes.Repeat(ctx.indentStr, ctx.baseIndent+indent)...)
} }
func encodeMarshalJSON(b []byte, v interface{}) ([]byte, error) {
rv := reflect.ValueOf(v)
bb, err := rv.Interface().(Marshaler).MarshalJSON()
if err != nil {
return nil, &MarshalerError{Type: rv.Type(), Err: err}
}
if len(bb) == 0 {
return nil, errUnexpectedEndOfJSON(
fmt.Sprintf("error calling MarshalJSON for type %s", rv.Type()),
0,
)
}
buf := bytes.NewBuffer(b)
//TODO: we should validate buffer with `compact`
if err := compact(buf, bb, false); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
func encodeMarshalText(b []byte, v interface{}) ([]byte, error) {
rv := reflect.ValueOf(v)
bytes, err := rv.Interface().(encoding.TextMarshaler).MarshalText()
if err != nil {
return nil, &MarshalerError{Type: rv.Type(), Err: err}
}
return encodeNoEscapedString(b, *(*string)(unsafe.Pointer(&bytes))), nil
}

View File

@ -167,7 +167,11 @@ func encodeOptimizeStructEnd(c *opcode) {
switch code.op { switch code.op {
case opStructEnd: case opStructEnd:
prev := code.prevField prev := code.prevField
if strings.Contains(prev.op.String(), "Head") { prevOp := prev.op.String()
if strings.Contains(prevOp, "Head") ||
strings.Contains(prevOp, "Slice") ||
strings.Contains(prevOp, "Array") ||
strings.Contains(prevOp, "Map") {
// not exists field // not exists field
code = code.next code = code.next
break break
@ -751,6 +755,8 @@ func encodeTypeToHeaderType(ctx *encodeCompileContext, code *opcode) opType {
return opStructFieldHeadStringPtr return opStructFieldHeadStringPtr
case opBool: case opBool:
return opStructFieldHeadBoolPtr return opStructFieldHeadBoolPtr
case opSliceHead:
return opStructFieldHeadSlicePtr
} }
} }
case opInt: case opInt:
@ -834,6 +840,8 @@ func encodeTypeToFieldType(ctx *encodeCompileContext, code *opcode) opType {
return opStructFieldStringPtr return opStructFieldStringPtr
case opBool: case opBool:
return opStructFieldBoolPtr return opStructFieldBoolPtr
case opSliceHead:
return opStructFieldSlicePtr
} }
} }
case opInt: case opInt:
@ -919,12 +927,18 @@ func encodeStructHeader(ctx *encodeCompileContext, fieldCode *opcode, valueCode
opStructFieldHeadStruct, opStructFieldHeadStruct,
opStructFieldHeadOmitEmpty, opStructFieldHeadOmitEmpty,
opStructFieldHeadOmitEmptySlice, opStructFieldHeadOmitEmptySlice,
opStructFieldHeadStringTagSlice,
opStructFieldHeadOmitEmptyArray, opStructFieldHeadOmitEmptyArray,
opStructFieldHeadOmitEmptyMap, opStructFieldHeadOmitEmptyMap,
opStructFieldHeadOmitEmptyMapLoad, opStructFieldHeadOmitEmptyMapLoad,
opStructFieldHeadOmitEmptyStruct, opStructFieldHeadOmitEmptyStruct,
opStructFieldHeadStringTag: opStructFieldHeadStringTag:
return valueCode.beforeLastCode() return valueCode.beforeLastCode()
case opStructFieldHeadSlicePtr,
opStructFieldHeadOmitEmptySlicePtr,
opStructFieldHeadStringTagSlicePtr:
*valueCode = *valueCode.next
return valueCode.beforeLastCode()
} }
ctx.decOpcodeIndex() ctx.decOpcodeIndex()
return (*opcode)(unsafe.Pointer(fieldCode)) return (*opcode)(unsafe.Pointer(fieldCode))
@ -946,12 +960,19 @@ func encodeStructField(ctx *encodeCompileContext, fieldCode *opcode, valueCode *
opStructFieldStruct, opStructFieldStruct,
opStructFieldOmitEmpty, opStructFieldOmitEmpty,
opStructFieldOmitEmptySlice, opStructFieldOmitEmptySlice,
opStructFieldStringTagSlice,
opStructFieldOmitEmptyArray, opStructFieldOmitEmptyArray,
opStructFieldStringTagArray,
opStructFieldOmitEmptyMap, opStructFieldOmitEmptyMap,
opStructFieldOmitEmptyMapLoad, opStructFieldOmitEmptyMapLoad,
opStructFieldOmitEmptyStruct, opStructFieldOmitEmptyStruct,
opStructFieldStringTag: opStructFieldStringTag:
return valueCode.beforeLastCode() return valueCode.beforeLastCode()
case opStructFieldSlicePtr,
opStructFieldOmitEmptySlicePtr,
opStructFieldStringTagSlicePtr:
*valueCode = *valueCode.next
return valueCode.beforeLastCode()
} }
ctx.decIndex() ctx.decIndex()
return code return code

File diff suppressed because it is too large Load Diff

View File

@ -2764,12 +2764,14 @@ func encodeRun(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt Enco
} }
b = encodeComma(b) b = encodeComma(b)
code = code.next code = code.next
case opStructFieldPtrHeadArray: case opStructFieldPtrHeadArray, opStructFieldPtrHeadStringTagArray,
opStructFieldPtrHeadSlice, opStructFieldPtrHeadStringTagSlice:
if code.indirect { if code.indirect {
store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx)))
} }
fallthrough fallthrough
case opStructFieldHeadArray: case opStructFieldHeadArray, opStructFieldHeadStringTagArray,
opStructFieldHeadSlice, opStructFieldHeadStringTagSlice:
p := load(ctxptr, code.idx) p := load(ctxptr, code.idx)
if p == 0 { if p == 0 {
b = encodeNull(b) b = encodeNull(b)
@ -2779,21 +2781,34 @@ func encodeRun(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt Enco
} }
b = append(b, '{') b = append(b, '{')
b = append(b, code.key...) b = append(b, code.key...)
p += code.offset
code = code.next code = code.next
store(ctxptr, code.idx, p) store(ctxptr, code.idx, p)
case opStructFieldPtrAnonymousHeadArray: case opStructFieldPtrHeadOmitEmptyArray, opStructFieldPtrHeadOmitEmptySlice:
store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) if code.indirect {
store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx)))
}
fallthrough fallthrough
case opStructFieldAnonymousHeadArray: case opStructFieldHeadOmitEmptyArray, opStructFieldHeadOmitEmptySlice:
ptr := load(ctxptr, code.idx) + code.offset p := load(ctxptr, code.idx)
if ptr == 0 { if p == 0 {
b = encodeNull(b)
b = encodeComma(b)
code = code.end.next code = code.end.next
break
}
b = append(b, '{')
p += code.offset
array := ptrToSlice(p)
if array.data == nil {
code = code.nextField
} else { } else {
b = append(b, code.key...) b = append(b, code.key...)
store(ctxptr, code.idx, ptr)
code = code.next code = code.next
store(ctxptr, code.idx, p)
} }
case opStructFieldPtrHeadSlice: case opStructFieldPtrHeadArrayPtr, opStructFieldPtrHeadStringTagArrayPtr,
opStructFieldPtrHeadSlicePtr, opStructFieldPtrHeadStringTagSlicePtr:
p := load(ctxptr, code.idx) p := load(ctxptr, code.idx)
if p == 0 { if p == 0 {
b = encodeNull(b) b = encodeNull(b)
@ -2803,37 +2818,139 @@ func encodeRun(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt Enco
} }
store(ctxptr, code.idx, ptrToPtr(p)) store(ctxptr, code.idx, ptrToPtr(p))
fallthrough fallthrough
case opStructFieldHeadSlice: case opStructFieldHeadArrayPtr, opStructFieldHeadStringTagArrayPtr,
ptr := load(ctxptr, code.idx) opStructFieldHeadSlicePtr, opStructFieldHeadStringTagSlicePtr:
p := ptr + code.offset p := load(ctxptr, code.idx)
if p == 0 { if p == 0 && code.indirect {
if code.op == opStructFieldPtrHeadSlice { b = encodeNull(b)
b = encodeNull(b) b = encodeComma(b)
b = encodeComma(b)
} else {
b = append(b, '[', ']', ',')
}
code = code.end.next code = code.end.next
break
}
b = append(b, '{')
b = append(b, code.key...)
if code.indirect {
p = ptrToPtr(p + code.offset)
}
if p == 0 {
b = encodeNull(b)
b = encodeComma(b)
code = code.nextField
} else { } else {
b = append(b, '{')
if !code.anonymousKey {
b = append(b, code.key...)
}
code = code.next code = code.next
store(ctxptr, code.idx, p) store(ctxptr, code.idx, p)
} }
case opStructFieldPtrAnonymousHeadSlice: case opStructFieldPtrHeadOmitEmptyArrayPtr, opStructFieldPtrHeadOmitEmptySlicePtr:
store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) p := load(ctxptr, code.idx)
fallthrough
case opStructFieldAnonymousHeadSlice:
ptr := load(ctxptr, code.idx)
p := ptr + code.offset
if p == 0 { if p == 0 {
b = encodeNull(b)
b = encodeComma(b)
code = code.end.next code = code.end.next
break
}
store(ctxptr, code.idx, ptrToPtr(p))
fallthrough
case opStructFieldHeadOmitEmptyArrayPtr, opStructFieldHeadOmitEmptySlicePtr:
p := load(ctxptr, code.idx)
if p == 0 && code.indirect {
b = encodeNull(b)
b = encodeComma(b)
code = code.end.next
break
}
b = append(b, '{')
if code.indirect {
p = ptrToPtr(p + code.offset)
}
if p == 0 {
code = code.nextField
} else { } else {
b = append(b, code.key...) b = append(b, code.key...)
store(ctxptr, code.idx, p)
code = code.next code = code.next
store(ctxptr, code.idx, p)
}
case opStructFieldPtrAnonymousHeadArray, opStructFieldPtrAnonymousHeadSlice:
if code.indirect {
store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx)))
}
fallthrough
case opStructFieldAnonymousHeadArray, opStructFieldAnonymousHeadSlice:
p := load(ctxptr, code.idx)
if p == 0 {
code = code.end.next
break
}
b = append(b, code.key...)
store(ctxptr, code.idx, p+code.offset)
code = code.next
case opStructFieldPtrAnonymousHeadOmitEmptyArray, opStructFieldPtrAnonymousHeadOmitEmptySlice:
if code.indirect {
store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx)))
}
fallthrough
case opStructFieldAnonymousHeadOmitEmptyArray, opStructFieldAnonymousHeadOmitEmptySlice:
p := load(ctxptr, code.idx)
if p == 0 {
code = code.end.next
break
}
array := ptrToSlice(p)
if array.data == nil {
code = code.nextField
} else {
b = append(b, code.key...)
code = code.next
store(ctxptr, code.idx, p)
}
case opStructFieldPtrAnonymousHeadArrayPtr, opStructFieldPtrAnonymousHeadSlicePtr:
p := load(ctxptr, code.idx)
if p == 0 {
code = code.end.next
break
}
store(ctxptr, code.idx, ptrToPtr(p))
fallthrough
case opStructFieldAnonymousHeadArrayPtr, opStructFieldAnonymousHeadSlicePtr:
p := load(ctxptr, code.idx)
if p == 0 && code.indirect {
code = code.end.next
break
}
b = append(b, code.key...)
if code.indirect {
p = ptrToPtr(p + code.offset)
}
if p == 0 {
b = encodeNull(b)
b = encodeComma(b)
code = code.nextField
} else {
code = code.next
store(ctxptr, code.idx, p)
}
case opStructFieldPtrAnonymousHeadOmitEmptyArrayPtr, opStructFieldPtrAnonymousHeadOmitEmptySlicePtr:
p := load(ctxptr, code.idx)
if p == 0 {
code = code.end.next
break
}
store(ctxptr, code.idx, ptrToPtr(p))
fallthrough
case opStructFieldAnonymousHeadOmitEmptyArrayPtr, opStructFieldAnonymousHeadOmitEmptySlicePtr:
p := load(ctxptr, code.idx)
if p == 0 && code.indirect {
code = code.end.next
break
}
if code.indirect {
p = ptrToPtr(p + code.offset)
}
if p == 0 {
code = code.nextField
} else {
b = append(b, code.key...)
code = code.next
store(ctxptr, code.idx, p)
} }
case opStructFieldPtrHeadMarshalJSON: case opStructFieldPtrHeadMarshalJSON:
p := load(ctxptr, code.idx) p := load(ctxptr, code.idx)
@ -2846,77 +2963,98 @@ func encodeRun(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt Enco
store(ctxptr, code.idx, ptrToPtr(p)) store(ctxptr, code.idx, ptrToPtr(p))
fallthrough fallthrough
case opStructFieldHeadMarshalJSON: case opStructFieldHeadMarshalJSON:
ptr := load(ctxptr, code.idx) p := load(ctxptr, code.idx)
if ptr == 0 { if p == 0 && code.indirect {
b = encodeNull(b) b = encodeNull(b)
b = encodeComma(b) b = encodeComma(b)
code = code.end.next code = code.end.next
break
}
b = append(b, '{')
b = append(b, code.key...)
bb, err := encodeMarshalJSON(b, ptrToInterface(code, p+code.offset))
if err != nil {
return nil, err
}
b = bb
b = encodeComma(b)
code = code.next
case opStructFieldPtrHeadOmitEmptyMarshalJSON:
p := load(ctxptr, code.idx)
if p == 0 {
b = encodeNull(b)
b = encodeComma(b)
code = code.end.next
break
}
store(ctxptr, code.idx, ptrToPtr(p))
fallthrough
case opStructFieldHeadOmitEmptyMarshalJSON:
ptr := load(ctxptr, code.idx)
if ptr == 0 && code.indirect {
b = encodeNull(b)
b = encodeComma(b)
code = code.end.next
break
}
b = append(b, '{')
p := ptrToUnsafePtr(ptr + code.offset)
isPtr := code.typ.Kind() == reflect.Ptr
if p == nil || (!isPtr && *(*unsafe.Pointer)(p) == nil) {
code = code.nextField
} else { } else {
b = append(b, '{') v := *(*interface{})(unsafe.Pointer(&interfaceHeader{typ: code.typ, ptr: p}))
b = append(b, code.key...) bb, err := v.(Marshaler).MarshalJSON()
ptr += code.offset
v := ptrToInterface(code, ptr)
rv := reflect.ValueOf(v)
if rv.Type().Kind() == reflect.Interface && rv.IsNil() {
b = encodeNull(b)
code = code.end
break
}
bb, err := rv.Interface().(Marshaler).MarshalJSON()
if err != nil { if err != nil {
return nil, errMarshaler(code, err) return nil, &MarshalerError{
Type: rtype2type(code.typ),
Err: err,
}
} }
if len(bb) == 0 { if len(bb) == 0 {
return nil, errUnexpectedEndOfJSON( if isPtr {
fmt.Sprintf("error calling MarshalJSON for type %s", code.typ), return nil, errUnexpectedEndOfJSON(
0, fmt.Sprintf("error calling MarshalJSON for type %s", code.typ),
) 0,
)
}
code = code.nextField
} else {
b = append(b, code.key...)
buf := bytes.NewBuffer(b)
//TODO: we should validate buffer with `compact`
if err := compact(buf, bb, false); err != nil {
return nil, err
}
b = buf.Bytes()
b = encodeComma(b)
code = code.next
} }
buf := bytes.NewBuffer(b)
//TODO: we should validate buffer with `compact`
if err := compact(buf, bb, false); err != nil {
return nil, err
}
b = buf.Bytes()
b = encodeComma(b)
code = code.next
} }
case opStructFieldPtrAnonymousHeadMarshalJSON: case opStructFieldPtrAnonymousHeadMarshalJSON:
store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) p := load(ctxptr, code.idx)
if p == 0 {
b = encodeNull(b)
b = encodeComma(b)
code = code.end.next
break
}
store(ctxptr, code.idx, ptrToPtr(p))
fallthrough fallthrough
case opStructFieldAnonymousHeadMarshalJSON: case opStructFieldAnonymousHeadMarshalJSON:
ptr := load(ctxptr, code.idx) p := load(ctxptr, code.idx)
if ptr == 0 { if p == 0 && code.indirect {
code = code.end.next code = code.end.next
} else { break
b = append(b, code.key...)
ptr += code.offset
v := ptrToInterface(code, ptr)
rv := reflect.ValueOf(v)
if rv.Type().Kind() == reflect.Interface && rv.IsNil() {
b = encodeNull(b)
code = code.end.next
break
}
bb, err := rv.Interface().(Marshaler).MarshalJSON()
if err != nil {
return nil, errMarshaler(code, err)
}
if len(bb) == 0 {
return nil, errUnexpectedEndOfJSON(
fmt.Sprintf("error calling MarshalJSON for type %s", code.typ),
0,
)
}
buf := bytes.NewBuffer(b)
//TODO: we should validate buffer with `compact`
if err := compact(buf, bb, false); err != nil {
return nil, err
}
b = buf.Bytes()
b = encodeComma(b)
code = code.next
} }
b = append(b, code.key...)
bb, err := encodeMarshalJSON(b, ptrToInterface(code, p+code.offset))
if err != nil {
return nil, err
}
b = bb
b = encodeComma(b)
code = code.next
case opStructFieldPtrHeadMarshalText: case opStructFieldPtrHeadMarshalText:
p := load(ctxptr, code.idx) p := load(ctxptr, code.idx)
if p == 0 { if p == 0 {
@ -2928,106 +3066,46 @@ func encodeRun(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt Enco
store(ctxptr, code.idx, ptrToPtr(p)) store(ctxptr, code.idx, ptrToPtr(p))
fallthrough fallthrough
case opStructFieldHeadMarshalText: case opStructFieldHeadMarshalText:
ptr := load(ctxptr, code.idx) p := load(ctxptr, code.idx)
if ptr == 0 { if p == 0 && code.indirect {
b = encodeNull(b) b = encodeNull(b)
b = encodeComma(b) b = encodeComma(b)
code = code.end.next code = code.end.next
} else { break
b = append(b, '{')
b = append(b, code.key...)
ptr += code.offset
v := ptrToInterface(code, ptr)
rv := reflect.ValueOf(v)
if rv.Type().Kind() == reflect.Interface && rv.IsNil() {
b = encodeNull(b)
b = encodeComma(b)
code = code.end
break
}
bytes, err := rv.Interface().(encoding.TextMarshaler).MarshalText()
if err != nil {
return nil, errMarshaler(code, err)
}
b = encodeNoEscapedString(b, *(*string)(unsafe.Pointer(&bytes)))
b = encodeComma(b)
code = code.next
} }
b = append(b, '{')
b = append(b, code.key...)
bb, err := encodeMarshalText(b, ptrToInterface(code, p+code.offset))
if err != nil {
return nil, err
}
b = bb
b = encodeComma(b)
code = code.next
case opStructFieldPtrAnonymousHeadMarshalText: case opStructFieldPtrAnonymousHeadMarshalText:
store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx))) p := load(ctxptr, code.idx)
if p == 0 {
b = encodeNull(b)
b = encodeComma(b)
code = code.end.next
break
}
store(ctxptr, code.idx, ptrToPtr(p))
fallthrough fallthrough
case opStructFieldAnonymousHeadMarshalText: case opStructFieldAnonymousHeadMarshalText:
ptr := load(ctxptr, code.idx) p := load(ctxptr, code.idx)
if ptr == 0 { if p == 0 && code.indirect {
code = code.end.next code = code.end.next
} else { break
b = append(b, code.key...)
ptr += code.offset
v := ptrToInterface(code, ptr)
rv := reflect.ValueOf(v)
if rv.Type().Kind() == reflect.Interface && rv.IsNil() {
b = encodeNull(b)
b = encodeComma(b)
code = code.end.next
break
}
bytes, err := rv.Interface().(encoding.TextMarshaler).MarshalText()
if err != nil {
return nil, errMarshaler(code, err)
}
b = encodeNoEscapedString(b, *(*string)(unsafe.Pointer(&bytes)))
b = encodeComma(b)
code = code.next
} }
case opStructFieldPtrHeadOmitEmptyMarshalJSON: b = append(b, code.key...)
ptr := load(ctxptr, code.idx) bb, err := encodeMarshalText(b, ptrToInterface(code, p+code.offset))
if ptr != 0 { if err != nil {
store(ctxptr, code.idx, ptrToPtr(ptr)) return nil, err
}
fallthrough
case opStructFieldHeadOmitEmptyMarshalJSON:
ptr := load(ctxptr, code.idx)
if ptr == 0 {
b = encodeNull(b)
b = encodeComma(b)
code = code.end.next
} else {
b = append(b, '{')
ptr += code.offset
p := ptrToUnsafePtr(ptr)
isPtr := code.typ.Kind() == reflect.Ptr
if p == nil || (!isPtr && *(*unsafe.Pointer)(p) == nil) {
code = code.nextField
} else {
v := *(*interface{})(unsafe.Pointer(&interfaceHeader{typ: code.typ, ptr: p}))
bb, err := v.(Marshaler).MarshalJSON()
if err != nil {
return nil, &MarshalerError{
Type: rtype2type(code.typ),
Err: err,
}
}
if len(bb) == 0 {
if isPtr {
return nil, errUnexpectedEndOfJSON(
fmt.Sprintf("error calling MarshalJSON for type %s", code.typ),
0,
)
}
code = code.nextField
} else {
b = append(b, code.key...)
buf := bytes.NewBuffer(b)
//TODO: we should validate buffer with `compact`
if err := compact(buf, bb, false); err != nil {
return nil, err
}
b = buf.Bytes()
b = encodeComma(b)
code = code.next
}
}
} }
b = bb
b = encodeComma(b)
code = code.next
case opStructFieldPtrAnonymousHeadOmitEmptyMarshalJSON: case opStructFieldPtrAnonymousHeadOmitEmptyMarshalJSON:
ptr := load(ctxptr, code.idx) ptr := load(ctxptr, code.idx)
if ptr != 0 { if ptr != 0 {
@ -3845,7 +3923,7 @@ func encodeRun(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt Enco
code = code.next code = code.next
store(ctxptr, code.idx, p) store(ctxptr, code.idx, p)
} }
case opStructFieldSlice: case opStructFieldSlice, opStructFieldStringTagSlice:
b = append(b, code.key...) b = append(b, code.key...)
ptr := load(ctxptr, code.headIdx) ptr := load(ctxptr, code.headIdx)
p := ptr + code.offset p := ptr + code.offset
@ -3862,6 +3940,22 @@ func encodeRun(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt Enco
code = code.next code = code.next
store(ctxptr, code.idx, p) store(ctxptr, code.idx, p)
} }
case opStructFieldSlicePtr, opStructFieldStringTagSlicePtr:
b = append(b, code.key...)
p := load(ctxptr, code.headIdx)
p = ptrToPtr(p + code.offset)
code = code.next
store(ctxptr, code.idx, p)
case opStructFieldOmitEmptySlicePtr:
p := load(ctxptr, code.headIdx)
p = ptrToPtr(p + code.offset)
if p != 0 {
b = append(b, code.key...)
code = code.next
store(ctxptr, code.idx, p)
} else {
code = code.nextField
}
case opStructFieldMap: case opStructFieldMap:
b = append(b, code.key...) b = append(b, code.key...)
ptr := load(ctxptr, code.headIdx) ptr := load(ctxptr, code.headIdx)