forked from mirror/go-json
Add test case for MarshalJSON type
This commit is contained in:
parent
249c4da6dd
commit
734267f9ae
File diff suppressed because it is too large
Load Diff
|
@ -790,8 +790,8 @@ func encodeTypeToHeaderType(ctx *encodeCompileContext, code *opcode) opType {
|
||||||
return opStructFieldHeadArray
|
return opStructFieldHeadArray
|
||||||
case opSliceHead:
|
case opSliceHead:
|
||||||
return opStructFieldHeadSlice
|
return opStructFieldHeadSlice
|
||||||
case opStructFieldHead:
|
// case opStructFieldHead:
|
||||||
return opStructFieldHeadStruct
|
// return opStructFieldHeadStruct
|
||||||
case opMarshalJSON:
|
case opMarshalJSON:
|
||||||
return opStructFieldHeadMarshalJSON
|
return opStructFieldHeadMarshalJSON
|
||||||
case opMarshalJSONPtr:
|
case opMarshalJSONPtr:
|
||||||
|
@ -1264,13 +1264,12 @@ 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
|
nilcheck := indirect //fieldType.Kind() == reflect.Ptr || isPtr && !indirect
|
||||||
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 && 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
|
||||||
ctx.typ = rtype_ptrTo(fieldType)
|
code, err := encodeCompileMarshalJSON(ctx.withType(rtype_ptrTo(fieldType)))
|
||||||
code, err := encodeCompileMarshalJSON(ctx)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -1278,9 +1277,16 @@ func encodeCompileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode, error)
|
||||||
nilcheck = false
|
nilcheck = false
|
||||||
indirect = false
|
indirect = false
|
||||||
disableIndirectConversion = true
|
disableIndirectConversion = true
|
||||||
} else if isPtr && fieldNum > 1 && fieldType.Kind() != reflect.Ptr && !fieldType.Implements(marshalJSONType) && rtype_ptrTo(fieldType).Implements(marshalJSONType) {
|
fmt.Println("nilcheck false")
|
||||||
ctx.typ = rtype_ptrTo(fieldType)
|
} else if isPtr && fieldType.Kind() != reflect.Ptr && !fieldType.Implements(marshalJSONType) && rtype_ptrTo(fieldType).Implements(marshalJSONType) {
|
||||||
code, err := encodeCompileMarshalJSON(ctx)
|
code, err := encodeCompileMarshalJSON(ctx.withType(rtype_ptrTo(fieldType)))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
nilcheck = false
|
||||||
|
valueCode = code
|
||||||
|
} else if fieldType.Implements(marshalJSONType) && fieldType.Kind() != reflect.Ptr {
|
||||||
|
code, err := encodeCompileMarshalJSON(ctx.withType(fieldType))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
165
encode_vm.go
165
encode_vm.go
|
@ -3222,7 +3222,9 @@ func encodeRun(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt Enco
|
||||||
code = code.end.next
|
code = code.end.next
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
if code.indirect {
|
||||||
store(ctxptr, code.idx, ptrToPtr(p))
|
store(ctxptr, code.idx, ptrToPtr(p))
|
||||||
|
}
|
||||||
fallthrough
|
fallthrough
|
||||||
case opStructFieldHeadMarshalJSON, opStructFieldHeadStringTagMarshalJSON:
|
case opStructFieldHeadMarshalJSON, opStructFieldHeadStringTagMarshalJSON:
|
||||||
p := load(ctxptr, code.idx)
|
p := load(ctxptr, code.idx)
|
||||||
|
@ -3234,6 +3236,7 @@ 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 p == 0 || code.nilcheck && code.typ.Kind() == reflect.Ptr && ptrToPtr(p) == 0 {
|
if p == 0 || code.nilcheck && code.typ.Kind() == reflect.Ptr && ptrToPtr(p) == 0 {
|
||||||
b = encodeNull(b)
|
b = encodeNull(b)
|
||||||
} else {
|
} else {
|
||||||
|
@ -3253,7 +3256,9 @@ func encodeRun(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt Enco
|
||||||
code = code.end.next
|
code = code.end.next
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
if code.indirect {
|
||||||
store(ctxptr, code.idx, ptrToPtr(p))
|
store(ctxptr, code.idx, ptrToPtr(p))
|
||||||
|
}
|
||||||
fallthrough
|
fallthrough
|
||||||
case opStructFieldHeadOmitEmptyMarshalJSON:
|
case opStructFieldHeadOmitEmptyMarshalJSON:
|
||||||
p := load(ctxptr, code.idx)
|
p := load(ctxptr, code.idx)
|
||||||
|
@ -3306,6 +3311,16 @@ func encodeRun(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt Enco
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
case opStructFieldPtrHeadMarshalJSONPtr, opStructFieldPtrHeadStringTagMarshalJSONPtr:
|
||||||
|
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 opStructFieldHeadMarshalJSONPtr, opStructFieldHeadStringTagMarshalJSONPtr:
|
case opStructFieldHeadMarshalJSONPtr, opStructFieldHeadStringTagMarshalJSONPtr:
|
||||||
p := load(ctxptr, code.idx)
|
p := load(ctxptr, code.idx)
|
||||||
if p == 0 && code.indirect {
|
if p == 0 && code.indirect {
|
||||||
|
@ -3330,6 +3345,16 @@ func encodeRun(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt Enco
|
||||||
}
|
}
|
||||||
b = encodeComma(b)
|
b = encodeComma(b)
|
||||||
code = code.next
|
code = code.next
|
||||||
|
case opStructFieldPtrHeadOmitEmptyMarshalJSONPtr:
|
||||||
|
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 opStructFieldHeadOmitEmptyMarshalJSONPtr:
|
case opStructFieldHeadOmitEmptyMarshalJSONPtr:
|
||||||
p := load(ctxptr, code.idx)
|
p := load(ctxptr, code.idx)
|
||||||
if p == 0 && code.indirect {
|
if p == 0 && code.indirect {
|
||||||
|
@ -3357,12 +3382,12 @@ func encodeRun(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt Enco
|
||||||
case opStructFieldPtrAnonymousHeadMarshalJSON:
|
case opStructFieldPtrAnonymousHeadMarshalJSON:
|
||||||
p := load(ctxptr, code.idx)
|
p := load(ctxptr, code.idx)
|
||||||
if p == 0 {
|
if p == 0 {
|
||||||
b = encodeNull(b)
|
|
||||||
b = encodeComma(b)
|
|
||||||
code = code.end.next
|
code = code.end.next
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
if code.indirect {
|
||||||
store(ctxptr, code.idx, ptrToPtr(p))
|
store(ctxptr, code.idx, ptrToPtr(p))
|
||||||
|
}
|
||||||
fallthrough
|
fallthrough
|
||||||
case opStructFieldAnonymousHeadMarshalJSON:
|
case opStructFieldAnonymousHeadMarshalJSON:
|
||||||
p := load(ctxptr, code.idx)
|
p := load(ctxptr, code.idx)
|
||||||
|
@ -3370,6 +3395,66 @@ func encodeRun(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt Enco
|
||||||
code = code.end.next
|
code = code.end.next
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
b = append(b, code.key...)
|
||||||
|
if p == 0 || code.nilcheck && code.typ.Kind() == reflect.Ptr && ptrToPtr(p) == 0 {
|
||||||
|
b = encodeNull(b)
|
||||||
|
} else {
|
||||||
|
bb, err := encodeMarshalJSON(b, ptrToInterface(code, p+code.offset))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
b = bb
|
||||||
|
}
|
||||||
|
b = encodeComma(b)
|
||||||
|
code = code.next
|
||||||
|
case opStructFieldPtrAnonymousHeadMarshalJSONPtr, opStructFieldPtrAnonymousHeadStringTagMarshalJSONPtr:
|
||||||
|
p := load(ctxptr, code.idx)
|
||||||
|
if p == 0 {
|
||||||
|
code = code.end.next
|
||||||
|
break
|
||||||
|
}
|
||||||
|
store(ctxptr, code.idx, ptrToPtr(p))
|
||||||
|
fallthrough
|
||||||
|
case opStructFieldAnonymousHeadMarshalJSONPtr, opStructFieldAnonymousHeadStringTagMarshalJSONPtr:
|
||||||
|
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)
|
||||||
|
} else {
|
||||||
|
bb, err := encodeMarshalJSON(b, ptrToInterface(code, p))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
b = bb
|
||||||
|
}
|
||||||
|
b = encodeComma(b)
|
||||||
|
code = code.next
|
||||||
|
case opStructFieldPtrAnonymousHeadOmitEmptyMarshalJSON:
|
||||||
|
p := load(ctxptr, code.idx)
|
||||||
|
if p == 0 {
|
||||||
|
code = code.end.next
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if code.indirect {
|
||||||
|
store(ctxptr, code.idx, ptrToPtr(p))
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
case opStructFieldAnonymousHeadOmitEmptyMarshalJSON:
|
||||||
|
p := load(ctxptr, code.idx)
|
||||||
|
if p == 0 && code.indirect {
|
||||||
|
code = code.end.next
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if p == 0 || code.nilcheck && code.typ.Kind() == reflect.Ptr && ptrToPtr(p) == 0 {
|
||||||
|
code = code.nextField
|
||||||
|
} else {
|
||||||
b = append(b, code.key...)
|
b = append(b, code.key...)
|
||||||
bb, err := encodeMarshalJSON(b, ptrToInterface(code, p+code.offset))
|
bb, err := encodeMarshalJSON(b, ptrToInterface(code, p+code.offset))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -3378,6 +3463,36 @@ 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
|
||||||
|
}
|
||||||
|
case opStructFieldPtrAnonymousHeadOmitEmptyMarshalJSONPtr:
|
||||||
|
p := load(ctxptr, code.idx)
|
||||||
|
if p == 0 {
|
||||||
|
code = code.end.next
|
||||||
|
break
|
||||||
|
}
|
||||||
|
store(ctxptr, code.idx, ptrToPtr(p))
|
||||||
|
fallthrough
|
||||||
|
case opStructFieldAnonymousHeadOmitEmptyMarshalJSONPtr:
|
||||||
|
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...)
|
||||||
|
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 {
|
||||||
|
@ -3429,52 +3544,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
|
||||||
case opStructFieldPtrAnonymousHeadOmitEmptyMarshalJSON:
|
|
||||||
ptr := load(ctxptr, code.idx)
|
|
||||||
if ptr != 0 {
|
|
||||||
store(ctxptr, code.idx, ptrToPtr(ptr))
|
|
||||||
}
|
|
||||||
fallthrough
|
|
||||||
case opStructFieldAnonymousHeadOmitEmptyMarshalJSON:
|
|
||||||
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
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case opStructFieldPtrHeadOmitEmptyMarshalText:
|
case opStructFieldPtrHeadOmitEmptyMarshalText:
|
||||||
ptr := load(ctxptr, code.idx)
|
ptr := load(ctxptr, code.idx)
|
||||||
if ptr != 0 {
|
if ptr != 0 {
|
||||||
|
|
Loading…
Reference in New Issue