summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@lukeshu.com>2022-07-31 01:36:16 -0600
committerLuke Shumaker <lukeshu@lukeshu.com>2022-07-31 01:40:36 -0600
commit326319cff84557e522b2ea8b21755b22764e85af (patch)
treebe2fd3eafaa17ebbfeb184974e28b9626dfe514f
parent128959707364340c942399283b15b5025d9aaa70 (diff)
have reencoder.WriteRune return the number of bytes written to output
-rw-r--r--lib/lowmemjson/encode.go2
-rw-r--r--lib/lowmemjson/misc.go15
-rw-r--r--lib/lowmemjson/reencode.go110
3 files changed, 68 insertions, 59 deletions
diff --git a/lib/lowmemjson/encode.go b/lib/lowmemjson/encode.go
index 3f671ea..329f6c2 100644
--- a/lib/lowmemjson/encode.go
+++ b/lib/lowmemjson/encode.go
@@ -282,7 +282,7 @@ func encodeString[T interface{ ~[]byte | ~string }](w io.Writer, str T) {
encodeWriteByte(w, '"')
for i := 0; i < len(str); {
c, size := decodeRune(str[i:])
- if err := writeStringChar(w, c, false, nil); err != nil {
+ if _, err := writeStringChar(w, c, false, nil); err != nil {
panic(encodeError{err})
}
i += size
diff --git a/lib/lowmemjson/misc.go b/lib/lowmemjson/misc.go
index d1f8f25..b9dbb9b 100644
--- a/lib/lowmemjson/misc.go
+++ b/lib/lowmemjson/misc.go
@@ -82,7 +82,7 @@ func UnicodeEscapeDefault(c rune, wasEscaped bool) bool {
}
}
-func writeStringUnicodeEscape(w io.Writer, c rune) error {
+func writeStringUnicodeEscape(w io.Writer, c rune) (int, error) {
buf := [6]byte{
'\\',
'u',
@@ -91,15 +91,13 @@ func writeStringUnicodeEscape(w io.Writer, c rune) error {
hex[(c>>4)&0xf],
hex[(c>>0)&0xf],
}
- _, err := w.Write(buf[:])
- return err
+ return w.Write(buf[:])
}
-func writeStringShortEscape(w io.Writer, c byte) error {
+func writeStringShortEscape(w io.Writer, c byte) (int, error) {
buf := [2]byte{'\\', c}
- _, err := w.Write(buf[:])
- return err
+ return w.Write(buf[:])
}
-func writeStringChar(w io.Writer, c rune, wasEscaped bool, escaper func(rune, bool) bool) error {
+func writeStringChar(w io.Writer, c rune, wasEscaped bool, escaper func(rune, bool) bool) (int, error) {
if escaper == nil {
escaper = UnicodeEscapeDefault
}
@@ -124,7 +122,6 @@ func writeStringChar(w io.Writer, c rune, wasEscaped bool, escaper func(rune, bo
return writeStringUnicodeEscape(w, c)
}
default:
- _, err := writeRune(w, c)
- return err
+ return writeRune(w, c)
}
}
diff --git a/lib/lowmemjson/reencode.go b/lib/lowmemjson/reencode.go
index 721b0b9..836c5f6 100644
--- a/lib/lowmemjson/reencode.go
+++ b/lib/lowmemjson/reencode.go
@@ -37,6 +37,7 @@ type ReEncoder struct {
// state: .WriteRune
err error
+ written int
stack []reencodeState
stack0IsNumber bool
curIndent int
@@ -57,13 +58,13 @@ func (enc *ReEncoder) Write(p []byte) (int, error) {
c, size := utf8.DecodeRune(enc.buf[:])
n += size - enc.bufLen
enc.bufLen = 0
- if err := enc.WriteRune(c); err != nil {
+ if _, err := enc.WriteRune(c); err != nil {
return 0, err
}
}
for utf8.FullRune(p[n:]) {
c, size := utf8.DecodeRune(p[n:])
- if err := enc.WriteRune(c); err != nil {
+ if _, err := enc.WriteRune(c); err != nil {
return n, err
}
n += size
@@ -90,37 +91,48 @@ func (enc *ReEncoder) Flush() error {
}
}
-func (enc *ReEncoder) WriteRune(c rune) (err error) {
+func (enc *ReEncoder) WriteRune(c rune) (n int, err error) {
if enc.err != nil {
- return enc.err
+ return 0, enc.err
}
- defer func() {
- if err != nil {
- enc.err = err
- }
- }()
if enc.bufLen != 0 {
- return errors.New("lowmemjson.ReEncoder: cannot .WriteRune() when there is a partial rune that has been .Write()n")
+ enc.err = errors.New("lowmemjson.ReEncoder: cannot .WriteRune() when there is a partial rune that has been .Write()n")
+ return 0, enc.err
}
- return enc.state(c)
+ enc.written = 0
+ enc.err = enc.state(c)
+ return enc.written, enc.err
}
// io helpers //////////////////////////////////////////////////////////////////
+func (enc *ReEncoder) emitByte(c byte) error {
+ err := writeByte(enc.Out, c)
+ if err == nil {
+ enc.written++
+ }
+ return err
+}
+
+func (enc *ReEncoder) emit(n int, err error) error {
+ enc.written += n
+ return err
+}
+
func (enc *ReEncoder) nlIndent() error {
if enc.Compact || enc.Indent == "" {
return nil
}
- if err := writeByte(enc.Out, '\n'); err != nil {
+ if err := enc.emitByte('\n'); err != nil {
return err
}
if enc.prefix != "" {
- if _, err := io.WriteString(enc.Out, enc.prefix); err != nil {
+ if err := enc.emit(io.WriteString(enc.Out, enc.prefix)); err != nil {
return err
}
}
for i := 0; i < enc.curIndent; i++ {
- if _, err := io.WriteString(enc.Out, enc.Indent); err != nil {
+ if err := enc.emit(io.WriteString(enc.Out, enc.Indent)); err != nil {
return err
}
}
@@ -186,7 +198,7 @@ func (enc *ReEncoder) stateAny(c rune) error {
default:
return fmt.Errorf("decode value: unexpected character: %c", c)
}
- return writeByte(enc.Out, byte(c))
+ return enc.emitByte(byte(c))
}
// object //////////////////////////////////////////////////////////////////////////////////////////
@@ -216,7 +228,7 @@ func (enc *ReEncoder) _stateInObject(c rune, nonempty bool) error {
default:
return fmt.Errorf("decode object: unexpected character: %c", c)
}
- return writeByte(enc.Out, byte(c))
+ return enc.emitByte(byte(c))
}
func (enc *ReEncoder) stateInKV(c rune) error {
switch c {
@@ -224,15 +236,15 @@ func (enc *ReEncoder) stateInKV(c rune) error {
if enc.Compact || enc.Indent != "" {
return nil
}
- return writeByte(enc.Out, byte(c))
+ return enc.emitByte(byte(c))
case ':':
enc.replaceState(enc.stateAfterV, false)
enc.pushState(enc.stateAny, false)
- if err := writeByte(enc.Out, byte(c)); err != nil {
+ if err := enc.emitByte(byte(c)); err != nil {
return err
}
if !enc.Compact && enc.Indent != "" {
- return writeByte(enc.Out, ' ')
+ return enc.emitByte(' ')
}
return nil
default:
@@ -256,7 +268,7 @@ func (enc *ReEncoder) stateAfterV(c rune) error {
default:
return fmt.Errorf("decode object member: unexpected character: %c", c)
}
- return writeByte(enc.Out, byte(c))
+ return enc.emitByte(byte(c))
}
// array ///////////////////////////////////////////////////////////////////////////////////////////
@@ -285,7 +297,7 @@ func (enc *ReEncoder) _stateInArray(c rune, nonempty bool) error {
enc.pushState(enc.stateAny, false)
return enc.state(c)
}
- return writeByte(enc.Out, byte(c))
+ return enc.emitByte(byte(c))
}
func (enc *ReEncoder) stateAfterItem(c rune) error {
switch c {
@@ -304,7 +316,7 @@ func (enc *ReEncoder) stateAfterItem(c rune) error {
default:
return fmt.Errorf("decode array: unexpected character: %c", c)
}
- return writeByte(enc.Out, byte(c))
+ return enc.emitByte(byte(c))
}
// string //////////////////////////////////////////////////////////////////////////////////////////
@@ -316,9 +328,9 @@ func (enc *ReEncoder) stateInString(c rune) error {
return nil
case c == '"':
enc.popState()
- return writeByte(enc.Out, byte(c))
+ return enc.emitByte(byte(c))
case 0x0020 <= c && c <= 0x10FFFF:
- return writeStringChar(enc.Out, c, false, enc.UnicodeEscape)
+ return enc.emit(writeStringChar(enc.Out, c, false, enc.UnicodeEscape))
default:
return fmt.Errorf("decode string: unexpected character: %c", c)
}
@@ -327,25 +339,25 @@ func (enc *ReEncoder) stateInBackslash(c rune) error {
switch c {
case '"':
enc.replaceState(enc.stateInString, false)
- return writeStringChar(enc.Out, '"', false, enc.UnicodeEscape)
+ return enc.emit(writeStringChar(enc.Out, '"', false, enc.UnicodeEscape))
case '\\':
enc.replaceState(enc.stateInString, false)
- return writeStringChar(enc.Out, '\\', false, enc.UnicodeEscape)
+ return enc.emit(writeStringChar(enc.Out, '\\', false, enc.UnicodeEscape))
case 'b':
enc.replaceState(enc.stateInString, false)
- return writeStringChar(enc.Out, '\b', false, enc.UnicodeEscape)
+ return enc.emit(writeStringChar(enc.Out, '\b', false, enc.UnicodeEscape))
case 'f':
enc.replaceState(enc.stateInString, false)
- return writeStringChar(enc.Out, '\f', false, enc.UnicodeEscape)
+ return enc.emit(writeStringChar(enc.Out, '\f', false, enc.UnicodeEscape))
case 'n':
enc.replaceState(enc.stateInString, false)
- return writeStringChar(enc.Out, '\n', false, enc.UnicodeEscape)
+ return enc.emit(writeStringChar(enc.Out, '\n', false, enc.UnicodeEscape))
case 'r':
enc.replaceState(enc.stateInString, false)
- return writeStringChar(enc.Out, '\r', false, enc.UnicodeEscape)
+ return enc.emit(writeStringChar(enc.Out, '\r', false, enc.UnicodeEscape))
case 't':
enc.replaceState(enc.stateInString, false)
- return writeStringChar(enc.Out, '\t', false, enc.UnicodeEscape)
+ return enc.emit(writeStringChar(enc.Out, '\t', false, enc.UnicodeEscape))
case 'u':
enc.replaceState(enc.stateInUnicode, false)
return nil
@@ -372,7 +384,7 @@ func (enc *ReEncoder) stateInUnicode(c rune) error {
rune(enc.stateBuf[2])<<4 |
rune(enc.stateBuf[3])<<0
enc.stateBuf = enc.stateBuf[:0]
- return writeStringChar(enc.Out, c, true, enc.UnicodeEscape)
+ return enc.emit(writeStringChar(enc.Out, c, true, enc.UnicodeEscape))
}
return nil
}
@@ -430,7 +442,7 @@ func (enc *ReEncoder) stateNumberA(c rune) error { // start
default:
return fmt.Errorf("decode number: unexpected character: %c", c)
}
- return writeByte(enc.Out, byte(c))
+ return enc.emitByte(byte(c))
}
func (enc *ReEncoder) stateNumberB(c rune) error { // got a leading "-"
switch c {
@@ -441,17 +453,17 @@ func (enc *ReEncoder) stateNumberB(c rune) error { // got a leading "-"
default:
return fmt.Errorf("decode number: unexpected character: %c", c)
}
- return writeByte(enc.Out, byte(c))
+ return enc.emitByte(byte(c))
}
func (enc *ReEncoder) stateNumberC(c rune) error { // ready for the fraction or exponent part to start
switch c {
case '.':
enc.replaceState(enc.stateNumberE, true)
- return writeByte(enc.Out, '.')
+ return enc.emitByte('.')
case 'e', 'E':
enc.replaceState(enc.stateNumberG, true)
enc.stateBuf = append(enc.stateBuf[:0], 0)
- return writeByte(enc.Out, 'e')
+ return enc.emitByte('e')
default:
enc.popState()
return enc.state(c)
@@ -460,14 +472,14 @@ func (enc *ReEncoder) stateNumberC(c rune) error { // ready for the fraction or
func (enc *ReEncoder) stateNumberD(c rune) error { // in the integer part
switch c {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
- return writeByte(enc.Out, byte(c))
+ return enc.emitByte(byte(c))
case '.':
enc.replaceState(enc.stateNumberE, true)
- return writeByte(enc.Out, '.')
+ return enc.emitByte('.')
case 'e', 'E':
enc.replaceState(enc.stateNumberG, true)
enc.stateBuf = append(enc.stateBuf[:0], 0)
- return writeByte(enc.Out, 'e')
+ return enc.emitByte('e')
default:
enc.popState()
return enc.state(c)
@@ -479,7 +491,7 @@ func (enc *ReEncoder) stateNumberE(c rune) error { // got a ".", ready to read a
switch c {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
enc.replaceState(enc.stateNumberF, true)
- return writeByte(enc.Out, byte(c))
+ return enc.emitByte(byte(c))
default:
return fmt.Errorf("decode number: unexpected character: %c", c)
}
@@ -495,7 +507,7 @@ func (enc *ReEncoder) stateNumberF(c rune) error { // in the fraction part
return nil
case '1', '2', '3', '4', '5', '6', '7', '8', '9':
for len(enc.stateBuf) > 0 {
- if err := writeByte(enc.Out, '0'); err != nil {
+ if err := enc.emitByte('0'); err != nil {
return err
}
if enc.stateBuf[len(enc.stateBuf)-1] == 1 {
@@ -504,11 +516,11 @@ func (enc *ReEncoder) stateNumberF(c rune) error { // in the fraction part
enc.stateBuf[len(enc.stateBuf)-1]--
}
}
- return writeByte(enc.Out, byte(c))
+ return enc.emitByte(byte(c))
case 'e', 'E':
enc.replaceState(enc.stateNumberG, true)
enc.stateBuf = append(enc.stateBuf[:0], 0)
- return writeByte(enc.Out, 'e')
+ return enc.emitByte('e')
default:
enc.stateBuf = enc.stateBuf[:0]
enc.popState()
@@ -521,14 +533,14 @@ func (enc *ReEncoder) stateNumberG(c rune) error { // got a leading "e"
switch c {
case '-', '+':
enc.replaceState(enc.stateNumberH, true)
- return writeByte(enc.Out, byte(c))
+ return enc.emitByte(byte(c))
case '0':
enc.replaceState(enc.stateNumberH, true)
return nil
case '1', '2', '3', '4', '5', '6', '7', '8', '9':
enc.replaceState(enc.stateNumberH, true)
enc.stateBuf[0] = 1
- return writeByte(enc.Out, byte(c))
+ return enc.emitByte(byte(c))
default:
enc.stateBuf = enc.stateBuf[:0]
return fmt.Errorf("decode number: unexpected character: %c", c)
@@ -540,13 +552,13 @@ func (enc *ReEncoder) stateNumberH(c rune) error { // in the exponent's number p
if enc.stateBuf[0] == 0 {
return nil
}
- return writeByte(enc.Out, '0')
+ return enc.emitByte('0')
case '1', '2', '3', '4', '5', '6', '7', '8', '9':
enc.stateBuf[0] = 1
- return writeByte(enc.Out, byte(c))
+ return enc.emitByte(byte(c))
default:
if enc.stateBuf[0] == 0 {
- if err := writeByte(enc.Out, '0'); err != nil {
+ if err := enc.emitByte('0'); err != nil {
return err
}
}
@@ -569,5 +581,5 @@ func (enc *ReEncoder) _stateInLiteral(c rune, full string) error {
if len(enc.stateBuf) == len(full) {
enc.popState()
}
- return writeByte(enc.Out, byte(c))
+ return enc.emitByte(byte(c))
}