diff options
Diffstat (limited to 'decode.go')
-rw-r--r-- | decode.go | 342 |
1 files changed, 231 insertions, 111 deletions
@@ -14,6 +14,8 @@ import ( "reflect" "strconv" "strings" + "unicode/utf16" + "unicode/utf8" ) type Decodable interface { @@ -26,6 +28,11 @@ type runeBuffer interface { Reset() } +type decodeStackItem struct { + par reflect.Type + idx any +} + type Decoder struct { io runeTypeScanner @@ -35,7 +42,7 @@ type Decoder struct { // state err error - stack []any + stack []decodeStackItem } func NewDecoder(r io.Reader) *Decoder { @@ -63,8 +70,18 @@ func (dec *Decoder) More() bool { return e == nil && t != RuneTypeEOF } -func (dec *Decoder) stackPush(idx any) { - dec.stack = append(dec.stack, idx) +const maxNestingDepth = 10000 + +func (dec *Decoder) stackPush(par reflect.Type, idx any) { + dec.stack = append(dec.stack, decodeStackItem{par, idx}) + if len(dec.stack) > maxNestingDepth { + panic(decodeError{ + Field: dec.stackStr(), + FieldParent: dec.stackParent(), + FieldName: dec.stackName(), + Err: ErrDecodeExceededMaxDepth, + }) + } } func (dec *Decoder) stackPop() { dec.stack = dec.stack[:len(dec.stack)-1] @@ -73,11 +90,30 @@ func (dec *Decoder) stackStr() string { var buf strings.Builder buf.WriteString("v") for _, item := range dec.stack { - fmt.Fprintf(&buf, "[%#v]", item) + fmt.Fprintf(&buf, "[%#v]", item.idx) } return buf.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() + } + 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)) + } + for i := 0; i < len(fields)/2; i++ { + j := (len(fields) - 1) - i + fields[i], fields[j] = fields[j], fields[i] + } + return strings.Join(fields, ".") +} + func Decode(r io.Reader, ptr any) error { return NewDecoder(r).Decode(ptr) } @@ -85,7 +121,7 @@ func Decode(r io.Reader, ptr any) error { func (dec *Decoder) Decode(ptr any) (err error) { ptrVal := reflect.ValueOf(ptr) if ptrVal.Kind() != reflect.Pointer || ptrVal.IsNil() || !ptrVal.Elem().CanSet() { - return &json.InvalidUnmarshalError{ + return &DecodeArgumentError{ // don't use ptrVal.Type() because ptrVal might be invalid if ptr==nil Type: reflect.TypeOf(ptr), } @@ -99,7 +135,8 @@ func (dec *Decoder) Decode(ptr any) (err error) { defer func() { if r := recover(); r != nil { if de, ok := r.(decodeError); ok { - dec.err = de.Err + pub := DecodeError(de) + dec.err = &pub err = dec.err } else { panic(r) @@ -112,19 +149,31 @@ func (dec *Decoder) Decode(ptr any) (err error) { // io helpers ////////////////////////////////////////////////////////////////////////////////////// -type decodeError struct { - Err error -} - -func (dec *Decoder) panicType(typ reflect.Type, err error) { - panic(decodeError{fmt.Errorf("json: type mismatch error at input byte %v: %s: type %v: %w", - dec.InputOffset(), dec.stackStr(), typ, err)}) +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(), + Err: &DecodeTypeError{ + GoType: gTyp, + JSONType: jTyp, + Err: err, + Offset: dec.InputOffset(), + }, + }) } func (dec *Decoder) readRune() (rune, RuneType) { c, _, t, e := dec.io.ReadRuneType() if e != nil { - panic(decodeError{e}) + panic(decodeError{ + Field: dec.stackStr(), + FieldParent: dec.stackParent(), + FieldName: dec.stackName(), + Err: e, + }) } return c, t } @@ -150,10 +199,10 @@ func (dec *Decoder) expectRune(ec rune, et RuneType) { } } -func (dec *Decoder) expectRuneType(ec rune, et RuneType) { +func (dec *Decoder) expectRuneType(ec rune, et RuneType, gt reflect.Type) { ac, at := dec.readRune() if ac != ec || at != et { - dec.panicType(nil, fmt.Errorf("TODO error message")) + dec.panicType(at.jsonType(), gt, nil) } } @@ -164,7 +213,12 @@ type decRuneTypeScanner struct { func (sc *decRuneTypeScanner) ReadRuneType() (rune, int, RuneType, error) { c, s, t, e := sc.dec.io.ReadRuneType() if e != nil { - panic(decodeError{e}) + panic(decodeError{ + Field: sc.dec.stackStr(), + FieldParent: sc.dec.stackParent(), + FieldName: sc.dec.stackName(), + Err: e, + }) } return c, s, t, nil } @@ -223,22 +277,25 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) { typ := val.Type() switch { case val.CanAddr() && reflect.PointerTo(typ) == rawMessagePtrType: + t := dec.peekRuneType() var buf bytes.Buffer dec.scan(&buf) if err := val.Addr().Interface().(*json.RawMessage).UnmarshalJSON(buf.Bytes()); err != nil { - dec.panicType(typ, err) + dec.panicType(t.jsonType(), typ, err) } case val.CanAddr() && reflect.PointerTo(typ).Implements(decodableType): + t := dec.peekRuneType() obj := val.Addr().Interface().(Decodable) if err := obj.DecodeJSON(dec.limitingScanner()); err != nil { - dec.panicType(typ, err) + dec.panicType(t.jsonType(), typ, err) } case val.CanAddr() && reflect.PointerTo(typ).Implements(jsonUnmarshalerType): + t := dec.peekRuneType() var buf bytes.Buffer dec.scan(&buf) obj := val.Addr().Interface().(json.Unmarshaler) if err := obj.UnmarshalJSON(buf.Bytes()); err != nil { - dec.panicType(typ, err) + dec.panicType(t.jsonType(), typ, err) } case val.CanAddr() && reflect.PointerTo(typ).Implements(textUnmarshalerType): if nullOK && dec.peekRuneType() == RuneTypeNullN { @@ -246,30 +303,29 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) { return } var buf bytes.Buffer - dec.decodeString(&buf) + dec.decodeString(typ, &buf) obj := val.Addr().Interface().(encoding.TextUnmarshaler) if err := obj.UnmarshalText(buf.Bytes()); err != nil { - dec.panicType(typ, err) + dec.panicType("string", typ, err) } default: - kind := typ.Kind() - switch kind { + switch kind := typ.Kind(); kind { case reflect.Bool: if nullOK && dec.peekRuneType() == RuneTypeNullN { dec.decodeNull() return } - val.SetBool(dec.decodeBool()) + val.SetBool(dec.decodeBool(typ)) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: if nullOK && dec.peekRuneType() == RuneTypeNullN { dec.decodeNull() return } var buf strings.Builder - dec.scanNumber(&buf) + dec.scanNumber(typ, &buf) n, err := strconv.ParseInt(buf.String(), 10, kind2bits[kind]) if err != nil { - dec.panicType(typ, err) + dec.panicType("number "+buf.String(), typ, err) } val.SetInt(n) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: @@ -278,10 +334,10 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) { return } var buf strings.Builder - dec.scanNumber(&buf) + dec.scanNumber(typ, &buf) n, err := strconv.ParseUint(buf.String(), 10, kind2bits[kind]) if err != nil { - dec.panicType(typ, err) + dec.panicType("number "+buf.String(), typ, err) } val.SetUint(n) case reflect.Float32, reflect.Float64: @@ -290,10 +346,10 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) { return } var buf strings.Builder - dec.scanNumber(&buf) + dec.scanNumber(typ, &buf) n, err := strconv.ParseFloat(buf.String(), kind2bits[kind]) if err != nil { - dec.panicType(typ, err) + dec.panicType("number "+buf.String(), typ, err) } val.SetFloat(n) case reflect.String: @@ -303,32 +359,44 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) { } var buf strings.Builder if typ == numberType { - dec.scanNumber(&buf) + dec.scanNumber(typ, &buf) val.SetString(buf.String()) } else { - dec.decodeString(&buf) + dec.decodeString(typ, &buf) val.SetString(buf.String()) } case reflect.Interface: if typ.NumMethod() > 0 { - dec.panicType(typ, fmt.Errorf("cannot decode in to non-empty interface")) + dec.panicType("", typ, fmt.Errorf("cannot decode in to non-empty interface")) + } + // 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() { + 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) { + dec.decode(ptr, false) + break + } } + // Couldn't get type information from a pointer; fall back to untyped mode. switch dec.peekRuneType() { case RuneTypeNullN: - if !val.IsNil() && val.Elem().Kind() == reflect.Pointer && val.Elem().Elem().Kind() == reflect.Pointer { - // XXX: I can't justify this case, other than "it's what encoding/json does, but - // I don't understand their rationale". - dec.decode(val.Elem(), false) - } else { - dec.decodeNull() - val.Set(reflect.Zero(typ)) - } + dec.decodeNull() + val.Set(reflect.Zero(typ)) default: - if !val.IsNil() && val.Elem().Kind() == reflect.Pointer { - dec.decode(val.Elem(), false) - } else { - val.Set(reflect.ValueOf(dec.decodeAny())) - } + val.Set(reflect.ValueOf(dec.decodeAny())) } case reflect.Struct: if nullOK && dec.peekRuneType() == RuneTypeNullN { @@ -337,14 +405,23 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) { } index := indexStruct(typ) var nameBuf strings.Builder - dec.decodeObject(&nameBuf, func() { + dec.decodeObject(typ, &nameBuf, func() { name := nameBuf.String() - dec.stackPush(name) + dec.stackPush(typ, name) defer dec.stackPop() idx, ok := index.byName[name] if !ok { + for oname, oidx := range index.byName { + if strings.EqualFold(name, oname) { + idx = oidx + ok = true + break + } + } + } + if !ok { if dec.disallowUnknownFields { - dec.panicType(typ, fmt.Errorf("unknown field %q", name)) + dec.panicType("", typ, fmt.Errorf("json: unknown field %q", name)) } dec.scan(io.Discard) return @@ -353,18 +430,20 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) { fVal := val for _, idx := range field.Path { if fVal.Kind() == reflect.Pointer { - if fVal.IsNil() { - if !fVal.CanSet() { // https://golang.org/issue/21357 - dec.panicType(fVal.Type().Elem(), fmt.Errorf("cannot set embedded pointer to unexported type")) + if fVal.IsNil() && !fVal.CanSet() { // https://golang.org/issue/21357 + dec.panicType("", fVal.Type().Elem(), fmt.Errorf("cannot set embedded pointer to unexported type")) + } + if dec.peekRuneType() != RuneTypeNullN { + if fVal.IsNil() { + fVal.Set(reflect.New(fVal.Type().Elem())) } - fVal.Set(reflect.New(fVal.Type().Elem())) + fVal = fVal.Elem() } - fVal = fVal.Elem() } fVal = fVal.Field(idx) } if field.Quote { - switch dec.peekRuneType() { + switch t := dec.peekRuneType(); t { case RuneTypeNullN: dec.decodeNull() switch fVal.Kind() { @@ -378,18 +457,25 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) { case RuneTypeStringBeg: // TODO: Figure out how to do this without buffering, have correct offsets. var buf bytes.Buffer - dec.decodeString(&buf) - subD := NewDecoder(&buf) - subD.decode(fVal, false) + dec.decodeString(nil, &buf) + if err := Decode(bytes.NewReader(buf.Bytes()), fVal.Addr().Interface()); err != nil { + if str := buf.String(); str != "null" { + dec.panicType("", fVal.Type(), + fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", + str, fVal.Type())) + } + } default: - dec.panicType(typ, fmt.Errorf(",string field TODO ERROR MESSAGE")) + dec.panicType(t.jsonType(), fVal.Type(), + fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal unquoted value into %v", + fVal.Type())) } } else { dec.decode(fVal, true) } }) case reflect.Map: - switch dec.peekRuneType() { + switch t := dec.peekRuneType(); t { case RuneTypeNullN: dec.decodeNull() val.Set(reflect.Zero(typ)) @@ -398,14 +484,14 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) { val.Set(reflect.MakeMap(typ)) } var nameBuf bytes.Buffer - dec.decodeObject(&nameBuf, func() { + dec.decodeObject(typ, &nameBuf, func() { nameValTyp := typ.Key() 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(nameValTyp, err) + dec.panicType("string", nameValTyp, err) } default: switch nameValTyp.Kind() { @@ -414,20 +500,20 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: n, err := strconv.ParseInt(nameBuf.String(), 10, kind2bits[nameValTyp.Kind()]) if err != nil { - dec.panicType(nameValTyp, err) + dec.panicType("number "+nameBuf.String(), nameValTyp, err) } nameValPtr.Elem().SetInt(n) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: n, err := strconv.ParseUint(nameBuf.String(), 10, kind2bits[nameValTyp.Kind()]) if err != nil { - dec.panicType(nameValTyp, err) + dec.panicType("number "+nameBuf.String(), nameValTyp, err) } nameValPtr.Elem().SetUint(n) default: - dec.panicType(typ, fmt.Errorf("invalid map key type: %v", nameValTyp)) + dec.panicType("object", typ, &DecodeArgumentError{nameValTyp}) } } - dec.stackPush(nameValPtr.Elem()) + dec.stackPush(typ, nameValPtr.Elem()) defer dec.stackPop() fValPtr := reflect.New(typ.Elem()) @@ -436,33 +522,39 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) { val.SetMapIndex(nameValPtr.Elem(), fValPtr.Elem()) }) default: - dec.panicType(typ, fmt.Errorf("map: TODO")) + dec.panicType(t.jsonType(), typ, nil) } case reflect.Slice: switch { - case typ.Elem().Kind() == reflect.Uint8: - switch dec.peekRuneType() { + case typ.Elem().Kind() == reflect.Uint8 && !(dec.peekRuneType() == RuneTypeArrayBeg && (false || + reflect.PointerTo(typ.Elem()).Implements(decodableType) || + reflect.PointerTo(typ.Elem()).Implements(jsonUnmarshalerType) || + reflect.PointerTo(typ.Elem()).Implements(textUnmarshalerType))): + switch t := dec.peekRuneType(); t { case RuneTypeNullN: dec.decodeNull() val.Set(reflect.Zero(typ)) case RuneTypeStringBeg: - var buf bytes.Buffer - dec.decodeString(newBase64Decoder(&buf)) if typ.Elem() == byteType { + var buf bytes.Buffer + dec.decodeString(typ, newBase64Decoder(&buf)) val.Set(reflect.ValueOf(buf.Bytes())) } else { + // TODO: Surely there's a better way. At the very least, we should + // avoid buffering. + var buf bytes.Buffer + dec.decodeString(typ, newBase64Decoder(&buf)) bs := buf.Bytes() - // TODO: Surely there's a better way. val.Set(reflect.MakeSlice(typ, len(bs), len(bs))) for i := 0; i < len(bs); i++ { val.Index(i).Set(reflect.ValueOf(bs[i]).Convert(typ.Elem())) } } default: - dec.panicType(typ, fmt.Errorf("byte slice: TODO")) + dec.panicType(t.jsonType(), typ, nil) } default: - switch dec.peekRuneType() { + switch t := dec.peekRuneType(); t { case RuneTypeNullN: dec.decodeNull() val.Set(reflect.Zero(typ)) @@ -474,8 +566,8 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) { val.Set(val.Slice(0, 0)) } i := 0 - dec.decodeArray(func() { - dec.stackPush(i) + dec.decodeArray(typ, func() { + dec.stackPush(typ, i) defer dec.stackPop() mValPtr := reflect.New(typ.Elem()) dec.decode(mValPtr.Elem(), false) @@ -483,7 +575,7 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) { i++ }) default: - dec.panicType(typ, fmt.Errorf("slice: TODO")) + dec.panicType(t.jsonType(), typ, nil) } } case reflect.Array: @@ -493,8 +585,8 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) { } i := 0 n := val.Len() - dec.decodeArray(func() { - dec.stackPush(i) + dec.decodeArray(typ, func() { + dec.stackPush(typ, i) defer dec.stackPop() if i < n { mValPtr := reflect.New(typ.Elem()) @@ -512,15 +604,6 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) { switch dec.peekRuneType() { case RuneTypeNullN: dec.decodeNull() - /* - for typ.Elem().Kind() == reflect.Pointer { - if val.IsNil() || !val.Elem().CanSet() { - val.Set(reflect.New(typ.Elem())) - } - val = val.Elem() - typ = val.Type() - } - */ val.Set(reflect.Zero(typ)) default: if val.IsNil() { @@ -529,7 +612,7 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) { dec.decode(val.Elem(), false) } default: - dec.panicType(typ, fmt.Errorf("unsupported type (kind=%v)", typ.Kind())) + dec.panicType("", typ, fmt.Errorf("unsupported type (kind=%v)", typ.Kind())) } } } @@ -545,9 +628,9 @@ func (dec *Decoder) scan(out io.Writer) { } } -func (dec *Decoder) scanNumber(out io.Writer) { - if !dec.peekRuneType().IsNumber() { - dec.panicType(numberType, fmt.Errorf("number: not a number")) +func (dec *Decoder) scanNumber(gTyp reflect.Type, out io.Writer) { + if t := dec.peekRuneType(); !t.IsNumber() { + dec.panicType(t.jsonType(), gTyp, nil) } dec.scan(out) } @@ -558,25 +641,27 @@ func (dec *Decoder) decodeAny() any { switch c { case '{': ret := make(map[string]any) + typ := reflect.TypeOf(ret) var nameBuf strings.Builder - dec.decodeObject(&nameBuf, func() { + dec.decodeObject(typ, &nameBuf, func() { name := nameBuf.String() - dec.stackPush(name) + dec.stackPush(typ, name) defer dec.stackPop() ret[name] = dec.decodeAny() }) return ret case '[': ret := []any{} - dec.decodeArray(func() { - dec.stackPush(len(ret)) + typ := reflect.TypeOf(ret) + dec.decodeArray(typ, func() { + dec.stackPush(typ, len(ret)) defer dec.stackPop() ret = append(ret, dec.decodeAny()) }) return ret case '"': var buf strings.Builder - dec.decodeString(&buf) + dec.decodeString(nil, &buf) return buf.String() case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': var buf strings.Builder @@ -591,7 +676,7 @@ func (dec *Decoder) decodeAny() any { } return f64 case 't', 'f': - return dec.decodeBool() + return dec.decodeBool(nil) case 'n': dec.decodeNull() return nil @@ -600,8 +685,8 @@ func (dec *Decoder) decodeAny() any { } } -func (dec *Decoder) decodeObject(nameBuf runeBuffer, decodeKVal func()) { - dec.expectRuneType('{', RuneTypeObjectBeg) +func (dec *Decoder) decodeObject(gTyp reflect.Type, nameBuf runeBuffer, decodeKVal func()) { + dec.expectRuneType('{', RuneTypeObjectBeg, gTyp) _, t := dec.readRune() switch t { case RuneTypeObjectEnd: @@ -610,7 +695,7 @@ func (dec *Decoder) decodeObject(nameBuf runeBuffer, decodeKVal func()) { decodeMember: dec.unreadRune() nameBuf.Reset() - dec.decodeString(nameBuf) + dec.decodeString(nil, nameBuf) dec.expectRune(':', RuneTypeObjectColon) decodeKVal() _, t := dec.readRune() @@ -628,8 +713,8 @@ func (dec *Decoder) decodeObject(nameBuf runeBuffer, decodeKVal func()) { } } -func (dec *Decoder) decodeArray(decodeMember func()) { - dec.expectRuneType('[', RuneTypeArrayBeg) +func (dec *Decoder) decodeArray(gTyp reflect.Type, decodeMember func()) { + dec.expectRuneType('[', RuneTypeArrayBeg, gTyp) _, t := dec.readRune() switch t { case RuneTypeArrayEnd: @@ -650,8 +735,8 @@ func (dec *Decoder) decodeArray(decodeMember func()) { } } -func (dec *Decoder) decodeString(out io.Writer) { - dec.expectRuneType('"', RuneTypeStringBeg) +func (dec *Decoder) decodeString(gTyp reflect.Type, out io.Writer) { + dec.expectRuneType('"', RuneTypeStringBeg, gTyp) var uhex [4]byte for { c, t := dec.readRune() @@ -694,7 +779,42 @@ func (dec *Decoder) decodeString(out io.Writer) { rune(uhex[1])<<8 | rune(uhex[2])<<4 | rune(uhex[3])<<0 - _, _ = writeRune(out, c) + handleUnicode: + if utf16.IsSurrogate(c) { + if dec.peekRuneType() != RuneTypeStringEsc { + _, _ = writeRune(out, utf8.RuneError) + break + } + dec.expectRune('\\', RuneTypeStringEsc) + if dec.peekRuneType() != RuneTypeStringEscU { + _, _ = writeRune(out, utf8.RuneError) + break + } + dec.expectRune('u', RuneTypeStringEscU) + + b, _ := dec.readRune() + uhex[0], _ = hex2int(b) + b, _ = dec.readRune() + uhex[1], _ = hex2int(b) + b, _ = dec.readRune() + uhex[2], _ = hex2int(b) + b, _ = dec.readRune() + uhex[3], _ = hex2int(b) + c2 := 0 | + rune(uhex[0])<<12 | + rune(uhex[1])<<8 | + rune(uhex[2])<<4 | + rune(uhex[3])<<0 + d := utf16.DecodeRune(c, c2) + if d == utf8.RuneError { + _, _ = writeRune(out, utf8.RuneError) + c = c2 + goto handleUnicode + } + _, _ = writeRune(out, d) + } else { + _, _ = writeRune(out, c) + } case RuneTypeStringEnd: return default: @@ -703,8 +823,8 @@ func (dec *Decoder) decodeString(out io.Writer) { } } -func (dec *Decoder) decodeBool() bool { - c, _ := dec.readRune() +func (dec *Decoder) decodeBool(gTyp reflect.Type) bool { + c, t := dec.readRune() switch c { case 't': dec.expectRune('r', RuneTypeTrueR) @@ -718,13 +838,13 @@ func (dec *Decoder) decodeBool() bool { dec.expectRune('e', RuneTypeFalseE) return false default: - dec.panicType(boolType, fmt.Errorf("bool: expected %q or %q but got %q", 't', 'f', c)) + dec.panicType(t.jsonType(), gTyp, nil) panic("not reached") } } func (dec *Decoder) decodeNull() { - dec.expectRuneType('n', RuneTypeNullN) + dec.expectRune('n', RuneTypeNullN) dec.expectRune('u', RuneTypeNullU) dec.expectRune('l', RuneTypeNullL1) dec.expectRune('l', RuneTypeNullL2) |