go-json/decode_map.go

82 lines
2.1 KiB
Go
Raw Normal View History

2020-04-25 16:48:16 +03:00
package json
import (
"unsafe"
)
type mapDecoder struct {
mapType *rtype
keyDecoder decoder
valueDecoder decoder
}
func newMapDecoder(mapType *rtype, keyDec decoder, valueDec decoder) *mapDecoder {
return &mapDecoder{
mapType: mapType,
keyDecoder: keyDec,
valueDecoder: valueDec,
}
}
//go:linkname makemap reflect.makemap
func makemap(*rtype, int) unsafe.Pointer
//go:linkname mapassign reflect.mapassign
//go:noescape
func mapassign(t *rtype, m unsafe.Pointer, key, val unsafe.Pointer)
2020-05-23 06:51:09 +03:00
func (d *mapDecoder) setKey(buf []byte, cursor int64, key interface{}) (int64, error) {
2020-04-25 16:48:16 +03:00
header := (*interfaceHeader)(unsafe.Pointer(&key))
2020-05-06 20:37:29 +03:00
return d.keyDecoder.decode(buf, cursor, uintptr(header.ptr))
2020-04-25 16:48:16 +03:00
}
2020-05-23 06:51:09 +03:00
func (d *mapDecoder) setValue(buf []byte, cursor int64, key interface{}) (int64, error) {
2020-04-25 16:48:16 +03:00
header := (*interfaceHeader)(unsafe.Pointer(&key))
2020-05-06 20:37:29 +03:00
return d.valueDecoder.decode(buf, cursor, uintptr(header.ptr))
2020-04-25 16:48:16 +03:00
}
2020-05-23 06:51:09 +03:00
func (d *mapDecoder) decode(buf []byte, cursor int64, p uintptr) (int64, error) {
2020-05-06 20:37:29 +03:00
cursor = skipWhiteSpace(buf, cursor)
2020-05-23 06:51:09 +03:00
buflen := int64(len(buf))
2020-04-25 16:48:16 +03:00
if buflen < 2 {
2020-05-23 06:51:09 +03:00
return 0, errExpected("{} for map", cursor)
2020-04-25 16:48:16 +03:00
}
if buf[cursor] != '{' {
2020-05-23 06:51:09 +03:00
return 0, errExpected("{ character for map value", cursor)
2020-04-25 16:48:16 +03:00
}
cursor++
mapValue := makemap(d.mapType, 0)
for ; cursor < buflen; cursor++ {
var key interface{}
2020-05-06 20:37:29 +03:00
keyCursor, err := d.setKey(buf, cursor, &key)
if err != nil {
return 0, err
2020-04-25 16:48:16 +03:00
}
2020-05-06 20:37:29 +03:00
cursor = keyCursor
cursor = skipWhiteSpace(buf, cursor)
2020-04-25 16:48:16 +03:00
if buf[cursor] != ':' {
2020-05-23 06:51:09 +03:00
return 0, errExpected("colon after object key", cursor)
2020-04-25 16:48:16 +03:00
}
cursor++
if cursor >= buflen {
2020-05-23 06:51:09 +03:00
return 0, errUnexpectedEndOfJSON("map", cursor)
2020-04-25 16:48:16 +03:00
}
var value interface{}
2020-05-06 20:37:29 +03:00
valueCursor, err := d.setValue(buf, cursor, &value)
if err != nil {
return 0, err
2020-04-25 16:48:16 +03:00
}
2020-05-06 20:37:29 +03:00
cursor = valueCursor
2020-04-25 16:48:16 +03:00
mapassign(d.mapType, mapValue, unsafe.Pointer(&key), unsafe.Pointer(&value))
2020-05-06 20:37:29 +03:00
cursor = skipWhiteSpace(buf, valueCursor)
2020-04-25 16:48:16 +03:00
if buf[cursor] == '}' {
*(*unsafe.Pointer)(unsafe.Pointer(p)) = mapValue
2020-05-06 20:37:29 +03:00
return cursor, nil
2020-04-25 16:48:16 +03:00
}
if buf[cursor] != ',' {
2020-05-23 06:51:09 +03:00
return 0, errExpected("semicolon after object value", cursor)
2020-04-25 16:48:16 +03:00
}
}
2020-05-06 20:37:29 +03:00
return cursor, nil
2020-04-25 16:48:16 +03:00
}