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