File size: 8,450 Bytes
e36aeda | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 | // Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build goexperiment.jsonv2
package json
import (
"bytes"
"errors"
"io"
"encoding/json/jsontext"
jsonv2 "encoding/json/v2"
)
// A Decoder reads and decodes JSON values from an input stream.
type Decoder struct {
dec *jsontext.Decoder
opts jsonv2.Options
err error
// hadPeeked reports whether [Decoder.More] was called.
// It is reset by [Decoder.Decode] and [Decoder.Token].
hadPeeked bool
}
// NewDecoder returns a new decoder that reads from r.
//
// The decoder introduces its own buffering and may
// read data from r beyond the JSON values requested.
func NewDecoder(r io.Reader) *Decoder {
// Hide bytes.Buffer from jsontext since it implements optimizations that
// also limits certain ways it could be used. For example, one cannot write
// to the bytes.Buffer while it is in use by jsontext.Decoder.
if _, ok := r.(*bytes.Buffer); ok {
r = struct{ io.Reader }{r}
}
dec := new(Decoder)
dec.opts = DefaultOptionsV1()
dec.dec = jsontext.NewDecoder(r, dec.opts)
return dec
}
// UseNumber causes the Decoder to unmarshal a number into an
// interface value as a [Number] instead of as a float64.
func (dec *Decoder) UseNumber() {
if useNumber, _ := jsonv2.GetOption(dec.opts, unmarshalAnyWithRawNumber); !useNumber {
dec.opts = jsonv2.JoinOptions(dec.opts, unmarshalAnyWithRawNumber(true))
}
}
// DisallowUnknownFields causes the Decoder to return an error when the destination
// is a struct and the input contains object keys which do not match any
// non-ignored, exported fields in the destination.
func (dec *Decoder) DisallowUnknownFields() {
if reject, _ := jsonv2.GetOption(dec.opts, jsonv2.RejectUnknownMembers); !reject {
dec.opts = jsonv2.JoinOptions(dec.opts, jsonv2.RejectUnknownMembers(true))
}
}
// Decode reads the next JSON-encoded value from its
// input and stores it in the value pointed to by v.
//
// See the documentation for [Unmarshal] for details about
// the conversion of JSON into a Go value.
func (dec *Decoder) Decode(v any) error {
if dec.err != nil {
return dec.err
}
b, err := dec.dec.ReadValue()
if err != nil {
dec.err = transformSyntacticError(err)
if dec.err.Error() == errUnexpectedEnd.Error() {
// NOTE: Decode has always been inconsistent with Unmarshal
// with regard to the exact error value for truncated input.
dec.err = io.ErrUnexpectedEOF
}
return dec.err
}
dec.hadPeeked = false
return jsonv2.Unmarshal(b, v, dec.opts)
}
// Buffered returns a reader of the data remaining in the Decoder's
// buffer. The reader is valid until the next call to [Decoder.Decode].
func (dec *Decoder) Buffered() io.Reader {
return bytes.NewReader(dec.dec.UnreadBuffer())
}
// An Encoder writes JSON values to an output stream.
type Encoder struct {
w io.Writer
opts jsonv2.Options
err error
buf bytes.Buffer
indentBuf bytes.Buffer
indentPrefix string
indentValue string
}
// NewEncoder returns a new encoder that writes to w.
func NewEncoder(w io.Writer) *Encoder {
enc := new(Encoder)
enc.w = w
enc.opts = DefaultOptionsV1()
return enc
}
// Encode writes the JSON encoding of v to the stream,
// followed by a newline character.
//
// See the documentation for [Marshal] for details about the
// conversion of Go values to JSON.
func (enc *Encoder) Encode(v any) error {
if enc.err != nil {
return enc.err
}
buf := &enc.buf
buf.Reset()
if err := jsonv2.MarshalWrite(buf, v, enc.opts); err != nil {
return err
}
if len(enc.indentPrefix)+len(enc.indentValue) > 0 {
enc.indentBuf.Reset()
if err := Indent(&enc.indentBuf, buf.Bytes(), enc.indentPrefix, enc.indentValue); err != nil {
return err
}
buf = &enc.indentBuf
}
buf.WriteByte('\n')
if _, err := enc.w.Write(buf.Bytes()); err != nil {
enc.err = err
return err
}
return nil
}
// SetIndent instructs the encoder to format each subsequent encoded
// value as if indented by the package-level function Indent(dst, src, prefix, indent).
// Calling SetIndent("", "") disables indentation.
func (enc *Encoder) SetIndent(prefix, indent string) {
enc.indentPrefix = prefix
enc.indentValue = indent
}
// SetEscapeHTML specifies whether problematic HTML characters
// should be escaped inside JSON quoted strings.
// The default behavior is to escape &, <, and > to \u0026, \u003c, and \u003e
// to avoid certain safety problems that can arise when embedding JSON in HTML.
//
// In non-HTML settings where the escaping interferes with the readability
// of the output, SetEscapeHTML(false) disables this behavior.
func (enc *Encoder) SetEscapeHTML(on bool) {
if escape, _ := jsonv2.GetOption(enc.opts, jsontext.EscapeForHTML); escape != on {
enc.opts = jsonv2.JoinOptions(enc.opts, jsontext.EscapeForHTML(on))
}
}
// RawMessage is a raw encoded JSON value.
// It implements [Marshaler] and [Unmarshaler] and can
// be used to delay JSON decoding or precompute a JSON encoding.
type RawMessage = jsontext.Value
// A Token holds a value of one of these types:
//
// - [Delim], for the four JSON delimiters [ ] { }
// - bool, for JSON booleans
// - float64, for JSON numbers
// - [Number], for JSON numbers
// - string, for JSON string literals
// - nil, for JSON null
type Token any
// A Delim is a JSON array or object delimiter, one of [ ] { or }.
type Delim rune
func (d Delim) String() string {
return string(d)
}
// Token returns the next JSON token in the input stream.
// At the end of the input stream, Token returns nil, [io.EOF].
//
// Token guarantees that the delimiters [ ] { } it returns are
// properly nested and matched: if Token encounters an unexpected
// delimiter in the input, it will return an error.
//
// The input stream consists of basic JSON values—bool, string,
// number, and null—along with delimiters [ ] { } of type [Delim]
// to mark the start and end of arrays and objects.
// Commas and colons are elided.
func (dec *Decoder) Token() (Token, error) {
if dec.err != nil {
return nil, dec.err
}
tok, err := dec.dec.ReadToken()
if err != nil {
// Historically, v1 would report just [io.EOF] if
// the stream is a prefix of a valid JSON value.
// It reports an unwrapped [io.ErrUnexpectedEOF] if
// truncated within a JSON token such as a literal, number, or string.
if errors.Is(err, io.ErrUnexpectedEOF) {
if len(bytes.Trim(dec.dec.UnreadBuffer(), " \r\n\t,:")) == 0 {
return nil, io.EOF
}
return nil, io.ErrUnexpectedEOF
}
return nil, transformSyntacticError(err)
}
dec.hadPeeked = false
switch k := tok.Kind(); k {
case 'n':
return nil, nil
case 'f':
return false, nil
case 't':
return true, nil
case '"':
return tok.String(), nil
case '0':
if useNumber, _ := jsonv2.GetOption(dec.opts, unmarshalAnyWithRawNumber); useNumber {
return Number(tok.String()), nil
}
return tok.Float(), nil
case '{', '}', '[', ']':
return Delim(k), nil
default:
panic("unreachable")
}
}
// More reports whether there is another element in the
// current array or object being parsed.
func (dec *Decoder) More() bool {
dec.hadPeeked = true
k := dec.dec.PeekKind()
if k == 0 {
if dec.err == nil {
// PeekKind doesn't distinguish between EOF and error,
// so read the next token to see which we get.
_, err := dec.dec.ReadToken()
if err == nil {
// This is only possible if jsontext violates its documentation.
err = errors.New("json: successful read after failed peek")
}
dec.err = transformSyntacticError(err)
}
return dec.err != io.EOF
}
return k != ']' && k != '}'
}
// InputOffset returns the input stream byte offset of the current decoder position.
// The offset gives the location of the end of the most recently returned token
// and the beginning of the next token.
func (dec *Decoder) InputOffset() int64 {
offset := dec.dec.InputOffset()
if dec.hadPeeked {
// Historically, InputOffset reported the location of
// the end of the most recently returned token
// unless [Decoder.More] is called, in which case, it reported
// the beginning of the next token.
unreadBuffer := dec.dec.UnreadBuffer()
trailingTokens := bytes.TrimLeft(unreadBuffer, " \n\r\t")
if len(trailingTokens) > 0 {
leadingWhitespace := len(unreadBuffer) - len(trailingTokens)
offset += int64(leadingWhitespace)
}
}
return offset
}
|