summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@lukeshu.com>2023-01-30 14:50:47 -0700
committerLuke Shumaker <lukeshu@lukeshu.com>2023-02-10 21:55:49 -0700
commit276ab5935873edc05e1882c06fc527a14babd27c (patch)
treeba9ec20307b4200f1010bc291d78c3786b57e326
parentc604347f1950e3dfbef2f524da8a63692848da27 (diff)
encoder, reencoder: Distinguish between syntax errors and I/O errors
-rw-r--r--ReleaseNotes.md7
-rw-r--r--encode.go6
-rw-r--r--errors.go24
-rw-r--r--reencode.go12
4 files changed, 46 insertions, 3 deletions
diff --git a/ReleaseNotes.md b/ReleaseNotes.md
index 9974f0e..e00bf10 100644
--- a/ReleaseNotes.md
+++ b/ReleaseNotes.md
@@ -8,6 +8,13 @@
a user of lowmemjson's native APIs does not need to import
`encoding/json` or compat/json in order to use them.
+ - Encoder, ReEncoder: If there was an error writing to the output
+ stream, it may have returned a `*ReEncodeSyntaxError` even though
+ it's not a syntax issue, or may have returned the underlying
+ error without wrapping it. If there is an error writing to the
+ output, Encoder and ReEncoder now return `*EncodeWriteError` and
+ `*ReEncodeWriteError` respectively.
+
# v0.3.5 (2023-02-10)
Theme: Compatibility bugfixes
diff --git a/encode.go b/encode.go
index b6541cd..d39c862 100644
--- a/encode.go
+++ b/encode.go
@@ -83,6 +83,12 @@ func (enc *Encoder) Encode(obj any) (err error) {
enc.w.par.Reset()
}
if err := encode(enc.w, reflect.ValueOf(obj), enc.w.BackslashEscape, false, 0, map[any]struct{}{}); err != nil {
+ if rwe, ok := err.(*ReEncodeWriteError); ok {
+ err = &EncodeWriteError{
+ Err: rwe.Err,
+ Offset: rwe.Offset,
+ }
+ }
return err
}
if enc.isRoot {
diff --git a/errors.go b/errors.go
index 0a47db4..516018c 100644
--- a/errors.go
+++ b/errors.go
@@ -121,6 +121,18 @@ func (e *DecodeError) Unwrap() error { return e.Err }
// encode errors ///////////////////////////////////////////////////////////////////////////////////
+// A EncodeWriteError is returned from Encode if there is an error
+// writing to the output stream.
+type EncodeWriteError struct {
+ Err error
+ Offset int64
+}
+
+func (e *EncodeWriteError) Error() string {
+ return fmt.Sprintf("json: I/O error at output byte %v: %v", e.Offset, e.Err)
+}
+func (e *EncodeWriteError) Unwrap() error { return e.Err }
+
// An EncodeTypeError is returned by Encode when attempting to encode
// an unsupported type.
//
@@ -155,6 +167,18 @@ func (e *EncodeMethodError) Unwrap() error { return e.Err }
// reencode errors /////////////////////////////////////////////////////////////////////////////////
+// A ReEncodeWriteError is returned from ReEncoder's methods if there
+// is an error writing to the output stream.
+type ReEncodeWriteError struct {
+ Err error
+ Offset int64
+}
+
+func (e *ReEncodeWriteError) Error() string {
+ return fmt.Sprintf("json: I/O error at output byte %v: %v", e.Offset, e.Err)
+}
+func (e *ReEncodeWriteError) Unwrap() error { return e.Err }
+
// A ReEncodeSyntaxError is returned from ReEncoder's methods if there
// is a syntax error in the input.
type ReEncodeSyntaxError struct {
diff --git a/reencode.go b/reencode.go
index e48c58c..d19dc1a 100644
--- a/reencode.go
+++ b/reencode.go
@@ -232,7 +232,7 @@ func (enc *ReEncoder) Close() error {
}
if len(enc.barriers) == 0 {
if err := enc.handleRune(0, jsonparse.RuneTypeError, enc.stackSize()); err != nil {
- enc.err = &ReEncodeSyntaxError{
+ enc.err = &ReEncodeWriteError{
Err: err,
Offset: enc.inputPos,
}
@@ -274,8 +274,14 @@ rehandle:
}
return enc.written, enc.err
}
- enc.err = enc.handleRune(c, t, enc.stackSize())
- if enc.err == nil && t == jsonparse.RuneTypeEOF {
+ if err := enc.handleRune(c, t, enc.stackSize()); err != nil {
+ enc.err = &ReEncodeWriteError{
+ Err: err,
+ Offset: enc.inputPos,
+ }
+ return enc.written, enc.err
+ }
+ if t == jsonparse.RuneTypeEOF {
if enc.AllowMultipleValues && len(enc.barriers) == 0 {
enc.par.Reset()
goto rehandle