summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@lukeshu.com>2023-02-10 21:52:34 -0700
committerLuke Shumaker <lukeshu@lukeshu.com>2023-02-10 21:52:34 -0700
commitcf8f8527e968c448995bdcaaad9c4351d3a2ab3f (patch)
treed228bb78a08586cab74e0a3df292fa8e9c266f90
parent95180a90db47990d32104ff7ab103e4862fd8426 (diff)
parentdadafd9cfabbea5555c404b339bbf44252ee7e6b (diff)
Merge branch 'lukeshu/decode-no-panic'
-rw-r--r--decode.go775
1 files changed, 498 insertions, 277 deletions
diff --git a/decode.go b/decode.go
index 645f8de..976cc6a 100644
--- a/decode.go
+++ b/decode.go
@@ -53,8 +53,8 @@ import (
// or another is encountered; if it does not, then the parent Decode
// call will return a *DecodeTypeError.
//
-// Implementor's note: "limitingScanner" is the thing to search for in
-// decode.go if you want to read up on that io.RuneScanner.
+// Implementor's note: "withLimitingScanner" is the thing to search
+// for in decode.go if you want to read up on that io.RuneScanner.
type Decodable interface {
DecodeJSON(io.RuneScanner) error
}
@@ -243,27 +243,17 @@ func (dec *Decoder) Decode(ptr any) (err error) {
dec.io.Reset()
dec.io.PushReadBarrier()
- defer func() {
- if r := recover(); r != nil {
- if de, ok := r.(decodeError); ok {
- pub := DecodeError(de)
- err = &pub
- } else {
- panic(r)
- }
- }
- }()
- dec.decode(ptrVal.Elem(), false)
+ if err := dec.decode(ptrVal.Elem(), false); err != nil {
+ return err
+ }
dec.io.PopReadBarrier()
return nil
}
// io helpers //////////////////////////////////////////////////////////////////////////////////////
-type decodeError DecodeError
-
-func (dec *Decoder) panicType(jTyp string, gTyp reflect.Type, err error) {
- panic(decodeError{
+func (dec *Decoder) newTypeError(jTyp string, gTyp reflect.Type, err error) *DecodeError {
+ return &DecodeError{
Field: dec.structStackStr(),
FieldParent: dec.structStackParent(),
FieldName: dec.structStackName(),
@@ -273,20 +263,20 @@ func (dec *Decoder) panicType(jTyp string, gTyp reflect.Type, err error) {
Err: err,
Offset: dec.posStack[len(dec.posStack)-1],
},
- })
+ }
}
-func (dec *Decoder) readRune() (rune, jsonparse.RuneType) {
+func (dec *Decoder) readRune() (rune, jsonparse.RuneType, *DecodeError) {
c, _, t, e := dec.io.ReadRuneType()
if e != nil {
- panic(decodeError{
+ return 0, 0, &DecodeError{
Field: dec.structStackStr(),
FieldParent: dec.structStackParent(),
FieldName: dec.structStackName(),
Err: e,
- })
+ }
}
- return c, t
+ return c, t, nil
}
func (dec *Decoder) unreadRune() {
@@ -297,24 +287,35 @@ func (dec *Decoder) unreadRune() {
}
}
-func (dec *Decoder) peekRuneType() jsonparse.RuneType {
- _, t := dec.readRune()
+func (dec *Decoder) peekRuneType() (jsonparse.RuneType, *DecodeError) {
+ _, t, err := dec.readRune()
+ if err != nil {
+ return 0, err
+ }
dec.unreadRune()
- return t
+ return t, nil
}
-func (dec *Decoder) expectRune(ec rune, et jsonparse.RuneType) {
- ac, at := dec.readRune()
+func (dec *Decoder) expectRune(ec rune, et jsonparse.RuneType) *DecodeError {
+ ac, at, err := dec.readRune()
+ if err != nil {
+ return err
+ }
if ac != ec || at != et {
panic("should not happen")
}
+ return nil
}
-func (dec *Decoder) expectRuneType(ec rune, et jsonparse.RuneType, gt reflect.Type) {
- ac, at := dec.readRune()
+func (dec *Decoder) expectRuneType(ec rune, et jsonparse.RuneType, gt reflect.Type) *DecodeError {
+ ac, at, err := dec.readRune()
+ if err != nil {
+ return err
+ }
if ac != ec || at != et {
- dec.panicType(at.JSONType(), gt, nil)
+ return dec.newTypeError(at.JSONType(), gt, nil)
}
+ return nil
}
type decRuneScanner struct {
@@ -322,6 +323,8 @@ type decRuneScanner struct {
eof bool
}
+type scannerPanic *DecodeError
+
func (sc *decRuneScanner) ReadRune() (rune, int, error) {
if sc.eof {
return 0, 0, io.EOF
@@ -333,12 +336,12 @@ func (sc *decRuneScanner) ReadRune() (rune, int, error) {
return 0, 0, io.EOF
}
if e != nil {
- panic(decodeError{
+ panic(scannerPanic(&DecodeError{
Field: sc.dec.structStackStr(),
FieldParent: sc.dec.structStackParent(),
FieldName: sc.dec.structStackName(),
Err: e,
- })
+ }))
}
return c, s, nil
}
@@ -347,11 +350,21 @@ func (sc *decRuneScanner) UnreadRune() error {
return sc.dec.io.UnreadRune()
}
-func (dec *Decoder) limitingScanner() io.RuneScanner {
+func (dec *Decoder) withLimitingScanner(fn func(io.RuneScanner) *DecodeError) (err *DecodeError) {
dec.io.PushReadBarrier()
- return &decRuneScanner{
- dec: dec,
+ defer func() {
+ if r := recover(); r != nil {
+ if sp, ok := r.(scannerPanic); ok {
+ err = (*DecodeError)(sp)
+ } else {
+ panic(r)
+ }
+ }
+ }()
+ if err := fn(&decRuneScanner{dec: dec}); err != nil {
+ return err
}
+ return nil
}
// decoder main ////////////////////////////////////////////////////////////////////////////////////
@@ -375,113 +388,145 @@ var kind2bits = map[reflect.Kind]int{
reflect.Float64: 64,
}
-func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
+func (dec *Decoder) decode(val reflect.Value, nullOK bool) *DecodeError {
dec.posStackPush()
defer dec.posStackPop()
typ := val.Type()
switch {
case val.CanAddr() && reflect.PointerTo(typ) == rawMessagePtrType:
- t := dec.peekRuneType()
+ t, err := dec.peekRuneType()
+ if err != nil {
+ return err
+ }
var buf bytes.Buffer
- dec.scan(&buf)
+ if err := dec.scan(&buf); err != nil {
+ return err
+ }
if err := val.Addr().Interface().(*RawMessage).UnmarshalJSON(buf.Bytes()); err != nil {
- dec.panicType(t.JSONType(), reflect.PointerTo(typ), err)
+ return dec.newTypeError(t.JSONType(), reflect.PointerTo(typ), err)
}
case val.CanAddr() && reflect.PointerTo(typ).Implements(decodableType):
- t := dec.peekRuneType()
- obj := val.Addr().Interface().(Decodable)
- l := dec.limitingScanner()
- if err := obj.DecodeJSON(l); err != nil {
- dec.panicType(t.JSONType(), reflect.PointerTo(typ), err)
- }
- if _, _, err := l.ReadRune(); err != io.EOF {
- dec.panicType(t.JSONType(), reflect.PointerTo(typ), fmt.Errorf("did not consume entire %s", t.JSONType()))
+ t, err := dec.peekRuneType()
+ if err != nil {
+ return err
}
+ obj := val.Addr().Interface().(Decodable)
+ return dec.withLimitingScanner(func(l io.RuneScanner) *DecodeError {
+ if err := obj.DecodeJSON(l); err != nil {
+ return dec.newTypeError(t.JSONType(), reflect.PointerTo(typ), err)
+ }
+ if _, _, err := l.ReadRune(); err != io.EOF {
+ return dec.newTypeError(t.JSONType(), reflect.PointerTo(typ), fmt.Errorf("did not consume entire %s", t.JSONType()))
+ }
+ return nil
+ })
case val.CanAddr() && reflect.PointerTo(typ).Implements(jsonUnmarshalerType):
- t := dec.peekRuneType()
+ t, err := dec.peekRuneType()
+ if err != nil {
+ return err
+ }
var buf bytes.Buffer
- dec.scan(&buf)
+ if err := dec.scan(&buf); err != nil {
+ return err
+ }
obj := val.Addr().Interface().(jsonUnmarshaler)
if err := obj.UnmarshalJSON(buf.Bytes()); err != nil {
- dec.panicType(t.JSONType(), reflect.PointerTo(typ), err)
+ return dec.newTypeError(t.JSONType(), reflect.PointerTo(typ), err)
}
case val.CanAddr() && reflect.PointerTo(typ).Implements(textUnmarshalerType):
- if nullOK && dec.peekRuneType() == jsonparse.RuneTypeNullN {
- dec.decodeNull()
- return
+ if ok, err := dec.maybeDecodeNull(nullOK); ok {
+ return err
}
var buf bytes.Buffer
- dec.decodeString(reflect.PointerTo(typ), &buf)
+ if err := dec.decodeString(reflect.PointerTo(typ), &buf); err != nil {
+ return err
+ }
obj := val.Addr().Interface().(encoding.TextUnmarshaler)
if err := obj.UnmarshalText(buf.Bytes()); err != nil {
- dec.panicType("string", reflect.PointerTo(typ), err)
+ return dec.newTypeError("string", reflect.PointerTo(typ), err)
}
default:
switch kind := typ.Kind(); kind {
case reflect.Bool:
- if nullOK && dec.peekRuneType() == jsonparse.RuneTypeNullN {
- dec.decodeNull()
- return
+ if ok, err := dec.maybeDecodeNull(nullOK); ok {
+ return err
+ }
+ b, err := dec.decodeBool(typ)
+ if err != nil {
+ return err
}
- val.SetBool(dec.decodeBool(typ))
+ val.SetBool(b)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- if nullOK && dec.peekRuneType() == jsonparse.RuneTypeNullN {
- dec.decodeNull()
- return
+ if ok, err := dec.maybeDecodeNull(nullOK); ok {
+ return err
}
var buf strings.Builder
- dec.scanNumber(typ, &buf)
+ if err := dec.scanNumber(typ, &buf); err != nil {
+ return err
+ }
n, err := strconv.ParseInt(buf.String(), 10, kind2bits[kind])
if err != nil {
- dec.panicType("number "+buf.String(), typ, err)
+ return dec.newTypeError("number "+buf.String(), typ, err)
}
val.SetInt(n)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- if nullOK && dec.peekRuneType() == jsonparse.RuneTypeNullN {
- dec.decodeNull()
- return
+ if ok, err := dec.maybeDecodeNull(nullOK); ok {
+ return err
}
var buf strings.Builder
- dec.scanNumber(typ, &buf)
+ if err := dec.scanNumber(typ, &buf); err != nil {
+ return err
+ }
n, err := strconv.ParseUint(buf.String(), 10, kind2bits[kind])
if err != nil {
- dec.panicType("number "+buf.String(), typ, err)
+ return dec.newTypeError("number "+buf.String(), typ, err)
}
val.SetUint(n)
case reflect.Float32, reflect.Float64:
- if nullOK && dec.peekRuneType() == jsonparse.RuneTypeNullN {
- dec.decodeNull()
- return
+ if ok, err := dec.maybeDecodeNull(nullOK); ok {
+ return err
}
var buf strings.Builder
- dec.scanNumber(typ, &buf)
+ if err := dec.scanNumber(typ, &buf); err != nil {
+ return err
+ }
n, err := strconv.ParseFloat(buf.String(), kind2bits[kind])
if err != nil {
- dec.panicType("number "+buf.String(), typ, err)
+ return dec.newTypeError("number "+buf.String(), typ, err)
}
val.SetFloat(n)
case reflect.String:
- if nullOK && dec.peekRuneType() == jsonparse.RuneTypeNullN {
- dec.decodeNull()
- return
+ if ok, err := dec.maybeDecodeNull(nullOK); ok {
+ return err
}
var buf strings.Builder
if typ == numberType {
- t := dec.peekRuneType()
- dec.scan(&buf)
+ t, err := dec.peekRuneType()
+ if err != nil {
+ return err
+ }
+ if err := dec.scan(&buf); err != nil {
+ return err
+ }
if !t.IsNumber() {
- dec.panicType(t.JSONType(), typ,
+ return dec.newTypeError(t.JSONType(), typ,
fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number",
buf.String()))
}
val.SetString(buf.String())
} else {
- dec.decodeString(typ, &buf)
+ if err := dec.decodeString(typ, &buf); err != nil {
+ return err
+ }
val.SetString(buf.String())
}
case reflect.Interface:
+ t, err := dec.peekRuneType()
+ if err != nil {
+ return err
+ }
if typ.NumMethod() > 0 {
- dec.panicType(dec.peekRuneType().JSONType(), typ, ErrDecodeNonEmptyInterface)
+ return dec.newTypeError(t.JSONType(), typ, ErrDecodeNonEmptyInterface)
}
// If the interface stores a pointer, try to use the type information of the pointer.
if !val.IsNil() && val.Elem().Kind() == reflect.Pointer {
@@ -502,36 +547,43 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
// in the loop) because the only way it's possible is if there's
// an interface in there, which'd break from the loop on its own.
//
- // ptr.CanSet() || dec.peekRuneType() != jsonparse.RuneTypeNullN
+ // ptr.CanSet() || t != jsonparse.RuneTypeNullN
//
// We only need the pointer itself to be settable if we're
// decoding null.
- if ptr.Elem() != val && (ptr.CanSet() || dec.peekRuneType() != jsonparse.RuneTypeNullN) {
- dec.decode(ptr, false)
+ if ptr.Elem() != val && (ptr.CanSet() || t != jsonparse.RuneTypeNullN) {
+ if err := dec.decode(ptr, false); err != nil {
+ return err
+ }
break
}
}
// Couldn't get type information from a pointer; fall back to untyped mode.
- switch dec.peekRuneType() {
+ switch t {
case jsonparse.RuneTypeNullN:
- dec.decodeNull()
+ if err := dec.decodeNull(); err != nil {
+ return err
+ }
val.Set(reflect.Zero(typ))
default:
- val.Set(reflect.ValueOf(dec.decodeAny()))
+ v, err := dec.decodeAny()
+ if err != nil {
+ return err
+ }
+ val.Set(reflect.ValueOf(v))
}
case reflect.Struct:
- if nullOK && dec.peekRuneType() == jsonparse.RuneTypeNullN {
- dec.decodeNull()
- return
+ if ok, err := dec.maybeDecodeNull(nullOK); ok {
+ return err
}
index := jsonstruct.IndexStruct(typ)
var nameBuf strings.Builder
- dec.decodeObject(typ, func() {
+ return dec.decodeObject(typ, func() *DecodeError {
dec.posStackPush()
defer dec.posStackPop()
nameBuf.Reset()
- dec.decodeString(nil, &nameBuf)
- }, func() {
+ return dec.decodeString(nil, &nameBuf)
+ }, func() *DecodeError {
dec.posStackPush()
defer dec.posStackPop()
name := nameBuf.String()
@@ -549,21 +601,24 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
}
if !ok {
if dec.disallowUnknownFields {
- dec.panicType("", typ, fmt.Errorf("json: unknown field %q", name))
+ return dec.newTypeError("", typ, fmt.Errorf("json: unknown field %q", name))
}
- dec.scan(fastio.Discard)
- return
+ return dec.scan(fastio.Discard)
}
field := index.ByPos[idx]
fVal := val
for _, idx := range field.Path {
if fVal.Kind() == reflect.Pointer {
if fVal.IsNil() && !fVal.CanSet() { // https://golang.org/issue/21357
- dec.panicType("", fVal.Type().Elem(),
+ return dec.newTypeError("", fVal.Type().Elem(),
fmt.Errorf("json: cannot set embedded pointer to unexported struct: %v",
fVal.Type().Elem()))
}
- if dec.peekRuneType() != jsonparse.RuneTypeNullN {
+ t, err := dec.peekRuneType()
+ if err != nil {
+ return err
+ }
+ if t != jsonparse.RuneTypeNullN {
if fVal.IsNil() {
fVal.Set(reflect.New(fVal.Type().Elem()))
}
@@ -573,9 +628,15 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
fVal = fVal.Field(idx)
}
if field.Quote {
- switch t := dec.peekRuneType(); t {
+ t, err := dec.peekRuneType()
+ if err != nil {
+ return err
+ }
+ switch t {
case jsonparse.RuneTypeNullN:
- dec.decodeNull()
+ if err := dec.decodeNull(); err != nil {
+ return err
+ }
switch fVal.Kind() {
// XXX: I can't justify this list, other than "it's what encoding/json
// does, but I don't understand their rationale".
@@ -587,27 +648,36 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
case jsonparse.RuneTypeStringBeg:
// TODO: Figure out how to do this without buffering, have correct offsets.
var buf bytes.Buffer
- dec.decodeString(nil, &buf)
+ if err := dec.decodeString(nil, &buf); err != nil {
+ return err
+ }
if err := NewDecoder(bytes.NewReader(buf.Bytes())).Decode(fVal.Addr().Interface()); err != nil {
if str := buf.String(); str != "null" {
- dec.panicType("", fVal.Type(),
+ return dec.newTypeError("", fVal.Type(),
fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v",
str, fVal.Type()))
}
}
default:
- dec.panicType(t.JSONType(), fVal.Type(),
+ return dec.newTypeError(t.JSONType(), fVal.Type(),
fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal unquoted value into %v",
fVal.Type()))
}
+ return nil
} else {
- dec.decode(fVal, true)
+ return dec.decode(fVal, true)
}
})
case reflect.Map:
- switch t := dec.peekRuneType(); t {
+ t, err := dec.peekRuneType()
+ if err != nil {
+ return err
+ }
+ switch t {
case jsonparse.RuneTypeNullN:
- dec.decodeNull()
+ if err := dec.decodeNull(); err != nil {
+ return err
+ }
val.Set(reflect.Zero(typ))
case jsonparse.RuneTypeObjectBeg:
if val.IsNil() {
@@ -615,18 +685,20 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
}
var nameBuf bytes.Buffer
var nameValPtr reflect.Value
- dec.decodeObject(typ, func() {
+ return dec.decodeObject(typ, func() *DecodeError {
dec.posStackPush()
defer dec.posStackPop()
nameBuf.Reset()
- dec.decodeString(nil, &nameBuf)
+ if err := dec.decodeString(nil, &nameBuf); err != nil {
+ return err
+ }
nameValTyp := typ.Key()
nameValPtr = reflect.New(nameValTyp)
switch {
case reflect.PointerTo(nameValTyp).Implements(textUnmarshalerType):
obj := nameValPtr.Interface().(encoding.TextUnmarshaler)
if err := obj.UnmarshalText(nameBuf.Bytes()); err != nil {
- dec.panicType("string", reflect.PointerTo(nameValTyp), err)
+ return dec.newTypeError("string", reflect.PointerTo(nameValTyp), err)
}
default:
switch nameValTyp.Kind() {
@@ -635,53 +707,67 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
n, err := strconv.ParseInt(nameBuf.String(), 10, kind2bits[nameValTyp.Kind()])
if err != nil {
- dec.panicType("number "+nameBuf.String(), nameValTyp, err)
+ return dec.newTypeError("number "+nameBuf.String(), nameValTyp, err)
}
nameValPtr.Elem().SetInt(n)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
n, err := strconv.ParseUint(nameBuf.String(), 10, kind2bits[nameValTyp.Kind()])
if err != nil {
- dec.panicType("number "+nameBuf.String(), nameValTyp, err)
+ return dec.newTypeError("number "+nameBuf.String(), nameValTyp, err)
}
nameValPtr.Elem().SetUint(n)
default:
- dec.panicType("object", typ, &DecodeArgumentError{Type: nameValTyp})
+ return dec.newTypeError("object", typ, &DecodeArgumentError{Type: nameValTyp})
}
}
- }, func() {
+ return nil
+ }, func() *DecodeError {
dec.posStackPush()
defer dec.posStackPop()
dec.structStackPush(typ, nameValPtr.Elem())
defer dec.structStackPop()
fValPtr := reflect.New(typ.Elem())
- dec.decode(fValPtr.Elem(), false)
+ if err := dec.decode(fValPtr.Elem(), false); err != nil {
+ return err
+ }
val.SetMapIndex(nameValPtr.Elem(), fValPtr.Elem())
+ return nil
})
default:
- dec.panicType(t.JSONType(), typ, nil)
+ return dec.newTypeError(t.JSONType(), typ, nil)
}
case reflect.Slice:
+ t, err := dec.peekRuneType()
+ if err != nil {
+ return err
+ }
switch {
- case typ.Elem().Kind() == reflect.Uint8 && !(dec.peekRuneType() == jsonparse.RuneTypeArrayBeg && (false ||
+ case typ.Elem().Kind() == reflect.Uint8 && !(t == jsonparse.RuneTypeArrayBeg && (false ||
reflect.PointerTo(typ.Elem()).Implements(decodableType) ||
reflect.PointerTo(typ.Elem()).Implements(jsonUnmarshalerType) ||
reflect.PointerTo(typ.Elem()).Implements(textUnmarshalerType))):
- switch t := dec.peekRuneType(); t {
+ switch t {
case jsonparse.RuneTypeNullN:
- dec.decodeNull()
+ if err := dec.decodeNull(); err != nil {
+ return err
+ }
val.Set(reflect.Zero(typ))
case jsonparse.RuneTypeStringBeg:
if typ.Elem() == byteType {
var buf bytes.Buffer
- dec.decodeString(typ, base64dec.NewBase64Decoder(&buf))
+ if err := dec.decodeString(typ, base64dec.NewBase64Decoder(&buf)); err != nil {
+ return err
+ }
val.Set(reflect.ValueOf(buf.Bytes()))
} else {
// TODO: Surely there's a better way. At the very least, we should
// avoid buffering.
var buf bytes.Buffer
- dec.decodeString(typ, base64dec.NewBase64Decoder(&buf))
+ if err := dec.decodeString(typ, base64dec.NewBase64Decoder(&buf)); err != nil {
+ return err
+ }
bs := buf.Bytes()
val.Set(reflect.MakeSlice(typ, len(bs), len(bs)))
for i := 0; i < len(bs); i++ {
@@ -689,12 +775,14 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
}
}
default:
- dec.panicType(t.JSONType(), typ, nil)
+ return dec.newTypeError(t.JSONType(), typ, nil)
}
default:
- switch t := dec.peekRuneType(); t {
+ switch t {
case jsonparse.RuneTypeNullN:
- dec.decodeNull()
+ if err := dec.decodeNull(); err != nil {
+ return err
+ }
val.Set(reflect.Zero(typ))
case jsonparse.RuneTypeArrayBeg:
if val.IsNil() {
@@ -704,133 +792,177 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
val.Set(val.Slice(0, 0))
}
i := 0
- dec.decodeArray(typ, func() {
+ return dec.decodeArray(typ, func() *DecodeError {
dec.posStackPush()
defer dec.posStackPop()
dec.structStackPush(typ, i)
defer dec.structStackPop()
mValPtr := reflect.New(typ.Elem())
- dec.decode(mValPtr.Elem(), false)
+ if err := dec.decode(mValPtr.Elem(), false); err != nil {
+ return err
+ }
val.Set(reflect.Append(val, mValPtr.Elem()))
i++
+ return nil
})
default:
- dec.panicType(t.JSONType(), typ, nil)
+ return dec.newTypeError(t.JSONType(), typ, nil)
}
}
case reflect.Array:
- if nullOK && dec.peekRuneType() == jsonparse.RuneTypeNullN {
- dec.decodeNull()
- return
+ if ok, err := dec.maybeDecodeNull(nullOK); ok {
+ return err
}
i := 0
n := val.Len()
- dec.decodeArray(typ, func() {
+ if err := dec.decodeArray(typ, func() *DecodeError {
dec.posStackPush()
defer dec.posStackPop()
dec.structStackPush(typ, i)
defer dec.structStackPop()
if i < n {
mValPtr := reflect.New(typ.Elem())
- dec.decode(mValPtr.Elem(), false)
+ if err := dec.decode(mValPtr.Elem(), false); err != nil {
+ return err
+ }
val.Index(i).Set(mValPtr.Elem())
} else {
- dec.scan(fastio.Discard)
+ if err := dec.scan(fastio.Discard); err != nil {
+ return err
+ }
}
i++
- })
+ return nil
+ }); err != nil {
+ return err
+ }
for ; i < n; i++ {
val.Index(i).Set(reflect.Zero(typ.Elem()))
}
case reflect.Pointer:
- switch dec.peekRuneType() {
+ t, err := dec.peekRuneType()
+ if err != nil {
+ return err
+ }
+ switch t {
case jsonparse.RuneTypeNullN:
- dec.decodeNull()
+ if err := dec.decodeNull(); err != nil {
+ return err
+ }
val.Set(reflect.Zero(typ))
default:
if val.IsNil() {
val.Set(reflect.New(typ.Elem()))
}
- dec.decode(val.Elem(), false)
+ return dec.decode(val.Elem(), false)
}
default:
- dec.panicType("", typ, fmt.Errorf("unsupported type (kind=%v)", typ.Kind()))
+ return dec.newTypeError("", typ, fmt.Errorf("unsupported type (kind=%v)", typ.Kind()))
}
}
+ return nil
}
-func (dec *Decoder) scan(out fastio.RuneWriter) {
- limiter := dec.limitingScanner()
+func (dec *Decoder) scan(out fastio.RuneWriter) *DecodeError {
+ dec.io.PushReadBarrier()
for {
- c, _, err := limiter.ReadRune()
- if err == io.EOF {
- return
+ c, t, err := dec.readRune()
+ if err != nil {
+ return err
+ }
+ if t == jsonparse.RuneTypeEOF {
+ break
}
_, _ = out.WriteRune(c)
}
+ dec.io.PopReadBarrier()
+ return nil
}
-func (dec *Decoder) scanNumber(gTyp reflect.Type, out fastio.RuneWriter) {
- if t := dec.peekRuneType(); !t.IsNumber() {
- dec.panicType(t.JSONType(), gTyp, nil)
+func (dec *Decoder) scanNumber(gTyp reflect.Type, out fastio.RuneWriter) *DecodeError {
+ t, err := dec.peekRuneType()
+ if err != nil {
+ return err
+ }
+ if !t.IsNumber() {
+ return dec.newTypeError(t.JSONType(), gTyp, nil)
}
- dec.scan(out)
+ return dec.scan(out)
}
-func (dec *Decoder) decodeAny() any {
- c, _ := dec.readRune()
- dec.unreadRune()
- switch c {
- case '{':
+func (dec *Decoder) decodeAny() (any, *DecodeError) {
+ t, err := dec.peekRuneType()
+ if err != nil {
+ return nil, err
+ }
+ switch t {
+ case jsonparse.RuneTypeObjectBeg:
ret := make(map[string]any)
typ := reflect.TypeOf(ret)
var nameBuf strings.Builder
- dec.decodeObject(typ, func() {
+ if err := dec.decodeObject(typ, func() *DecodeError {
dec.posStackPush()
defer dec.posStackPop()
nameBuf.Reset()
- dec.decodeString(nil, &nameBuf)
- }, func() {
+ return dec.decodeString(nil, &nameBuf)
+ }, func() *DecodeError {
dec.posStackPush()
defer dec.posStackPop()
name := nameBuf.String()
dec.structStackPush(typ, name)
defer dec.structStackPop()
- ret[name] = dec.decodeAny()
- })
- return ret
- case '[':
+ v, err := dec.decodeAny()
+ if err != nil {
+ return err
+ }
+ ret[name] = v
+ return nil
+ }); err != nil {
+ return nil, err
+ }
+ return ret, nil
+ case jsonparse.RuneTypeArrayBeg:
ret := []any{}
typ := reflect.TypeOf(ret)
- dec.decodeArray(typ, func() {
+ if err := dec.decodeArray(typ, func() *DecodeError {
dec.posStackPush()
defer dec.posStackPop()
dec.structStackPush(typ, len(ret))
defer dec.structStackPop()
- ret = append(ret, dec.decodeAny())
- })
- return ret
- case '"':
+ v, err := dec.decodeAny()
+ if err != nil {
+ return err
+ }
+ ret = append(ret, v)
+ return nil
+ }); err != nil {
+ return nil, err
+ }
+ return ret, nil
+ case jsonparse.RuneTypeStringBeg:
var buf strings.Builder
- dec.decodeString(nil, &buf)
- return buf.String()
- case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+ if err := dec.decodeString(nil, &buf); err != nil {
+ return nil, err
+ }
+ return buf.String(), nil
+ case jsonparse.RuneTypeNumberIntNeg, jsonparse.RuneTypeNumberIntZero, jsonparse.RuneTypeNumberIntDig:
var buf strings.Builder
- dec.scan(&buf)
+ if err := dec.scan(&buf); err != nil {
+ return nil, err
+ }
num := Number(buf.String())
if dec.useNumber {
- return num
+ return num, nil
}
f64, err := num.Float64()
if err != nil {
- dec.panicType("number "+buf.String(), float64Type, err)
+ return nil, dec.newTypeError("number "+buf.String(), float64Type, err)
}
- return f64
- case 't', 'f':
+ return f64, nil
+ case jsonparse.RuneTypeTrueT, jsonparse.RuneTypeFalseF:
return dec.decodeBool(nil)
- case 'n':
- dec.decodeNull()
- return nil
+ case jsonparse.RuneTypeNullN:
+ return nil, dec.decodeNull()
default:
panic("should not happen")
}
@@ -844,17 +976,7 @@ func (dec *Decoder) decodeAny() any {
// Outside of implementing Decodable.DecodeJSON methods, callers
// should instead simply use NewDecoder(r).Decode(&val) rather than
// attempting to call DecodeObject directly.
-func DecodeObject(r io.RuneScanner, decodeKey, decodeVal func(io.RuneScanner) error) (err error) {
- defer func() {
- if r := recover(); r != nil {
- if de, ok := r.(decodeError); ok {
- pub := DecodeError(de)
- err = &pub
- } else {
- panic(r)
- }
- }
- }()
+func DecodeObject(r io.RuneScanner, decodeKey, decodeVal func(io.RuneScanner) error) error {
var dec *Decoder
if dr, ok := r.(*decRuneScanner); ok {
dec = dr.dec
@@ -863,56 +985,81 @@ func DecodeObject(r io.RuneScanner, decodeKey, decodeVal func(io.RuneScanner) er
}
dec.posStackPush()
defer dec.posStackPop()
- dec.decodeObject(nil,
- func() {
+ if err := dec.decodeObject(nil,
+ func() *DecodeError {
dec.posStackPush()
defer dec.posStackPop()
- l := dec.limitingScanner()
- if err := decodeKey(l); err != nil {
- // TODO: Find a better Go type to use than `nil`.
- dec.panicType("string", nil, err)
- }
- if _, _, err := l.ReadRune(); err != io.EOF {
- // TODO: Find a better Go type to use than `nil`.
- dec.panicType("string", nil, fmt.Errorf("did not consume entire string"))
- }
+ return dec.withLimitingScanner(func(l io.RuneScanner) *DecodeError {
+ if err := decodeKey(l); err != nil {
+ // TODO: Find a better Go type to use than `nil`.
+ return dec.newTypeError("string", nil, err)
+ }
+ if _, _, err := l.ReadRune(); err != io.EOF {
+ // TODO: Find a better Go type to use than `nil`.
+ return dec.newTypeError("string", nil, fmt.Errorf("did not consume entire string"))
+ }
+ return nil
+ })
},
- func() {
+ func() *DecodeError {
dec.posStackPush()
defer dec.posStackPop()
- t := dec.peekRuneType()
- l := dec.limitingScanner()
- if err := decodeVal(l); err != nil {
- // TODO: Find a better Go type to use than `nil`.
- dec.panicType(t.JSONType(), nil, err)
- }
- if _, _, err := l.ReadRune(); err != io.EOF {
- // TODO: Find a better Go type to use than `nil`.
- dec.panicType(t.JSONType(), nil, fmt.Errorf("did not consume entire %s", t.JSONType()))
+ t, err := dec.peekRuneType()
+ if err != nil {
+ return err
}
- })
+ return dec.withLimitingScanner(func(l io.RuneScanner) *DecodeError {
+ if err := decodeVal(l); err != nil {
+ // TODO: Find a better Go type to use than `nil`.
+ return dec.newTypeError(t.JSONType(), nil, err)
+ }
+ if _, _, err := l.ReadRune(); err != io.EOF {
+ // TODO: Find a better Go type to use than `nil`.
+ return dec.newTypeError(t.JSONType(), nil, fmt.Errorf("did not consume entire %s", t.JSONType()))
+ }
+ return nil
+ })
+ }); err != nil {
+ return err
+ }
return nil
}
-func (dec *Decoder) decodeObject(gTyp reflect.Type, decodeKey, decodeVal func()) {
- dec.expectRuneType('{', jsonparse.RuneTypeObjectBeg, gTyp)
- _, t := dec.readRune()
+func (dec *Decoder) decodeObject(gTyp reflect.Type, decodeKey, decodeVal func() *DecodeError) *DecodeError {
+ if err := dec.expectRuneType('{', jsonparse.RuneTypeObjectBeg, gTyp); err != nil {
+ return err
+ }
+ _, t, err := dec.readRune()
+ if err != nil {
+ return err
+ }
switch t {
case jsonparse.RuneTypeObjectEnd:
- return
+ return nil
case jsonparse.RuneTypeStringBeg:
decodeMember:
dec.unreadRune()
- decodeKey()
- dec.expectRune(':', jsonparse.RuneTypeObjectColon)
- decodeVal()
- _, t := dec.readRune()
+ if err := decodeKey(); err != nil {
+ return err
+ }
+ if err := dec.expectRune(':', jsonparse.RuneTypeObjectColon); err != nil {
+ return err
+ }
+ if err := decodeVal(); err != nil {
+ return err
+ }
+ _, t, err := dec.readRune()
+ if err != nil {
+ return err
+ }
switch t {
case jsonparse.RuneTypeObjectComma:
- dec.expectRune('"', jsonparse.RuneTypeStringBeg)
+ if err := dec.expectRune('"', jsonparse.RuneTypeStringBeg); err != nil {
+ return err
+ }
goto decodeMember
case jsonparse.RuneTypeObjectEnd:
- return
+ return nil
default:
panic("should not happen")
}
@@ -929,17 +1076,7 @@ func (dec *Decoder) decodeObject(gTyp reflect.Type, decodeKey, decodeVal func())
// Outside of implementing Decodable.DecodeJSON methods, callers
// should instead simply use NewDecoder(r).Decode(&val) rather than
// attempting to call DecodeArray directly.
-func DecodeArray(r io.RuneScanner, decodeMember func(r io.RuneScanner) error) (err error) {
- defer func() {
- if r := recover(); r != nil {
- if de, ok := r.(decodeError); ok {
- pub := DecodeError(de)
- err = &pub
- } else {
- panic(r)
- }
- }
- }()
+func DecodeArray(r io.RuneScanner, decodeMember func(r io.RuneScanner) error) error {
var dec *Decoder
if dr, ok := r.(*decRuneScanner); ok {
dec = dr.dec
@@ -948,50 +1085,72 @@ func DecodeArray(r io.RuneScanner, decodeMember func(r io.RuneScanner) error) (e
}
dec.posStackPush()
defer dec.posStackPop()
- dec.decodeArray(nil, func() {
+ if err := dec.decodeArray(nil, func() *DecodeError {
dec.posStackPush()
defer dec.posStackPop()
- t := dec.peekRuneType()
- l := dec.limitingScanner()
- if err := decodeMember(l); err != nil {
- // TODO: Find a better Go type to use than `nil`.
- dec.panicType(t.JSONType(), nil, err)
- }
- if _, _, err := l.ReadRune(); err != io.EOF {
- // TODO: Find a better Go type to use than `nil`.
- dec.panicType(t.JSONType(), nil, fmt.Errorf("did not consume entire %s", t.JSONType()))
+ t, err := dec.peekRuneType()
+ if err != nil {
+ return err
}
- })
+ return dec.withLimitingScanner(func(l io.RuneScanner) *DecodeError {
+ if err := decodeMember(l); err != nil {
+ // TODO: Find a better Go type to use than `nil`.
+ return dec.newTypeError(t.JSONType(), nil, err)
+ }
+ if _, _, err := l.ReadRune(); err != io.EOF {
+ // TODO: Find a better Go type to use than `nil`.
+ return dec.newTypeError(t.JSONType(), nil, fmt.Errorf("did not consume entire %s", t.JSONType()))
+ }
+ return nil
+ })
+ }); err != nil {
+ return err
+ }
return nil
}
-func (dec *Decoder) decodeArray(gTyp reflect.Type, decodeMember func()) {
- dec.expectRuneType('[', jsonparse.RuneTypeArrayBeg, gTyp)
- _, t := dec.readRune()
+func (dec *Decoder) decodeArray(gTyp reflect.Type, decodeMember func() *DecodeError) *DecodeError {
+ if err := dec.expectRuneType('[', jsonparse.RuneTypeArrayBeg, gTyp); err != nil {
+ return err
+ }
+ _, t, err := dec.readRune()
+ if err != nil {
+ return err
+ }
switch t {
case jsonparse.RuneTypeArrayEnd:
- return
+ return nil
default:
dec.unreadRune()
decodeNextMember:
- decodeMember()
- _, t := dec.readRune()
+ if err := decodeMember(); err != nil {
+ return err
+ }
+ _, t, err := dec.readRune()
+ if err != nil {
+ return err
+ }
switch t {
case jsonparse.RuneTypeArrayComma:
goto decodeNextMember
case jsonparse.RuneTypeArrayEnd:
- return
+ return nil
default:
panic("should not happen")
}
}
}
-func (dec *Decoder) decodeString(gTyp reflect.Type, out fastio.RuneWriter) {
- dec.expectRuneType('"', jsonparse.RuneTypeStringBeg, gTyp)
+func (dec *Decoder) decodeString(gTyp reflect.Type, out fastio.RuneWriter) *DecodeError {
+ if err := dec.expectRuneType('"', jsonparse.RuneTypeStringBeg, gTyp); err != nil {
+ return err
+ }
var uhex [4]byte
for {
- c, t := dec.readRune()
+ c, t, err := dec.readRune()
+ if err != nil {
+ return err
+ }
switch t {
case jsonparse.RuneTypeStringChar:
_, _ = out.WriteRune(c)
@@ -1033,24 +1192,48 @@ func (dec *Decoder) decodeString(gTyp reflect.Type, out fastio.RuneWriter) {
rune(uhex[3])<<0
handleUnicode:
if utf16.IsSurrogate(c) {
- if dec.peekRuneType() != jsonparse.RuneTypeStringEsc {
+ t, err := dec.peekRuneType()
+ if err != nil {
+ return err
+ }
+ if t != jsonparse.RuneTypeStringEsc {
_, _ = out.WriteRune(utf8.RuneError)
break
}
- dec.expectRune('\\', jsonparse.RuneTypeStringEsc)
- if dec.peekRuneType() != jsonparse.RuneTypeStringEscU {
+ if err := dec.expectRune('\\', jsonparse.RuneTypeStringEsc); err != nil {
+ return err
+ }
+ t, err = dec.peekRuneType()
+ if err != nil {
+ return err
+ }
+ if t != jsonparse.RuneTypeStringEscU {
_, _ = out.WriteRune(utf8.RuneError)
break
}
- dec.expectRune('u', jsonparse.RuneTypeStringEscU)
+ if err := dec.expectRune('u', jsonparse.RuneTypeStringEscU); err != nil {
+ return err
+ }
- b, _ := dec.readRune()
+ b, _, err := dec.readRune()
+ if err != nil {
+ return err
+ }
uhex[0], _ = jsonparse.HexToInt(b)
- b, _ = dec.readRune()
+ b, _, err = dec.readRune()
+ if err != nil {
+ return err
+ }
uhex[1], _ = jsonparse.HexToInt(b)
- b, _ = dec.readRune()
+ b, _, err = dec.readRune()
+ if err != nil {
+ return err
+ }
uhex[2], _ = jsonparse.HexToInt(b)
- b, _ = dec.readRune()
+ b, _, err = dec.readRune()
+ if err != nil {
+ return err
+ }
uhex[3], _ = jsonparse.HexToInt(b)
c2 := 0 |
rune(uhex[0])<<12 |
@@ -1068,36 +1251,74 @@ func (dec *Decoder) decodeString(gTyp reflect.Type, out fastio.RuneWriter) {
_, _ = out.WriteRune(c)
}
case jsonparse.RuneTypeStringEnd:
- return
+ return nil
default:
panic("should not happen")
}
}
}
-func (dec *Decoder) decodeBool(gTyp reflect.Type) bool {
- c, t := dec.readRune()
+func (dec *Decoder) decodeBool(gTyp reflect.Type) (bool, *DecodeError) {
+ c, t, err := dec.readRune()
+ if err != nil {
+ return false, err
+ }
switch c {
case 't':
- dec.expectRune('r', jsonparse.RuneTypeTrueR)
- dec.expectRune('u', jsonparse.RuneTypeTrueU)
- dec.expectRune('e', jsonparse.RuneTypeTrueE)
- return true
+ if err := dec.expectRune('r', jsonparse.RuneTypeTrueR); err != nil {
+ return false, err
+ }
+ if err := dec.expectRune('u', jsonparse.RuneTypeTrueU); err != nil {
+ return false, err
+ }
+ if err := dec.expectRune('e', jsonparse.RuneTypeTrueE); err != nil {
+ return false, err
+ }
+ return true, nil
case 'f':
- dec.expectRune('a', jsonparse.RuneTypeFalseA)
- dec.expectRune('l', jsonparse.RuneTypeFalseL)
- dec.expectRune('s', jsonparse.RuneTypeFalseS)
- dec.expectRune('e', jsonparse.RuneTypeFalseE)
- return false
+ if err := dec.expectRune('a', jsonparse.RuneTypeFalseA); err != nil {
+ return false, err
+ }
+ if err := dec.expectRune('l', jsonparse.RuneTypeFalseL); err != nil {
+ return false, err
+ }
+ if err := dec.expectRune('s', jsonparse.RuneTypeFalseS); err != nil {
+ return false, err
+ }
+ if err := dec.expectRune('e', jsonparse.RuneTypeFalseE); err != nil {
+ return false, err
+ }
+ return false, nil
default:
- dec.panicType(t.JSONType(), gTyp, nil)
- panic("not reached")
+ return false, dec.newTypeError(t.JSONType(), gTyp, nil)
}
}
-func (dec *Decoder) decodeNull() {
- dec.expectRune('n', jsonparse.RuneTypeNullN)
- dec.expectRune('u', jsonparse.RuneTypeNullU)
- dec.expectRune('l', jsonparse.RuneTypeNullL1)
- dec.expectRune('l', jsonparse.RuneTypeNullL2)
+func (dec *Decoder) decodeNull() *DecodeError {
+ if err := dec.expectRune('n', jsonparse.RuneTypeNullN); err != nil {
+ return err
+ }
+ if err := dec.expectRune('u', jsonparse.RuneTypeNullU); err != nil {
+ return err
+ }
+ if err := dec.expectRune('l', jsonparse.RuneTypeNullL1); err != nil {
+ return err
+ }
+ if err := dec.expectRune('l', jsonparse.RuneTypeNullL2); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (dec *Decoder) maybeDecodeNull(nullOK bool) (ok bool, err *DecodeError) {
+ if nullOK {
+ t, err := dec.peekRuneType()
+ if err != nil {
+ return true, err
+ }
+ if t == jsonparse.RuneTypeNullN {
+ return true, dec.decodeNull()
+ }
+ }
+ return false, nil
}