summaryrefslogtreecommitdiff
path: root/vendor/github.com/goccy/go-json/decode.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/goccy/go-json/decode.go')
-rw-r--r--vendor/github.com/goccy/go-json/decode.go232
1 files changed, 232 insertions, 0 deletions
diff --git a/vendor/github.com/goccy/go-json/decode.go b/vendor/github.com/goccy/go-json/decode.go
new file mode 100644
index 000000000..d99749d05
--- /dev/null
+++ b/vendor/github.com/goccy/go-json/decode.go
@@ -0,0 +1,232 @@
+package json
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "reflect"
+ "unsafe"
+
+ "github.com/goccy/go-json/internal/decoder"
+ "github.com/goccy/go-json/internal/errors"
+ "github.com/goccy/go-json/internal/runtime"
+)
+
+type Decoder struct {
+ s *decoder.Stream
+}
+
+const (
+ nul = '\000'
+)
+
+type emptyInterface struct {
+ typ *runtime.Type
+ ptr unsafe.Pointer
+}
+
+func unmarshal(data []byte, v interface{}, optFuncs ...DecodeOptionFunc) error {
+ src := make([]byte, len(data)+1) // append nul byte to the end
+ copy(src, data)
+
+ header := (*emptyInterface)(unsafe.Pointer(&v))
+
+ if err := validateType(header.typ, uintptr(header.ptr)); err != nil {
+ return err
+ }
+ dec, err := decoder.CompileToGetDecoder(header.typ)
+ if err != nil {
+ return err
+ }
+ ctx := decoder.TakeRuntimeContext()
+ ctx.Buf = src
+ ctx.Option.Flags = 0
+ for _, optFunc := range optFuncs {
+ optFunc(ctx.Option)
+ }
+ cursor, err := dec.Decode(ctx, 0, 0, header.ptr)
+ if err != nil {
+ decoder.ReleaseRuntimeContext(ctx)
+ return err
+ }
+ decoder.ReleaseRuntimeContext(ctx)
+ return validateEndBuf(src, cursor)
+}
+
+func unmarshalContext(ctx context.Context, data []byte, v interface{}, optFuncs ...DecodeOptionFunc) error {
+ src := make([]byte, len(data)+1) // append nul byte to the end
+ copy(src, data)
+
+ header := (*emptyInterface)(unsafe.Pointer(&v))
+
+ if err := validateType(header.typ, uintptr(header.ptr)); err != nil {
+ return err
+ }
+ dec, err := decoder.CompileToGetDecoder(header.typ)
+ if err != nil {
+ return err
+ }
+ rctx := decoder.TakeRuntimeContext()
+ rctx.Buf = src
+ rctx.Option.Flags = 0
+ rctx.Option.Flags |= decoder.ContextOption
+ rctx.Option.Context = ctx
+ for _, optFunc := range optFuncs {
+ optFunc(rctx.Option)
+ }
+ cursor, err := dec.Decode(rctx, 0, 0, header.ptr)
+ if err != nil {
+ decoder.ReleaseRuntimeContext(rctx)
+ return err
+ }
+ decoder.ReleaseRuntimeContext(rctx)
+ return validateEndBuf(src, cursor)
+}
+
+func unmarshalNoEscape(data []byte, v interface{}, optFuncs ...DecodeOptionFunc) error {
+ src := make([]byte, len(data)+1) // append nul byte to the end
+ copy(src, data)
+
+ header := (*emptyInterface)(unsafe.Pointer(&v))
+
+ if err := validateType(header.typ, uintptr(header.ptr)); err != nil {
+ return err
+ }
+ dec, err := decoder.CompileToGetDecoder(header.typ)
+ if err != nil {
+ return err
+ }
+
+ ctx := decoder.TakeRuntimeContext()
+ ctx.Buf = src
+ ctx.Option.Flags = 0
+ for _, optFunc := range optFuncs {
+ optFunc(ctx.Option)
+ }
+ cursor, err := dec.Decode(ctx, 0, 0, noescape(header.ptr))
+ if err != nil {
+ decoder.ReleaseRuntimeContext(ctx)
+ return err
+ }
+ decoder.ReleaseRuntimeContext(ctx)
+ return validateEndBuf(src, cursor)
+}
+
+func validateEndBuf(src []byte, cursor int64) error {
+ for {
+ switch src[cursor] {
+ case ' ', '\t', '\n', '\r':
+ cursor++
+ continue
+ case nul:
+ return nil
+ }
+ return errors.ErrSyntax(
+ fmt.Sprintf("invalid character '%c' after top-level value", src[cursor]),
+ cursor+1,
+ )
+ }
+}
+
+//nolint:staticcheck
+//go:nosplit
+func noescape(p unsafe.Pointer) unsafe.Pointer {
+ x := uintptr(p)
+ return unsafe.Pointer(x ^ 0)
+}
+
+func validateType(typ *runtime.Type, p uintptr) error {
+ if typ == nil || typ.Kind() != reflect.Ptr || p == 0 {
+ return &InvalidUnmarshalError{Type: runtime.RType2Type(typ)}
+ }
+ return nil
+}
+
+// NewDecoder returns a new decoder that reads from r.
+//
+// The decoder introduces its own buffering and may
+// read data from r beyond the JSON values requested.
+func NewDecoder(r io.Reader) *Decoder {
+ s := decoder.NewStream(r)
+ return &Decoder{
+ s: s,
+ }
+}
+
+// Buffered returns a reader of the data remaining in the Decoder's
+// buffer. The reader is valid until the next call to Decode.
+func (d *Decoder) Buffered() io.Reader {
+ return d.s.Buffered()
+}
+
+// Decode reads the next JSON-encoded value from its
+// input and stores it in the value pointed to by v.
+//
+// See the documentation for Unmarshal for details about
+// the conversion of JSON into a Go value.
+func (d *Decoder) Decode(v interface{}) error {
+ return d.DecodeWithOption(v)
+}
+
+// DecodeContext reads the next JSON-encoded value from its
+// input and stores it in the value pointed to by v with context.Context.
+func (d *Decoder) DecodeContext(ctx context.Context, v interface{}) error {
+ d.s.Option.Flags |= decoder.ContextOption
+ d.s.Option.Context = ctx
+ return d.DecodeWithOption(v)
+}
+
+func (d *Decoder) DecodeWithOption(v interface{}, optFuncs ...DecodeOptionFunc) error {
+ header := (*emptyInterface)(unsafe.Pointer(&v))
+ typ := header.typ
+ ptr := uintptr(header.ptr)
+ typeptr := uintptr(unsafe.Pointer(typ))
+ // noescape trick for header.typ ( reflect.*rtype )
+ copiedType := *(**runtime.Type)(unsafe.Pointer(&typeptr))
+
+ if err := validateType(copiedType, ptr); err != nil {
+ return err
+ }
+
+ dec, err := decoder.CompileToGetDecoder(typ)
+ if err != nil {
+ return err
+ }
+ if err := d.s.PrepareForDecode(); err != nil {
+ return err
+ }
+ s := d.s
+ for _, optFunc := range optFuncs {
+ optFunc(s.Option)
+ }
+ if err := dec.DecodeStream(s, 0, header.ptr); err != nil {
+ return err
+ }
+ s.Reset()
+ return nil
+}
+
+func (d *Decoder) More() bool {
+ return d.s.More()
+}
+
+func (d *Decoder) Token() (Token, error) {
+ return d.s.Token()
+}
+
+// DisallowUnknownFields causes the Decoder to return an error when the destination
+// is a struct and the input contains object keys which do not match any
+// non-ignored, exported fields in the destination.
+func (d *Decoder) DisallowUnknownFields() {
+ d.s.DisallowUnknownFields = true
+}
+
+func (d *Decoder) InputOffset() int64 {
+ return d.s.TotalOffset()
+}
+
+// UseNumber causes the Decoder to unmarshal a number into an interface{} as a
+// Number instead of as a float64.
+func (d *Decoder) UseNumber() {
+ d.s.UseNumber = true
+}