forked from mirror/go-json
Merge pull request #43 from goccy/feature/fix-recursive-call
Fix decoding of recursive structure
This commit is contained in:
commit
0709cb2fa0
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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:
|
||||||
|
|
Loading…
Reference in New Issue