github.com/zerosnake0/jzon@v0.0.9-0.20230801092939-1b135cb83f7f/val_decoder_native_struct.go (about) 1 package jzon 2 3 import ( 4 "unsafe" 5 ) 6 7 type structDecoderBuilder struct { 8 decoder *structDecoder 9 fields structFields 10 } 11 12 func newStructDecoder(fields structFields) *structDecoderBuilder { 13 return &structDecoderBuilder{ 14 decoder: &structDecoder{}, 15 fields: fields, 16 } 17 } 18 19 func (builder *structDecoderBuilder) build(cache decoderCache) { 20 builder.decoder.fields.init(len(builder.fields)) 21 for i := range builder.fields { 22 fi := &builder.fields[i] 23 fiPtrRType := rtypeOfType(fi.ptrType) 24 builder.decoder.fields.add(fi, cache[fiPtrRType]) 25 } 26 } 27 28 type decoderFieldInfo struct { 29 offsets []offset 30 nameBytes []byte // []byte(name) 31 equalFold func(s, t []byte) bool // bytes.EqualFold or equivalent 32 quoted bool 33 decoder ValDecoder 34 } 35 36 func (dfi *decoderFieldInfo) initFrom(f *field) { 37 dfi.offsets = f.offsets 38 dfi.nameBytes = f.nameBytes 39 dfi.equalFold = f.equalFold 40 dfi.quoted = f.quoted 41 } 42 43 type decoderFields struct { 44 list []decoderFieldInfo 45 nameIndex map[string]int 46 nameIndexUpper map[string]int 47 } 48 49 func (df *decoderFields) init(size int) { 50 df.list = make([]decoderFieldInfo, 0, size) 51 df.nameIndex = make(map[string]int, size) 52 df.nameIndexUpper = make(map[string]int, size) 53 } 54 55 func (df *decoderFields) add(f *field, dec ValDecoder) { 56 df.nameIndex[f.name] = len(df.list) 57 nameUpper := string(f.nameBytesUpper) 58 if _, ok := df.nameIndexUpper[nameUpper]; !ok { 59 df.nameIndexUpper[nameUpper] = len(df.list) 60 } 61 var dfi decoderFieldInfo 62 dfi.initFrom(f) 63 dfi.decoder = dec 64 df.list = append(df.list, dfi) 65 } 66 67 // key and buf 68 func (df *decoderFields) find(key, buf []byte, caseSensitive bool) (*decoderFieldInfo, []byte) { 69 if i, ok := df.nameIndex[localByteToString(key)]; ok { 70 return &df.list[i], buf 71 } 72 if caseSensitive { 73 return nil, buf 74 } 75 l := len(buf) 76 // TODO: compare performance 77 if true { 78 // use the same buffer 79 upper := toUpper(key, buf) 80 i, ok := df.nameIndexUpper[localByteToString(upper[l:])] 81 if ok { 82 return &df.list[i], upper 83 } 84 return nil, upper 85 } 86 for i := range df.list { 87 ff := &df.list[i] 88 if ff.equalFold(ff.nameBytes, key) { 89 return ff, buf 90 } 91 } 92 return nil, buf 93 } 94 95 type structDecoder struct { 96 fields decoderFields 97 } 98 99 func (dec *structDecoder) Decode(ptr unsafe.Pointer, it *Iterator, _ *DecOpts) (err error) { 100 c, err := it.nextToken() 101 if err != nil { 102 return err 103 } 104 if c == 'n' { 105 it.head++ 106 err = it.expectBytes("ull") 107 return 108 } 109 if c != '{' { 110 return UnexpectedByteError{got: c, exp2: 'n', exp: '{'} 111 } 112 it.head++ 113 c, err = it.nextToken() 114 if err != nil { 115 return 116 } 117 if c == '}' { 118 it.head++ 119 return 120 } 121 if c != '"' { 122 return UnexpectedByteError{got: c, exp: '}', exp2: '"'} 123 } 124 it.head++ 125 for { 126 field, err := it.readObjectFieldAsSlice() 127 if err != nil { 128 return err 129 } 130 stField, fieldOut := dec.fields.find(field, field, it.cfg.caseSensitive) 131 it.tmpBuffer = fieldOut 132 if stField != nil { 133 curPtr := add(ptr, stField.offsets[0].val, "struct field") 134 for _, offset := range stField.offsets[1:] { 135 subPtr := *(*unsafe.Pointer)(curPtr) 136 if subPtr == nil { 137 if offset.rtype == 0 { // the ptr field is not exported 138 return ErrNilEmbeddedPointer 139 } 140 subPtr = unsafe_New(offset.rtype) 141 *(*unsafe.Pointer)(curPtr) = subPtr 142 } 143 curPtr = add(subPtr, offset.val, "struct field") 144 } 145 opt := DecOpts{ 146 Quoted: stField.quoted, 147 } 148 if err = stField.decoder.Decode(curPtr, it, opt.noescape()); err != nil { 149 return err 150 } 151 } else { 152 if it.disallowUnknownFields { 153 return UnknownFieldError(field) 154 } 155 if err = it.Skip(); err != nil { 156 return err 157 } 158 } 159 c, err = it.nextToken() 160 if err != nil { 161 return err 162 } 163 switch c { 164 case '}': 165 it.head++ 166 return nil 167 case ',': 168 it.head++ 169 c, err = it.nextToken() 170 if err != nil { 171 return err 172 } 173 if c != '"' { 174 return UnexpectedByteError{got: c, exp: '"'} 175 } 176 it.head++ 177 default: 178 return UnexpectedByteError{got: c, exp: '}', exp2: ','} 179 } 180 } 181 }