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",
|
||||
"intString", "uintString",
|
||||
"intPtr", "uintPtr", "float32Ptr", "float64Ptr", "boolPtr", "stringPtr", "bytesPtr",
|
||||
"arrayPtr", "slicePtr", "mapPtr",
|
||||
"intNPtr", "uintNPtr", "float32NPtr", "float64NPtr", "boolNPtr", "stringNPtr", "bytesNPtr",
|
||||
}
|
||||
primitiveTypesUpper := []string{}
|
||||
|
|
|
@ -19,6 +19,7 @@ func float32ptr(v float32) *float32 { return &v }
|
|||
func float64ptr(v float64) *float64 { return &v }
|
||||
func stringptr(v string) *string { return &v }
|
||||
func boolptr(v bool) *bool { return &v }
|
||||
func sliceptr(v []int) *[]int { return &v }
|
||||
|
||||
func encodeByEncodingJSON(data interface{}, indent, escape bool) string {
|
||||
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 (
|
||||
"bytes"
|
||||
"encoding"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
@ -362,3 +365,32 @@ func appendIndent(ctx *encodeRuntimeContext, b []byte, indent int) []byte {
|
|||
b = append(b, ctx.prefix...)
|
||||
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 {
|
||||
case opStructEnd:
|
||||
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
|
||||
code = code.next
|
||||
break
|
||||
|
@ -751,6 +755,8 @@ func encodeTypeToHeaderType(ctx *encodeCompileContext, code *opcode) opType {
|
|||
return opStructFieldHeadStringPtr
|
||||
case opBool:
|
||||
return opStructFieldHeadBoolPtr
|
||||
case opSliceHead:
|
||||
return opStructFieldHeadSlicePtr
|
||||
}
|
||||
}
|
||||
case opInt:
|
||||
|
@ -834,6 +840,8 @@ func encodeTypeToFieldType(ctx *encodeCompileContext, code *opcode) opType {
|
|||
return opStructFieldStringPtr
|
||||
case opBool:
|
||||
return opStructFieldBoolPtr
|
||||
case opSliceHead:
|
||||
return opStructFieldSlicePtr
|
||||
}
|
||||
}
|
||||
case opInt:
|
||||
|
@ -919,12 +927,18 @@ func encodeStructHeader(ctx *encodeCompileContext, fieldCode *opcode, valueCode
|
|||
opStructFieldHeadStruct,
|
||||
opStructFieldHeadOmitEmpty,
|
||||
opStructFieldHeadOmitEmptySlice,
|
||||
opStructFieldHeadStringTagSlice,
|
||||
opStructFieldHeadOmitEmptyArray,
|
||||
opStructFieldHeadOmitEmptyMap,
|
||||
opStructFieldHeadOmitEmptyMapLoad,
|
||||
opStructFieldHeadOmitEmptyStruct,
|
||||
opStructFieldHeadStringTag:
|
||||
return valueCode.beforeLastCode()
|
||||
case opStructFieldHeadSlicePtr,
|
||||
opStructFieldHeadOmitEmptySlicePtr,
|
||||
opStructFieldHeadStringTagSlicePtr:
|
||||
*valueCode = *valueCode.next
|
||||
return valueCode.beforeLastCode()
|
||||
}
|
||||
ctx.decOpcodeIndex()
|
||||
return (*opcode)(unsafe.Pointer(fieldCode))
|
||||
|
@ -946,12 +960,19 @@ func encodeStructField(ctx *encodeCompileContext, fieldCode *opcode, valueCode *
|
|||
opStructFieldStruct,
|
||||
opStructFieldOmitEmpty,
|
||||
opStructFieldOmitEmptySlice,
|
||||
opStructFieldStringTagSlice,
|
||||
opStructFieldOmitEmptyArray,
|
||||
opStructFieldStringTagArray,
|
||||
opStructFieldOmitEmptyMap,
|
||||
opStructFieldOmitEmptyMapLoad,
|
||||
opStructFieldOmitEmptyStruct,
|
||||
opStructFieldStringTag:
|
||||
return valueCode.beforeLastCode()
|
||||
case opStructFieldSlicePtr,
|
||||
opStructFieldOmitEmptySlicePtr,
|
||||
opStructFieldStringTagSlicePtr:
|
||||
*valueCode = *valueCode.next
|
||||
return valueCode.beforeLastCode()
|
||||
}
|
||||
ctx.decIndex()
|
||||
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)
|
||||
code = code.next
|
||||
case opStructFieldPtrHeadArray:
|
||||
case opStructFieldPtrHeadArray, opStructFieldPtrHeadStringTagArray,
|
||||
opStructFieldPtrHeadSlice, opStructFieldPtrHeadStringTagSlice:
|
||||
if code.indirect {
|
||||
store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx)))
|
||||
}
|
||||
fallthrough
|
||||
case opStructFieldHeadArray:
|
||||
case opStructFieldHeadArray, opStructFieldHeadStringTagArray,
|
||||
opStructFieldHeadSlice, opStructFieldHeadStringTagSlice:
|
||||
p := load(ctxptr, code.idx)
|
||||
if p == 0 {
|
||||
b = encodeNull(b)
|
||||
|
@ -2779,21 +2781,34 @@ func encodeRun(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt Enco
|
|||
}
|
||||
b = append(b, '{')
|
||||
b = append(b, code.key...)
|
||||
p += code.offset
|
||||
code = code.next
|
||||
store(ctxptr, code.idx, p)
|
||||
case opStructFieldPtrAnonymousHeadArray:
|
||||
store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx)))
|
||||
case opStructFieldPtrHeadOmitEmptyArray, opStructFieldPtrHeadOmitEmptySlice:
|
||||
if code.indirect {
|
||||
store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx)))
|
||||
}
|
||||
fallthrough
|
||||
case opStructFieldAnonymousHeadArray:
|
||||
ptr := load(ctxptr, code.idx) + code.offset
|
||||
if ptr == 0 {
|
||||
case opStructFieldHeadOmitEmptyArray, opStructFieldHeadOmitEmptySlice:
|
||||
p := load(ctxptr, code.idx)
|
||||
if p == 0 {
|
||||
b = encodeNull(b)
|
||||
b = encodeComma(b)
|
||||
code = code.end.next
|
||||
break
|
||||
}
|
||||
b = append(b, '{')
|
||||
p += code.offset
|
||||
array := ptrToSlice(p)
|
||||
if array.data == nil {
|
||||
code = code.nextField
|
||||
} else {
|
||||
b = append(b, code.key...)
|
||||
store(ctxptr, code.idx, ptr)
|
||||
code = code.next
|
||||
store(ctxptr, code.idx, p)
|
||||
}
|
||||
case opStructFieldPtrHeadSlice:
|
||||
case opStructFieldPtrHeadArrayPtr, opStructFieldPtrHeadStringTagArrayPtr,
|
||||
opStructFieldPtrHeadSlicePtr, opStructFieldPtrHeadStringTagSlicePtr:
|
||||
p := load(ctxptr, code.idx)
|
||||
if p == 0 {
|
||||
b = encodeNull(b)
|
||||
|
@ -2803,37 +2818,139 @@ func encodeRun(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt Enco
|
|||
}
|
||||
store(ctxptr, code.idx, ptrToPtr(p))
|
||||
fallthrough
|
||||
case opStructFieldHeadSlice:
|
||||
ptr := load(ctxptr, code.idx)
|
||||
p := ptr + code.offset
|
||||
if p == 0 {
|
||||
if code.op == opStructFieldPtrHeadSlice {
|
||||
b = encodeNull(b)
|
||||
b = encodeComma(b)
|
||||
} else {
|
||||
b = append(b, '[', ']', ',')
|
||||
}
|
||||
case opStructFieldHeadArrayPtr, opStructFieldHeadStringTagArrayPtr,
|
||||
opStructFieldHeadSlicePtr, opStructFieldHeadStringTagSlicePtr:
|
||||
p := load(ctxptr, code.idx)
|
||||
if p == 0 && code.indirect {
|
||||
b = encodeNull(b)
|
||||
b = encodeComma(b)
|
||||
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 {
|
||||
b = append(b, '{')
|
||||
if !code.anonymousKey {
|
||||
b = append(b, code.key...)
|
||||
}
|
||||
code = code.next
|
||||
store(ctxptr, code.idx, p)
|
||||
}
|
||||
case opStructFieldPtrAnonymousHeadSlice:
|
||||
store(ctxptr, code.idx, ptrToPtr(load(ctxptr, code.idx)))
|
||||
fallthrough
|
||||
case opStructFieldAnonymousHeadSlice:
|
||||
ptr := load(ctxptr, code.idx)
|
||||
p := ptr + code.offset
|
||||
case opStructFieldPtrHeadOmitEmptyArrayPtr, opStructFieldPtrHeadOmitEmptySlicePtr:
|
||||
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 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 {
|
||||
b = append(b, code.key...)
|
||||
store(ctxptr, code.idx, p)
|
||||
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:
|
||||
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))
|
||||
fallthrough
|
||||
case opStructFieldHeadMarshalJSON:
|
||||
ptr := load(ctxptr, code.idx)
|
||||
if ptr == 0 {
|
||||
p := load(ctxptr, code.idx)
|
||||
if p == 0 && code.indirect {
|
||||
b = encodeNull(b)
|
||||
b = encodeComma(b)
|
||||
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 {
|
||||
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)
|
||||
code = code.end
|
||||
break
|
||||
}
|
||||
bb, err := rv.Interface().(Marshaler).MarshalJSON()
|
||||
v := *(*interface{})(unsafe.Pointer(&interfaceHeader{typ: code.typ, ptr: p}))
|
||||
bb, err := v.(Marshaler).MarshalJSON()
|
||||
if err != nil {
|
||||
return nil, errMarshaler(code, err)
|
||||
return nil, &MarshalerError{
|
||||
Type: rtype2type(code.typ),
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
if len(bb) == 0 {
|
||||
return nil, errUnexpectedEndOfJSON(
|
||||
fmt.Sprintf("error calling MarshalJSON for type %s", code.typ),
|
||||
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
|
||||
}
|
||||
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:
|
||||
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
|
||||
case opStructFieldAnonymousHeadMarshalJSON:
|
||||
ptr := load(ctxptr, code.idx)
|
||||
if ptr == 0 {
|
||||
p := load(ctxptr, code.idx)
|
||||
if p == 0 && code.indirect {
|
||||
code = code.end.next
|
||||
} else {
|
||||
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
|
||||
break
|
||||
}
|
||||
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:
|
||||
p := load(ctxptr, code.idx)
|
||||
if p == 0 {
|
||||
|
@ -2928,106 +3066,46 @@ func encodeRun(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt Enco
|
|||
store(ctxptr, code.idx, ptrToPtr(p))
|
||||
fallthrough
|
||||
case opStructFieldHeadMarshalText:
|
||||
ptr := load(ctxptr, code.idx)
|
||||
if ptr == 0 {
|
||||
p := load(ctxptr, code.idx)
|
||||
if p == 0 && code.indirect {
|
||||
b = encodeNull(b)
|
||||
b = encodeComma(b)
|
||||
code = code.end.next
|
||||
} else {
|
||||
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
|
||||
break
|
||||
}
|
||||
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:
|
||||
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
|
||||
case opStructFieldAnonymousHeadMarshalText:
|
||||
ptr := load(ctxptr, code.idx)
|
||||
if ptr == 0 {
|
||||
p := load(ctxptr, code.idx)
|
||||
if p == 0 && code.indirect {
|
||||
code = code.end.next
|
||||
} else {
|
||||
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
|
||||
break
|
||||
}
|
||||
case opStructFieldPtrHeadOmitEmptyMarshalJSON:
|
||||
ptr := load(ctxptr, code.idx)
|
||||
if ptr != 0 {
|
||||
store(ctxptr, code.idx, ptrToPtr(ptr))
|
||||
}
|
||||
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 = 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 opStructFieldPtrAnonymousHeadOmitEmptyMarshalJSON:
|
||||
ptr := load(ctxptr, code.idx)
|
||||
if ptr != 0 {
|
||||
|
@ -3845,7 +3923,7 @@ func encodeRun(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt Enco
|
|||
code = code.next
|
||||
store(ctxptr, code.idx, p)
|
||||
}
|
||||
case opStructFieldSlice:
|
||||
case opStructFieldSlice, opStructFieldStringTagSlice:
|
||||
b = append(b, code.key...)
|
||||
ptr := load(ctxptr, code.headIdx)
|
||||
p := ptr + code.offset
|
||||
|
@ -3862,6 +3940,22 @@ func encodeRun(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt Enco
|
|||
code = code.next
|
||||
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:
|
||||
b = append(b, code.key...)
|
||||
ptr := load(ctxptr, code.headIdx)
|
||||
|
|
Loading…
Reference in New Issue