Skip to content

Commit 97787fd

Browse files
authored
Merge pull request #39 from goccy/feature/fix-nil-marshaler
Fix nested embedded structure that has same name fields
2 parents 991c8c4 + 7ada1b2 commit 97787fd

File tree

6 files changed

+437
-33
lines changed

6 files changed

+437
-33
lines changed

encode.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,10 @@ func (e *Encoder) encodeForMarshal(v interface{}) ([]byte, error) {
148148
}
149149

150150
func (e *Encoder) encode(v interface{}) error {
151+
if v == nil {
152+
e.encodeNull()
153+
return nil
154+
}
151155
header := (*interfaceHeader)(unsafe.Pointer(&v))
152156
typ := header.typ
153157

encode_compile.go

Lines changed: 159 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,151 @@ func (e *Encoder) structField(fieldCode *structFieldCode, valueCode *opcode, tag
566566
}
567567
return code
568568
}
569+
570+
func (e *Encoder) isNotExistsField(head *structFieldCode) bool {
571+
if head == nil {
572+
return false
573+
}
574+
if head.op != opStructFieldAnonymousHead {
575+
return false
576+
}
577+
if head.next == nil {
578+
return false
579+
}
580+
if head.nextField == nil {
581+
return false
582+
}
583+
if head.nextField.op != opStructAnonymousEnd {
584+
return false
585+
}
586+
if head.next.op == opStructAnonymousEnd {
587+
return true
588+
}
589+
if head.next.op.codeType() != codeStructField {
590+
return false
591+
}
592+
return e.isNotExistsField(head.next.toStructFieldCode())
593+
}
594+
595+
func (e *Encoder) optimizeAnonymousFields(head *structFieldCode) {
596+
code := head
597+
var prev *structFieldCode
598+
for {
599+
if code.op == opStructEnd || code.op == opStructEndIndent {
600+
break
601+
}
602+
if code.op == opStructField || code.op == opStructFieldIndent {
603+
codeType := code.next.op.codeType()
604+
if codeType == codeStructField {
605+
if e.isNotExistsField(code.next.toStructFieldCode()) {
606+
code.next = code.nextField
607+
linkPrevToNextField(prev, code)
608+
code = prev
609+
}
610+
}
611+
}
612+
prev = code
613+
code = code.nextField.toStructFieldCode()
614+
}
615+
}
616+
617+
type structFieldPair struct {
618+
prevField *structFieldCode
619+
curField *structFieldCode
620+
isTaggedKey bool
621+
linked bool
622+
}
623+
624+
func (e *Encoder) anonymousStructFieldPairMap(typ *rtype, tags structTags, valueCode *structFieldCode) map[string][]structFieldPair {
625+
//fmt.Println("type = ", typ, "valueCode = ", valueCode.dump())
626+
anonymousFields := map[string][]structFieldPair{}
627+
f := valueCode
628+
var prevAnonymousField *structFieldCode
629+
for {
630+
existsKey := tags.existsKey(f.displayKey)
631+
op := f.op.headToAnonymousHead()
632+
if op != f.op {
633+
if existsKey {
634+
f.op = opStructFieldAnonymousHead
635+
} else {
636+
f.op = op
637+
}
638+
} else if f.op == opStructEnd {
639+
f.op = opStructAnonymousEnd
640+
} else if existsKey {
641+
linkPrevToNextField(prevAnonymousField, f)
642+
}
643+
644+
if f.displayKey == "" {
645+
if f.nextField == nil {
646+
break
647+
}
648+
prevAnonymousField = f
649+
f = f.nextField.toStructFieldCode()
650+
continue
651+
}
652+
653+
anonymousFields[f.displayKey] = append(anonymousFields[f.displayKey], structFieldPair{
654+
prevField: prevAnonymousField,
655+
curField: f,
656+
isTaggedKey: f.isTaggedKey,
657+
})
658+
if f.next != nil && f.nextField != f.next && f.next.op.codeType() == codeStructField {
659+
for k, v := range e.anonymousStructFieldPairMap(typ, tags, f.next.toStructFieldCode()) {
660+
anonymousFields[k] = append(anonymousFields[k], v...)
661+
}
662+
}
663+
if f.nextField == nil {
664+
break
665+
}
666+
prevAnonymousField = f
667+
f = f.nextField.toStructFieldCode()
668+
}
669+
return anonymousFields
670+
}
671+
672+
func (e *Encoder) optimizeConflictAnonymousFields(anonymousFields map[string][]structFieldPair) {
673+
for _, fieldPairs := range anonymousFields {
674+
if len(fieldPairs) == 1 {
675+
continue
676+
}
677+
// conflict anonymous fields
678+
taggedPairs := []structFieldPair{}
679+
for _, fieldPair := range fieldPairs {
680+
if fieldPair.isTaggedKey {
681+
taggedPairs = append(taggedPairs, fieldPair)
682+
} else {
683+
if !fieldPair.linked {
684+
if fieldPair.prevField == nil {
685+
// head operation
686+
fieldPair.curField.op = opStructFieldAnonymousHead
687+
} else {
688+
linkPrevToNextField(fieldPair.prevField, fieldPair.curField)
689+
}
690+
fieldPair.linked = true
691+
}
692+
}
693+
}
694+
if len(taggedPairs) > 1 {
695+
for _, fieldPair := range taggedPairs {
696+
if !fieldPair.linked {
697+
if fieldPair.prevField == nil {
698+
// head operation
699+
fieldPair.curField.op = opStructFieldAnonymousHead
700+
} else {
701+
linkPrevToNextField(fieldPair.prevField, fieldPair.curField)
702+
}
703+
fieldPair.linked = true
704+
}
705+
}
706+
} else {
707+
for _, fieldPair := range taggedPairs {
708+
fieldPair.curField.isTaggedKey = false
709+
}
710+
}
711+
}
712+
}
713+
569714
func (e *Encoder) compileStruct(typ *rtype, isPtr, root, withIndent bool) (*opcode, error) {
570715
if code := e.compiledCode(typ, withIndent); code != nil {
571716
return code, nil
@@ -588,12 +733,17 @@ func (e *Encoder) compileStruct(typ *rtype, isPtr, root, withIndent bool) (*opco
588733
prevField *structFieldCode
589734
)
590735
e.indent++
736+
tags := structTags{}
737+
anonymousFields := map[string][]structFieldPair{}
591738
for i := 0; i < fieldNum; i++ {
592739
field := typ.Field(i)
593740
if isIgnoredStructField(field) {
594741
continue
595742
}
596-
tag := structTagFromField(field)
743+
tags = append(tags, structTagFromField(field))
744+
}
745+
for i, tag := range tags {
746+
field := tag.field
597747
fieldType := type2rtype(field.Type)
598748
if isPtr && i == 0 {
599749
// head field of pointer structure at top level
@@ -609,16 +759,8 @@ func (e *Encoder) compileStruct(typ *rtype, isPtr, root, withIndent bool) (*opco
609759
return nil, err
610760
}
611761
if field.Anonymous {
612-
f := valueCode.toStructFieldCode()
613-
for {
614-
f.op = f.op.headToAnonymousHead()
615-
if f.op == opStructEnd {
616-
f.op = opStructAnonymousEnd
617-
}
618-
if f.nextField == nil {
619-
break
620-
}
621-
f = f.nextField.toStructFieldCode()
762+
for k, v := range e.anonymousStructFieldPairMap(typ, tags, valueCode.toStructFieldCode()) {
763+
anonymousFields[k] = append(anonymousFields[k], v...)
622764
}
623765
}
624766
if fieldNum == 1 && valueCode.op == opPtr {
@@ -640,6 +782,8 @@ func (e *Encoder) compileStruct(typ *rtype, isPtr, root, withIndent bool) (*opco
640782
},
641783
anonymousKey: field.Anonymous,
642784
key: []byte(key),
785+
isTaggedKey: tag.isTaggedKey,
786+
displayKey: tag.key,
643787
offset: field.Offset,
644788
}
645789
if fieldIdx == 0 {
@@ -690,6 +834,10 @@ func (e *Encoder) compileStruct(typ *rtype, isPtr, root, withIndent bool) (*opco
690834
}
691835
head.end = structEndCode
692836
code.next = structEndCode
837+
838+
e.optimizeConflictAnonymousFields(anonymousFields)
839+
e.optimizeAnonymousFields(head)
840+
693841
ret := (*opcode)(unsafe.Pointer(head))
694842
compiled.code = ret
695843

encode_opcode.go

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,12 @@ func (c *opcode) beforeLastCode() *opcode {
5353
code := c
5454
for {
5555
var nextCode *opcode
56-
switch code.op {
57-
case opArrayElem, opArrayElemIndent:
56+
switch code.op.codeType() {
57+
case codeArrayElem:
5858
nextCode = code.toArrayElemCode().end
59-
case opSliceElem, opSliceElemIndent, opRootSliceElemIndent:
59+
case codeSliceElem:
6060
nextCode = code.toSliceElemCode().end
61-
case opMapKey, opMapKeyIndent, opRootMapKeyIndent:
61+
case codeMapKey:
6262
nextCode = code.toMapKeyCode().end
6363
default:
6464
nextCode = code.next
@@ -112,13 +112,13 @@ func (c *opcode) dump() string {
112112
codes := []string{}
113113
for code := c; code.op != opEnd; {
114114
indent := strings.Repeat(" ", code.indent)
115-
codes = append(codes, fmt.Sprintf("%s%s", indent, code.op))
116-
switch code.op {
117-
case opArrayElem, opArrayElemIndent:
115+
codes = append(codes, fmt.Sprintf("%s%s ( %p )", indent, code.op, unsafe.Pointer(code)))
116+
switch code.op.codeType() {
117+
case codeArrayElem:
118118
code = code.toArrayElemCode().end
119-
case opSliceElem, opSliceElemIndent, opRootSliceElemIndent:
119+
case codeSliceElem:
120120
code = code.toSliceElemCode().end
121-
case opMapKey, opMapKeyIndent, opRootMapKeyIndent:
121+
case codeMapKey:
122122
code = code.toMapKeyCode().end
123123
default:
124124
code = code.next
@@ -305,12 +305,44 @@ func (c *arrayElemCode) copy(codeMap map[uintptr]*opcode) *opcode {
305305
type structFieldCode struct {
306306
*opcodeHeader
307307
key []byte
308+
displayKey string
309+
isTaggedKey bool
308310
offset uintptr
309311
anonymousKey bool
310312
nextField *opcode
311313
end *opcode
312314
}
313315

316+
func linkPrevToNextField(prev, cur *structFieldCode) {
317+
prev.nextField = cur.nextField
318+
code := prev.toOpcode()
319+
fcode := cur.toOpcode()
320+
for {
321+
var nextCode *opcode
322+
switch code.op.codeType() {
323+
case codeArrayElem:
324+
nextCode = code.toArrayElemCode().end
325+
case codeSliceElem:
326+
nextCode = code.toSliceElemCode().end
327+
case codeMapKey:
328+
nextCode = code.toMapKeyCode().end
329+
default:
330+
nextCode = code.next
331+
}
332+
if nextCode == fcode {
333+
code.next = fcode.next
334+
break
335+
} else if nextCode.op == opEnd {
336+
break
337+
}
338+
code = nextCode
339+
}
340+
}
341+
342+
func (c *structFieldCode) toOpcode() *opcode {
343+
return (*opcode)(unsafe.Pointer(c))
344+
}
345+
314346
func (c *structFieldCode) copy(codeMap map[uintptr]*opcode) *opcode {
315347
if c == nil {
316348
return nil
@@ -321,6 +353,8 @@ func (c *structFieldCode) copy(codeMap map[uintptr]*opcode) *opcode {
321353
}
322354
field := &structFieldCode{
323355
key: c.key,
356+
isTaggedKey: c.isTaggedKey,
357+
displayKey: c.displayKey,
324358
anonymousKey: c.anonymousKey,
325359
offset: c.offset,
326360
}

0 commit comments

Comments
 (0)