summaryrefslogtreecommitdiff
path: root/decode.go
diff options
context:
space:
mode:
Diffstat (limited to 'decode.go')
-rw-r--r--decode.go140
1 files changed, 93 insertions, 47 deletions
diff --git a/decode.go b/decode.go
index f351037..7ae723c 100644
--- a/decode.go
+++ b/decode.go
@@ -90,8 +90,9 @@ type Decoder struct {
useNumber bool
// state
- err error
- stack []decodeStackItem
+ err error
+ posStack []int64
+ structStack []decodeStackItem
}
const maxNestingDepth = 10000
@@ -150,40 +151,48 @@ func (dec *Decoder) More() bool {
return e == nil && t != internal.RuneTypeEOF
}
-func (dec *Decoder) stackPush(par reflect.Type, idx any) {
- dec.stack = append(dec.stack, decodeStackItem{par, idx})
+func (dec *Decoder) posStackPush() {
+ dec.posStack = append(dec.posStack, dec.InputOffset())
}
-func (dec *Decoder) stackPop() {
- dec.stack = dec.stack[:len(dec.stack)-1]
+func (dec *Decoder) posStackPop() {
+ dec.posStack = dec.posStack[:len(dec.posStack)-1]
}
-func (dec *Decoder) stackStr() string {
+func (dec *Decoder) structStackPush(par reflect.Type, idx any) {
+ dec.structStack = append(dec.structStack, decodeStackItem{par, idx})
+}
+
+func (dec *Decoder) structStackPop() {
+ dec.structStack = dec.structStack[:len(dec.structStack)-1]
+}
+
+func (dec *Decoder) structStackStr() string {
var buf strings.Builder
buf.WriteString("v")
- for _, item := range dec.stack {
+ for _, item := range dec.structStack {
fmt.Fprintf(&buf, "[%#v]", item.idx)
}
return buf.String()
}
-func (dec *Decoder) stackParent() string {
- last := len(dec.stack) - 1
- if last > 0 && dec.stack[last].par.Kind() != reflect.Struct && dec.stack[last-1].par.Kind() == reflect.Struct {
+func (dec *Decoder) structStackParent() string {
+ last := len(dec.structStack) - 1
+ if last > 0 && dec.structStack[last].par.Kind() != reflect.Struct && dec.structStack[last-1].par.Kind() == reflect.Struct {
last--
}
- if last >= 0 && dec.stack[last].par.Kind() == reflect.Struct {
- return dec.stack[last].par.Name()
+ if last >= 0 && dec.structStack[last].par.Kind() == reflect.Struct {
+ return dec.structStack[last].par.Name()
}
return ""
}
-func (dec *Decoder) stackName() string {
- if dec.stackParent() == "" {
+func (dec *Decoder) structStackName() string {
+ if dec.structStackParent() == "" {
return ""
}
var fields []string
- for _, elem := range dec.stack {
+ for _, elem := range dec.structStack {
if elem.par.Kind() == reflect.Struct {
fields = append(fields, elem.idx.(string))
}
@@ -259,14 +268,14 @@ type decodeError DecodeError
func (dec *Decoder) panicType(jTyp string, gTyp reflect.Type, err error) {
panic(decodeError{
- Field: dec.stackStr(),
- FieldParent: dec.stackParent(),
- FieldName: dec.stackName(),
+ Field: dec.structStackStr(),
+ FieldParent: dec.structStackParent(),
+ FieldName: dec.structStackName(),
Err: &DecodeTypeError{
GoType: gTyp,
JSONType: jTyp,
Err: err,
- Offset: dec.InputOffset(),
+ Offset: dec.posStack[len(dec.posStack)-1],
},
})
}
@@ -275,9 +284,9 @@ func (dec *Decoder) readRune() (rune, internal.RuneType) {
c, _, t, e := dec.io.ReadRuneType()
if e != nil {
panic(decodeError{
- Field: dec.stackStr(),
- FieldParent: dec.stackParent(),
- FieldName: dec.stackName(),
+ Field: dec.structStackStr(),
+ FieldParent: dec.structStackParent(),
+ FieldName: dec.structStackName(),
Err: e,
})
}
@@ -320,9 +329,9 @@ func (sc *decRuneTypeScanner) ReadRuneType() (rune, int, internal.RuneType, erro
c, s, t, e := sc.dec.io.ReadRuneType()
if e != nil {
panic(decodeError{
- Field: sc.dec.stackStr(),
- FieldParent: sc.dec.stackParent(),
- FieldName: sc.dec.stackName(),
+ Field: sc.dec.structStackStr(),
+ FieldParent: sc.dec.structStackParent(),
+ FieldName: sc.dec.structStackName(),
Err: e,
})
}
@@ -381,6 +390,8 @@ var kind2bits = map[reflect.Kind]int{
}
func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
+ dec.posStackPush()
+ defer dec.posStackPop()
typ := val.Type()
switch {
case val.CanAddr() && reflect.PointerTo(typ) == rawMessagePtrType:
@@ -388,17 +399,17 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
var buf bytes.Buffer
dec.scan(&buf)
if err := val.Addr().Interface().(*json.RawMessage).UnmarshalJSON(buf.Bytes()); err != nil {
- dec.panicType(t.JSONType(), typ, err)
+ dec.panicType(t.JSONType(), reflect.PointerTo(typ), err)
}
case val.CanAddr() && reflect.PointerTo(typ).Implements(decodableType):
t := dec.peekRuneType()
obj := val.Addr().Interface().(Decodable)
l := dec.limitingScanner()
if err := obj.DecodeJSON(l); err != nil {
- dec.panicType(t.JSONType(), typ, err)
+ dec.panicType(t.JSONType(), reflect.PointerTo(typ), err)
}
if _, _, err := l.ReadRune(); err != io.EOF {
- dec.panicType(t.JSONType(), typ, fmt.Errorf("did not consume entire %s", t.JSONType()))
+ dec.panicType(t.JSONType(), reflect.PointerTo(typ), fmt.Errorf("did not consume entire %s", t.JSONType()))
}
case val.CanAddr() && reflect.PointerTo(typ).Implements(jsonUnmarshalerType):
t := dec.peekRuneType()
@@ -406,7 +417,7 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
dec.scan(&buf)
obj := val.Addr().Interface().(json.Unmarshaler)
if err := obj.UnmarshalJSON(buf.Bytes()); err != nil {
- dec.panicType(t.JSONType(), typ, err)
+ dec.panicType(t.JSONType(), reflect.PointerTo(typ), err)
}
case val.CanAddr() && reflect.PointerTo(typ).Implements(textUnmarshalerType):
if nullOK && dec.peekRuneType() == internal.RuneTypeNullN {
@@ -530,12 +541,16 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
index := indexStruct(typ)
var nameBuf strings.Builder
dec.decodeObject(typ, func() {
+ dec.posStackPush()
+ defer dec.posStackPop()
nameBuf.Reset()
dec.decodeString(nil, &nameBuf)
}, func() {
+ dec.posStackPush()
+ defer dec.posStackPop()
name := nameBuf.String()
- dec.stackPush(typ, name)
- defer dec.stackPop()
+ dec.structStackPush(typ, name)
+ defer dec.structStackPop()
idx, ok := index.byName[name]
if !ok {
for oidx := range index.byPos {
@@ -613,17 +628,19 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
val.Set(reflect.MakeMap(typ))
}
var nameBuf bytes.Buffer
+ var nameValPtr reflect.Value
dec.decodeObject(typ, func() {
+ dec.posStackPush()
+ defer dec.posStackPop()
nameBuf.Reset()
dec.decodeString(nil, &nameBuf)
- }, func() {
nameValTyp := typ.Key()
- nameValPtr := reflect.New(nameValTyp)
+ nameValPtr = reflect.New(nameValTyp)
switch {
case reflect.PointerTo(nameValTyp).Implements(textUnmarshalerType):
obj := nameValPtr.Interface().(encoding.TextUnmarshaler)
if err := obj.UnmarshalText(nameBuf.Bytes()); err != nil {
- dec.panicType("string", nameValTyp, err)
+ dec.panicType("string", reflect.PointerTo(nameValTyp), err)
}
default:
switch nameValTyp.Kind() {
@@ -645,8 +662,11 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
dec.panicType("object", typ, &DecodeArgumentError{Type: nameValTyp})
}
}
- dec.stackPush(typ, nameValPtr.Elem())
- defer dec.stackPop()
+ }, func() {
+ dec.posStackPush()
+ defer dec.posStackPop()
+ dec.structStackPush(typ, nameValPtr.Elem())
+ defer dec.structStackPop()
fValPtr := reflect.New(typ.Elem())
dec.decode(fValPtr.Elem(), false)
@@ -699,8 +719,10 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
}
i := 0
dec.decodeArray(typ, func() {
- dec.stackPush(typ, i)
- defer dec.stackPop()
+ dec.posStackPush()
+ defer dec.posStackPop()
+ dec.structStackPush(typ, i)
+ defer dec.structStackPop()
mValPtr := reflect.New(typ.Elem())
dec.decode(mValPtr.Elem(), false)
val.Set(reflect.Append(val, mValPtr.Elem()))
@@ -718,8 +740,10 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
i := 0
n := val.Len()
dec.decodeArray(typ, func() {
- dec.stackPush(typ, i)
- defer dec.stackPop()
+ dec.posStackPush()
+ defer dec.posStackPop()
+ dec.structStackPush(typ, i)
+ defer dec.structStackPop()
if i < n {
mValPtr := reflect.New(typ.Elem())
dec.decode(mValPtr.Elem(), false)
@@ -776,12 +800,16 @@ func (dec *Decoder) decodeAny() any {
typ := reflect.TypeOf(ret)
var nameBuf strings.Builder
dec.decodeObject(typ, func() {
+ dec.posStackPush()
+ defer dec.posStackPop()
nameBuf.Reset()
dec.decodeString(nil, &nameBuf)
}, func() {
+ dec.posStackPush()
+ defer dec.posStackPop()
name := nameBuf.String()
- dec.stackPush(typ, name)
- defer dec.stackPop()
+ dec.structStackPush(typ, name)
+ defer dec.structStackPop()
ret[name] = dec.decodeAny()
})
return ret
@@ -789,8 +817,10 @@ func (dec *Decoder) decodeAny() any {
ret := []any{}
typ := reflect.TypeOf(ret)
dec.decodeArray(typ, func() {
- dec.stackPush(typ, len(ret))
- defer dec.stackPop()
+ dec.posStackPush()
+ defer dec.posStackPop()
+ dec.structStackPush(typ, len(ret))
+ defer dec.structStackPop()
ret = append(ret, dec.decodeAny())
})
return ret
@@ -840,27 +870,37 @@ func DecodeObject(r io.RuneScanner, decodeKey, decodeVal func(io.RuneScanner) er
}
}()
dec := NewDecoder(r)
+ dec.posStackPush()
+ defer dec.posStackPop()
dec.decodeObject(nil,
func() {
+ dec.posStackPush()
+ defer dec.posStackPop()
l := dec.limitingScanner()
if err := decodeKey(l); err != nil {
+ // TODO: Find a better Go type to use than `nil`.
dec.panicType("string", nil, err)
}
if _, _, err := l.ReadRune(); err != io.EOF {
+ // TODO: Find a better Go type to use than `nil`.
dec.panicType("string", nil, fmt.Errorf("did not consume entire string"))
}
},
func() {
+ dec.posStackPush()
+ defer dec.posStackPop()
t := dec.peekRuneType()
l := dec.limitingScanner()
if err := decodeVal(l); err != nil {
+ // TODO: Find a better Go type to use than `nil`.
dec.panicType(t.JSONType(), nil, err)
}
if _, _, err := l.ReadRune(); err != io.EOF {
+ // TODO: Find a better Go type to use than `nil`.
dec.panicType(t.JSONType(), nil, fmt.Errorf("did not consume entire %s", t.JSONType()))
}
})
- return err
+ return nil
}
func (dec *Decoder) decodeObject(gTyp reflect.Type, decodeKey, decodeVal func()) {
@@ -910,17 +950,23 @@ func DecodeArray(r io.RuneScanner, decodeMember func(r io.RuneScanner) error) (e
}
}()
dec := NewDecoder(r)
+ dec.posStackPush()
+ defer dec.posStackPop()
dec.decodeArray(nil, func() {
+ dec.posStackPush()
+ defer dec.posStackPop()
t := dec.peekRuneType()
l := dec.limitingScanner()
if err := decodeMember(l); err != nil {
+ // TODO: Find a better Go type to use than `nil`.
dec.panicType(t.JSONType(), nil, err)
}
if _, _, err := l.ReadRune(); err != io.EOF {
+ // TODO: Find a better Go type to use than `nil`.
dec.panicType(t.JSONType(), nil, fmt.Errorf("did not consume entire %s", t.JSONType()))
}
})
- return
+ return nil
}
func (dec *Decoder) decodeArray(gTyp reflect.Type, decodeMember func()) {