Source File
v2_stream.go
Belonging Package
encoding/json
// 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.jsonv2package jsonimport (jsonv2)// A Decoder reads and decodes JSON values from an input stream.type Decoder struct {dec *jsontext.Decoderopts jsonv2.Optionserr error// hadPeeked reports whether [Decoder.More] was called.// It is reset by [Decoder.Decode] and [Decoder.Token].hadPeeked bool// hadEOF reports whether [Decoder.Token] had hit [io.EOF].// It is reset by [Decoder.Decode] and [Decoder.Token].hadEOF 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 ( io.Reader) *Decoder {// Hide bytes.Buffer from jsontext since it implements optimizations that// also limit certain ways it could be used. For example, one cannot write// to the bytes.Buffer while it is in use by jsontext.Decoder.if , := .(*bytes.Buffer); {= struct{ io.Reader }{}}:= new(Decoder).opts = DefaultOptionsV1().dec = jsontext.NewDecoder(, .opts)return}// UseNumber causes the Decoder to unmarshal a number into an// interface value as a [Number] instead of as a float64.func ( *Decoder) () {if , := jsonv2.GetOption(.opts, unmarshalAnyWithRawNumber); ! {.opts = jsonv2.JoinOptions(.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 ( *Decoder) () {if , := jsonv2.GetOption(.opts, jsonv2.RejectUnknownMembers); ! {.opts = jsonv2.JoinOptions(.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 ( *Decoder) ( any) error {if .err != nil {return .err}, := .dec.ReadValue()if != nil {.err = transformSyntacticError()if .err.Error() == errUnexpectedEnd.Error() {// NOTE: Decode has always been inconsistent with Unmarshal// with regard to the exact error value for truncated input..err = io.ErrUnexpectedEOF}return .err}.hadPeeked = false.hadEOF = falsereturn jsonv2.Unmarshal(, , .opts)}// Buffered returns a reader of the data remaining in the unread buffer,// which may contain zero or more bytes.// This is the data already consumed from the input [io.Reader],// but not yet read by a [Decoder.Decode] or [Decoder.Token] call.// It may contain bytes that do not form valid JSON as it has not yet// been validated according to the JSON grammar.// The exact amount of buffered data is an implementation detail// of the Decoder and may change over time.//// It is the caller's responsibility to concatenate this buffer with// the remainder of the input Reader to obtain the full sequence// of bytes after the last decoded JSON value.//// The reader is valid until the next call to [Decoder.Decode] or [Decoder.Token].func ( *Decoder) () io.Reader {return bytes.NewReader(.dec.UnreadBuffer())}// An Encoder writes JSON values to an output stream.type Encoder struct {w io.Writeropts jsonv2.Optionserr errorindentBuf bytes.BufferindentPrefix stringindentValue string}// NewEncoder returns a new encoder that writes to w.func ( io.Writer) *Encoder {:= new(Encoder).w =.opts = DefaultOptionsV1()return}// 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 ( *Encoder) ( any) error {if .err != nil {return .err}:= export.GetBufferedEncoder(.opts)defer export.PutBufferedEncoder()if := jsonv2.MarshalEncode(, ); != nil {return}:= export.Encoder().Buf // b must not leak current scopeif len(.indentPrefix)+len(.indentValue) > 0 {.indentBuf.Reset()if := Indent(&.indentBuf, , .indentPrefix, .indentValue); != nil {return}= .indentBuf.Bytes()}= append(, '\n')if , := .w.Write(); != nil {.err =return}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 ( *Encoder) (, string) {// NOTE: Do not rely on the newer [jsontext.WithIndent] option since// the v1 [Indent] behavior has historical bugs that cannot be changed// for backward compatibility reasons..indentPrefix =.indentValue =}// 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 ( *Encoder) ( bool) {if , := jsonv2.GetOption(.opts, jsontext.EscapeForHTML); != {.opts = jsonv2.JoinOptions(.opts, jsontext.EscapeForHTML())}}// 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 nulltype Token any// A Delim is a JSON array or object delimiter, one of [ ] { or }.type Delim runefunc ( Delim) () string {return string()}// 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 ( *Decoder) () (Token, error) {if .err != nil {return nil, .err}, := .dec.ReadToken()if != 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 the underlying [io.Reader] produced the [io.ErrUnexpectedEOF],// then return the error as-is (including any wrapping).if errors.Is(, io.ErrUnexpectedEOF) && !export.IsIOError() {if len(bytes.Trim(.dec.UnreadBuffer(), " \r\n\t,:")) == 0 {.hadEOF = truereturn nil, io.EOF}return nil, io.ErrUnexpectedEOF}return nil, transformSyntacticError()}.hadPeeked = false.hadEOF = falseswitch := .Kind(); {case 'n':return nil, nilcase 'f':return false, nilcase 't':return true, nilcase '"':return .String(), nilcase '0':if , := jsonv2.GetOption(.opts, unmarshalAnyWithRawNumber); {return Number(.String()), nil}, := .Float()if != nil {return nil, &UnmarshalTypeError{Value: "number " + .String(), Type: reflect.TypeFor[float64](), Offset: .InputOffset()}}return , nilcase '{', '}', '[', ']':return Delim(), nildefault:panic("unreachable")}}// More reports whether there is another element in the// current array or object being parsed.func ( *Decoder) () bool {.hadPeeked = true:= .dec.PeekKind()if == 0 {if .err == nil {// PeekKind doesn't distinguish between EOF and error,// so read the next token to see which we get., := .dec.ReadToken()if == nil {// This is only possible if jsontext violates its documentation.= errors.New("json: successful read after failed peek")}.err = transformSyntacticError()}return .err != io.EOF}return != ']' && != '}'}// 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 ( *Decoder) () int64 {:= .dec.InputOffset()if .hadPeeked || .hadEOF {// 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.:= .dec.UnreadBuffer():= bytes.TrimLeft(, " \n\r\t")if len() > 0 {:= len() - len()+= int64()// If [Decoder.Token] had encountered [io.EOF],// then it also includes the upcoming comma or colon.if .hadEOF && ([0] == ',' || [0] == ':') {++}}}return}
The pages are generated with Golds v0.8.4. (GOOS=linux GOARCH=amd64)