Fix decoding of interface type

This commit is contained in:
Masaaki Goshima 2021-01-22 13:28:03 +09:00
parent 020aaffd4c
commit ccf319b2b0
1 changed files with 46 additions and 0 deletions

View File

@ -1,6 +1,7 @@
package json package json
import ( import (
"encoding"
"reflect" "reflect"
"unsafe" "unsafe"
) )
@ -39,11 +40,56 @@ var (
) )
) )
func decodeWithUnmarshaler(s *stream, unmarshaler Unmarshaler) error {
start := s.cursor
if err := s.skipValue(); err != nil {
return err
}
src := s.buf[start:s.cursor]
dst := make([]byte, len(src))
copy(dst, src)
if err := unmarshaler.UnmarshalJSON(dst); err != nil {
return err
}
return nil
}
func decodeWithTextUnmarshaler(s *stream, unmarshaler encoding.TextUnmarshaler) error {
start := s.cursor
if err := s.skipValue(); err != nil {
return err
}
src := s.buf[start:s.cursor]
dst := make([]byte, len(src))
copy(dst, src)
if err := unmarshaler.UnmarshalText(dst); err != nil {
return err
}
return nil
}
func (d *interfaceDecoder) decodeStream(s *stream, p unsafe.Pointer) error { func (d *interfaceDecoder) decodeStream(s *stream, p unsafe.Pointer) error {
s.skipWhiteSpace() s.skipWhiteSpace()
for { for {
switch s.char() { switch s.char() {
case '{': case '{':
runtimeInterfaceValue := *(*interface{})(unsafe.Pointer(&interfaceHeader{
typ: d.typ,
ptr: p,
}))
rv := reflect.ValueOf(runtimeInterfaceValue)
if rv.NumMethod() > 0 && rv.CanInterface() {
if u, ok := rv.Interface().(Unmarshaler); ok {
return decodeWithUnmarshaler(s, u)
}
if u, ok := rv.Interface().(encoding.TextUnmarshaler); ok {
return decodeWithTextUnmarshaler(s, u)
}
return nil
}
// empty interface
var v map[string]interface{} var v map[string]interface{}
ptr := unsafe.Pointer(&v) ptr := unsafe.Pointer(&v)
if err := newMapDecoder( if err := newMapDecoder(