summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@datawire.io>2022-08-21 13:22:14 -0600
committerLuke Shumaker <lukeshu@datawire.io>2022-08-21 13:34:01 -0600
commitd25456172946e5921747cd57fb04eb5b6da72fb6 (patch)
treece011fc8bf5c2e303b0d5defb203d9c0036480f8
parent6ba16f05e9c36d4341da4590600eb2c4221ac642 (diff)
decode: Add DecodeObject and DecodeArray helper methods
-rw-r--r--decode.go76
1 files changed, 63 insertions, 13 deletions
diff --git a/decode.go b/decode.go
index 98a0e5b..c160192 100644
--- a/decode.go
+++ b/decode.go
@@ -21,12 +21,6 @@ type Decodable interface {
DecodeJSON(io.RuneScanner) error
}
-type runeBuffer interface {
- io.Writer
- WriteRune(rune) (int, error)
- Reset()
-}
-
type decodeStackItem struct {
par reflect.Type
idx any
@@ -438,7 +432,10 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
}
index := indexStruct(typ)
var nameBuf strings.Builder
- dec.decodeObject(typ, &nameBuf, func() {
+ dec.decodeObject(typ, func() {
+ nameBuf.Reset()
+ dec.decodeString(nil, &nameBuf)
+ }, func() {
name := nameBuf.String()
dec.stackPush(typ, name)
defer dec.stackPop()
@@ -519,7 +516,10 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
val.Set(reflect.MakeMap(typ))
}
var nameBuf bytes.Buffer
- dec.decodeObject(typ, &nameBuf, func() {
+ dec.decodeObject(typ, func() {
+ nameBuf.Reset()
+ dec.decodeString(nil, &nameBuf)
+ }, func() {
nameValTyp := typ.Key()
nameValPtr := reflect.New(nameValTyp)
switch {
@@ -678,7 +678,10 @@ func (dec *Decoder) decodeAny() any {
ret := make(map[string]any)
typ := reflect.TypeOf(ret)
var nameBuf strings.Builder
- dec.decodeObject(typ, &nameBuf, func() {
+ dec.decodeObject(typ, func() {
+ nameBuf.Reset()
+ dec.decodeString(nil, &nameBuf)
+ }, func() {
name := nameBuf.String()
dec.stackPush(typ, name)
defer dec.stackPop()
@@ -720,7 +723,34 @@ func (dec *Decoder) decodeAny() any {
}
}
-func (dec *Decoder) decodeObject(gTyp reflect.Type, nameBuf runeBuffer, decodeKVal func()) {
+// DecodeObject is a helper function for implementing the Decoder interface.
+func DecodeObject(r io.RuneScanner, decodeKey, decodeVal func() error) (err error) {
+ defer func() {
+ if r := recover(); r != nil {
+ if de, ok := r.(decodeError); ok {
+ pub := DecodeError(de)
+ err = &pub
+ } else {
+ panic(r)
+ }
+ }
+ }()
+ dec := NewDecoder(r)
+ dec.decodeObject(nil,
+ func() {
+ if err := decodeKey(); err != nil {
+ dec.panicType("string", nil, err)
+ }
+ },
+ func() {
+ if err := decodeVal(); err != nil {
+ dec.panicType("", nil, err)
+ }
+ })
+ return
+}
+
+func (dec *Decoder) decodeObject(gTyp reflect.Type, decodeKey, decodeVal func()) {
dec.expectRuneType('{', RuneTypeObjectBeg, gTyp)
_, t := dec.readRune()
switch t {
@@ -729,10 +759,9 @@ func (dec *Decoder) decodeObject(gTyp reflect.Type, nameBuf runeBuffer, decodeKV
case RuneTypeStringBeg:
decodeMember:
dec.unreadRune()
- nameBuf.Reset()
- dec.decodeString(nil, nameBuf)
+ decodeKey()
dec.expectRune(':', RuneTypeObjectColon)
- decodeKVal()
+ decodeVal()
_, t := dec.readRune()
switch t {
case RuneTypeObjectComma:
@@ -748,6 +777,27 @@ func (dec *Decoder) decodeObject(gTyp reflect.Type, nameBuf runeBuffer, decodeKV
}
}
+// DecodeArray is a helper function for implementing the Decoder interface.
+func DecodeArray(r io.RuneScanner, decodeMember func() error) (err error) {
+ defer func() {
+ if r := recover(); r != nil {
+ if de, ok := r.(decodeError); ok {
+ pub := DecodeError(de)
+ err = &pub
+ } else {
+ panic(r)
+ }
+ }
+ }()
+ dec := NewDecoder(r)
+ dec.decodeArray(nil, func() {
+ if err := decodeMember(); err != nil {
+ dec.panicType("array", nil, err)
+ }
+ })
+ return
+}
+
func (dec *Decoder) decodeArray(gTyp reflect.Type, decodeMember func()) {
dec.expectRuneType('[', RuneTypeArrayBeg, gTyp)
_, t := dec.readRune()