diff options
author | Luke Shumaker <lukeshu@lukeshu.com> | 2023-02-10 21:52:34 -0700 |
---|---|---|
committer | Luke Shumaker <lukeshu@lukeshu.com> | 2023-02-10 21:52:34 -0700 |
commit | cf8f8527e968c448995bdcaaad9c4351d3a2ab3f (patch) | |
tree | d228bb78a08586cab74e0a3df292fa8e9c266f90 /decode.go | |
parent | 95180a90db47990d32104ff7ab103e4862fd8426 (diff) | |
parent | dadafd9cfabbea5555c404b339bbf44252ee7e6b (diff) |
Merge branch 'lukeshu/decode-no-panic'
Diffstat (limited to 'decode.go')
-rw-r--r-- | decode.go | 775 |
1 files changed, 498 insertions, 277 deletions
@@ -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 } |