2
0
Fork 0
mirror of https://github.com/ii64/sonic.git synced 2026-06-21 17:06:47 +08:00

fix: support dynamic interface indirection

This commit is contained in:
chenzhuoyu 2021-07-06 20:46:31 +08:00 committed by Oxygen
parent 91e58904fe
commit 4937f48f3c
10 changed files with 315 additions and 92 deletions

View file

@ -17,6 +17,7 @@
package decoder
import (
`encoding/json`
`fmt`
`math`
`reflect`
@ -88,8 +89,10 @@ const (
_LB_error = "_error"
_LB_im_error = "_im_error"
_LB_eof_error = "_eof_error"
_LB_type_error = "_type_error"
_LB_field_error = "_field_error"
_LB_range_error = "_range_error"
_LB_stack_error = "_stack_error"
_LB_base64_error = "_base64_error"
_LB_unquote_error = "_unquote_error"
_LB_parsing_error = "_parsing_error"
@ -201,8 +204,10 @@ func (self *_Assembler) compile() {
self.prologue()
self.instrs()
self.epilogue()
self.type_error()
self.field_error()
self.range_error()
self.stack_error()
self.base64_error()
self.parsing_error()
}
@ -211,6 +216,7 @@ func (self *_Assembler) compile() {
var _OpFuncTab = [256]func(*_Assembler, *_Instr) {
_OP_any : (*_Assembler)._asm_OP_any,
_OP_dyn : (*_Assembler)._asm_OP_dyn,
_OP_str : (*_Assembler)._asm_OP_str,
_OP_bin : (*_Assembler)._asm_OP_bin,
_OP_bool : (*_Assembler)._asm_OP_bool,
@ -373,6 +379,7 @@ func (self *_Assembler) call_vf(fn obj.Addr) {
var (
_F_convT64 = jit.Func(convT64)
_F_error_wrap = jit.Func(error_wrap)
_F_error_type = jit.Func(error_type)
_F_error_field = jit.Func(error_field)
_F_error_value = jit.Func(error_value)
)
@ -392,6 +399,20 @@ var (
_I_base64_CorruptInputError = jit.Itab(_T_error, base64CorruptInputError)
)
var (
_V_stackOverflow = jit.Imm(int64(uintptr(unsafe.Pointer(&stackOverflow))))
_I_json_UnsupportedValueError = jit.Itab(_T_error, reflect.TypeOf(new(json.UnsupportedValueError)))
)
func (self *_Assembler) type_error() {
self.Link(_LB_type_error) // _type_error:
self.Emit("MOVQ", _ET, jit.Ptr(_SP, 0)) // MOVQ ET, (SP)
self.call_go(_F_error_type) // CALL_GO error_type
self.Emit("MOVQ", jit.Ptr(_SP, 8), _ET) // MOVQ 8(SP), ET
self.Emit("MOVQ", jit.Ptr(_SP, 16), _EP) // MOVQ 16(SP), EP
self.Sjmp("JMP" , _LB_error) // JMP _error
}
func (self *_Assembler) field_error() {
self.Link(_LB_field_error) // _field_error:
self.Emit("MOVOU", _VAR_sv, _X0) // MOVOU sv, X0
@ -415,6 +436,13 @@ func (self *_Assembler) range_error() {
self.Sjmp("JMP" , _LB_error) // JMP _error
}
func (self *_Assembler) stack_error() {
self.Link(_LB_stack_error) // _stack_error:
self.Emit("MOVQ", _V_stackOverflow, _EP) // MOVQ ${_V_stackOverflow}, EP
self.Emit("MOVQ", _I_json_UnsupportedValueError, _ET) // MOVQ ${_I_json_UnsupportedValueError}, ET
self.Sjmp("JMP" , _LB_error) // JMP _error
}
func (self *_Assembler) base64_error() {
self.Link(_LB_base64_error)
self.Emit("NEGQ", _AX) // NEGQ AX
@ -697,13 +725,13 @@ func (self *_Assembler) mem_clear_fn(ptrfree bool) {
}
func (self *_Assembler) mem_clear_rem(size int64, ptrfree bool) {
self.Emit("MOVQ" , jit.Imm(size), _CX) // MOVQ ${size}, CX
self.Emit("MOVQ" , jit.Ptr(_ST, 0), _AX) // MOVQ (ST), AX
self.Emit("MOVQ" , jit.Sib(_ST, _AX, 1, 0), _AX) // MOVQ (ST)(AX), AX
self.Emit("SUBQ" , _VP, _AX) // SUBQ VP, AX
self.Emit("ADDQ" , _AX, _CX) // ADDQ AX, CX
self.Emit("MOVQ" , _VP, jit.Ptr(_SP, 0)) // MOVQ VP, (SP)
self.Emit("MOVQ" , _CX, jit.Ptr(_SP, 8)) // MOVQ CX, 8(SP)
self.Emit("MOVQ", jit.Imm(size), _CX) // MOVQ ${size}, CX
self.Emit("MOVQ", jit.Ptr(_ST, 0), _AX) // MOVQ (ST), AX
self.Emit("MOVQ", jit.Sib(_ST, _AX, 1, 0), _AX) // MOVQ (ST)(AX), AX
self.Emit("SUBQ", _VP, _AX) // SUBQ VP, AX
self.Emit("ADDQ", _AX, _CX) // ADDQ AX, CX
self.Emit("MOVQ", _VP, jit.Ptr(_SP, 0)) // MOVQ VP, (SP)
self.Emit("MOVQ", _CX, jit.Ptr(_SP, 8)) // MOVQ CX, 8(SP)
self.mem_clear_fn(ptrfree) // CALL_GO memclr{Has,NoHeap}Pointers
}
@ -859,6 +887,33 @@ func (self *_Assembler) unmarshal_func(t reflect.Type, fn obj.Addr, deref bool)
self.Sjmp("JNZ" , _LB_error) // JNZ _error
}
/** Dynamic Decoding Routine **/
var (
_F_decodeTypedPointer obj.Addr
)
func init() {
_F_decodeTypedPointer = jit.Func(decodeTypedPointer)
}
func (self *_Assembler) decode_dynamic(vt obj.Addr, vp obj.Addr) {
self.Emit("MOVQ" , _ARG_fv, _CX) // MOVQ fv, CX
self.Emit("MOVOU", _ARG_sp, _X0) // MOVOU sp, X0
self.Emit("MOVOU", _X0, jit.Ptr(_SP, 0)) // MOVOU X0, (SP)
self.Emit("MOVQ" , _IC, jit.Ptr(_SP, 16)) // MOVQ IC, 16(SP)
self.Emit("MOVQ" , vt, jit.Ptr(_SP, 24)) // MOVQ ${vt}, 24(SP)
self.Emit("MOVQ" , vp, jit.Ptr(_SP, 32)) // MOVQ ${vp}, 32(SP)
self.Emit("MOVQ" , _ST, jit.Ptr(_SP, 40)) // MOVQ ST, 40(SP)
self.Emit("MOVQ" , _CX, jit.Ptr(_SP, 48)) // MOVQ CX, 48(SP)
self.call_go(_F_decodeTypedPointer) // CALL_GO decodeTypedPointer
self.Emit("MOVQ" , jit.Ptr(_SP, 64), _ET) // MOVQ 64(SP), ET
self.Emit("MOVQ" , jit.Ptr(_SP, 72), _EP) // MOVQ 72(SP), EP
self.Emit("TESTQ", _ET, _ET) // TESTQ ET, ET
self.Sjmp("JNZ" , _LB_error) // JNZ _error
self.Emit("MOVQ" , jit.Ptr(_SP, 56), _IC) // MOVQ 56(SP), IC
}
/** OpCode Assembler Functions **/
var (
@ -885,7 +940,6 @@ var (
)
var (
_F_decodeTypedPointer obj.Addr
_F_FieldMap_GetCaseInsensitive obj.Addr
)
@ -895,16 +949,50 @@ const (
_Fe_Hash = int64(unsafe.Offsetof(caching.FieldEntry{}.Hash))
)
const (
_Vk_Ptr = int64(reflect.Ptr)
_Gt_KindFlags = int64(unsafe.Offsetof(rt.GoType{}.KindFlags))
)
func init() {
_F_decodeTypedPointer = jit.Func(decodeTypedPointer)
_F_FieldMap_GetCaseInsensitive = jit.Func((*caching.FieldMap).GetCaseInsensitive)
}
func (self *_Assembler) _asm_OP_any(_ *_Instr) {
self.Emit("MOVQ" , _ARG_fv, _DF) // MOVQ fv, DF
self.call(_F_decodeValue) // CALL decodeValue
self.Emit("TESTQ", _EP, _EP) // TESTQ EP, EP
self.Sjmp("JNZ" , _LB_parsing_error) // JNZ _parsing_error
self.Emit("MOVQ" , jit.Ptr(_VP, 8), _CX) // MOVQ 8(VP), CX
self.Emit("TESTQ" , _CX, _CX) // TESTQ CX, CX
self.Sjmp("JZ" , "_decode_{n}") // JZ _decode_{n}
self.Emit("CMPQ" , _CX, _VP) // CMPQ CX, VP
self.Sjmp("JE" , "_decode_{n}") // JE _decode_{n}
self.Emit("MOVQ" , jit.Ptr(_VP, 0), _AX) // MOVQ (VP), AX
self.Emit("MOVBLZX", jit.Ptr(_AX, _Gt_KindFlags), _DX) // MOVBLZX _Gt_KindFlags(AX), DX
self.Emit("ANDL" , jit.Imm(rt.F_kind_mask), _DX) // ANDL ${F_kind_mask}, DX
self.Emit("CMPL" , _DX, jit.Imm(_Vk_Ptr)) // CMPL DX, ${reflect.Ptr}
self.Sjmp("JNE" , "_decode_{n}") // JNE _decode_{n}
self.Emit("LEAQ" , jit.Ptr(_VP, 8), _DI) // LEAQ 8(VP), DI
self.decode_dynamic(_AX, _DI) // DECODE AX, DI
self.Sjmp("JMP" , "_decode_end_{n}") // JMP _decode_end_{n}
self.Link("_decode_{n}") // _decode_{n}:
self.Emit("MOVQ" , _ARG_fv, _DF) // MOVQ fv, DF
self.call(_F_decodeValue) // CALL decodeValue
self.Emit("TESTQ" , _EP, _EP) // TESTQ EP, EP
self.Sjmp("JNZ" , _LB_parsing_error) // JNZ _parsing_error
self.Link("_decode_end_{n}") // _decode_end_{n}:
}
func (self *_Assembler) _asm_OP_dyn(p *_Instr) {
self.Emit("MOVQ" , jit.Type(p.vt()), _ET) // MOVQ ${p.vt()}, ET
self.Emit("CMPQ" , jit.Ptr(_VP, 8), jit.Imm(0)) // CMPQ 8(VP), $0
self.Sjmp("JE" , _LB_type_error) // JE _type_error
self.Emit("MOVQ" , jit.Ptr(_VP, 0), _AX) // MOVQ (VP), AX
self.Emit("MOVQ" , jit.Ptr(_AX, 8), _AX) // MOVQ 8(AX), AX
self.Emit("MOVBLZX", jit.Ptr(_AX, _Gt_KindFlags), _DX) // MOVBLZX _Gt_KindFlags(AX), DX
self.Emit("ANDL" , jit.Imm(rt.F_kind_mask), _DX) // ANDL ${F_kind_mask}, DX
self.Emit("CMPL" , _DX, jit.Imm(_Vk_Ptr)) // CMPL DX, ${reflect.Ptr}
self.Sjmp("JNE" , _LB_type_error) // JNE _type_error
self.Emit("LEAQ" , jit.Ptr(_VP, 8), _DI) // LEAQ 8(VP), DI
self.decode_dynamic(_AX, _DI) // DECODE AX, DI
self.Link("_decode_end_{n}") // _decode_end_{n}:
}
func (self *_Assembler) _asm_OP_str(_ *_Instr) {
@ -1374,6 +1462,8 @@ func (self *_Assembler) _asm_OP_load(_ *_Instr) {
func (self *_Assembler) _asm_OP_save(_ *_Instr) {
self.Emit("MOVQ", jit.Ptr(_ST, 0), _AX) // MOVQ (ST), AX
self.Emit("CMPQ", _AX, jit.Imm(_MaxStack)) // CMPQ AX, ${_MaxStack}
self.Sjmp("JA" , _LB_stack_error) // JA _stack_error
self.Emit("MOVQ", _VP, jit.Sib(_ST, _AX, 1, 8)) // MOVQ VP, 8(ST)(AX)
self.Emit("ADDQ", jit.Imm(8), _AX) // ADDQ $8, AX
self.Emit("MOVQ", _AX, jit.Ptr(_ST, 0)) // MOVQ AX, (ST)
@ -1398,21 +1488,8 @@ func (self *_Assembler) _asm_OP_drop_2(_ *_Instr) {
}
func (self *_Assembler) _asm_OP_recurse(p *_Instr) {
self.Emit("MOVQ" , jit.Type(p.vt()), _AX) // MOVQ ${p.vt()}, AX
self.Emit("MOVQ" , _ARG_fv, _CX) // MOVQ fv, cx
self.Emit("MOVOU", _ARG_sp, _X0) // MOVOU sp, X0
self.Emit("MOVOU", _X0, jit.Ptr(_SP, 0)) // MOVOU X0, (SP)
self.Emit("MOVQ" , _IC, jit.Ptr(_SP, 16)) // MOVQ IC, 16(SP)
self.Emit("MOVQ" , _AX, jit.Ptr(_SP, 24)) // MOVQ AX, 24(SP)
self.Emit("MOVQ" , _VP, jit.Ptr(_SP, 32)) // MOVQ VP, 32(SP)
self.Emit("MOVQ" , _ST, jit.Ptr(_SP, 40)) // MOVQ ST, 40(SP)
self.Emit("MOVQ" , _CX, jit.Ptr(_SP, 48)) // MOVQ CX, 48(SP)
self.call_go(_F_decodeTypedPointer) // CALL_GO decodeTypedPointer
self.Emit("MOVQ" , jit.Ptr(_SP, 64), _ET) // MOVQ 64(SP), ET
self.Emit("MOVQ" , jit.Ptr(_SP, 72), _EP) // MOVQ 72(SP), EP
self.Emit("TESTQ", _ET, _ET) // TESTQ ET, ET
self.Sjmp("JNZ" , _LB_error) // JNZ _error
self.Emit("MOVQ" , jit.Ptr(_SP, 56), _IC) // MOVQ 56(SP), IC
self.Emit("MOVQ", jit.Type(p.vt()), _AX) // MOVQ ${p.vt()}, AX
self.decode_dynamic(_AX, _VP) // DECODE AX, VP
}
func (self *_Assembler) _asm_OP_goto(p *_Instr) {

View file

@ -17,6 +17,7 @@
package decoder
import (
`encoding/json`
`fmt`
`reflect`
`sort`
@ -33,6 +34,7 @@ type _Op uint8
const (
_OP_any _Op = iota + 1
_OP_dyn
_OP_str
_OP_bin
_OP_bool
@ -104,6 +106,7 @@ const (
var _OpNames = [256]string {
_OP_any : "any",
_OP_dyn : "dyn",
_OP_str : "str",
_OP_bin : "bin",
_OP_bool : "bool",
@ -295,7 +298,7 @@ func (self _Instr) i64() int64 {
}
func (self _Instr) vlen() int {
return (*rt.GoType)(self.p).Size()
return int((*rt.GoType)(self.p).Size)
}
func (self _Instr) isBranch() bool {
@ -310,6 +313,7 @@ func (self _Instr) isBranch() bool {
func (self _Instr) disassemble() string {
switch self.op() {
case _OP_dyn : fallthrough
case _OP_deref : fallthrough
case _OP_map_key_i8 : fallthrough
case _OP_map_key_i16 : fallthrough
@ -573,7 +577,7 @@ func (self *_Compiler) compileOps(p *_Program, sp int, vt reflect.Type) {
case reflect.Ptr : self.compilePtr (p, sp, vt)
case reflect.Slice : self.compileSlice (p, sp, vt.Elem())
case reflect.Struct : self.compileStruct (p, sp, vt)
default : panic (error_type(vt))
default : panic (&json.UnmarshalTypeError{Type: vt})
}
}
@ -603,7 +607,7 @@ func (self *_Compiler) compileMapUt(p *_Program, sp int, vt reflect.Type) {
case reflect.Float32 : self.compileMapOp(p, sp, vt, _OP_map_key_f32)
case reflect.Float64 : self.compileMapOp(p, sp, vt, _OP_map_key_f64)
case reflect.String : self.compileMapOp(p, sp, vt, _OP_map_key_str)
default : panic(error_type(vt))
default : panic(&json.UnmarshalTypeError{Type: vt})
}
}
@ -708,7 +712,7 @@ func (self *_Compiler) compileArray(p *_Program, sp int, vt reflect.Type) {
p.rel(v)
/* check for pointer data */
if rt.UnpackType(vt.Elem()).NoPtr() {
if rt.UnpackType(vt.Elem()).PtrData == 0 {
p.int(_OP_array_clear, int(vt.Size()))
} else {
p.int(_OP_array_clear_p, int(vt.Size()))
@ -991,16 +995,16 @@ func (self *_Compiler) compileStructFieldStr(p *_Program, sp int, vt reflect.Typ
func (self *_Compiler) compileInterface(p *_Program, vt reflect.Type) {
i := p.pc()
n := vt.NumMethod()
p.add(_OP_is_null)
/* only empty interface is acceptable */
if n != 0 {
panic(error_type(vt))
/* check for empty interface */
if vt.NumMethod() == 0 {
p.add(_OP_any)
} else {
p.rtt(_OP_dyn, vt)
}
/* check for nil, and compile the interface */
p.add(_OP_is_null)
p.add(_OP_any)
/* finish the OpCode */
j := p.pc()
p.add(_OP_goto)
p.pin(i)
@ -1034,30 +1038,33 @@ func (self *_Compiler) compileUnmarshalEnd(p *_Program, vt reflect.Type, i int)
func (self *_Compiler) compileUnmarshalJson(p *_Program, vt reflect.Type) {
i := p.pc()
v := _OP_unmarshal
p.add(_OP_is_null)
/* must not be an interface */
/* check for dynamic interface */
if vt.Kind() == reflect.Interface {
panic(error_type(vt))
v = _OP_dyn
}
/* call the unmarshaler */
p.rtt(_OP_unmarshal, vt)
p.rtt(v, vt)
self.compileUnmarshalEnd(p, vt, i)
}
func (self *_Compiler) compileUnmarshalText(p *_Program, vt reflect.Type) {
i := p.pc()
v := _OP_unmarshal_text
p.add(_OP_is_null)
p.chr(_OP_match_char, '"')
/* must not be an interface */
/* check for dynamic interface */
if vt.Kind() == reflect.Interface {
panic(error_type(vt))
v = _OP_dyn
} else {
p.chr(_OP_match_char, '"')
}
/* call the unmarshaler */
p.rtt(_OP_unmarshal_text, vt)
p.rtt(v, vt)
self.compileUnmarshalEnd(p, vt, i)
}

View file

@ -25,6 +25,7 @@ import (
`strings`
`github.com/bytedance/sonic/internal/native/types`
`github.com/bytedance/sonic/internal/rt`
)
type SyntaxError struct {
@ -86,6 +87,14 @@ func clamp_zero(v int) int {
}
}
/** JIT Error Helpers **/
var stackOverflow = &json.UnsupportedValueError {
Str : "Value nesting too deep",
Value : reflect.ValueOf("..."),
}
//go:nosplit
func error_wrap(src string, pos int, code types.ParsingError) error {
return SyntaxError {
Pos : pos,
@ -94,10 +103,12 @@ func error_wrap(src string, pos int, code types.ParsingError) error {
}
}
func error_type(vtype reflect.Type) error {
return &json.UnmarshalTypeError{Type: vtype}
//go:nosplit
func error_type(vt *rt.GoType) error {
return &json.UnmarshalTypeError{Type: vt.Pack()}
}
//go:nosplit
func error_field(name string) error {
return errors.New("json: unknown field " + strconv.Quote(name))
}

View file

@ -239,7 +239,7 @@ func (self _Instr) i64() int64 {
}
func (self _Instr) vlen() int {
return (*rt.GoType)(self.p).Size()
return int((*rt.GoType)(self.p).Size)
}
func (self _Instr) isBranch() bool {

View file

@ -71,7 +71,7 @@ func encodeTypedPointer(buf *[]byte, vt *rt.GoType, vp *unsafe.Pointer, sb *_Sta
return encodeNil(buf)
} else if fn, err := findOrCompile(vt); err != nil {
return err
} else if vt.Indir() {
} else if (vt.KindFlags & rt.F_direct) == 0 {
return fn(buf, *vp, sb)
} else {
return fn(buf, unsafe.Pointer(vp), sb)
@ -95,7 +95,7 @@ func encodeTextMarshaler(buf *[]byte, val encoding.TextMarshaler) error {
}
func isZeroSafe(p unsafe.Pointer, vt *rt.GoType) bool {
if native.Lzero(p, vt.Size()) == 0 {
if native.Lzero(p, int(vt.Size)) == 0 {
return true
} else {
return isZeroTyped(p, vt)

View file

@ -29,34 +29,34 @@ var _subr__b64encode uintptr
//go:noescape
//go:linkname memmove runtime.memmove
//goland:noinspection ALL
//goland:noinspection GoUnusedParameter
func memmove(to unsafe.Pointer, from unsafe.Pointer, n uintptr)
//go:linkname newobject runtime.newobject
//goland:noinspection ALL
//goland:noinspection GoUnusedParameter
func newobject(typ *rt.GoType) unsafe.Pointer
//go:linkname growslice runtime.growslice
//goland:noinspection ALL
//goland:noinspection GoUnusedParameter
func growslice(et *rt.GoType, old rt.GoSlice, cap int) rt.GoSlice
//go:linkname assertI2I runtime.assertI2I
//goland:noinspection ALL
//goland:noinspection GoUnusedParameter
func assertI2I(inter *rt.GoType, i rt.GoIface) rt.GoIface
//go:linkname mapiternext runtime.mapiternext
//goland:noinspection ALL
//goland:noinspection GoUnusedParameter
func mapiternext(it unsafe.Pointer)
//go:linkname mapiterinit runtime.mapiterinit
//goland:noinspection ALL
//goland:noinspection GoUnusedParameter
func mapiterinit(t *rt.GoType, m unsafe.Pointer, it *rt.GoMapIterator)
//go:linkname isValidNumber encoding/json.isValidNumber
//goland:noinspection ALL
//goland:noinspection GoUnusedParameter
func isValidNumber(s string) bool
//go:noescape
//go:linkname memclrNoHeapPointers runtime.memclrNoHeapPointers
//goland:noinspection ALL
//goland:noinspection GoUnusedParameter
func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr)

View file

@ -52,7 +52,7 @@ func newProgramMap() *_ProgramMap {
func (self *_ProgramMap) get(vt *rt.GoType) interface{} {
i := self.m + 1
p := vt.Hash() & self.m
p := vt.Hash & self.m
/* linear probing */
for ; i > 0; i-- {
@ -99,7 +99,7 @@ func (self *_ProgramMap) rehash() *_ProgramMap {
}
func (self *_ProgramMap) insert(vt *rt.GoType, fn interface{}) {
h := vt.Hash()
h := vt.Hash
p := h & self.m
/* linear probing */

View file

@ -21,37 +21,31 @@ import (
`unsafe`
)
var reflectRtypeItab = findReflectRtypeItab()
var (
reflectRtypeItab = findReflectRtypeItab()
)
const (
_KindMask = (1 << 5) - 1
_DirectIface = 1 << 5
F_direct = 1 << 5
F_kind_mask = (1 << 5) - 1
)
type GoType struct {
nb uintptr
ptrd uintptr
hash uint32
tflags uint8
align uint8
falign uint8
kflags uint8
traits unsafe.Pointer
gcdata *byte
str int32
p int32
}
func (self *GoType) Size() int {
return int(self.nb)
}
func (self *GoType) Hash() uint32 {
return self.hash
Size uintptr
PtrData uintptr
Hash uint32
Flags uint8
Align uint8
FieldAlign uint8
KindFlags uint8
Traits unsafe.Pointer
GCData *byte
Str int32
PtrToSelf int32
}
func (self *GoType) Kind() reflect.Kind {
return reflect.Kind(self.kflags & _KindMask)
return reflect.Kind(self.KindFlags & F_kind_mask)
}
func (self *GoType) Pack() (t reflect.Type) {
@ -60,14 +54,6 @@ func (self *GoType) Pack() (t reflect.Type) {
return
}
func (self *GoType) NoPtr() bool {
return self.ptrd == 0
}
func (self *GoType) Indir() bool {
return (self.kflags & _DirectIface) == 0
}
func (self *GoType) String() string {
return self.Pack().String()
}

111
issue39_test.go Normal file
View file

@ -0,0 +1,111 @@
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sonic
import (
`testing`
`github.com/bytedance/sonic/decoder`
`github.com/stretchr/testify/require`
)
type normalIfaceIssue39 interface {
Foo()
}
type normalWrapIssue39 struct {
F normalIfaceIssue39
}
type normalImplIssue39 struct {
X int
}
func (_ *normalImplIssue39) Foo() {}
type jsonIfaceIssue39 interface {
UnmarshalJSON(b []byte) error
}
type jsonWrapIssue39 struct {
F jsonIfaceIssue39
}
type jsonImplIssue39 struct {
a string
}
func (self *jsonImplIssue39) UnmarshalJSON(b []byte) error{
self.a = string(b)
return nil
}
type textIfaceIssue39 interface {
UnmarshalText(b []byte) error
}
type textWrapIssue39 struct {
F textIfaceIssue39
}
type textImplIssue39 struct {
a string
}
func (self *textImplIssue39) UnmarshalText(b []byte) error{
self.a = string(b)
return nil
}
func TestIssue39_Iface(t *testing.T) {
p := new(normalImplIssue39)
obj := normalWrapIssue39{F: p}
err := Unmarshal([]byte(`{"F":{"X":123}}`), &obj)
if err != nil {
if v, ok := err.(decoder.SyntaxError); ok {
println(v.Description())
}
require.NoError(t, err)
}
require.Equal(t, 123, p.X)
}
func TestIssue39_UnmarshalJSON(t *testing.T) {
p := &jsonImplIssue39{}
obj := jsonWrapIssue39{F: p}
err := Unmarshal([]byte(`{"F":"xx"}`), &obj)
if err != nil {
if v, ok := err.(decoder.SyntaxError); ok {
println(v.Description())
}
require.NoError(t, err)
}
require.Equal(t, `"xx"`, p.a)
}
func TestIssue39_UnmarshalText(t *testing.T) {
p := &textImplIssue39{}
obj := textWrapIssue39{F: p}
err := Unmarshal([]byte(`{"F":"xx"}`), &obj)
if err != nil {
if v, ok := err.(decoder.SyntaxError); ok {
println(v.Description())
}
require.NoError(t, err)
}
require.Equal(t, `xx`, p.a)
}

31
issue5_test.go Normal file
View file

@ -0,0 +1,31 @@
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sonic
import (
`testing`
`github.com/stretchr/testify/require`
)
func TestIssue5(t *testing.T) {
var x int
var i interface{} = &x
err := Unmarshal([]byte(`1`), &i)
require.NoError(t, err)
require.Equal(t, 1, x)
}