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  

View as plain text