summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@lukeshu.com>2023-02-23 22:08:27 -0700
committerLuke Shumaker <lukeshu@lukeshu.com>2023-02-25 01:18:12 -0700
commita4ffa83919375653415b670fdbf136e29c1b1c2c (patch)
treec2c0dd1bbf549087cab5f0a688e98314177ea9b2
parent03778c094d995791f6c3df08afeeb792f33f35a5 (diff)
compat/json: Unify the error conversion
-rw-r--r--compat/json/compat.go168
1 files changed, 93 insertions, 75 deletions
diff --git a/compat/json/compat.go b/compat/json/compat.go
index 695c1a8..c2d47c0 100644
--- a/compat/json/compat.go
+++ b/compat/json/compat.go
@@ -40,22 +40,100 @@ type (
// MarshalerError = json.MarshalerError // Duplicated to access a private field.
)
-// Encode wrappers ///////////////////////////////////////////////////
+// Error conversion //////////////////////////////////////////////////
-func convertEncodeError(err error) error {
- if me, ok := err.(*lowmemjson.EncodeMethodError); ok {
- err = &MarshalerError{
- Type: me.Type,
- Err: me.Err,
- sourceFunc: me.SourceFunc,
+func convertError(err error, isUnmarshal bool) error {
+ switch err := err.(type) {
+ case nil:
+ return nil
+ case *lowmemjson.DecodeArgumentError:
+ return err
+ case *lowmemjson.DecodeError:
+ switch suberr := err.Err.(type) {
+ case *lowmemjson.DecodeReadError:
+ return err
+ case *lowmemjson.DecodeSyntaxError:
+ switch {
+ case errors.Is(err, io.EOF):
+ return io.EOF
+ case errors.Is(err, io.ErrUnexpectedEOF) && isUnmarshal:
+ return &SyntaxError{
+ msg: "unexpected end of JSON input",
+ Offset: suberr.Offset,
+ }
+ default:
+ return &SyntaxError{
+ msg: suberr.Err.Error(),
+ Offset: suberr.Offset + 1,
+ }
+ }
+ case *lowmemjson.DecodeTypeError:
+ switch subsuberr := suberr.Err.(type) {
+ case *UnmarshalTypeError:
+ // Populate the .Struct and .Field members.
+ subsuberr.Struct = err.FieldParent
+ subsuberr.Field = err.FieldName
+ return subsuberr
+ default:
+ switch {
+ case errors.Is(err, lowmemjson.ErrDecodeNonEmptyInterface),
+ errors.Is(err, strconv.ErrSyntax),
+ errors.Is(err, strconv.ErrRange):
+ return &UnmarshalTypeError{
+ Value: suberr.JSONType,
+ Type: suberr.GoType,
+ Offset: suberr.Offset,
+ Struct: err.FieldParent,
+ Field: err.FieldName,
+ }
+ default:
+ return subsuberr
+ }
+ case nil, *lowmemjson.DecodeArgumentError:
+ return &UnmarshalTypeError{
+ Value: suberr.JSONType,
+ Type: suberr.GoType,
+ Offset: suberr.Offset,
+ Struct: err.FieldParent,
+ Field: err.FieldName,
+ }
+ }
+ default:
+ panic(fmt.Errorf("should not happen: unexpected lowmemjson.DecodeError sub-type: %T: %w", suberr, err))
+ }
+ case *lowmemjson.EncodeWriteError:
+ return err
+ case *lowmemjson.EncodeTypeError:
+ return err
+ case *lowmemjson.EncodeValueError:
+ return err
+ case *lowmemjson.EncodeMethodError:
+ return &MarshalerError{
+ Type: err.Type,
+ Err: err.Err,
+ sourceFunc: err.SourceFunc,
+ }
+ case *lowmemjson.ReEncodeWriteError:
+ return err
+ case *lowmemjson.ReEncodeSyntaxError:
+ ret := &SyntaxError{
+ msg: err.Err.Error(),
+ Offset: err.Offset + 1,
}
+ if errors.Is(err, io.ErrUnexpectedEOF) {
+ ret.msg = "unexpected end of JSON input"
+ }
+ return ret
+ default:
+ panic(fmt.Errorf("should not happen: unexpected lowmemjson error type: %T: %w", err, err))
}
- return err
}
+// Encode wrappers ///////////////////////////////////////////////////
+
func marshal(v any, cfg lowmemjson.ReEncoderConfig) ([]byte, error) {
var buf bytes.Buffer
- if err := convertEncodeError(lowmemjson.NewEncoder(lowmemjson.NewReEncoder(&buf, cfg)).Encode(v)); err != nil {
+ if err := convertError(lowmemjson.NewEncoder(lowmemjson.NewReEncoder(&buf, cfg)).Encode(v), false); err != nil {
return nil, err
}
return buf.Bytes(), nil
@@ -105,7 +183,7 @@ func (enc *Encoder) refreshConfig() {
}
func (enc *Encoder) Encode(v any) error {
- if err := convertEncodeError(enc.encoder.Encode(v)); err != nil {
+ if err := convertError(enc.encoder.Encode(v), false); err != nil {
enc.buf.Reset()
return err
}
@@ -133,19 +211,6 @@ func (enc *Encoder) SetIndent(prefix, indent string) {
// ReEncode wrappers /////////////////////////////////////////////////
-func convertReEncodeError(err error) error {
- if se, ok := err.(*lowmemjson.ReEncodeSyntaxError); ok {
- err = &SyntaxError{
- msg: se.Err.Error(),
- Offset: se.Offset + 1,
- }
- if errors.Is(se.Err, io.ErrUnexpectedEOF) {
- err.(*SyntaxError).msg = "unexpected end of JSON input"
- }
- }
- return err
-}
-
func HTMLEscape(dst *bytes.Buffer, src []byte) {
for n := 0; n < len(src); {
c, size := utf8.DecodeRune(src[n:])
@@ -172,7 +237,7 @@ func reencode(dst io.Writer, src []byte, cfg lowmemjson.ReEncoderConfig) error {
if err == nil {
err = formatter.Close()
}
- return convertReEncodeError(err)
+ return convertError(err, false)
}
func Compact(dst *bytes.Buffer, src []byte) error {
@@ -237,53 +302,6 @@ func Valid(data []byte) bool {
// Decode wrappers ///////////////////////////////////////////////////
-func convertDecodeError(err error, isUnmarshal bool) error {
- if derr, ok := err.(*lowmemjson.DecodeError); ok {
- switch terr := derr.Err.(type) {
- case *lowmemjson.DecodeSyntaxError:
- switch {
- case errors.Is(terr.Err, io.EOF):
- err = io.EOF
- case errors.Is(terr.Err, io.ErrUnexpectedEOF) && isUnmarshal:
- err = &SyntaxError{
- msg: "unexpected end of JSON input",
- Offset: terr.Offset,
- }
- default:
- err = &SyntaxError{
- msg: terr.Err.Error(),
- Offset: terr.Offset + 1,
- }
- }
- case *lowmemjson.DecodeTypeError:
- if typeErr, ok := terr.Err.(*json.UnmarshalTypeError); ok {
- err = &UnmarshalTypeError{
- Value: typeErr.Value,
- Type: typeErr.Type,
- Offset: typeErr.Offset,
- Struct: derr.FieldParent,
- Field: derr.FieldName,
- }
- } else if _, isArgErr := terr.Err.(*lowmemjson.DecodeArgumentError); terr.Err != nil &&
- !isArgErr &&
- !errors.Is(terr.Err, lowmemjson.ErrDecodeNonEmptyInterface) &&
- !errors.Is(terr.Err, strconv.ErrSyntax) &&
- !errors.Is(terr.Err, strconv.ErrRange) {
- err = terr.Err
- } else {
- err = &UnmarshalTypeError{
- Value: terr.JSONType,
- Type: terr.GoType,
- Offset: terr.Offset,
- Struct: derr.FieldParent,
- Field: derr.FieldName,
- }
- }
- }
- }
- return err
-}
-
type decodeValidator struct{}
func (*decodeValidator) DecodeJSON(r io.RuneScanner) error {
@@ -301,10 +319,10 @@ func (*decodeValidator) DecodeJSON(r io.RuneScanner) error {
var _ lowmemjson.Decodable = (*decodeValidator)(nil)
func Unmarshal(data []byte, ptr any) error {
- if err := convertDecodeError(lowmemjson.NewDecoder(bytes.NewReader(data)).DecodeThenEOF(&decodeValidator{}), true); err != nil {
+ if err := convertError(lowmemjson.NewDecoder(bytes.NewReader(data)).DecodeThenEOF(&decodeValidator{}), true); err != nil {
return err
}
- if err := convertDecodeError(lowmemjson.NewDecoder(bytes.NewReader(data)).DecodeThenEOF(ptr), true); err != nil {
+ if err := convertError(lowmemjson.NewDecoder(bytes.NewReader(data)).DecodeThenEOF(ptr), true); err != nil {
return err
}
return nil
@@ -363,10 +381,10 @@ func NewDecoder(r io.Reader) *Decoder {
}
func (dec *Decoder) Decode(ptr any) error {
- if err := convertDecodeError(dec.validator.Decode(&decodeValidator{}), false); err != nil {
+ if err := convertError(dec.validator.Decode(&decodeValidator{}), false); err != nil {
return err
}
- if err := convertDecodeError(dec.Decoder.Decode(ptr), false); err != nil {
+ if err := convertError(dec.Decoder.Decode(ptr), false); err != nil {
return err
}
return nil