Merge pull request #43 from goccy/feature/fix-recursive-call

Fix decoding of recursive structure
This commit is contained in:
Masaaki Goshima 2020-08-25 19:25:44 +09:00 committed by GitHub
commit 0709cb2fa0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 20 additions and 6 deletions

View File

@ -23,6 +23,7 @@ type decoder interface {
type Decoder struct { type Decoder struct {
s *stream s *stream
disallowUnknownFields bool disallowUnknownFields bool
structTypeToDecoder map[uintptr]decoder
} }
type decoderMap struct { type decoderMap struct {
@ -61,7 +62,9 @@ const (
func NewDecoder(r io.Reader) *Decoder { func NewDecoder(r io.Reader) *Decoder {
s := &stream{r: r} s := &stream{r: r}
s.read() s.read()
return &Decoder{s: s} return &Decoder{
s: s,
}
} }
// Buffered returns a reader of the data remaining in the Decoder's // Buffered returns a reader of the data remaining in the Decoder's
@ -90,7 +93,7 @@ func (d *Decoder) decode(src []byte, header *interfaceHeader) error {
} }
dec := cachedDecoder.get(typeptr) dec := cachedDecoder.get(typeptr)
if dec == nil { if dec == nil {
d.structTypeToDecoder = map[uintptr]decoder{}
compiledDec, err := d.compileHead(copiedType) compiledDec, err := d.compileHead(copiedType)
if err != nil { if err != nil {
return err return err
@ -155,6 +158,7 @@ func (d *Decoder) Decode(v interface{}) error {
dec := cachedDecoder.get(typeptr) dec := cachedDecoder.get(typeptr)
if dec == nil { if dec == nil {
d.structTypeToDecoder = map[uintptr]decoder{}
compiledDec, err := d.compileHead(typ) compiledDec, err := d.compileHead(typ)
if err != nil { if err != nil {
return err return err

View File

@ -204,6 +204,12 @@ func (d *Decoder) compileInterface(typ *rtype) (decoder, error) {
func (d *Decoder) compileStruct(typ *rtype) (decoder, error) { func (d *Decoder) compileStruct(typ *rtype) (decoder, error) {
fieldNum := typ.NumField() fieldNum := typ.NumField()
fieldMap := map[string]*structFieldSet{} fieldMap := map[string]*structFieldSet{}
typeptr := uintptr(unsafe.Pointer(typ))
if dec, exists := d.structTypeToDecoder[typeptr]; exists {
return dec, nil
}
structDec := newStructDecoder(fieldMap)
d.structTypeToDecoder[typeptr] = structDec
for i := 0; i < fieldNum; i++ { for i := 0; i < fieldNum; i++ {
field := typ.Field(i) field := typ.Field(i)
if isIgnoredStructField(field) { if isIgnoredStructField(field) {
@ -222,5 +228,6 @@ func (d *Decoder) compileStruct(typ *rtype) (decoder, error) {
fieldMap[tag.key] = fieldSet fieldMap[tag.key] = fieldSet
fieldMap[strings.ToLower(tag.key)] = fieldSet fieldMap[strings.ToLower(tag.key)] = fieldSet
} }
return newStructDecoder(fieldMap), nil delete(d.structTypeToDecoder, typeptr)
return structDec, nil
} }

View File

@ -74,9 +74,12 @@ func (e *Encoder) run(code *opcode) error {
if ptr == 0 || header.Data == 0 { if ptr == 0 || header.Data == 0 {
e.encodeNull() e.encodeNull()
} else { } else {
s := base64.StdEncoding.EncodeToString(e.ptrToBytes(code.ptr)) b := e.ptrToBytes(code.ptr)
encodedLen := base64.StdEncoding.EncodedLen(len(b))
e.encodeByte('"') e.encodeByte('"')
e.encodeBytes(*(*[]byte)(unsafe.Pointer(&s))) buf := make([]byte, encodedLen)
base64.StdEncoding.Encode(buf, b)
e.encodeBytes(buf)
e.encodeByte('"') e.encodeByte('"')
} }
code = code.next code = code.next
@ -550,7 +553,7 @@ func (e *Encoder) run(code *opcode) error {
e.encodeBytes(field.key) e.encodeBytes(field.key)
} }
code = field.next code = field.next
code.ptr = ptr code.ptr = ptr + field.offset
field.nextField.ptr = ptr field.nextField.ptr = ptr
} }
case opStructFieldAnonymousHead: case opStructFieldAnonymousHead: