summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/goccy/go-json/internal/decoder/interface.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/goccy/go-json/internal/decoder/interface.go')
-rw-r--r--vendor/github.com/goccy/go-json/internal/decoder/interface.go458
1 files changed, 458 insertions, 0 deletions
diff --git a/vendor/github.com/goccy/go-json/internal/decoder/interface.go b/vendor/github.com/goccy/go-json/internal/decoder/interface.go
new file mode 100644
index 0000000000..ea1b4aa579
--- /dev/null
+++ b/vendor/github.com/goccy/go-json/internal/decoder/interface.go
@@ -0,0 +1,458 @@
+package decoder
+
+import (
+ "bytes"
+ "encoding"
+ "encoding/json"
+ "reflect"
+ "unsafe"
+
+ "github.com/goccy/go-json/internal/errors"
+ "github.com/goccy/go-json/internal/runtime"
+)
+
+type interfaceDecoder struct {
+ typ *runtime.Type
+ structName string
+ fieldName string
+ sliceDecoder *sliceDecoder
+ mapDecoder *mapDecoder
+ floatDecoder *floatDecoder
+ numberDecoder *numberDecoder
+ stringDecoder *stringDecoder
+}
+
+func newEmptyInterfaceDecoder(structName, fieldName string) *interfaceDecoder {
+ ifaceDecoder := &interfaceDecoder{
+ typ: emptyInterfaceType,
+ structName: structName,
+ fieldName: fieldName,
+ floatDecoder: newFloatDecoder(structName, fieldName, func(p unsafe.Pointer, v float64) {
+ *(*interface{})(p) = v
+ }),
+ numberDecoder: newNumberDecoder(structName, fieldName, func(p unsafe.Pointer, v json.Number) {
+ *(*interface{})(p) = v
+ }),
+ stringDecoder: newStringDecoder(structName, fieldName),
+ }
+ ifaceDecoder.sliceDecoder = newSliceDecoder(
+ ifaceDecoder,
+ emptyInterfaceType,
+ emptyInterfaceType.Size(),
+ structName, fieldName,
+ )
+ ifaceDecoder.mapDecoder = newMapDecoder(
+ interfaceMapType,
+ stringType,
+ ifaceDecoder.stringDecoder,
+ interfaceMapType.Elem(),
+ ifaceDecoder,
+ structName,
+ fieldName,
+ )
+ return ifaceDecoder
+}
+
+func newInterfaceDecoder(typ *runtime.Type, structName, fieldName string) *interfaceDecoder {
+ emptyIfaceDecoder := newEmptyInterfaceDecoder(structName, fieldName)
+ stringDecoder := newStringDecoder(structName, fieldName)
+ return &interfaceDecoder{
+ typ: typ,
+ structName: structName,
+ fieldName: fieldName,
+ sliceDecoder: newSliceDecoder(
+ emptyIfaceDecoder,
+ emptyInterfaceType,
+ emptyInterfaceType.Size(),
+ structName, fieldName,
+ ),
+ mapDecoder: newMapDecoder(
+ interfaceMapType,
+ stringType,
+ stringDecoder,
+ interfaceMapType.Elem(),
+ emptyIfaceDecoder,
+ structName,
+ fieldName,
+ ),
+ floatDecoder: newFloatDecoder(structName, fieldName, func(p unsafe.Pointer, v float64) {
+ *(*interface{})(p) = v
+ }),
+ numberDecoder: newNumberDecoder(structName, fieldName, func(p unsafe.Pointer, v json.Number) {
+ *(*interface{})(p) = v
+ }),
+ stringDecoder: stringDecoder,
+ }
+}
+
+func (d *interfaceDecoder) numDecoder(s *Stream) Decoder {
+ if s.UseNumber {
+ return d.numberDecoder
+ }
+ return d.floatDecoder
+}
+
+var (
+ emptyInterfaceType = runtime.Type2RType(reflect.TypeOf((*interface{})(nil)).Elem())
+ interfaceMapType = runtime.Type2RType(
+ reflect.TypeOf((*map[string]interface{})(nil)).Elem(),
+ )
+ stringType = runtime.Type2RType(
+ reflect.TypeOf(""),
+ )
+)
+
+func decodeStreamUnmarshaler(s *Stream, depth int64, unmarshaler json.Unmarshaler) error {
+ start := s.cursor
+ if err := s.skipValue(depth); err != nil {
+ return err
+ }
+ src := s.buf[start:s.cursor]
+ dst := make([]byte, len(src))
+ copy(dst, src)
+
+ if err := unmarshaler.UnmarshalJSON(dst); err != nil {
+ return err
+ }
+ return nil
+}
+
+func decodeStreamUnmarshalerContext(s *Stream, depth int64, unmarshaler unmarshalerContext) error {
+ start := s.cursor
+ if err := s.skipValue(depth); err != nil {
+ return err
+ }
+ src := s.buf[start:s.cursor]
+ dst := make([]byte, len(src))
+ copy(dst, src)
+
+ if err := unmarshaler.UnmarshalJSON(s.Option.Context, dst); err != nil {
+ return err
+ }
+ return nil
+}
+
+func decodeUnmarshaler(buf []byte, cursor, depth int64, unmarshaler json.Unmarshaler) (int64, error) {
+ cursor = skipWhiteSpace(buf, cursor)
+ start := cursor
+ end, err := skipValue(buf, cursor, depth)
+ if err != nil {
+ return 0, err
+ }
+ src := buf[start:end]
+ dst := make([]byte, len(src))
+ copy(dst, src)
+
+ if err := unmarshaler.UnmarshalJSON(dst); err != nil {
+ return 0, err
+ }
+ return end, nil
+}
+
+func decodeUnmarshalerContext(ctx *RuntimeContext, buf []byte, cursor, depth int64, unmarshaler unmarshalerContext) (int64, error) {
+ cursor = skipWhiteSpace(buf, cursor)
+ start := cursor
+ end, err := skipValue(buf, cursor, depth)
+ if err != nil {
+ return 0, err
+ }
+ src := buf[start:end]
+ dst := make([]byte, len(src))
+ copy(dst, src)
+
+ if err := unmarshaler.UnmarshalJSON(ctx.Option.Context, dst); err != nil {
+ return 0, err
+ }
+ return end, nil
+}
+
+func decodeStreamTextUnmarshaler(s *Stream, depth int64, unmarshaler encoding.TextUnmarshaler, p unsafe.Pointer) error {
+ start := s.cursor
+ if err := s.skipValue(depth); err != nil {
+ return err
+ }
+ src := s.buf[start:s.cursor]
+ if bytes.Equal(src, nullbytes) {
+ *(*unsafe.Pointer)(p) = nil
+ return nil
+ }
+
+ dst := make([]byte, len(src))
+ copy(dst, src)
+
+ if err := unmarshaler.UnmarshalText(dst); err != nil {
+ return err
+ }
+ return nil
+}
+
+func decodeTextUnmarshaler(buf []byte, cursor, depth int64, unmarshaler encoding.TextUnmarshaler, p unsafe.Pointer) (int64, error) {
+ cursor = skipWhiteSpace(buf, cursor)
+ start := cursor
+ end, err := skipValue(buf, cursor, depth)
+ if err != nil {
+ return 0, err
+ }
+ src := buf[start:end]
+ if bytes.Equal(src, nullbytes) {
+ *(*unsafe.Pointer)(p) = nil
+ return end, nil
+ }
+ if s, ok := unquoteBytes(src); ok {
+ src = s
+ }
+ if err := unmarshaler.UnmarshalText(src); err != nil {
+ return 0, err
+ }
+ return end, nil
+}
+
+func (d *interfaceDecoder) decodeStreamEmptyInterface(s *Stream, depth int64, p unsafe.Pointer) error {
+ c := s.skipWhiteSpace()
+ for {
+ switch c {
+ case '{':
+ var v map[string]interface{}
+ ptr := unsafe.Pointer(&v)
+ if err := d.mapDecoder.DecodeStream(s, depth, ptr); err != nil {
+ return err
+ }
+ *(*interface{})(p) = v
+ return nil
+ case '[':
+ var v []interface{}
+ ptr := unsafe.Pointer(&v)
+ if err := d.sliceDecoder.DecodeStream(s, depth, ptr); err != nil {
+ return err
+ }
+ *(*interface{})(p) = v
+ return nil
+ case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+ return d.numDecoder(s).DecodeStream(s, depth, p)
+ case '"':
+ s.cursor++
+ start := s.cursor
+ for {
+ switch s.char() {
+ case '\\':
+ if _, err := decodeEscapeString(s, nil); err != nil {
+ return err
+ }
+ case '"':
+ literal := s.buf[start:s.cursor]
+ s.cursor++
+ *(*interface{})(p) = string(literal)
+ return nil
+ case nul:
+ if s.read() {
+ continue
+ }
+ return errors.ErrUnexpectedEndOfJSON("string", s.totalOffset())
+ }
+ s.cursor++
+ }
+ case 't':
+ if err := trueBytes(s); err != nil {
+ return err
+ }
+ **(**interface{})(unsafe.Pointer(&p)) = true
+ return nil
+ case 'f':
+ if err := falseBytes(s); err != nil {
+ return err
+ }
+ **(**interface{})(unsafe.Pointer(&p)) = false
+ return nil
+ case 'n':
+ if err := nullBytes(s); err != nil {
+ return err
+ }
+ *(*interface{})(p) = nil
+ return nil
+ case nul:
+ if s.read() {
+ c = s.char()
+ continue
+ }
+ }
+ break
+ }
+ return errors.ErrNotAtBeginningOfValue(s.totalOffset())
+}
+
+type emptyInterface struct {
+ typ *runtime.Type
+ ptr unsafe.Pointer
+}
+
+func (d *interfaceDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error {
+ runtimeInterfaceValue := *(*interface{})(unsafe.Pointer(&emptyInterface{
+ typ: d.typ,
+ ptr: p,
+ }))
+ rv := reflect.ValueOf(runtimeInterfaceValue)
+ if rv.NumMethod() > 0 && rv.CanInterface() {
+ if u, ok := rv.Interface().(unmarshalerContext); ok {
+ return decodeStreamUnmarshalerContext(s, depth, u)
+ }
+ if u, ok := rv.Interface().(json.Unmarshaler); ok {
+ return decodeStreamUnmarshaler(s, depth, u)
+ }
+ if u, ok := rv.Interface().(encoding.TextUnmarshaler); ok {
+ return decodeStreamTextUnmarshaler(s, depth, u, p)
+ }
+ if s.skipWhiteSpace() == 'n' {
+ if err := nullBytes(s); err != nil {
+ return err
+ }
+ *(*interface{})(p) = nil
+ return nil
+ }
+ return d.errUnmarshalType(rv.Type(), s.totalOffset())
+ }
+ iface := rv.Interface()
+ ifaceHeader := (*emptyInterface)(unsafe.Pointer(&iface))
+ typ := ifaceHeader.typ
+ if ifaceHeader.ptr == nil || d.typ == typ || typ == nil {
+ // concrete type is empty interface
+ return d.decodeStreamEmptyInterface(s, depth, p)
+ }
+ if typ.Kind() == reflect.Ptr && typ.Elem() == d.typ || typ.Kind() != reflect.Ptr {
+ return d.decodeStreamEmptyInterface(s, depth, p)
+ }
+ if s.skipWhiteSpace() == 'n' {
+ if err := nullBytes(s); err != nil {
+ return err
+ }
+ *(*interface{})(p) = nil
+ return nil
+ }
+ decoder, err := CompileToGetDecoder(typ)
+ if err != nil {
+ return err
+ }
+ return decoder.DecodeStream(s, depth, ifaceHeader.ptr)
+}
+
+func (d *interfaceDecoder) errUnmarshalType(typ reflect.Type, offset int64) *errors.UnmarshalTypeError {
+ return &errors.UnmarshalTypeError{
+ Value: typ.String(),
+ Type: typ,
+ Offset: offset,
+ Struct: d.structName,
+ Field: d.fieldName,
+ }
+}
+
+func (d *interfaceDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) {
+ buf := ctx.Buf
+ runtimeInterfaceValue := *(*interface{})(unsafe.Pointer(&emptyInterface{
+ typ: d.typ,
+ ptr: p,
+ }))
+ rv := reflect.ValueOf(runtimeInterfaceValue)
+ if rv.NumMethod() > 0 && rv.CanInterface() {
+ if u, ok := rv.Interface().(unmarshalerContext); ok {
+ return decodeUnmarshalerContext(ctx, buf, cursor, depth, u)
+ }
+ if u, ok := rv.Interface().(json.Unmarshaler); ok {
+ return decodeUnmarshaler(buf, cursor, depth, u)
+ }
+ if u, ok := rv.Interface().(encoding.TextUnmarshaler); ok {
+ return decodeTextUnmarshaler(buf, cursor, depth, u, p)
+ }
+ cursor = skipWhiteSpace(buf, cursor)
+ if buf[cursor] == 'n' {
+ if err := validateNull(buf, cursor); err != nil {
+ return 0, err
+ }
+ cursor += 4
+ **(**interface{})(unsafe.Pointer(&p)) = nil
+ return cursor, nil
+ }
+ return 0, d.errUnmarshalType(rv.Type(), cursor)
+ }
+
+ iface := rv.Interface()
+ ifaceHeader := (*emptyInterface)(unsafe.Pointer(&iface))
+ typ := ifaceHeader.typ
+ if ifaceHeader.ptr == nil || d.typ == typ || typ == nil {
+ // concrete type is empty interface
+ return d.decodeEmptyInterface(ctx, cursor, depth, p)
+ }
+ if typ.Kind() == reflect.Ptr && typ.Elem() == d.typ || typ.Kind() != reflect.Ptr {
+ return d.decodeEmptyInterface(ctx, cursor, depth, p)
+ }
+ cursor = skipWhiteSpace(buf, cursor)
+ if buf[cursor] == 'n' {
+ if err := validateNull(buf, cursor); err != nil {
+ return 0, err
+ }
+ cursor += 4
+ **(**interface{})(unsafe.Pointer(&p)) = nil
+ return cursor, nil
+ }
+ decoder, err := CompileToGetDecoder(typ)
+ if err != nil {
+ return 0, err
+ }
+ return decoder.Decode(ctx, cursor, depth, ifaceHeader.ptr)
+}
+
+func (d *interfaceDecoder) decodeEmptyInterface(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) {
+ buf := ctx.Buf
+ cursor = skipWhiteSpace(buf, cursor)
+ switch buf[cursor] {
+ case '{':
+ var v map[string]interface{}
+ ptr := unsafe.Pointer(&v)
+ cursor, err := d.mapDecoder.Decode(ctx, cursor, depth, ptr)
+ if err != nil {
+ return 0, err
+ }
+ **(**interface{})(unsafe.Pointer(&p)) = v
+ return cursor, nil
+ case '[':
+ var v []interface{}
+ ptr := unsafe.Pointer(&v)
+ cursor, err := d.sliceDecoder.Decode(ctx, cursor, depth, ptr)
+ if err != nil {
+ return 0, err
+ }
+ **(**interface{})(unsafe.Pointer(&p)) = v
+ return cursor, nil
+ case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+ return d.floatDecoder.Decode(ctx, cursor, depth, p)
+ case '"':
+ var v string
+ ptr := unsafe.Pointer(&v)
+ cursor, err := d.stringDecoder.Decode(ctx, cursor, depth, ptr)
+ if err != nil {
+ return 0, err
+ }
+ **(**interface{})(unsafe.Pointer(&p)) = v
+ return cursor, nil
+ case 't':
+ if err := validateTrue(buf, cursor); err != nil {
+ return 0, err
+ }
+ cursor += 4
+ **(**interface{})(unsafe.Pointer(&p)) = true
+ return cursor, nil
+ case 'f':
+ if err := validateFalse(buf, cursor); err != nil {
+ return 0, err
+ }
+ cursor += 5
+ **(**interface{})(unsafe.Pointer(&p)) = false
+ return cursor, nil
+ case 'n':
+ if err := validateNull(buf, cursor); err != nil {
+ return 0, err
+ }
+ cursor += 4
+ **(**interface{})(unsafe.Pointer(&p)) = nil
+ return cursor, nil
+ }
+ return cursor, errors.ErrNotAtBeginningOfValue(cursor)
+}