Add test case for MarshalJSON type

This commit is contained in:
Masaaki Goshima 2021-03-05 18:40:09 +09:00
parent 249c4da6dd
commit 734267f9ae
3 changed files with 2746 additions and 1366 deletions

File diff suppressed because it is too large Load Diff

View File

@ -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
} }

View File

@ -3222,7 +3222,9 @@ func encodeRun(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt Enco
code = code.end.next code = code.end.next
break break
} }
store(ctxptr, code.idx, ptrToPtr(p)) if code.indirect {
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
} }
store(ctxptr, code.idx, ptrToPtr(p)) if code.indirect {
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
} }
store(ctxptr, code.idx, ptrToPtr(p)) if code.indirect {
store(ctxptr, code.idx, ptrToPtr(p))
}
fallthrough fallthrough
case opStructFieldAnonymousHeadMarshalJSON: case opStructFieldAnonymousHeadMarshalJSON:
p := load(ctxptr, code.idx) p := load(ctxptr, code.idx)
@ -3371,13 +3396,103 @@ func encodeRun(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt Enco
break break
} }
b = append(b, code.key...) b = append(b, code.key...)
bb, err := encodeMarshalJSON(b, ptrToInterface(code, p+code.offset)) if p == 0 || code.nilcheck && code.typ.Kind() == reflect.Ptr && ptrToPtr(p) == 0 {
if err != nil { b = encodeNull(b)
return nil, err } else {
bb, err := encodeMarshalJSON(b, ptrToInterface(code, p+code.offset))
if err != nil {
return nil, err
}
b = bb
} }
b = bb
b = encodeComma(b) b = encodeComma(b)
code = code.next 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...)
bb, err := encodeMarshalJSON(b, ptrToInterface(code, p+code.offset))
if err != nil {
return nil, err
}
b = bb
b = encodeComma(b)
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 {