forked from mirror/go-json
Work MarshalJSON test
This commit is contained in:
parent
734267f9ae
commit
88cd2ddd6e
|
@ -206,9 +206,9 @@ func encodeImplementsMarshaler(typ *rtype) bool {
|
||||||
func encodeCompile(ctx *encodeCompileContext, isPtr bool) (*opcode, error) {
|
func encodeCompile(ctx *encodeCompileContext, isPtr bool) (*opcode, error) {
|
||||||
typ := ctx.typ
|
typ := ctx.typ
|
||||||
switch {
|
switch {
|
||||||
case isPtr && typ.Kind() == reflect.Ptr && typ.Implements(marshalJSONType) && !typ.Elem().Implements(marshalJSONType):
|
//case isPtr && typ.Kind() == reflect.Ptr && typ.Implements(marshalJSONType) && !typ.Elem().Implements(marshalJSONType):
|
||||||
// *struct{ field *implementedMarshalJSONType }
|
// *struct{ field *implementedMarshalJSONType }
|
||||||
return encodeCompileMarshalJSONPtr(ctx)
|
// return encodeCompileMarshalJSONPtr(ctx)
|
||||||
case typ.Implements(marshalJSONType) && (typ.Kind() != reflect.Ptr || !typ.Elem().Implements(marshalJSONType)):
|
case typ.Implements(marshalJSONType) && (typ.Kind() != reflect.Ptr || !typ.Elem().Implements(marshalJSONType)):
|
||||||
return encodeCompileMarshalJSON(ctx)
|
return encodeCompileMarshalJSON(ctx)
|
||||||
// case rtype_ptrTo(typ).Implements(marshalJSONType):
|
// case rtype_ptrTo(typ).Implements(marshalJSONType):
|
||||||
|
@ -1230,6 +1230,7 @@ func encodeCompileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode, error)
|
||||||
// |__________|
|
// |__________|
|
||||||
fieldNum := typ.NumField()
|
fieldNum := typ.NumField()
|
||||||
indirect := ifaceIndir(typ)
|
indirect := ifaceIndir(typ)
|
||||||
|
//fmt.Println("indirect = ", indirect, "type = ", typ, "isPtr = ", isPtr)
|
||||||
fieldIdx := 0
|
fieldIdx := 0
|
||||||
disableIndirectConversion := false
|
disableIndirectConversion := false
|
||||||
var (
|
var (
|
||||||
|
@ -1264,9 +1265,10 @@ func encodeCompileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode, error)
|
||||||
fieldOpcodeIndex := ctx.opcodeIndex
|
fieldOpcodeIndex := ctx.opcodeIndex
|
||||||
fieldPtrIndex := ctx.ptrIndex
|
fieldPtrIndex := ctx.ptrIndex
|
||||||
ctx.incIndex()
|
ctx.incIndex()
|
||||||
nilcheck := indirect //fieldType.Kind() == reflect.Ptr || isPtr && !indirect
|
nilcheck := true //isPtr || indirect //fieldType.Kind() == reflect.Ptr || isPtr && !indirect
|
||||||
|
fmt.Println("default nilcheck = ", nilcheck, "opcodeIndex = ", ctx.opcodeIndex)
|
||||||
var valueCode *opcode
|
var valueCode *opcode
|
||||||
if i == 0 && fieldNum == 1 && isPtr && rtype_ptrTo(fieldType).Implements(marshalJSONType) && !fieldType.Implements(marshalJSONType) {
|
if i == 0 && fieldNum == 1 && isPtr && fieldType.Kind() != reflect.Ptr && rtype_ptrTo(fieldType).Implements(marshalJSONType) && !fieldType.Implements(marshalJSONType) {
|
||||||
// *struct{ field implementedMarshalJSONType } => struct { field *implementedMarshalJSONType }
|
// *struct{ field implementedMarshalJSONType } => struct { field *implementedMarshalJSONType }
|
||||||
// move pointer position from head to first field
|
// move pointer position from head to first field
|
||||||
code, err := encodeCompileMarshalJSON(ctx.withType(rtype_ptrTo(fieldType)))
|
code, err := encodeCompileMarshalJSON(ctx.withType(rtype_ptrTo(fieldType)))
|
||||||
|
@ -1277,7 +1279,6 @@ func encodeCompileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode, error)
|
||||||
nilcheck = false
|
nilcheck = false
|
||||||
indirect = false
|
indirect = false
|
||||||
disableIndirectConversion = true
|
disableIndirectConversion = true
|
||||||
fmt.Println("nilcheck false")
|
|
||||||
} else if isPtr && fieldType.Kind() != reflect.Ptr && !fieldType.Implements(marshalJSONType) && rtype_ptrTo(fieldType).Implements(marshalJSONType) {
|
} else if isPtr && fieldType.Kind() != reflect.Ptr && !fieldType.Implements(marshalJSONType) && rtype_ptrTo(fieldType).Implements(marshalJSONType) {
|
||||||
code, err := encodeCompileMarshalJSON(ctx.withType(rtype_ptrTo(fieldType)))
|
code, err := encodeCompileMarshalJSON(ctx.withType(rtype_ptrTo(fieldType)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1290,10 +1291,16 @@ func encodeCompileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode, error)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
nilcheck = false
|
//nilcheck = false
|
||||||
|
valueCode = code
|
||||||
|
} else if fieldType.Implements(marshalJSONType) && fieldType.Kind() == reflect.Ptr && !fieldType.Elem().Implements(marshalJSONType) {
|
||||||
|
code, err := encodeCompileMarshalJSON(ctx.withType(fieldType))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
valueCode = code
|
valueCode = code
|
||||||
} else {
|
} else {
|
||||||
code, err := encodeCompile(ctx.withType(fieldType), i == 0 && isPtr)
|
code, err := encodeCompile(ctx.withType(fieldType), isPtr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -1318,7 +1325,6 @@ func encodeCompileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode, error)
|
||||||
key := fmt.Sprintf(`"%s":`, tag.key)
|
key := fmt.Sprintf(`"%s":`, tag.key)
|
||||||
escapedKey := fmt.Sprintf(`%s:`, string(encodeEscapedString([]byte{}, tag.key)))
|
escapedKey := fmt.Sprintf(`%s:`, string(encodeEscapedString([]byte{}, tag.key)))
|
||||||
valueCode.indirect = indirect
|
valueCode.indirect = indirect
|
||||||
valueCode.nilcheck = nilcheck
|
|
||||||
fieldCode := &opcode{
|
fieldCode := &opcode{
|
||||||
typ: valueCode.typ,
|
typ: valueCode.typ,
|
||||||
displayIdx: fieldOpcodeIndex,
|
displayIdx: fieldOpcodeIndex,
|
||||||
|
|
122
encode_vm.go
122
encode_vm.go
|
@ -9,6 +9,7 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -544,7 +545,7 @@ func encodeRun(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt Enco
|
||||||
}
|
}
|
||||||
b = append(b, '{')
|
b = append(b, '{')
|
||||||
p += code.offset
|
p += code.offset
|
||||||
if p == 0 {
|
if p == 0 || (strings.Contains(code.next.op.String(), "Ptr") && ptrToPtr(p) == 0) {
|
||||||
code = code.nextField
|
code = code.nextField
|
||||||
} else {
|
} else {
|
||||||
b = append(b, code.key...)
|
b = append(b, code.key...)
|
||||||
|
@ -607,7 +608,7 @@ func encodeRun(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt Enco
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
p += code.offset
|
p += code.offset
|
||||||
if p == 0 || *(*uintptr)(*(*unsafe.Pointer)(unsafe.Pointer(&p))) == 0 {
|
if p == 0 || (strings.Contains(code.next.op.String(), "Ptr") && ptrToPtr(p) == 0) {
|
||||||
code = code.nextField
|
code = code.nextField
|
||||||
} else {
|
} else {
|
||||||
b = append(b, code.key...)
|
b = append(b, code.key...)
|
||||||
|
@ -3236,11 +3237,19 @@ 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...)
|
||||||
fmt.Println("p = ", p, "nilcheck = ", code.nilcheck)
|
if code.typ.Kind() == reflect.Ptr {
|
||||||
if p == 0 || code.nilcheck && code.typ.Kind() == reflect.Ptr && ptrToPtr(p) == 0 {
|
if code.indirect || (code.op == opStructFieldPtrHeadMarshalJSON || code.op == opStructFieldPtrHeadStringTagMarshalJSON) {
|
||||||
|
p = ptrToPtr(p + code.offset)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println("p = ", p, "nilcheck = ", code.nilcheck, "indirect = ", code.indirect)
|
||||||
|
//fmt.Println("type = ", code.typ, "isNilPointer = ", code.typ.Kind() == reflect.Ptr && reflect.ValueOf(iface).IsNil())
|
||||||
|
//fmt.Println("iface = ", iface, "isNil = ", iface == nil)
|
||||||
|
if code.nilcheck && p == 0 /* || code.nilcheck && code.typ.Kind() == reflect.Ptr && ptrToPtr(p) == 0*/ {
|
||||||
b = encodeNull(b)
|
b = encodeNull(b)
|
||||||
} else {
|
} else {
|
||||||
bb, err := encodeMarshalJSON(b, ptrToInterface(code, p+code.offset))
|
iface := ptrToInterface(code, p)
|
||||||
|
bb, err := encodeMarshalJSON(b, iface)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -3269,7 +3278,12 @@ func encodeRun(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt Enco
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
b = append(b, '{')
|
b = append(b, '{')
|
||||||
if p == 0 || code.nilcheck && code.typ.Kind() == reflect.Ptr && ptrToPtr(p) == 0 {
|
if code.typ.Kind() == reflect.Ptr && code.indirect {
|
||||||
|
p = ptrToPtr(p + code.offset)
|
||||||
|
} else if code.op == opStructFieldPtrHeadOmitEmptyMarshalJSON && code.typ.Kind() == reflect.Ptr {
|
||||||
|
p = ptrToPtr(p + code.offset)
|
||||||
|
}
|
||||||
|
if code.nilcheck && p == 0 {
|
||||||
code = code.nextField
|
code = code.nextField
|
||||||
} else {
|
} else {
|
||||||
b = append(b, code.key...)
|
b = append(b, code.key...)
|
||||||
|
@ -3280,36 +3294,6 @@ func encodeRun(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt Enco
|
||||||
b = bb
|
b = bb
|
||||||
b = encodeComma(b)
|
b = encodeComma(b)
|
||||||
code = code.next
|
code = code.next
|
||||||
/*
|
|
||||||
p := ptrToUnsafePtr(p + code.offset)
|
|
||||||
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
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
case opStructFieldPtrHeadMarshalJSONPtr, opStructFieldPtrHeadStringTagMarshalJSONPtr:
|
case opStructFieldPtrHeadMarshalJSONPtr, opStructFieldPtrHeadStringTagMarshalJSONPtr:
|
||||||
p := load(ctxptr, code.idx)
|
p := load(ctxptr, code.idx)
|
||||||
|
@ -3346,6 +3330,7 @@ func encodeRun(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt Enco
|
||||||
b = encodeComma(b)
|
b = encodeComma(b)
|
||||||
code = code.next
|
code = code.next
|
||||||
case opStructFieldPtrHeadOmitEmptyMarshalJSONPtr:
|
case opStructFieldPtrHeadOmitEmptyMarshalJSONPtr:
|
||||||
|
fmt.Println("type = ", code.typ)
|
||||||
p := load(ctxptr, code.idx)
|
p := load(ctxptr, code.idx)
|
||||||
if p == 0 {
|
if p == 0 {
|
||||||
b = encodeNull(b)
|
b = encodeNull(b)
|
||||||
|
@ -3366,6 +3351,7 @@ func encodeRun(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt Enco
|
||||||
if code.indirect {
|
if code.indirect {
|
||||||
p = ptrToPtr(p + code.offset)
|
p = ptrToPtr(p + code.offset)
|
||||||
}
|
}
|
||||||
|
fmt.Println("p = ", p)
|
||||||
b = append(b, '{')
|
b = append(b, '{')
|
||||||
if p == 0 {
|
if p == 0 {
|
||||||
code = code.nextField
|
code = code.nextField
|
||||||
|
@ -3379,7 +3365,7 @@ func encodeRun(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt Enco
|
||||||
b = encodeComma(b)
|
b = encodeComma(b)
|
||||||
code = code.next
|
code = code.next
|
||||||
}
|
}
|
||||||
case opStructFieldPtrAnonymousHeadMarshalJSON:
|
case opStructFieldPtrAnonymousHeadMarshalJSON, opStructFieldPtrAnonymousHeadStringTagMarshalJSON:
|
||||||
p := load(ctxptr, code.idx)
|
p := load(ctxptr, code.idx)
|
||||||
if p == 0 {
|
if p == 0 {
|
||||||
code = code.end.next
|
code = code.end.next
|
||||||
|
@ -3389,14 +3375,19 @@ 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 opStructFieldAnonymousHeadMarshalJSON:
|
case opStructFieldAnonymousHeadMarshalJSON, opStructFieldAnonymousHeadStringTagMarshalJSON:
|
||||||
p := load(ctxptr, code.idx)
|
p := load(ctxptr, code.idx)
|
||||||
if p == 0 && code.indirect {
|
if p == 0 && code.indirect {
|
||||||
code = code.end.next
|
code = code.end.next
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
b = append(b, code.key...)
|
b = append(b, code.key...)
|
||||||
if p == 0 || code.nilcheck && code.typ.Kind() == reflect.Ptr && ptrToPtr(p) == 0 {
|
if code.typ.Kind() == reflect.Ptr {
|
||||||
|
if code.indirect || (code.op != opStructFieldAnonymousHeadMarshalJSON && code.op != opStructFieldAnonymousHeadStringTagMarshalJSON) {
|
||||||
|
p = ptrToPtr(p + code.offset)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if code.nilcheck && p == 0 {
|
||||||
b = encodeNull(b)
|
b = encodeNull(b)
|
||||||
} else {
|
} else {
|
||||||
bb, err := encodeMarshalJSON(b, ptrToInterface(code, p+code.offset))
|
bb, err := encodeMarshalJSON(b, ptrToInterface(code, p+code.offset))
|
||||||
|
@ -3452,7 +3443,12 @@ func encodeRun(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt Enco
|
||||||
code = code.end.next
|
code = code.end.next
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if p == 0 || code.nilcheck && code.typ.Kind() == reflect.Ptr && ptrToPtr(p) == 0 {
|
if code.typ.Kind() == reflect.Ptr {
|
||||||
|
if code.indirect || code.op != opStructFieldAnonymousHeadOmitEmptyMarshalJSON {
|
||||||
|
p = ptrToPtr(p + code.offset)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if p == 0 && code.nilcheck {
|
||||||
code = code.nextField
|
code = code.nextField
|
||||||
} else {
|
} else {
|
||||||
b = append(b, code.key...)
|
b = append(b, code.key...)
|
||||||
|
@ -3609,50 +3605,6 @@ func encodeRun(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt Enco
|
||||||
code = code.next
|
code = code.next
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case opStructFieldPtrAnonymousHeadStringTagMarshalJSON:
|
|
||||||
ptr := load(ctxptr, code.idx)
|
|
||||||
if ptr != 0 {
|
|
||||||
store(ctxptr, code.idx, ptrToPtr(ptr))
|
|
||||||
}
|
|
||||||
fallthrough
|
|
||||||
case opStructFieldAnonymousHeadStringTagMarshalJSON:
|
|
||||||
ptr := load(ctxptr, code.idx)
|
|
||||||
if ptr == 0 {
|
|
||||||
code = code.end.next
|
|
||||||
} else {
|
|
||||||
ptr += code.offset
|
|
||||||
p := ptrToUnsafePtr(ptr)
|
|
||||||
isPtr := code.typ.Kind() == reflect.Ptr
|
|
||||||
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,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
b = append(b, code.key...)
|
|
||||||
b = append(b, '"', '"')
|
|
||||||
b = encodeComma(b)
|
|
||||||
code = code.nextField
|
|
||||||
} else {
|
|
||||||
var buf bytes.Buffer
|
|
||||||
if err := compact(&buf, bb, false); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
b = append(b, code.key...)
|
|
||||||
b = encodeNoEscapedString(b, buf.String())
|
|
||||||
b = encodeComma(b)
|
|
||||||
code = code.next
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case opStructFieldPtrHeadStringTagMarshalText:
|
case opStructFieldPtrHeadStringTagMarshalText:
|
||||||
ptr := load(ctxptr, code.idx)
|
ptr := load(ctxptr, code.idx)
|
||||||
if ptr != 0 {
|
if ptr != 0 {
|
||||||
|
@ -3715,7 +3667,7 @@ func encodeRun(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt Enco
|
||||||
case opStructFieldOmitEmpty:
|
case opStructFieldOmitEmpty:
|
||||||
ptr := load(ctxptr, code.headIdx)
|
ptr := load(ctxptr, code.headIdx)
|
||||||
p := ptr + code.offset
|
p := ptr + code.offset
|
||||||
if p == 0 {
|
if p == 0 || (strings.Contains(code.next.op.String(), "Ptr") && ptrToPtr(p) == 0) {
|
||||||
code = code.nextField
|
code = code.nextField
|
||||||
} else {
|
} else {
|
||||||
b = append(b, code.key...)
|
b = append(b, code.key...)
|
||||||
|
|
Loading…
Reference in New Issue