summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@datawire.io>2022-08-21 12:06:50 -0600
committerLuke Shumaker <lukeshu@datawire.io>2022-08-21 12:06:50 -0600
commit6ba16f05e9c36d4341da4590600eb2c4221ac642 (patch)
treeadccf15073073237eafc1926110fe3da46ea2aee
parentfb063e2955debb9d02debf3f59de291d99017058 (diff)
decode: Lean in to io.RuneScanner
So that it's easier to compose your own .DecodeJSON methods, since .DecodeJSON takes an io.RuneScanner.
-rw-r--r--decode.go19
-rw-r--r--decode_scan.go10
-rw-r--r--decode_scan_test.go10
3 files changed, 14 insertions, 25 deletions
diff --git a/decode.go b/decode.go
index 51402e7..98a0e5b 100644
--- a/decode.go
+++ b/decode.go
@@ -5,7 +5,6 @@
package lowmemjson
import (
- "bufio"
"bytes"
"encoding"
"encoding/json"
@@ -47,15 +46,11 @@ type Decoder struct {
const maxNestingDepth = 10000
-func NewDecoder(r io.Reader) *Decoder {
- rr, ok := r.(io.RuneReader)
- if !ok {
- rr = bufio.NewReader(r)
- }
+func NewDecoder(r io.RuneScanner) *Decoder {
return &Decoder{
io: &noWSRuneTypeScanner{
inner: &runeTypeScannerImpl{
- inner: rr,
+ inner: r,
parser: Parser{
MaxDepth: maxNestingDepth,
},
@@ -114,18 +109,16 @@ func (dec *Decoder) stackName() string {
return strings.Join(fields, ".")
}
-func Decode(r interface {
- io.Reader
- io.RuneScanner // enforce that the reader have .UnreadRune() so that we don't risk reading too far when decoding a number
-}, ptr any) error {
+func Decode(r io.RuneScanner, ptr any) error {
return NewDecoder(r).Decode(ptr)
}
-// DecodeThenEOF is like decode, but emits an error if there is extra data after the JSON.
-func DecodeThenEOF(r io.Reader, ptr any) error {
+func DecodeThenEOF(r io.RuneScanner, ptr any) error {
return NewDecoder(r).DecodeThenEOF(ptr)
}
+// DecodeThenEOF is like decode, but emits an error if there is extra
+// data after the JSON.
func (dec *Decoder) DecodeThenEOF(ptr any) (err error) {
if err := dec.Decode(ptr); err != nil {
return err
diff --git a/decode_scan.go b/decode_scan.go
index fb8a6ec..eee61fc 100644
--- a/decode_scan.go
+++ b/decode_scan.go
@@ -28,7 +28,7 @@ type runeTypeScanner interface {
// runeTypeScannerImpl /////////////////////////////////////////////////////////////////////////////
type runeTypeScannerImpl struct {
- inner io.RuneReader
+ inner io.RuneScanner
initialized bool
@@ -73,9 +73,7 @@ func (sc *runeTypeScannerImpl) ReadRuneType() (rune, int, RuneType, error) {
case sc.stuck:
// do nothing
case sc.repeat:
- if _, ok := sc.inner.(io.RuneScanner); ok {
- _, _, _ = sc.inner.ReadRune()
- }
+ _, _, _ = sc.inner.ReadRune()
default:
var err error
sc.rRune, sc.rSize, err = sc.inner.ReadRune()
@@ -138,9 +136,7 @@ func (sc *runeTypeScannerImpl) UnreadRune() error {
return ErrInvalidUnreadRune
}
sc.repeat = true
- if rs, ok := sc.inner.(io.RuneScanner); ok {
- _ = rs.UnreadRune()
- }
+ _ = sc.inner.UnreadRune()
return nil
}
diff --git a/decode_scan_test.go b/decode_scan_test.go
index 27b60c0..70e2874 100644
--- a/decode_scan_test.go
+++ b/decode_scan_test.go
@@ -31,7 +31,7 @@ type runeTypeScannerTestcase struct {
Exp []ReadRuneTypeResult
}
-func testRuneTypeScanner(t *testing.T, testcases map[string]runeTypeScannerTestcase, factory func(io.RuneReader) runeTypeScanner) {
+func testRuneTypeScanner(t *testing.T, testcases map[string]runeTypeScannerTestcase, factory func(io.RuneScanner) runeTypeScanner) {
for tcName, tc := range testcases {
t.Run(tcName, func(t *testing.T) {
reader := strings.NewReader(tc.Input)
@@ -158,7 +158,7 @@ func TestRuneTypeScanner(t *testing.T) {
{0, 0, RuneTypeError, &DecodeSyntaxError{Offset: 0, Err: io.EOF}},
}},
}
- testRuneTypeScanner(t, testcases, func(reader io.RuneReader) runeTypeScanner {
+ testRuneTypeScanner(t, testcases, func(reader io.RuneScanner) runeTypeScanner {
return &runeTypeScannerImpl{
inner: reader,
}
@@ -230,7 +230,7 @@ func TestNoWSRuneTypeScanner(t *testing.T) {
{0, 0, RuneTypeError, &DecodeSyntaxError{Offset: 2, Err: io.ErrUnexpectedEOF}},
}},
}
- testRuneTypeScanner(t, testcases, func(reader io.RuneReader) runeTypeScanner {
+ testRuneTypeScanner(t, testcases, func(reader io.RuneScanner) runeTypeScanner {
return &noWSRuneTypeScanner{
inner: &runeTypeScannerImpl{
inner: reader,
@@ -276,7 +276,7 @@ func TestElemRuneTypeScanner(t *testing.T) {
}},
}
t.Run("top-level", func(t *testing.T) {
- testRuneTypeScanner(t, testcases, func(reader io.RuneReader) runeTypeScanner {
+ testRuneTypeScanner(t, testcases, func(reader io.RuneScanner) runeTypeScanner {
return &elemRuneTypeScanner{
inner: &noWSRuneTypeScanner{
inner: &runeTypeScannerImpl{
@@ -297,7 +297,7 @@ func TestElemRuneTypeScanner(t *testing.T) {
testcases[tcName] = tc
}
t.Run("child", func(t *testing.T) {
- testRuneTypeScanner(t, testcases, func(reader io.RuneReader) runeTypeScanner {
+ testRuneTypeScanner(t, testcases, func(reader io.RuneScanner) runeTypeScanner {
inner := &noWSRuneTypeScanner{
inner: &runeTypeScannerImpl{
inner: reader,