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 } }