summaryrefslogtreecommitdiff
path: root/lib/lowmemjson/decode.go
diff options
context:
space:
mode:
Diffstat (limited to 'lib/lowmemjson/decode.go')
-rw-r--r--lib/lowmemjson/decode.go812
1 files changed, 0 insertions, 812 deletions
diff --git a/lib/lowmemjson/decode.go b/lib/lowmemjson/decode.go
deleted file mode 100644
index 03d5b7a..0000000
--- a/lib/lowmemjson/decode.go
+++ /dev/null
@@ -1,812 +0,0 @@
-// Copyright (C) 2022 Luke Shumaker <lukeshu@lukeshu.com>
-//
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-package lowmemjson
-
-import (
- "bufio"
- "bytes"
- "encoding"
- "encoding/json"
- "fmt"
- "io"
- "reflect"
- "strconv"
- "strings"
-)
-
-type Decodable interface {
- DecodeJSON(io.RuneScanner) error
-}
-
-type runeBuffer interface {
- io.Writer
- WriteRune(rune) (int, error)
- Reset()
-}
-
-type Decoder struct {
- r io.RuneScanner
-
- // config
- disallowUnknownFields bool
- useNumber bool
-
- // state
- err error
- curPos int64
- nxtPos int64
- stack []any
-}
-
-var forceBufio bool
-
-func NewDecoder(r io.Reader) *Decoder {
- rs, ok := r.(io.RuneScanner)
- if forceBufio || !ok {
- rs = bufio.NewReader(r)
- }
- return &Decoder{
- r: rs,
- }
-}
-
-func (dec *Decoder) DisallowUnknownFields() { dec.disallowUnknownFields = true }
-func (dec *Decoder) UseNumber() { dec.useNumber = true }
-func (dec *Decoder) InputOffset() int64 { return dec.curPos }
-
-func (dec *Decoder) More() bool {
- dec.decodeWS()
- _, ok := dec.peekRuneOrEOF()
- return ok
-}
-
-func (dec *Decoder) stackStr() string {
- var buf strings.Builder
- buf.WriteString("v")
- for _, item := range dec.stack {
- fmt.Fprintf(&buf, "[%#v]", item)
- }
- return buf.String()
-}
-
-func (dec *Decoder) stackPush(idx any) {
- dec.stack = append(dec.stack, idx)
-}
-func (dec *Decoder) stackPop() {
- dec.stack = dec.stack[:len(dec.stack)-1]
-}
-
-type decodeError struct {
- Err error
-}
-
-func (dec *Decoder) panicIO(err error) {
- panic(decodeError{fmt.Errorf("json: I/O error at input byte %v: %s: %w",
- dec.nxtPos, dec.stackStr(), err)})
-}
-func (dec *Decoder) panicSyntax(err error) {
- panic(decodeError{fmt.Errorf("json: syntax error at input byte %v: %s: %w",
- dec.curPos, dec.stackStr(), err)})
-}
-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.curPos, dec.stackStr(), typ, err)})
-}
-
-func Decode(r io.Reader, ptr any) error {
- return NewDecoder(r).Decode(ptr)
-}
-
-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{
- // don't use ptrVal.Type() because ptrVal might be invalid if ptr==nil
- Type: reflect.TypeOf(ptr),
- }
- }
-
- if dec.err != nil {
- return dec.err
- }
-
- defer func() {
- if r := recover(); r != nil {
- if de, ok := r.(decodeError); ok {
- dec.err = de.Err
- err = dec.err
- } else {
- panic(r)
- }
- }
- }()
- dec.decodeWS()
- dec.decode(ptrVal.Elem(), false)
- return nil
-}
-
-func (dec *Decoder) readRune() rune {
- c, size, err := dec.r.ReadRune()
- if err != nil {
- if err == io.EOF {
- dec.panicSyntax(io.ErrUnexpectedEOF)
- }
- dec.panicIO(err)
- }
- dec.curPos = dec.nxtPos
- dec.nxtPos = dec.curPos + int64(size)
- return c
-}
-
-func (dec *Decoder) readRuneOrEOF() (c rune, ok bool) {
- c, size, err := dec.r.ReadRune()
- if err != nil {
- if err == io.EOF {
- return 0, false
- }
- dec.panicIO(err)
- }
- dec.curPos = dec.nxtPos
- dec.nxtPos = dec.curPos + int64(size)
- return c, true
-}
-
-func (dec *Decoder) unreadRune() {
- if err := dec.r.UnreadRune(); err != nil {
- // .UnreadRune() must succeed if the previous call was
- // .ReadRune(), which it always is for this code.
- panic(err)
- }
- dec.nxtPos = dec.curPos
-}
-
-func (dec *Decoder) peekRune() rune {
- c, _, err := dec.r.ReadRune()
- if err != nil {
- if err == io.EOF {
- dec.panicSyntax(io.ErrUnexpectedEOF)
- }
- dec.panicIO(err)
- }
- if err := dec.r.UnreadRune(); err != nil {
- // .UnreadRune() must succeed if the previous call was
- // .ReadRune(), which it always is for this code.
- panic(err)
- }
- return c
-}
-
-func (dec *Decoder) peekRuneOrEOF() (rune, bool) {
- c, _, err := dec.r.ReadRune()
- if err != nil {
- if err == io.EOF {
- return 0, false
- }
- dec.panicIO(err)
- }
- if err := dec.r.UnreadRune(); err != nil {
- // .UnreadRune() must succeed if the previous call was
- // .ReadRune(), which it always is for this code.
- panic(err)
- }
- return c, true
-}
-
-func (dec *Decoder) expectRune(exp rune) {
- act := dec.readRune()
- if act != exp {
- dec.panicSyntax(fmt.Errorf("expected %q but got %q", exp, act))
- }
-}
-
-var (
- rawMessagePtrType = reflect.TypeOf((*json.RawMessage)(nil))
- decodableType = reflect.TypeOf((*Decodable)(nil)).Elem()
- jsonUnmarshalerType = reflect.TypeOf((*json.Unmarshaler)(nil)).Elem()
- textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
-)
-
-var kind2bits = map[reflect.Kind]int{
- reflect.Int: int(32 << (^uint(0) >> 63)),
- reflect.Int8: 8,
- reflect.Int16: 16,
- reflect.Int32: 32,
- reflect.Int64: 64,
-
- reflect.Uint: int(32 << (^uint(0) >> 63)),
- reflect.Uint8: 8,
- reflect.Uint16: 16,
- reflect.Uint32: 32,
- reflect.Uint64: 64,
-
- reflect.Uintptr: int(32 << (^uintptr(0) >> 63)),
-
- reflect.Float32: 32,
- reflect.Float64: 64,
-}
-
-func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
- typ := val.Type()
- switch {
- case val.CanAddr() && reflect.PointerTo(typ) == rawMessagePtrType:
- var buf bytes.Buffer
- dec.scan(&buf)
- if err := val.Addr().Interface().(*json.RawMessage).UnmarshalJSON(buf.Bytes()); err != nil {
- dec.panicSyntax(err)
- }
- case val.CanAddr() && reflect.PointerTo(typ).Implements(decodableType):
- obj := val.Addr().Interface().(Decodable)
- if err := obj.DecodeJSON(dec.r); err != nil {
- dec.panicSyntax(err)
- }
- case val.CanAddr() && reflect.PointerTo(typ).Implements(jsonUnmarshalerType):
- var buf bytes.Buffer
- dec.scan(&buf)
- obj := val.Addr().Interface().(json.Unmarshaler)
- if err := obj.UnmarshalJSON(buf.Bytes()); err != nil {
- dec.panicSyntax(err)
- }
- case val.CanAddr() && reflect.PointerTo(typ).Implements(textUnmarshalerType):
- if nullOK && dec.peekRune() == 'n' {
- dec.decodeNull()
- return
- }
- var buf bytes.Buffer
- dec.decodeString(&buf)
- obj := val.Addr().Interface().(encoding.TextUnmarshaler)
- if err := obj.UnmarshalText(buf.Bytes()); err != nil {
- dec.panicSyntax(err)
- }
- default:
- kind := typ.Kind()
- switch kind {
- case reflect.Bool:
- if nullOK && dec.peekRune() == 'n' {
- dec.decodeNull()
- return
- }
- val.SetBool(dec.decodeBool())
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- if nullOK && dec.peekRune() == 'n' {
- dec.decodeNull()
- return
- }
- var buf strings.Builder
- dec.scanNumber(&buf)
- n, err := strconv.ParseInt(buf.String(), 10, kind2bits[kind])
- if err != nil {
- dec.panicSyntax(err)
- }
- val.SetInt(n)
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- if nullOK && dec.peekRune() == 'n' {
- dec.decodeNull()
- return
- }
- var buf strings.Builder
- dec.scanNumber(&buf)
- n, err := strconv.ParseUint(buf.String(), 10, kind2bits[kind])
- if err != nil {
- dec.panicSyntax(err)
- }
- val.SetUint(n)
- case reflect.Float32, reflect.Float64:
- if nullOK && dec.peekRune() == 'n' {
- dec.decodeNull()
- return
- }
- var buf strings.Builder
- dec.scanNumber(&buf)
- n, err := strconv.ParseFloat(buf.String(), kind2bits[kind])
- if err != nil {
- dec.panicSyntax(err)
- }
- val.SetFloat(n)
- case reflect.String:
- if nullOK && dec.peekRune() == 'n' {
- dec.decodeNull()
- return
- }
- var buf strings.Builder
- if typ == numberType {
- dec.scanNumber(&buf)
- val.SetString(buf.String())
- } else {
- dec.decodeString(&buf)
- val.SetString(buf.String())
- }
- case reflect.Interface:
- if typ.NumMethod() > 0 {
- dec.panicType(typ, fmt.Errorf("cannot decode in to non-empty interface"))
- }
- switch dec.peekRune() {
- case 'n':
- 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))
- }
- default:
- if !val.IsNil() && val.Elem().Kind() == reflect.Pointer {
- dec.decode(val.Elem(), false)
- } else {
- val.Set(reflect.ValueOf(dec.decodeAny()))
- }
- }
- case reflect.Struct:
- if nullOK && dec.peekRune() == 'n' {
- dec.decodeNull()
- return
- }
- index := indexStruct(typ)
- var nameBuf strings.Builder
- dec.decodeObject(&nameBuf, func() {
- name := nameBuf.String()
- dec.stackPush(name)
- defer dec.stackPop()
- idx, ok := index.byName[name]
- if !ok {
- if dec.disallowUnknownFields {
- dec.panicType(typ, fmt.Errorf("unknown field %q", name))
- }
- dec.scan(io.Discard)
- return
- }
- field := index.byPos[idx]
- 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"))
- }
- fVal.Set(reflect.New(fVal.Type().Elem()))
- }
- fVal = fVal.Elem()
- }
- fVal = fVal.Field(idx)
- }
- if field.Quote {
- switch dec.peekRune() {
- case 'n':
- dec.decodeNull()
- switch fVal.Kind() {
- // XXX: I can't justify this list, other than "it's what encoding/json
- // does, but I don't understand their rationale".
- case reflect.Interface, reflect.Pointer, reflect.Map, reflect.Slice:
- fVal.Set(reflect.Zero(fVal.Type()))
- }
- case '"':
- // TODO: Figure out how to do this without buffering.
- var buf bytes.Buffer
- subD := *dec // capture the .curPos *before* calling .decodeString
- dec.decodeString(&buf)
- subD.r = &buf
- subD.decode(fVal, false)
- default:
- dec.panicSyntax(fmt.Errorf(",string field: expected %q or %q but got %q",
- 'n', '"', dec.peekRune()))
- }
- } else {
- dec.decode(fVal, true)
- }
- })
- case reflect.Map:
- switch dec.peekRune() {
- case 'n':
- dec.decodeNull()
- val.Set(reflect.Zero(typ))
- case '{':
- if val.IsNil() {
- val.Set(reflect.MakeMap(typ))
- }
- var nameBuf bytes.Buffer
- dec.decodeObject(&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.panicSyntax(err)
- }
- default:
- switch nameValTyp.Kind() {
- case reflect.String:
- nameValPtr.Elem().SetString(nameBuf.String())
- 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.panicSyntax(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.panicSyntax(err)
- }
- nameValPtr.Elem().SetUint(n)
- default:
- dec.panicType(typ, fmt.Errorf("invalid map key type: %v", nameValTyp))
- }
- }
- dec.stackPush(nameValPtr.Elem())
- defer dec.stackPop()
-
- fValPtr := reflect.New(typ.Elem())
- dec.decode(fValPtr.Elem(), false)
-
- val.SetMapIndex(nameValPtr.Elem(), fValPtr.Elem())
- })
- default:
- dec.panicSyntax(fmt.Errorf("map: expected %q or %q bug got %q", 'n', '{', dec.peekRune()))
- }
- case reflect.Slice:
- switch {
- case typ.Elem().Kind() == reflect.Uint8:
- switch dec.peekRune() {
- case 'n':
- dec.decodeNull()
- val.Set(reflect.Zero(typ))
- case '"':
- var buf bytes.Buffer
- dec.decodeString(newBase64Decoder(&buf))
- if typ.Elem() == byteType {
- val.Set(reflect.ValueOf(buf.Bytes()))
- } else {
- 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.panicSyntax(fmt.Errorf("byte slice: expected %q or %q but got %q", 'n', '"', dec.peekRune()))
- }
- default:
- switch dec.peekRune() {
- case 'n':
- dec.decodeNull()
- val.Set(reflect.Zero(typ))
- case '[':
- if val.IsNil() {
- val.Set(reflect.MakeSlice(typ, 0, 0))
- }
- if val.Len() > 0 {
- val.Set(val.Slice(0, 0))
- }
- i := 0
- dec.decodeArray(func() {
- dec.stackPush(i)
- defer dec.stackPop()
- mValPtr := reflect.New(typ.Elem())
- dec.decode(mValPtr.Elem(), false)
- val.Set(reflect.Append(val, mValPtr.Elem()))
- i++
- })
- default:
- dec.panicSyntax(fmt.Errorf("slice: expected %q or %q but got %q", 'n', '[', dec.peekRune()))
- }
- }
- case reflect.Array:
- if nullOK && dec.peekRune() == 'n' {
- dec.decodeNull()
- return
- }
- i := 0
- n := val.Len()
- dec.decodeArray(func() {
- dec.stackPush(i)
- defer dec.stackPop()
- if i < n {
- mValPtr := reflect.New(typ.Elem())
- dec.decode(mValPtr.Elem(), false)
- val.Index(i).Set(mValPtr.Elem())
- } else {
- dec.scan(io.Discard)
- }
- i++
- })
- for ; i < n; i++ {
- val.Index(i).Set(reflect.Zero(typ.Elem()))
- }
- case reflect.Pointer:
- switch dec.peekRune() {
- case 'n':
- 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() {
- val.Set(reflect.New(typ.Elem()))
- }
- dec.decode(val.Elem(), false)
- }
- default:
- dec.panicType(typ, fmt.Errorf("unsupported type (kind=%v)", typ.Kind()))
- }
- }
-}
-
-func (dec *Decoder) decodeWS() {
- for {
- c, ok := dec.readRuneOrEOF()
- if !ok {
- return
- }
- switch c {
- // NB: The JSON definition of whitespace is more
- // narrow than unicode.IsSpace
- case 0x0020, 0x000A, 0x000D, 0x0009:
- // do nothing
- default:
- dec.unreadRune()
- return
- }
- }
-}
-
-func (dec *Decoder) scan(out io.Writer) {
- scanner := &ReEncoder{
- Out: out,
- Compact: true,
- }
- if _, err := scanner.WriteRune(dec.readRune()); err != nil {
- dec.panicSyntax(err)
- }
- scanner.bailAfterCurrent = true
- var err error
- var eof bool
- for err == nil {
- c, ok := dec.readRuneOrEOF()
- if ok {
- _, err = scanner.WriteRune(c)
- } else {
- eof = true
- err = scanner.Flush()
- break
- }
- }
- if err != nil {
- if err == errBailedAfterCurrent {
- if !eof {
- dec.unreadRune()
- }
- } else {
- dec.panicSyntax(err)
- }
- }
-}
-
-func (dec *Decoder) scanNumber(out io.Writer) {
- c := dec.peekRune()
- switch c {
- case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
- dec.scan(out)
- default:
- dec.panicSyntax(fmt.Errorf("number: expected %q or a digit, but got %q", '-', c))
- }
-}
-
-func (dec *Decoder) decodeAny() any {
- c := dec.peekRune()
- switch c {
- case '{':
- ret := make(map[string]any)
- var nameBuf strings.Builder
- dec.decodeObject(&nameBuf, func() {
- name := nameBuf.String()
- dec.stackPush(name)
- defer dec.stackPop()
- ret[name] = dec.decodeAny()
- })
- return ret
- case '[':
- ret := []any{}
- dec.decodeArray(func() {
- dec.stackPush(len(ret))
- defer dec.stackPop()
- ret = append(ret, dec.decodeAny())
- })
- return ret
- case '"':
- var buf strings.Builder
- dec.decodeString(&buf)
- return buf.String()
- case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
- var buf strings.Builder
- dec.scanNumber(&buf)
- num := json.Number(buf.String())
- if dec.useNumber {
- return num
- }
- f64, err := num.Float64()
- if err != nil {
- dec.panicSyntax(err)
- }
- return f64
- case 't', 'f':
- return dec.decodeBool()
- case 'n':
- dec.decodeNull()
- return nil
- default:
- dec.panicSyntax(fmt.Errorf("any: unexpected character: %c", c))
- panic("not reached")
- }
-}
-
-func (dec *Decoder) decodeObject(nameBuf runeBuffer, decodeKVal func()) {
- dec.expectRune('{')
- dec.decodeWS()
- c := dec.readRune()
- switch c {
- case '"':
- decodeMember:
- dec.unreadRune()
- nameBuf.Reset()
- dec.decodeString(nameBuf)
- dec.decodeWS()
- dec.expectRune(':')
- dec.decodeWS()
- decodeKVal()
- dec.decodeWS()
- c := dec.readRune()
- switch c {
- case ',':
- dec.decodeWS()
- dec.expectRune('"')
- goto decodeMember
- case '}':
- return
- default:
- dec.panicSyntax(fmt.Errorf("object: expected %q or %q but got %q", ',', '}', c))
- }
- case '}':
- return
- default:
- dec.panicSyntax(fmt.Errorf("object: expected %q or %q but got %q", '"', '}', c))
- }
-}
-
-func (dec *Decoder) decodeArray(decodeMember func()) {
- dec.expectRune('[')
- dec.decodeWS()
- c := dec.readRune()
- switch c {
- case ']':
- return
- default:
- dec.unreadRune()
- decodeNextMember:
- decodeMember()
- dec.decodeWS()
- c := dec.readRune()
- switch c {
- case ',':
- dec.decodeWS()
- goto decodeNextMember
- case ']':
- return
- default:
- dec.panicSyntax(fmt.Errorf("array: expected %c or %c but got %c", ',', ']', c))
- }
- }
-}
-
-func (dec *Decoder) decodeHex() rune {
- c := dec.readRune()
- switch {
- case '0' <= c && c <= '9':
- return c - '0'
- case 'a' <= c && c <= 'f':
- return c - 'a' + 10
- case 'A' <= c && c <= 'F':
- return c - 'A' + 10
- default:
- dec.panicSyntax(fmt.Errorf("string: expected a hex digit but got %q", c))
- panic("not reached")
- }
-}
-
-func (dec *Decoder) decodeString(out io.Writer) {
- dec.expectRune('"')
- for {
- c := dec.readRune()
- switch {
- case 0x0020 <= c && c <= 0x10FFFF && c != '"' && c != '\\':
- if _, err := writeRune(out, c); err != nil {
- dec.panicSyntax(err)
- }
- case c == '\\':
- c = dec.readRune()
- switch c {
- case '"':
- if _, err := writeRune(out, '"'); err != nil {
- dec.panicSyntax(err)
- }
- case '\\':
- if _, err := writeRune(out, '\\'); err != nil {
- dec.panicSyntax(err)
- }
- case '/':
- if _, err := writeRune(out, '/'); err != nil {
- dec.panicSyntax(err)
- }
- case 'b':
- if _, err := writeRune(out, '\b'); err != nil {
- dec.panicSyntax(err)
- }
- case 'f':
- if _, err := writeRune(out, '\f'); err != nil {
- dec.panicSyntax(err)
- }
- case 'n':
- if _, err := writeRune(out, '\n'); err != nil {
- dec.panicSyntax(err)
- }
- case 'r':
- if _, err := writeRune(out, '\r'); err != nil {
- dec.panicSyntax(err)
- }
- case 't':
- if _, err := writeRune(out, '\t'); err != nil {
- dec.panicSyntax(err)
- }
- case 'u':
- c = dec.decodeHex()
- c = (c << 4) | dec.decodeHex()
- c = (c << 4) | dec.decodeHex()
- c = (c << 4) | dec.decodeHex()
- if _, err := writeRune(out, c); err != nil {
- dec.panicSyntax(err)
- }
- }
- case c == '"':
- return
- default:
- dec.panicSyntax(fmt.Errorf("string: unexpected %c", c))
- }
- }
-}
-
-func (dec *Decoder) decodeBool() bool {
- c := dec.readRune()
- switch c {
- case 't':
- dec.expectRune('r')
- dec.expectRune('u')
- dec.expectRune('e')
- return true
- case 'f':
- dec.expectRune('a')
- dec.expectRune('l')
- dec.expectRune('s')
- dec.expectRune('e')
- return false
- default:
- dec.panicSyntax(fmt.Errorf("bool: expected %q or %q but got %q", 't', 'f', c))
- panic("not reached")
- }
-}
-
-func (dec *Decoder) decodeNull() {
- dec.expectRune('n')
- dec.expectRune('u')
- dec.expectRune('l')
- dec.expectRune('l')
-}