diff options
Diffstat (limited to 'decode.go')
-rw-r--r-- | decode.go | 140 |
1 files changed, 93 insertions, 47 deletions
@@ -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()) { |