summaryrefslogtreecommitdiff
path: root/decode.go
diff options
context:
space:
mode:
Diffstat (limited to 'decode.go')
-rw-r--r--decode.go104
1 files changed, 56 insertions, 48 deletions
diff --git a/decode.go b/decode.go
index 7ae723c..60b530f 100644
--- a/decode.go
+++ b/decode.go
@@ -104,12 +104,10 @@ const maxNestingDepth = 10000
// an io.Reader.
func NewDecoder(r io.RuneScanner) *Decoder {
return &Decoder{
- io: &noWSRuneTypeScanner{
- inner: &runeTypeScannerImpl{
- inner: r,
- parser: internal.Parser{
- MaxDepth: maxNestingDepth,
- },
+ io: runeTypeScanner{
+ inner: r,
+ parser: internal.Parser{
+ MaxDepth: maxNestingDepth,
},
},
}
@@ -247,6 +245,7 @@ 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 {
@@ -259,6 +258,7 @@ func (dec *Decoder) Decode(ptr any) (err error) {
}
}()
dec.decode(ptrVal.Elem(), false)
+ dec.io.PopReadBarrier()
return nil
}
@@ -321,12 +321,21 @@ func (dec *Decoder) expectRuneType(ec rune, et internal.RuneType, gt reflect.Typ
}
}
-type decRuneTypeScanner struct {
+type decRuneScanner struct {
dec *Decoder
+ eof bool
}
-func (sc *decRuneTypeScanner) ReadRuneType() (rune, int, internal.RuneType, error) {
+func (sc *decRuneScanner) ReadRune() (rune, int, error) {
+ if sc.eof {
+ return 0, 0, io.EOF
+ }
c, s, t, e := sc.dec.io.ReadRuneType()
+ if t == internal.RuneTypeEOF {
+ sc.eof = true
+ sc.dec.io.PopReadBarrier()
+ return 0, 0, io.EOF
+ }
if e != nil {
panic(decodeError{
Field: sc.dec.structStackStr(),
@@ -335,28 +344,17 @@ func (sc *decRuneTypeScanner) ReadRuneType() (rune, int, internal.RuneType, erro
Err: e,
})
}
- return c, s, t, nil
+ return c, s, nil
}
-func (sc *decRuneTypeScanner) ReadRune() (rune, int, error) {
- r, s, t, _ := sc.ReadRuneType()
- switch t {
- case internal.RuneTypeEOF:
- return 0, 0, io.EOF
- default:
- return r, s, nil
- }
+func (sc *decRuneScanner) UnreadRune() error {
+ return sc.dec.io.UnreadRune()
}
-func (sc *decRuneTypeScanner) UnreadRune() error { return sc.dec.io.UnreadRune() }
-func (sc *decRuneTypeScanner) InputOffset() int64 { return sc.dec.InputOffset() }
-func (sc *decRuneTypeScanner) Reset() { sc.dec.io.Reset() }
-
-func (dec *Decoder) limitingScanner() runeTypeScanner {
- return &elemRuneTypeScanner{
- inner: &decRuneTypeScanner{
- dec: dec,
- },
+func (dec *Decoder) limitingScanner() io.RuneScanner {
+ dec.io.PushReadBarrier()
+ return &decRuneScanner{
+ dec: dec,
}
}
@@ -565,7 +563,7 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
if dec.disallowUnknownFields {
dec.panicType("", typ, fmt.Errorf("json: unknown field %q", name))
}
- dec.scan(io.Discard)
+ dec.scan(internal.Discard)
return
}
field := index.byPos[idx]
@@ -749,7 +747,7 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
dec.decode(mValPtr.Elem(), false)
val.Index(i).Set(mValPtr.Elem())
} else {
- dec.scan(io.Discard)
+ dec.scan(internal.Discard)
}
i++
})
@@ -773,18 +771,18 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
}
}
-func (dec *Decoder) scan(out io.Writer) {
+func (dec *Decoder) scan(out internal.RuneWriter) {
limiter := dec.limitingScanner()
for {
c, _, err := limiter.ReadRune()
if err == io.EOF {
return
}
- _, _ = writeRune(out, c)
+ _, _ = out.WriteRune(c)
}
}
-func (dec *Decoder) scanNumber(gTyp reflect.Type, out io.Writer) {
+func (dec *Decoder) scanNumber(gTyp reflect.Type, out internal.RuneWriter) {
if t := dec.peekRuneType(); !t.IsNumber() {
dec.panicType(t.JSONType(), gTyp, nil)
}
@@ -869,7 +867,12 @@ func DecodeObject(r io.RuneScanner, decodeKey, decodeVal func(io.RuneScanner) er
}
}
}()
- dec := NewDecoder(r)
+ var dec *Decoder
+ if dr, ok := r.(*decRuneScanner); ok {
+ dec = dr.dec
+ } else {
+ dec = NewDecoder(r)
+ }
dec.posStackPush()
defer dec.posStackPop()
dec.decodeObject(nil,
@@ -949,7 +952,12 @@ func DecodeArray(r io.RuneScanner, decodeMember func(r io.RuneScanner) error) (e
}
}
}()
- dec := NewDecoder(r)
+ var dec *Decoder
+ if dr, ok := r.(*decRuneScanner); ok {
+ dec = dr.dec
+ } else {
+ dec = NewDecoder(r)
+ }
dec.posStackPush()
defer dec.posStackPop()
dec.decodeArray(nil, func() {
@@ -991,34 +999,34 @@ func (dec *Decoder) decodeArray(gTyp reflect.Type, decodeMember func()) {
}
}
-func (dec *Decoder) decodeString(gTyp reflect.Type, out io.Writer) {
+func (dec *Decoder) decodeString(gTyp reflect.Type, out internal.RuneWriter) {
dec.expectRuneType('"', internal.RuneTypeStringBeg, gTyp)
var uhex [4]byte
for {
c, t := dec.readRune()
switch t {
case internal.RuneTypeStringChar:
- _, _ = writeRune(out, c)
+ _, _ = out.WriteRune(c)
case internal.RuneTypeStringEsc, internal.RuneTypeStringEscU:
// do nothing
case internal.RuneTypeStringEsc1:
switch c {
case '"':
- _, _ = writeRune(out, '"')
+ _, _ = out.WriteRune('"')
case '\\':
- _, _ = writeRune(out, '\\')
+ _, _ = out.WriteRune('\\')
case '/':
- _, _ = writeRune(out, '/')
+ _, _ = out.WriteRune('/')
case 'b':
- _, _ = writeRune(out, '\b')
+ _, _ = out.WriteRune('\b')
case 'f':
- _, _ = writeRune(out, '\f')
+ _, _ = out.WriteRune('\f')
case 'n':
- _, _ = writeRune(out, '\n')
+ _, _ = out.WriteRune('\n')
case 'r':
- _, _ = writeRune(out, '\r')
+ _, _ = out.WriteRune('\r')
case 't':
- _, _ = writeRune(out, '\t')
+ _, _ = out.WriteRune('\t')
default:
panic("should not happen")
}
@@ -1038,12 +1046,12 @@ func (dec *Decoder) decodeString(gTyp reflect.Type, out io.Writer) {
handleUnicode:
if utf16.IsSurrogate(c) {
if dec.peekRuneType() != internal.RuneTypeStringEsc {
- _, _ = writeRune(out, utf8.RuneError)
+ _, _ = out.WriteRune(utf8.RuneError)
break
}
dec.expectRune('\\', internal.RuneTypeStringEsc)
if dec.peekRuneType() != internal.RuneTypeStringEscU {
- _, _ = writeRune(out, utf8.RuneError)
+ _, _ = out.WriteRune(utf8.RuneError)
break
}
dec.expectRune('u', internal.RuneTypeStringEscU)
@@ -1063,13 +1071,13 @@ func (dec *Decoder) decodeString(gTyp reflect.Type, out io.Writer) {
rune(uhex[3])<<0
d := utf16.DecodeRune(c, c2)
if d == utf8.RuneError {
- _, _ = writeRune(out, utf8.RuneError)
+ _, _ = out.WriteRune(utf8.RuneError)
c = c2
goto handleUnicode
}
- _, _ = writeRune(out, d)
+ _, _ = out.WriteRune(d)
} else {
- _, _ = writeRune(out, c)
+ _, _ = out.WriteRune(c)
}
case internal.RuneTypeStringEnd:
return