forked from mirror/go-json
Add slice test
This commit is contained in:
parent
83122027f5
commit
2a2a19319d
|
@ -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{}
|
||||||
|
|
|
@ -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
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
32
encode.go
32
encode.go
|
@ -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
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
1722
encode_optype.go
1722
encode_optype.go
File diff suppressed because it is too large
Load Diff
450
encode_vm.go
450
encode_vm.go
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue