summaryrefslogtreecommitdiff
path: root/decode.go
diff options
context:
space:
mode:
Diffstat (limited to 'decode.go')
-rw-r--r--decode.go81
1 files changed, 63 insertions, 18 deletions
diff --git a/decode.go b/decode.go
index c987d79..d4ecd4f 100644
--- a/decode.go
+++ b/decode.go
@@ -1011,6 +1011,7 @@ func DecodeObject(r io.RuneScanner, decodeKey, decodeVal func(io.RuneScanner) er
}
dec.posStackPush()
defer dec.posStackPop()
+ // TODO Find a better Go type to use than `nil`.
if err := dec.decodeObject(nil,
func() *DecodeError {
dec.posStackPush()
@@ -1101,6 +1102,7 @@ func DecodeArray(r io.RuneScanner, decodeMember func(r io.RuneScanner) error) er
}
dec.posStackPush()
defer dec.posStackPop()
+ // TODO Find a better Go type to use than `nil`.
if err := dec.decodeArray(nil, func() *DecodeError {
dec.posStackPush()
defer dec.posStackPop()
@@ -1151,6 +1153,38 @@ func (dec *Decoder) decodeArray(gTyp reflect.Type, decodeMember func() *DecodeEr
}
}
+// DecodeString is a helper function to eas implementing the Decodable
+// interface; allowing the lowmemjson package to handle decoding
+// character escapes and such, while the Decodable only needs to
+// handle what to do with the decoded runes.
+//
+// Outside of implementing Decodable.DecodeJSON methods, callers
+// should instead simply use NewDecoder(r).Decode(&val) rather than
+// attempting to call DecodeString directly.
+func DecodeString(in io.RuneScanner, out fastio.RuneWriter) error {
+ var dec *Decoder
+ if dr, ok := in.(*decRuneScanner); ok {
+ dec = dr.dec
+ } else {
+ dec = NewDecoder(in)
+ }
+ if dec.typeErr != nil {
+ oldTypeErr := dec.typeErr
+ dec.typeErr = nil
+ defer func() { dec.typeErr = oldTypeErr }()
+ }
+ dec.posStackPush()
+ defer dec.posStackPop()
+ // TODO Find a better Go type to use than `nil`.
+ if err := dec.decodeString(nil, out); err != nil {
+ return err
+ }
+ if dec.typeErr != nil {
+ return dec.typeErr
+ }
+ return nil
+}
+
func (dec *Decoder) decodeString(gTyp reflect.Type, out fastio.RuneWriter) *DecodeError {
if _, t, err := dec.readRune(); err != nil {
return err
@@ -1167,29 +1201,30 @@ func (dec *Decoder) decodeString(gTyp reflect.Type, out fastio.RuneWriter) *Deco
}
switch t {
case jsonparse.RuneTypeStringChar:
- _, _ = out.WriteRune(c)
+ if _, err := out.WriteRune(c); err != nil {
+ dec.newTypeError("string", gTyp, err)
+ }
case jsonparse.RuneTypeStringEsc, jsonparse.RuneTypeStringEscU:
// do nothing
case jsonparse.RuneTypeStringEsc1:
switch c {
- case '"':
- _, _ = out.WriteRune('"')
- case '\\':
- _, _ = out.WriteRune('\\')
- case '/':
- _, _ = out.WriteRune('/')
+ case '"', '\\', '/':
+ // self
case 'b':
- _, _ = out.WriteRune('\b')
+ c = '\b'
case 'f':
- _, _ = out.WriteRune('\f')
+ c = '\f'
case 'n':
- _, _ = out.WriteRune('\n')
+ c = '\n'
case 'r':
- _, _ = out.WriteRune('\r')
+ c = '\r'
case 't':
- _, _ = out.WriteRune('\t')
+ c = '\t'
default:
- panic(fmt.Errorf("should not happen: unexpected rune after backslash: %q", c))
+ panic(fmt.Errorf("should not happen: rune %q is not a RuneTypeStringEsc1", c))
+ }
+ if _, err := out.WriteRune(c); err != nil {
+ dec.newTypeError("string", gTyp, err)
}
case jsonparse.RuneTypeStringEscUA:
uhex[0] = byte(c)
@@ -1206,7 +1241,9 @@ func (dec *Decoder) decodeString(gTyp reflect.Type, out fastio.RuneWriter) *Deco
return err
}
if t != jsonparse.RuneTypeStringEsc {
- _, _ = out.WriteRune(utf8.RuneError)
+ if _, err := out.WriteRune(utf8.RuneError); err != nil {
+ dec.newTypeError("string", gTyp, err)
+ }
break
}
if err := dec.expectRuneOrPanic('\\', jsonparse.RuneTypeStringEsc); err != nil {
@@ -1217,7 +1254,9 @@ func (dec *Decoder) decodeString(gTyp reflect.Type, out fastio.RuneWriter) *Deco
return err
}
if t != jsonparse.RuneTypeStringEscU {
- _, _ = out.WriteRune(utf8.RuneError)
+ if _, err := out.WriteRune(utf8.RuneError); err != nil {
+ dec.newTypeError("string", gTyp, err)
+ }
break
}
if err := dec.expectRuneOrPanic('u', jsonparse.RuneTypeStringEscU); err != nil {
@@ -1246,13 +1285,19 @@ func (dec *Decoder) decodeString(gTyp reflect.Type, out fastio.RuneWriter) *Deco
c2 := hexToRune(uhex[0], uhex[1], uhex[2], byte(b))
d := utf16.DecodeRune(c, c2)
if d == utf8.RuneError {
- _, _ = out.WriteRune(utf8.RuneError)
+ if _, err := out.WriteRune(utf8.RuneError); err != nil {
+ dec.newTypeError("string", gTyp, err)
+ }
c = c2
goto handleUnicode
}
- _, _ = out.WriteRune(d)
+ if _, err := out.WriteRune(d); err != nil {
+ dec.newTypeError("string", gTyp, err)
+ }
} else {
- _, _ = out.WriteRune(c)
+ if _, err := out.WriteRune(c); err != nil {
+ dec.newTypeError("string", gTyp, err)
+ }
}
case jsonparse.RuneTypeStringEnd:
return nil