Work MarshalJSON test

This commit is contained in:
Masaaki Goshima 2021-03-05 23:57:44 +09:00
parent 734267f9ae
commit 88cd2ddd6e
2 changed files with 52 additions and 94 deletions

View File

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

View File

@ -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...)