diff options
author | Luke Shumaker <lukeshu@datawire.io> | 2022-08-21 13:22:14 -0600 |
---|---|---|
committer | Luke Shumaker <lukeshu@datawire.io> | 2022-08-21 13:34:01 -0600 |
commit | d25456172946e5921747cd57fb04eb5b6da72fb6 (patch) | |
tree | ce011fc8bf5c2e303b0d5defb203d9c0036480f8 | |
parent | 6ba16f05e9c36d4341da4590600eb2c4221ac642 (diff) |
decode: Add DecodeObject and DecodeArray helper methods
-rw-r--r-- | decode.go | 76 |
1 files changed, 63 insertions, 13 deletions
@@ -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() |