Skip to content

Commit

Permalink
Merge pull request #94 from goccy/feature/fix-issue93
Browse files Browse the repository at this point in the history
Fix some bugs of encoder/decoder ( for #93 )
  • Loading branch information
goccy committed Jan 22, 2021
2 parents 020aaff + 3682ec0 commit d4b5171
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 1 deletion.
46 changes: 46 additions & 0 deletions decode_interface.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package json

import (
"encoding"
"reflect"
"unsafe"
)
Expand Down Expand Up @@ -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 {
s.skipWhiteSpace()
for {
switch s.char() {
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{}
ptr := unsafe.Pointer(&v)
if err := newMapDecoder(
Expand Down
5 changes: 4 additions & 1 deletion decode_unmarshal_json.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,14 @@ func (d *unmarshalJSONDecoder) decode(buf []byte, cursor int64, p unsafe.Pointer
return 0, err
}
src := buf[start:end]
dst := make([]byte, len(src))
copy(dst, src)

v := *(*interface{})(unsafe.Pointer(&interfaceHeader{
typ: d.typ,
ptr: p,
}))
if err := v.(Unmarshaler).UnmarshalJSON(src); err != nil {
if err := v.(Unmarshaler).UnmarshalJSON(dst); err != nil {
d.annotateError(cursor, err)
return 0, err
}
Expand Down
6 changes: 6 additions & 0 deletions encode_vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,12 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, code *opcode) ([]byte
code = code.next
case opMarshalJSON:
ptr := load(ctxptr, code.idx)
if ptr == 0 {
b = encodeNull(b)
b = encodeComma(b)
code = code.next
break
}
v := e.ptrToInterface(code, ptr)
bb, err := v.(Marshaler).MarshalJSON()
if err != nil {
Expand Down
6 changes: 6 additions & 0 deletions encode_vm_escaped.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,12 @@ func (e *Encoder) runEscaped(ctx *encodeRuntimeContext, b []byte, code *opcode)
code = code.next
case opMarshalJSON:
ptr := load(ctxptr, code.idx)
if ptr == 0 {
b = encodeNull(b)
b = encodeComma(b)
code = code.next
break
}
v := e.ptrToInterface(code, ptr)
bb, err := v.(Marshaler).MarshalJSON()
if err != nil {
Expand Down
6 changes: 6 additions & 0 deletions encode_vm_escaped_indent.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,12 @@ func (e *Encoder) runEscapedIndent(ctx *encodeRuntimeContext, b []byte, code *op
code = code.next
case opMarshalJSON:
ptr := load(ctxptr, code.idx)
if ptr == 0 {
b = encodeNull(b)
b = encodeIndentComma(b)
code = code.next
break
}
v := e.ptrToInterface(code, ptr)
bb, err := v.(Marshaler).MarshalJSON()
if err != nil {
Expand Down
6 changes: 6 additions & 0 deletions encode_vm_indent.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,12 @@ func (e *Encoder) runIndent(ctx *encodeRuntimeContext, b []byte, code *opcode) (
code = code.next
case opMarshalJSON:
ptr := load(ctxptr, code.idx)
if ptr == 0 {
b = encodeNull(b)
b = encodeIndentComma(b)
code = code.next
break
}
v := e.ptrToInterface(code, ptr)
bb, err := v.(Marshaler).MarshalJSON()
if err != nil {
Expand Down

0 comments on commit d4b5171

Please sign in to comment.