github.com/3JoB/go-json@v0.10.4/internal/decoder/map.go (about) 1 package decoder 2 3 import ( 4 "unsafe" 5 6 "github.com/3JoB/go-reflect" 7 "github.com/3JoB/unsafeConvert" 8 9 "github.com/3JoB/go-json/internal/errors" 10 "github.com/3JoB/go-json/internal/runtime" 11 ) 12 13 type mapDecoder struct { 14 mapType *runtime.Type 15 keyType *runtime.Type 16 valueType *runtime.Type 17 canUseAssignFaststrType bool 18 keyDecoder Decoder 19 valueDecoder Decoder 20 structName string 21 fieldName string 22 } 23 24 func newMapDecoder(mapType *runtime.Type, keyType *runtime.Type, keyDec Decoder, valueType *runtime.Type, valueDec Decoder, structName, fieldName string) *mapDecoder { 25 return &mapDecoder{ 26 mapType: mapType, 27 keyDecoder: keyDec, 28 keyType: keyType, 29 canUseAssignFaststrType: canUseAssignFaststrType(keyType, valueType), 30 valueType: valueType, 31 valueDecoder: valueDec, 32 structName: structName, 33 fieldName: fieldName, 34 } 35 } 36 37 const ( 38 mapMaxElemSize = 128 39 ) 40 41 // See detail: https://github.com/3JoB/go-json/pull/283 42 func canUseAssignFaststrType(key *runtime.Type, value *runtime.Type) bool { 43 indirectElem := value.Size() > mapMaxElemSize 44 if indirectElem { 45 return false 46 } 47 return key.Kind() == reflect.String 48 } 49 50 //go:linkname makemap reflect.makemap 51 func makemap(*runtime.Type, int) unsafe.Pointer 52 53 //nolint:golint 54 //go:linkname mapassign_faststr runtime.mapassign_faststr 55 //go:noescape 56 func mapassign_faststr(t *runtime.Type, m unsafe.Pointer, s string) unsafe.Pointer 57 58 //go:linkname mapassign reflect.mapassign 59 //go:noescape 60 func mapassign(t *runtime.Type, m unsafe.Pointer, k, v unsafe.Pointer) 61 62 func (d *mapDecoder) mapassign(t *runtime.Type, m, k, v unsafe.Pointer) { 63 if d.canUseAssignFaststrType { 64 mapV := mapassign_faststr(t, m, *(*string)(k)) 65 typedmemmove(d.valueType, mapV, v) 66 } else { 67 mapassign(t, m, k, v) 68 } 69 } 70 71 func (d *mapDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error { 72 depth++ 73 if depth > maxDecodeNestingDepth { 74 return errors.ErrExceededMaxDepth(s.char(), s.cursor) 75 } 76 77 switch s.skipWhiteSpace() { 78 case 'n': 79 if err := nullBytes(s); err != nil { 80 return err 81 } 82 **(**unsafe.Pointer)(unsafe.Pointer(&p)) = nil 83 return nil 84 case '{': 85 default: 86 return errors.ErrExpected("{ character for map value", s.totalOffset()) 87 } 88 mapValue := *(*unsafe.Pointer)(p) 89 if mapValue == nil { 90 mapValue = makemap(d.mapType, 0) 91 } 92 s.cursor++ 93 if s.skipWhiteSpace() == '}' { 94 *(*unsafe.Pointer)(p) = mapValue 95 s.cursor++ 96 return nil 97 } 98 for { 99 k := unsafe_New(d.keyType) 100 if err := d.keyDecoder.DecodeStream(s, depth, k); err != nil { 101 return err 102 } 103 s.skipWhiteSpace() 104 if !s.equalChar(':') { 105 return errors.ErrExpected("colon after object key", s.totalOffset()) 106 } 107 s.cursor++ 108 v := unsafe_New(d.valueType) 109 if err := d.valueDecoder.DecodeStream(s, depth, v); err != nil { 110 return err 111 } 112 d.mapassign(d.mapType, mapValue, k, v) 113 s.skipWhiteSpace() 114 if s.equalChar('}') { 115 **(**unsafe.Pointer)(unsafe.Pointer(&p)) = mapValue 116 s.cursor++ 117 return nil 118 } 119 if !s.equalChar(',') { 120 return errors.ErrExpected("comma after object value", s.totalOffset()) 121 } 122 s.cursor++ 123 } 124 } 125 126 func (d *mapDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) { 127 buf := ctx.Buf 128 depth++ 129 if depth > maxDecodeNestingDepth { 130 return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor) 131 } 132 133 cursor = skipWhiteSpace(buf, cursor) 134 buflen := int64(len(buf)) 135 if buflen < 2 { 136 return 0, errors.ErrExpected("{} for map", cursor) 137 } 138 switch buf[cursor] { 139 case 'n': 140 if err := validateNull(buf, cursor); err != nil { 141 return 0, err 142 } 143 cursor += 4 144 **(**unsafe.Pointer)(unsafe.Pointer(&p)) = nil 145 return cursor, nil 146 case '{': 147 default: 148 return 0, errors.ErrExpected("{ character for map value", cursor) 149 } 150 cursor++ 151 cursor = skipWhiteSpace(buf, cursor) 152 mapValue := *(*unsafe.Pointer)(p) 153 if mapValue == nil { 154 mapValue = makemap(d.mapType, 0) 155 } 156 if buf[cursor] == '}' { 157 **(**unsafe.Pointer)(unsafe.Pointer(&p)) = mapValue 158 cursor++ 159 return cursor, nil 160 } 161 for { 162 k := unsafe_New(d.keyType) 163 keyCursor, err := d.keyDecoder.Decode(ctx, cursor, depth, k) 164 if err != nil { 165 return 0, err 166 } 167 cursor = skipWhiteSpace(buf, keyCursor) 168 if buf[cursor] != ':' { 169 return 0, errors.ErrExpected("colon after object key", cursor) 170 } 171 cursor++ 172 v := unsafe_New(d.valueType) 173 valueCursor, err := d.valueDecoder.Decode(ctx, cursor, depth, v) 174 if err != nil { 175 return 0, err 176 } 177 d.mapassign(d.mapType, mapValue, k, v) 178 cursor = skipWhiteSpace(buf, valueCursor) 179 if buf[cursor] == '}' { 180 **(**unsafe.Pointer)(unsafe.Pointer(&p)) = mapValue 181 cursor++ 182 return cursor, nil 183 } 184 if buf[cursor] != ',' { 185 return 0, errors.ErrExpected("comma after object value", cursor) 186 } 187 cursor++ 188 } 189 } 190 191 func (d *mapDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) { 192 buf := ctx.Buf 193 depth++ 194 if depth > maxDecodeNestingDepth { 195 return nil, 0, errors.ErrExceededMaxDepth(buf[cursor], cursor) 196 } 197 198 cursor = skipWhiteSpace(buf, cursor) 199 buflen := int64(len(buf)) 200 if buflen < 2 { 201 return nil, 0, errors.ErrExpected("{} for map", cursor) 202 } 203 switch buf[cursor] { 204 case 'n': 205 if err := validateNull(buf, cursor); err != nil { 206 return nil, 0, err 207 } 208 cursor += 4 209 return [][]byte{nullbytes}, cursor, nil 210 case '{': 211 default: 212 return nil, 0, errors.ErrExpected("{ character for map value", cursor) 213 } 214 cursor++ 215 cursor = skipWhiteSpace(buf, cursor) 216 if buf[cursor] == '}' { 217 cursor++ 218 return nil, cursor, nil 219 } 220 keyDecoder, ok := d.keyDecoder.(*stringDecoder) 221 if !ok { 222 return nil, 0, &errors.UnmarshalTypeError{ 223 Value: "string", 224 Type: reflect.TypeOf(""), 225 Offset: cursor, 226 Struct: d.structName, 227 Field: d.fieldName, 228 } 229 } 230 ret := [][]byte{} 231 for { 232 key, keyCursor, err := keyDecoder.decodeByte(buf, cursor) 233 if err != nil { 234 return nil, 0, err 235 } 236 cursor = skipWhiteSpace(buf, keyCursor) 237 if buf[cursor] != ':' { 238 return nil, 0, errors.ErrExpected("colon after object key", cursor) 239 } 240 cursor++ 241 child, found, err := ctx.Option.Path.Field(unsafeConvert.StringReflect(key)) 242 if err != nil { 243 return nil, 0, err 244 } 245 if found { 246 if child != nil { 247 oldPath := ctx.Option.Path.node 248 ctx.Option.Path.node = child 249 paths, c, err := d.valueDecoder.DecodePath(ctx, cursor, depth) 250 if err != nil { 251 return nil, 0, err 252 } 253 ctx.Option.Path.node = oldPath 254 ret = append(ret, paths...) 255 cursor = c 256 } else { 257 start := cursor 258 end, err := skipValue(buf, cursor, depth) 259 if err != nil { 260 return nil, 0, err 261 } 262 ret = append(ret, buf[start:end]) 263 cursor = end 264 } 265 } else { 266 c, err := skipValue(buf, cursor, depth) 267 if err != nil { 268 return nil, 0, err 269 } 270 cursor = c 271 } 272 cursor = skipWhiteSpace(buf, cursor) 273 if buf[cursor] == '}' { 274 cursor++ 275 return ret, cursor, nil 276 } 277 if buf[cursor] != ',' { 278 return nil, 0, errors.ErrExpected("comma after object value", cursor) 279 } 280 cursor++ 281 } 282 }