You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

203 lines
4.8 KiB
Go

package stt
import (
"bytes"
"fmt"
"github.com/modern-go/reflect2"
"io"
"strings"
"unsafe"
)
func decoderOfStruct(ctx *ctx, typ reflect2.Type) ValDecoder {
bindings := map[string]*Binding{}
structDescriptor := describeStruct(ctx, typ)
for _, binding := range structDescriptor.Fields {
for _, fromName := range binding.FromNames {
old := bindings[fromName]
if old == nil {
bindings[fromName] = binding
continue
}
ignoreOld, ignoreNew := resolveConflictBinding(ctx.frozenConfig, old, binding)
if ignoreOld {
delete(bindings, fromName)
}
if !ignoreNew {
bindings[fromName] = binding
}
}
}
fields := map[string]*structFieldDecoder{}
for k, binding := range bindings {
fields[k] = binding.Decoder.(*structFieldDecoder)
}
return createStructDecoder(ctx, typ, fields)
}
func createStructDecoder(ctx *ctx, typ reflect2.Type, fields map[string]*structFieldDecoder) ValDecoder {
switch len(fields) {
case 0:
return &skipObjectDecoder{typ}
}
return &generalStructDecoder{typ, fields}
}
type generalStructDecoder struct {
typ reflect2.Type
fields map[string]*structFieldDecoder
}
func (decoder *generalStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
if !iter.incrementDepth() {
return
}
var splitBytes = encryptBytes([]byte{'/'}, iter.depth)
cc := splitBytes
var c byte = '/'
for {
if iter.head >= iter.tail {
break
}
if iter.depth > 1 {
if bytes.Equal(cc, splitBytes) {
nc := iter.nextToken()
iter.unreadByte()
if nc != '/' && nc != '@' {
decoder.decodeOneField(ptr, iter)
cc = cc[:0]
for i, sbLen := 0, len(splitBytes); i < sbLen; i++ {
cc = append(cc, iter.nextToken())
}
} else {
break
}
} else {
cc = cc[:1]
for i, sbLen := 0, len(splitBytes); i < sbLen; i++ {
cc = append(cc, iter.nextToken())
}
continue
}
} else {
if c == '/' {
nc := iter.nextToken()
iter.unreadByte()
if nc != '/' {
decoder.decodeOneField(ptr, iter)
c = iter.nextToken()
} else {
break
}
} else {
c = iter.nextToken()
continue
}
}
}
if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 {
iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error())
}
if c != '/' {
iter.ReportError("struct Decode", `expect /, but found `+string([]byte{c}))
}
iter.decrementDepth()
}
func (decoder *generalStructDecoder) decodeOneField(ptr unsafe.Pointer, iter *Iterator) {
var field string
var fieldDecoder *structFieldDecoder
field = iter.ReadFieldName()
fieldDecoder = decoder.fields[field]
if fieldDecoder == nil && !iter.cfg.caseSensitive {
fieldDecoder = decoder.fields[strings.ToLower(field)]
}
if fieldDecoder == nil {
c := iter.nextToken()
if c != '@' {
iter.ReportError("ReadObject", "expect @ after object field, but found "+string([]byte{c}))
}
iter.skipBytes('=')
iter.Skip()
return
}
c := iter.nextToken()
if c != '@' {
iter.ReportError("ReadObject", "expect @ after object field, but found "+string([]byte{c}))
}
iter.unreadByte()
if iter.depth > 1 {
iter.skipBytes(encryptBytes([]byte("@="), iter.depth)...)
} else {
iter.skipBytes('@', '=')
}
fieldDecoder.Decode(ptr, iter)
}
type skipObjectDecoder struct {
typ reflect2.Type
}
func (decoder *skipObjectDecoder) Decode(_ unsafe.Pointer, iter *Iterator) {
valueType := iter.WhatIsNext()
if valueType != NilValue {
iter.ReportError("skipObjectDecoder", "expect object or null")
return
}
iter.Skip()
}
type structFieldDecoder struct {
field reflect2.StructField
fieldDecoder ValDecoder
}
func (decoder *structFieldDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
fieldPtr := decoder.field.UnsafeGet(ptr)
decoder.fieldDecoder.Decode(fieldPtr, iter)
if iter.Error != nil && iter.Error != io.EOF {
iter.Error = fmt.Errorf("%s: %s", decoder.field.Name(), iter.Error.Error())
}
}
type stringModeStringDecoder struct {
elemDecoder ValDecoder
cfg *frozenConfig
}
func (decoder *stringModeStringDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
decoder.elemDecoder.Decode(ptr, iter)
str := *((*string)(ptr))
tempIter := decoder.cfg.BorrowIterator([]byte(str))
defer decoder.cfg.ReturnIterator(tempIter)
*((*string)(ptr)) = tempIter.ReadString()
}
type stringModeNumberDecoder struct {
elemDecoder ValDecoder
}
func (decoder *stringModeNumberDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
if iter.WhatIsNext() == NilValue {
decoder.elemDecoder.Decode(ptr, iter)
return
}
c := iter.nextToken()
if c != '"' {
iter.ReportError("stringModeNumberDecoder", `expect ", but found `+string([]byte{c}))
return
}
decoder.elemDecoder.Decode(ptr, iter)
if iter.Error != nil {
return
}
c = iter.readByte()
if c != '"' {
iter.ReportError("stringModeNumberDecoder", `expect ", but found `+string([]byte{c}))
return
}
}