summaryrefslogtreecommitdiff
path: root/decode.go
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@datawire.io>2022-08-16 00:15:57 -0600
committerLuke Shumaker <lukeshu@datawire.io>2022-08-16 02:08:39 -0600
commit8c0513a04ff3870f57bde230507aaa8c6b7e6e86 (patch)
tree4e9c8082bb9168c923eee2c6bd17f01e44206f0a /decode.go
parent83ec1924ae051b60f911aa8b53b741c5371faaf8 (diff)
Get borrowed_decode_test.go passing
Diffstat (limited to 'decode.go')
-rw-r--r--decode.go66
1 files changed, 43 insertions, 23 deletions
diff --git a/decode.go b/decode.go
index b1cc90f..f630541 100644
--- a/decode.go
+++ b/decode.go
@@ -91,20 +91,25 @@ func (dec *Decoder) stackStr() string {
}
func (dec *Decoder) stackParent() string {
- if len(dec.stack) > 0 && dec.stack[len(dec.stack)-1].par.Kind() == reflect.Struct {
- return dec.stack[len(dec.stack)-1].par.Name()
+ last := len(dec.stack) - 1
+ if last > 0 && dec.stack[last].par.Kind() != reflect.Struct && dec.stack[last-1].par.Kind() == reflect.Struct {
+ last--
+ }
+ if last >= 0 && dec.stack[last].par.Kind() == reflect.Struct {
+ return dec.stack[last].par.Name()
}
return ""
}
func (dec *Decoder) stackName() string {
- var fields []string
- for i := len(dec.stack) - 1; i >= 0 && dec.stack[i].par.Kind() == reflect.Struct; i-- {
- fields = append(fields, dec.stack[i].idx.(string))
+ if dec.stackParent() == "" {
+ return ""
}
- for i := 0; i < len(fields)/2; i++ {
- j := (len(fields) - 1) - i
- fields[i], fields[j] = fields[j], fields[i]
+ var fields []string
+ for _, elem := range dec.stack {
+ if elem.par.Kind() == reflect.Struct {
+ fields = append(fields, elem.idx.(string))
+ }
}
return strings.Join(fields, ".")
}
@@ -298,10 +303,10 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
return
}
var buf bytes.Buffer
- dec.decodeString(typ, &buf)
+ dec.decodeString(reflect.PointerTo(typ), &buf)
obj := val.Addr().Interface().(encoding.TextUnmarshaler)
if err := obj.UnmarshalText(buf.Bytes()); err != nil {
- dec.panicType("string", typ, err)
+ dec.panicType("string", reflect.PointerTo(typ), err)
}
default:
switch kind := typ.Kind(); kind {
@@ -354,7 +359,13 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
}
var buf strings.Builder
if typ == numberType {
- dec.scanNumber(typ, &buf)
+ t := dec.peekRuneType()
+ dec.scan(&buf)
+ if !t.IsNumber() {
+ dec.panicType(t.jsonType(), typ,
+ fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number",
+ buf.String()))
+ }
val.SetString(buf.String())
} else {
dec.decodeString(typ, &buf)
@@ -362,25 +373,32 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
}
case reflect.Interface:
if typ.NumMethod() > 0 {
- dec.panicType("", typ, fmt.Errorf("cannot decode in to non-empty interface"))
+ dec.panicType(dec.peekRuneType().jsonType(), typ, ErrDecodeNonEmptyInterface)
}
// If the interface stores a pointer, try to use the type information of the pointer.
if !val.IsNil() && val.Elem().Kind() == reflect.Pointer {
// Follow a chain of pointers until we find the first settable
// pointer (if any).
ptr := val.Elem()
- for ptr.Kind() == reflect.Pointer {
- if ptr.CanSet() {
- break
- }
- if ptr.IsNil() {
+ for {
+ if ptr.CanSet() || ptr.IsNil() || ptr.Elem().Kind() != reflect.Pointer {
+ // We've reached the end of the line, good or bad.
break
}
ptr = ptr.Elem()
}
- // We only neet to be able to set the pointer itself if we're
- // decoding "null", so add a "||" clause.
- if ptr.Kind() == reflect.Pointer && (ptr.CanSet() || dec.peekRuneType() != RuneTypeNullN) {
+ // ptr.Elem() != val
+ //
+ // Avoid the loop of an interface storing a pointer to its own
+ // address. We only need to worry about this at the leaf (and not
+ // in the loop) because the only way it's possible is if there's
+ // an interface in there, which'd break from the loop on its own.
+ //
+ // ptr.CanSet() || dec.peekRuneType() != RuneTypeNullN
+ //
+ // We only need the pointer itself to be settable if we're
+ // decoding null.
+ if ptr.Elem() != val && (ptr.CanSet() || dec.peekRuneType() != RuneTypeNullN) {
dec.decode(ptr, false)
break
}
@@ -406,8 +424,8 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
defer dec.stackPop()
idx, ok := index.byName[name]
if !ok {
- for oname, oidx := range index.byName {
- if strings.EqualFold(name, oname) {
+ for oidx := range index.byPos {
+ if strings.EqualFold(name, index.byPos[oidx].Name) {
idx = oidx
ok = true
break
@@ -426,7 +444,9 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
for _, idx := range field.Path {
if fVal.Kind() == reflect.Pointer {
if fVal.IsNil() && !fVal.CanSet() { // https://golang.org/issue/21357
- dec.panicType("", fVal.Type().Elem(), fmt.Errorf("cannot set embedded pointer to unexported type"))
+ dec.panicType("", fVal.Type().Elem(),
+ fmt.Errorf("json: cannot set embedded pointer to unexported struct: %v",
+ fVal.Type().Elem()))
}
if dec.peekRuneType() != RuneTypeNullN {
if fVal.IsNil() {