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