vendor dependencies
This commit is contained in:
		
							
								
								
									
										3
									
								
								vendor/github.com/go-json-experiment/json/AUTHORS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/go-json-experiment/json/AUTHORS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| # This source code refers to The Go Authors for copyright purposes. | ||||
| # The master list of authors is in the main Go distribution, | ||||
| # visible at https://tip.golang.org/AUTHORS. | ||||
							
								
								
									
										3
									
								
								vendor/github.com/go-json-experiment/json/CONTRIBUTORS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/go-json-experiment/json/CONTRIBUTORS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| # This source code was written by the Go contributors. | ||||
| # The master list of contributors is in the main Go distribution, | ||||
| # visible at https://tip.golang.org/CONTRIBUTORS. | ||||
							
								
								
									
										27
									
								
								vendor/github.com/go-json-experiment/json/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								vendor/github.com/go-json-experiment/json/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| Copyright (c) 2020 The Go Authors. All rights reserved. | ||||
|  | ||||
| Redistribution and use in source and binary forms, with or without | ||||
| modification, are permitted provided that the following conditions are | ||||
| met: | ||||
|  | ||||
|    * Redistributions of source code must retain the above copyright | ||||
| notice, this list of conditions and the following disclaimer. | ||||
|    * Redistributions in binary form must reproduce the above | ||||
| copyright notice, this list of conditions and the following disclaimer | ||||
| in the documentation and/or other materials provided with the | ||||
| distribution. | ||||
|    * Neither the name of Google Inc. nor the names of its | ||||
| contributors may be used to endorse or promote products derived from | ||||
| this software without specific prior written permission. | ||||
|  | ||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||||
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||||
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||||
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||||
| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||
| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||||
| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||
| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||
| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
							
								
								
									
										175
									
								
								vendor/github.com/go-json-experiment/json/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										175
									
								
								vendor/github.com/go-json-experiment/json/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,175 @@ | ||||
| # JSON Serialization (v2) | ||||
|  | ||||
| [](https://pkg.go.dev/github.com/go-json-experiment/json) | ||||
| [](https://github.com/go-json-experiment/json/actions) | ||||
|  | ||||
| This module hosts an experimental implementation of v2 `encoding/json`. | ||||
| The API is unstable and breaking changes will regularly be made. | ||||
| Do not depend on this in publicly available modules. | ||||
|  | ||||
| Any commits that make breaking API or behavior changes will be marked | ||||
| with the string "WARNING: " near the top of the commit message. | ||||
| It is your responsibility to inspect the list of commit changes | ||||
| when upgrading the module. Not all breaking changes will lead to build failures. | ||||
|  | ||||
| A [proposal to include this module in Go as `encoding/json/v2` and `encoding/json/jsontext`](https://github.com/golang/go/issues/71497) has been started on the Go Github project on 2025-01-30. Please provide your feedback there. | ||||
|  | ||||
| ## Goals and objectives | ||||
|  | ||||
| * **Mostly backwards compatible:** If possible, v2 should aim to be _mostly_ | ||||
| compatible with v1 in terms of both API and default behavior to ease migration. | ||||
| For example, the `Marshal` and `Unmarshal` functions are the most widely used | ||||
| declarations in the v1 package. It seems sensible for equivalent functionality | ||||
| in v2 to be named the same and have a mostly compatible signature. | ||||
| Behaviorally, we should aim for 95% to 99% backwards compatibility. | ||||
| We do not aim for 100% compatibility since we want the freedom to break | ||||
| certain behaviors that are now considered to have been a mistake. | ||||
| Options exist that can bring the v2 implementation to 100% compatibility, | ||||
| but it will not be the default. | ||||
|  | ||||
| * **More flexible:** There is a | ||||
| [long list of feature requests](https://github.com/golang/go/issues?q=is%3Aissue+is%3Aopen+encoding%2Fjson+in%3Atitle). | ||||
| We should aim to provide the most flexible features that addresses most usages. | ||||
| We do not want to over fit the v2 API to handle every possible use case. | ||||
| Ideally, the features provided should be orthogonal in nature such that | ||||
| any combination of features results in as few surprising edge cases as possible. | ||||
|  | ||||
| * **More performant:** JSON serialization is widely used and any bit of extra | ||||
| performance gains will be greatly appreciated. Some rarely used behaviors of v1 | ||||
| may be dropped in favor of better performance. For example, | ||||
| despite `Encoder` and `Decoder` operating on an `io.Writer` and `io.Reader`, | ||||
| they do not operate in a truly streaming manner, | ||||
| leading to a loss in performance. The v2 implementation should aim to be truly | ||||
| streaming by default (see [#33714](https://golang.org/issue/33714)). | ||||
|  | ||||
| * **Easy to use (hard to misuse):** The v2 API should aim to make | ||||
| the common case easy and the less common case at least possible. | ||||
| The API should avoid behavior that goes contrary to user expectation, | ||||
| which may result in subtle bugs (see [#36225](https://golang.org/issue/36225)). | ||||
|  | ||||
| * **v1 and v2 maintainability:** Since the v1 implementation must stay forever, | ||||
| it would be beneficial if v1 could be implemented under the hood with v2, | ||||
| allowing for less maintenance burden in the future. This probably implies that | ||||
| behavioral changes in v2 relative to v1 need to be exposed as options. | ||||
|  | ||||
| * **Avoid unsafe:** Standard library packages generally avoid the use of | ||||
| package `unsafe` even if it could provide a performance boost. | ||||
| We aim to preserve this property. | ||||
|  | ||||
| ## Expectations | ||||
|  | ||||
| While this module aims to possibly be the v2 implementation of `encoding/json`, | ||||
| there is no guarantee that this outcome will occur. As with any major change | ||||
| to the Go standard library, this will eventually go through the | ||||
| [Go proposal process](https://github.com/golang/proposal#readme). | ||||
| At the present moment, this is still in the design and experimentation phase | ||||
| and is not ready for a formal proposal. | ||||
|  | ||||
| There are several possible outcomes from this experiment: | ||||
| 1. We determine that a v2 `encoding/json` would not provide sufficient benefit | ||||
| over the existing v1 `encoding/json` package. Thus, we abandon this effort. | ||||
| 2. We propose a v2 `encoding/json` design, but it is rejected in favor of some | ||||
| other design that is considered superior. | ||||
| 3. We propose a v2 `encoding/json` design, but rather than adding an entirely | ||||
| new v2 `encoding/json` package, we decide to merge its functionality into | ||||
| the existing v1 `encoding/json` package. | ||||
| 4. We propose a v2 `encoding/json` design and it is accepted, resulting in | ||||
| its addition to the standard library. | ||||
| 5. Some other unforeseen outcome (among the infinite number of possibilities). | ||||
|  | ||||
| ## Development | ||||
|  | ||||
| This module is primarily developed by | ||||
| [@dsnet](https://github.com/dsnet), | ||||
| [@mvdan](https://github.com/mvdan), and | ||||
| [@johanbrandhorst](https://github.com/johanbrandhorst) | ||||
| with feedback provided by | ||||
| [@rogpeppe](https://github.com/rogpeppe), | ||||
| [@ChrisHines](https://github.com/ChrisHines), and | ||||
| [@rsc](https://github.com/rsc). | ||||
|  | ||||
| Discussion about semantics occur semi-regularly, where a | ||||
| [record of past meetings can be found here](https://docs.google.com/document/d/1rovrOTd-wTawGMPPlPuKhwXaYBg9VszTXR9AQQL5LfI/edit?usp=sharing). | ||||
|  | ||||
| ## Design overview | ||||
|  | ||||
| This package aims to provide a clean separation between syntax and semantics. | ||||
| Syntax deals with the structural representation of JSON (as specified in | ||||
| [RFC 4627](https://tools.ietf.org/html/rfc4627), | ||||
| [RFC 7159](https://tools.ietf.org/html/rfc7159), | ||||
| [RFC 7493](https://tools.ietf.org/html/rfc7493), | ||||
| [RFC 8259](https://tools.ietf.org/html/rfc8259), and | ||||
| [RFC 8785](https://tools.ietf.org/html/rfc8785)). | ||||
| Semantics deals with the meaning of syntactic data as usable application data. | ||||
|  | ||||
| The `Encoder` and `Decoder` types are streaming tokenizers concerned with the | ||||
| packing or parsing of JSON data. They operate on `Token` and `Value` types | ||||
| which represent the common data structures that are representable in JSON. | ||||
| `Encoder` and `Decoder` do not aim to provide any interpretation of the data. | ||||
|  | ||||
| Functions like `Marshal`, `MarshalWrite`, `MarshalEncode`, `Unmarshal`, | ||||
| `UnmarshalRead`, and `UnmarshalDecode` provide semantic meaning by correlating | ||||
| any arbitrary Go type with some JSON representation of that type (as stored in | ||||
| data types like `[]byte`, `io.Writer`, `io.Reader`, `Encoder`, or `Decoder`). | ||||
|  | ||||
|  | ||||
|  | ||||
| This diagram provides a high-level overview of the v2 `json` and `jsontext` packages. | ||||
| Purple blocks represent types, while blue blocks represent functions or methods. | ||||
| The arrows and their direction represent the approximate flow of data. | ||||
| The bottom half of the diagram contains functionality that is only concerned | ||||
| with syntax (implemented by the `jsontext` package), | ||||
| while the upper half contains functionality that assigns | ||||
| semantic meaning to syntactic data handled by the bottom half | ||||
| (as implemented by the v2 `json` package). | ||||
|  | ||||
| In contrast to v1 `encoding/json`, options are represented as separate types | ||||
| rather than being setter methods on the `Encoder` or `Decoder` types. | ||||
| Some options affects JSON serialization at the syntactic layer, | ||||
| while others affect it at the semantic layer. | ||||
| Some options only affect JSON when decoding, | ||||
| while others affect JSON while encoding. | ||||
|  | ||||
| ## Behavior changes | ||||
|  | ||||
| The v2 `json` package changes the default behavior of `Marshal` and `Unmarshal` | ||||
| relative to the v1 `json` package to be more sensible. | ||||
| Some of these behavior changes have options and workarounds to opt into | ||||
| behavior similar to what v1 provided. | ||||
|  | ||||
| This table shows an overview of the changes: | ||||
|  | ||||
| | v1 | v2 | Details | | ||||
| | -- | -- | ------- | | ||||
| | JSON object members are unmarshaled into a Go struct using a **case-insensitive name match**. | JSON object members are unmarshaled into a Go struct using a **case-sensitive name match**. | [CaseSensitivity](/v1/diff_test.go#:~:text=TestCaseSensitivity) | | ||||
| | When marshaling a Go struct, a struct field marked as `omitempty` is omitted if **the field value is an empty Go value**, which is defined as false, 0, a nil pointer, a nil interface value, and any empty array, slice, map, or string. | When marshaling a Go struct, a struct field marked as `omitempty` is omitted if **the field value would encode as an empty JSON value**, which is defined as a JSON null, or an empty JSON string, object, or array. | [OmitEmptyOption](/v1/diff_test.go#:~:text=TestOmitEmptyOption) | | ||||
| | The `string` option **does affect** Go strings and bools. | The `string` option **does not affect** Go strings or bools. | [StringOption](/v1/diff_test.go#:~:text=TestStringOption) | | ||||
| | The `string` option **does not recursively affect** sub-values of the Go field value. | The `string` option **does recursively affect** sub-values of the Go field value. | [StringOption](/v1/diff_test.go#:~:text=TestStringOption) | | ||||
| | The `string` option **sometimes accepts** a JSON null escaped within a JSON string. | The `string` option **never accepts** a JSON null escaped within a JSON string. | [StringOption](/v1/diff_test.go#:~:text=TestStringOption) | | ||||
| | A nil Go slice is marshaled as a **JSON null**. | A nil Go slice is marshaled as an **empty JSON array**. | [NilSlicesAndMaps](/v1/diff_test.go#:~:text=TestNilSlicesAndMaps) | | ||||
| | A nil Go map is marshaled as a **JSON null**. | A nil Go map is marshaled as an **empty JSON object**. | [NilSlicesAndMaps](/v1/diff_test.go#:~:text=TestNilSlicesAndMaps) | | ||||
| | A Go array may be unmarshaled from a **JSON array of any length**. | A Go array must be unmarshaled from a **JSON array of the same length**. | [Arrays](/v1/diff_test.go#:~:text=Arrays) | | ||||
| | A Go byte array is represented as a **JSON array of JSON numbers**. | A Go byte array is represented as a **Base64-encoded JSON string**. | [ByteArrays](/v1/diff_test.go#:~:text=TestByteArrays) | | ||||
| | `MarshalJSON` and `UnmarshalJSON` methods declared on a pointer receiver are **inconsistently called**. | `MarshalJSON` and `UnmarshalJSON` methods declared on a pointer receiver are **consistently called**. | [PointerReceiver](/v1/diff_test.go#:~:text=TestPointerReceiver) | | ||||
| | A Go map is marshaled in a **deterministic order**. | A Go map is marshaled in a **non-deterministic order**. | [MapDeterminism](/v1/diff_test.go#:~:text=TestMapDeterminism) | | ||||
| | JSON strings are encoded **with HTML-specific characters being escaped**. | JSON strings are encoded **without any characters being escaped** (unless necessary). | [EscapeHTML](/v1/diff_test.go#:~:text=TestEscapeHTML) | | ||||
| | When marshaling, invalid UTF-8 within a Go string **are silently replaced**. | When marshaling, invalid UTF-8 within a Go string **results in an error**. | [InvalidUTF8](/v1/diff_test.go#:~:text=TestInvalidUTF8) | | ||||
| | When unmarshaling, invalid UTF-8 within a JSON string **are silently replaced**. | When unmarshaling, invalid UTF-8 within a JSON string **results in an error**. | [InvalidUTF8](/v1/diff_test.go#:~:text=TestInvalidUTF8) | | ||||
| | When marshaling, **an error does not occur** if the output JSON value contains objects with duplicate names. | When marshaling, **an error does occur** if the output JSON value contains objects with duplicate names. | [DuplicateNames](/v1/diff_test.go#:~:text=TestDuplicateNames) | | ||||
| | When unmarshaling, **an error does not occur** if the input JSON value contains objects with duplicate names. | When unmarshaling, **an error does occur** if the input JSON value contains objects with duplicate names. | [DuplicateNames](/v1/diff_test.go#:~:text=TestDuplicateNames) | | ||||
| | Unmarshaling a JSON null into a non-empty Go value **inconsistently clears the value or does nothing**. | Unmarshaling a JSON null into a non-empty Go value **always clears the value**. | [MergeNull](/v1/diff_test.go#:~:text=TestMergeNull) | | ||||
| | Unmarshaling a JSON value into a non-empty Go value **follows inconsistent and bizarre behavior**. | Unmarshaling a JSON value into a non-empty Go value **always merges if the input is an object, and otherwise replaces**.  | [MergeComposite](/v1/diff_test.go#:~:text=TestMergeComposite) | | ||||
| | A `time.Duration` is represented as a **JSON number containing the decimal number of nanoseconds**. | A `time.Duration` is represented as a **JSON string containing the formatted duration (e.g., "1h2m3.456s")**. | [TimeDurations](/v1/diff_test.go#:~:text=TestTimeDurations) | | ||||
| | A Go struct with only unexported fields **can be serialized**. | A Go struct with only unexported fields **cannot be serialized**. | [EmptyStructs](/v1/diff_test.go#:~:text=TestEmptyStructs) | | ||||
|  | ||||
| See [diff_test.go](/v1/diff_test.go) for details about every change. | ||||
|  | ||||
| ## Performance | ||||
|  | ||||
| One of the goals of the v2 module is to be more performant than v1, | ||||
| but not at the expense of correctness. | ||||
| In general, v2 is at performance parity with v1 for marshaling, | ||||
| but dramatically faster for unmarshaling. | ||||
|  | ||||
| See https://github.com/go-json-experiment/jsonbench for benchmarks | ||||
| comparing v2 with v1 and a number of other popular JSON implementations. | ||||
							
								
								
									
										
											BIN
										
									
								
								vendor/github.com/go-json-experiment/json/api.png
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								vendor/github.com/go-json-experiment/json/api.png
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 151 KiB | 
							
								
								
									
										568
									
								
								vendor/github.com/go-json-experiment/json/arshal.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										568
									
								
								vendor/github.com/go-json-experiment/json/arshal.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,568 @@ | ||||
| // Copyright 2020 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. | ||||
|  | ||||
| package json | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding" | ||||
| 	"io" | ||||
| 	"reflect" | ||||
| 	"slices" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/go-json-experiment/json/internal" | ||||
| 	"github.com/go-json-experiment/json/internal/jsonflags" | ||||
| 	"github.com/go-json-experiment/json/internal/jsonopts" | ||||
| 	"github.com/go-json-experiment/json/jsontext" | ||||
| ) | ||||
|  | ||||
| // Reference encoding and time packages to assist pkgsite | ||||
| // in being able to hotlink references to those packages. | ||||
| var ( | ||||
| 	_ encoding.TextMarshaler | ||||
| 	_ encoding.TextAppender | ||||
| 	_ encoding.TextUnmarshaler | ||||
| 	_ time.Time | ||||
| 	_ time.Duration | ||||
| ) | ||||
|  | ||||
| // export exposes internal functionality of the "jsontext" package. | ||||
| var export = jsontext.Internal.Export(&internal.AllowInternalUse) | ||||
|  | ||||
| // Marshal serializes a Go value as a []byte according to the provided | ||||
| // marshal and encode options (while ignoring unmarshal or decode options). | ||||
| // It does not terminate the output with a newline. | ||||
| // | ||||
| // Type-specific marshal functions and methods take precedence | ||||
| // over the default representation of a value. | ||||
| // Functions or methods that operate on *T are only called when encoding | ||||
| // a value of type T (by taking its address) or a non-nil value of *T. | ||||
| // Marshal ensures that a value is always addressable | ||||
| // (by boxing it on the heap if necessary) so that | ||||
| // these functions and methods can be consistently called. For performance, | ||||
| // it is recommended that Marshal be passed a non-nil pointer to the value. | ||||
| // | ||||
| // The input value is encoded as JSON according the following rules: | ||||
| // | ||||
| //   - If any type-specific functions in a [WithMarshalers] option match | ||||
| //     the value type, then those functions are called to encode the value. | ||||
| //     If all applicable functions return [SkipFunc], | ||||
| //     then the value is encoded according to subsequent rules. | ||||
| // | ||||
| //   - If the value type implements [MarshalerTo], | ||||
| //     then the MarshalJSONTo method is called to encode the value. | ||||
| // | ||||
| //   - If the value type implements [Marshaler], | ||||
| //     then the MarshalJSON method is called to encode the value. | ||||
| // | ||||
| //   - If the value type implements [encoding.TextAppender], | ||||
| //     then the AppendText method is called to encode the value and | ||||
| //     subsequently encode its result as a JSON string. | ||||
| // | ||||
| //   - If the value type implements [encoding.TextMarshaler], | ||||
| //     then the MarshalText method is called to encode the value and | ||||
| //     subsequently encode its result as a JSON string. | ||||
| // | ||||
| //   - Otherwise, the value is encoded according to the value's type | ||||
| //     as described in detail below. | ||||
| // | ||||
| // Most Go types have a default JSON representation. | ||||
| // Certain types support specialized formatting according to | ||||
| // a format flag optionally specified in the Go struct tag | ||||
| // for the struct field that contains the current value | ||||
| // (see the “JSON Representation of Go structs” section for more details). | ||||
| // | ||||
| // The representation of each type is as follows: | ||||
| // | ||||
| //   - A Go boolean is encoded as a JSON boolean (e.g., true or false). | ||||
| //     It does not support any custom format flags. | ||||
| // | ||||
| //   - A Go string is encoded as a JSON string. | ||||
| //     It does not support any custom format flags. | ||||
| // | ||||
| //   - A Go []byte or [N]byte is encoded as a JSON string containing | ||||
| //     the binary value encoded using RFC 4648. | ||||
| //     If the format is "base64" or unspecified, then this uses RFC 4648, section 4. | ||||
| //     If the format is "base64url", then this uses RFC 4648, section 5. | ||||
| //     If the format is "base32", then this uses RFC 4648, section 6. | ||||
| //     If the format is "base32hex", then this uses RFC 4648, section 7. | ||||
| //     If the format is "base16" or "hex", then this uses RFC 4648, section 8. | ||||
| //     If the format is "array", then the bytes value is encoded as a JSON array | ||||
| //     where each byte is recursively JSON-encoded as each JSON array element. | ||||
| // | ||||
| //   - A Go integer is encoded as a JSON number without fractions or exponents. | ||||
| //     If [StringifyNumbers] is specified or encoding a JSON object name, | ||||
| //     then the JSON number is encoded within a JSON string. | ||||
| //     It does not support any custom format flags. | ||||
| // | ||||
| //   - A Go float is encoded as a JSON number. | ||||
| //     If [StringifyNumbers] is specified or encoding a JSON object name, | ||||
| //     then the JSON number is encoded within a JSON string. | ||||
| //     If the format is "nonfinite", then NaN, +Inf, and -Inf are encoded as | ||||
| //     the JSON strings "NaN", "Infinity", and "-Infinity", respectively. | ||||
| //     Otherwise, the presence of non-finite numbers results in a [SemanticError]. | ||||
| // | ||||
| //   - A Go map is encoded as a JSON object, where each Go map key and value | ||||
| //     is recursively encoded as a name and value pair in the JSON object. | ||||
| //     The Go map key must encode as a JSON string, otherwise this results | ||||
| //     in a [SemanticError]. The Go map is traversed in a non-deterministic order. | ||||
| //     For deterministic encoding, consider using the [Deterministic] option. | ||||
| //     If the format is "emitnull", then a nil map is encoded as a JSON null. | ||||
| //     If the format is "emitempty", then a nil map is encoded as an empty JSON object, | ||||
| //     regardless of whether [FormatNilMapAsNull] is specified. | ||||
| //     Otherwise by default, a nil map is encoded as an empty JSON object. | ||||
| // | ||||
| //   - A Go struct is encoded as a JSON object. | ||||
| //     See the “JSON Representation of Go structs” section | ||||
| //     in the package-level documentation for more details. | ||||
| // | ||||
| //   - A Go slice is encoded as a JSON array, where each Go slice element | ||||
| //     is recursively JSON-encoded as the elements of the JSON array. | ||||
| //     If the format is "emitnull", then a nil slice is encoded as a JSON null. | ||||
| //     If the format is "emitempty", then a nil slice is encoded as an empty JSON array, | ||||
| //     regardless of whether [FormatNilSliceAsNull] is specified. | ||||
| //     Otherwise by default, a nil slice is encoded as an empty JSON array. | ||||
| // | ||||
| //   - A Go array is encoded as a JSON array, where each Go array element | ||||
| //     is recursively JSON-encoded as the elements of the JSON array. | ||||
| //     The JSON array length is always identical to the Go array length. | ||||
| //     It does not support any custom format flags. | ||||
| // | ||||
| //   - A Go pointer is encoded as a JSON null if nil, otherwise it is | ||||
| //     the recursively JSON-encoded representation of the underlying value. | ||||
| //     Format flags are forwarded to the encoding of the underlying value. | ||||
| // | ||||
| //   - A Go interface is encoded as a JSON null if nil, otherwise it is | ||||
| //     the recursively JSON-encoded representation of the underlying value. | ||||
| //     It does not support any custom format flags. | ||||
| // | ||||
| //   - A Go [time.Time] is encoded as a JSON string containing the timestamp | ||||
| //     formatted in RFC 3339 with nanosecond precision. | ||||
| //     If the format matches one of the format constants declared | ||||
| //     in the time package (e.g., RFC1123), then that format is used. | ||||
| //     If the format is "unix", "unixmilli", "unixmicro", or "unixnano", | ||||
| //     then the timestamp is encoded as a JSON number of the number of seconds | ||||
| //     (or milliseconds, microseconds, or nanoseconds) since the Unix epoch, | ||||
| //     which is January 1st, 1970 at 00:00:00 UTC. | ||||
| //     Otherwise, the format is used as-is with [time.Time.Format] if non-empty. | ||||
| // | ||||
| //   - A Go [time.Duration] is encoded as a JSON string containing the duration | ||||
| //     formatted according to [time.Duration.String]. | ||||
| //     If the format is "sec", "milli", "micro", or "nano", | ||||
| //     then the duration is encoded as a JSON number of the number of seconds | ||||
| //     (or milliseconds, microseconds, or nanoseconds) in the duration. | ||||
| //     If the format is "units", it uses [time.Duration.String]. | ||||
| // | ||||
| //   - All other Go types (e.g., complex numbers, channels, and functions) | ||||
| //     have no default representation and result in a [SemanticError]. | ||||
| // | ||||
| // JSON cannot represent cyclic data structures and Marshal does not handle them. | ||||
| // Passing cyclic structures will result in an error. | ||||
| func Marshal(in any, opts ...Options) (out []byte, err error) { | ||||
| 	enc := export.GetBufferedEncoder(opts...) | ||||
| 	defer export.PutBufferedEncoder(enc) | ||||
| 	xe := export.Encoder(enc) | ||||
| 	xe.Flags.Set(jsonflags.OmitTopLevelNewline | 1) | ||||
| 	err = marshalEncode(enc, in, &xe.Struct) | ||||
| 	if err != nil && xe.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { | ||||
| 		return nil, internal.TransformMarshalError(in, err) | ||||
| 	} | ||||
| 	return bytes.Clone(xe.Buf), err | ||||
| } | ||||
|  | ||||
| // MarshalWrite serializes a Go value into an [io.Writer] according to the provided | ||||
| // marshal and encode options (while ignoring unmarshal or decode options). | ||||
| // It does not terminate the output with a newline. | ||||
| // See [Marshal] for details about the conversion of a Go value into JSON. | ||||
| func MarshalWrite(out io.Writer, in any, opts ...Options) (err error) { | ||||
| 	enc := export.GetStreamingEncoder(out, opts...) | ||||
| 	defer export.PutStreamingEncoder(enc) | ||||
| 	xe := export.Encoder(enc) | ||||
| 	xe.Flags.Set(jsonflags.OmitTopLevelNewline | 1) | ||||
| 	err = marshalEncode(enc, in, &xe.Struct) | ||||
| 	if err != nil && xe.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { | ||||
| 		return internal.TransformMarshalError(in, err) | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // MarshalEncode serializes a Go value into an [jsontext.Encoder] according to | ||||
| // the provided marshal options (while ignoring unmarshal, encode, or decode options). | ||||
| // Any marshal-relevant options already specified on the [jsontext.Encoder] | ||||
| // take lower precedence than the set of options provided by the caller. | ||||
| // Unlike [Marshal] and [MarshalWrite], encode options are ignored because | ||||
| // they must have already been specified on the provided [jsontext.Encoder]. | ||||
| // | ||||
| // See [Marshal] for details about the conversion of a Go value into JSON. | ||||
| func MarshalEncode(out *jsontext.Encoder, in any, opts ...Options) (err error) { | ||||
| 	xe := export.Encoder(out) | ||||
| 	if len(opts) > 0 { | ||||
| 		optsOriginal := xe.Struct | ||||
| 		defer func() { xe.Struct = optsOriginal }() | ||||
| 		xe.Struct.JoinWithoutCoderOptions(opts...) | ||||
| 	} | ||||
| 	err = marshalEncode(out, in, &xe.Struct) | ||||
| 	if err != nil && xe.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { | ||||
| 		return internal.TransformMarshalError(in, err) | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func marshalEncode(out *jsontext.Encoder, in any, mo *jsonopts.Struct) (err error) { | ||||
| 	v := reflect.ValueOf(in) | ||||
| 	if !v.IsValid() || (v.Kind() == reflect.Pointer && v.IsNil()) { | ||||
| 		return out.WriteToken(jsontext.Null) | ||||
| 	} | ||||
| 	// Shallow copy non-pointer values to obtain an addressable value. | ||||
| 	// It is beneficial to performance to always pass pointers to avoid this. | ||||
| 	forceAddr := v.Kind() != reflect.Pointer | ||||
| 	if forceAddr { | ||||
| 		v2 := reflect.New(v.Type()) | ||||
| 		v2.Elem().Set(v) | ||||
| 		v = v2 | ||||
| 	} | ||||
| 	va := addressableValue{v.Elem(), forceAddr} // dereferenced pointer is always addressable | ||||
| 	t := va.Type() | ||||
|  | ||||
| 	// Lookup and call the marshal function for this type. | ||||
| 	marshal := lookupArshaler(t).marshal | ||||
| 	if mo.Marshalers != nil { | ||||
| 		marshal, _ = mo.Marshalers.(*Marshalers).lookup(marshal, t) | ||||
| 	} | ||||
| 	if err := marshal(out, va, mo); err != nil { | ||||
| 		if !mo.Flags.Get(jsonflags.AllowDuplicateNames) { | ||||
| 			export.Encoder(out).Tokens.InvalidateDisabledNamespaces() | ||||
| 		} | ||||
| 		return err | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Unmarshal decodes a []byte input into a Go value according to the provided | ||||
| // unmarshal and decode options (while ignoring marshal or encode options). | ||||
| // The input must be a single JSON value with optional whitespace interspersed. | ||||
| // The output must be a non-nil pointer. | ||||
| // | ||||
| // Type-specific unmarshal functions and methods take precedence | ||||
| // over the default representation of a value. | ||||
| // Functions or methods that operate on *T are only called when decoding | ||||
| // a value of type T (by taking its address) or a non-nil value of *T. | ||||
| // Unmarshal ensures that a value is always addressable | ||||
| // (by boxing it on the heap if necessary) so that | ||||
| // these functions and methods can be consistently called. | ||||
| // | ||||
| // The input is decoded into the output according the following rules: | ||||
| // | ||||
| //   - If any type-specific functions in a [WithUnmarshalers] option match | ||||
| //     the value type, then those functions are called to decode the JSON | ||||
| //     value. If all applicable functions return [SkipFunc], | ||||
| //     then the input is decoded according to subsequent rules. | ||||
| // | ||||
| //   - If the value type implements [UnmarshalerFrom], | ||||
| //     then the UnmarshalJSONFrom method is called to decode the JSON value. | ||||
| // | ||||
| //   - If the value type implements [Unmarshaler], | ||||
| //     then the UnmarshalJSON method is called to decode the JSON value. | ||||
| // | ||||
| //   - If the value type implements [encoding.TextUnmarshaler], | ||||
| //     then the input is decoded as a JSON string and | ||||
| //     the UnmarshalText method is called with the decoded string value. | ||||
| //     This fails with a [SemanticError] if the input is not a JSON string. | ||||
| // | ||||
| //   - Otherwise, the JSON value is decoded according to the value's type | ||||
| //     as described in detail below. | ||||
| // | ||||
| // Most Go types have a default JSON representation. | ||||
| // Certain types support specialized formatting according to | ||||
| // a format flag optionally specified in the Go struct tag | ||||
| // for the struct field that contains the current value | ||||
| // (see the “JSON Representation of Go structs” section for more details). | ||||
| // A JSON null may be decoded into every supported Go value where | ||||
| // it is equivalent to storing the zero value of the Go value. | ||||
| // If the input JSON kind is not handled by the current Go value type, | ||||
| // then this fails with a [SemanticError]. Unless otherwise specified, | ||||
| // the decoded value replaces any pre-existing value. | ||||
| // | ||||
| // The representation of each type is as follows: | ||||
| // | ||||
| //   - A Go boolean is decoded from a JSON boolean (e.g., true or false). | ||||
| //     It does not support any custom format flags. | ||||
| // | ||||
| //   - A Go string is decoded from a JSON string. | ||||
| //     It does not support any custom format flags. | ||||
| // | ||||
| //   - A Go []byte or [N]byte is decoded from a JSON string | ||||
| //     containing the binary value encoded using RFC 4648. | ||||
| //     If the format is "base64" or unspecified, then this uses RFC 4648, section 4. | ||||
| //     If the format is "base64url", then this uses RFC 4648, section 5. | ||||
| //     If the format is "base32", then this uses RFC 4648, section 6. | ||||
| //     If the format is "base32hex", then this uses RFC 4648, section 7. | ||||
| //     If the format is "base16" or "hex", then this uses RFC 4648, section 8. | ||||
| //     If the format is "array", then the Go slice or array is decoded from a | ||||
| //     JSON array where each JSON element is recursively decoded for each byte. | ||||
| //     When decoding into a non-nil []byte, the slice length is reset to zero | ||||
| //     and the decoded input is appended to it. | ||||
| //     When decoding into a [N]byte, the input must decode to exactly N bytes, | ||||
| //     otherwise it fails with a [SemanticError]. | ||||
| // | ||||
| //   - A Go integer is decoded from a JSON number. | ||||
| //     It must be decoded from a JSON string containing a JSON number | ||||
| //     if [StringifyNumbers] is specified or decoding a JSON object name. | ||||
| //     It fails with a [SemanticError] if the JSON number | ||||
| //     has a fractional or exponent component. | ||||
| //     It also fails if it overflows the representation of the Go integer type. | ||||
| //     It does not support any custom format flags. | ||||
| // | ||||
| //   - A Go float is decoded from a JSON number. | ||||
| //     It must be decoded from a JSON string containing a JSON number | ||||
| //     if [StringifyNumbers] is specified or decoding a JSON object name. | ||||
| //     It fails if it overflows the representation of the Go float type. | ||||
| //     If the format is "nonfinite", then the JSON strings | ||||
| //     "NaN", "Infinity", and "-Infinity" are decoded as NaN, +Inf, and -Inf. | ||||
| //     Otherwise, the presence of such strings results in a [SemanticError]. | ||||
| // | ||||
| //   - A Go map is decoded from a JSON object, | ||||
| //     where each JSON object name and value pair is recursively decoded | ||||
| //     as the Go map key and value. Maps are not cleared. | ||||
| //     If the Go map is nil, then a new map is allocated to decode into. | ||||
| //     If the decoded key matches an existing Go map entry, the entry value | ||||
| //     is reused by decoding the JSON object value into it. | ||||
| //     The formats "emitnull" and "emitempty" have no effect when decoding. | ||||
| // | ||||
| //   - A Go struct is decoded from a JSON object. | ||||
| //     See the “JSON Representation of Go structs” section | ||||
| //     in the package-level documentation for more details. | ||||
| // | ||||
| //   - A Go slice is decoded from a JSON array, where each JSON element | ||||
| //     is recursively decoded and appended to the Go slice. | ||||
| //     Before appending into a Go slice, a new slice is allocated if it is nil, | ||||
| //     otherwise the slice length is reset to zero. | ||||
| //     The formats "emitnull" and "emitempty" have no effect when decoding. | ||||
| // | ||||
| //   - A Go array is decoded from a JSON array, where each JSON array element | ||||
| //     is recursively decoded as each corresponding Go array element. | ||||
| //     Each Go array element is zeroed before decoding into it. | ||||
| //     It fails with a [SemanticError] if the JSON array does not contain | ||||
| //     the exact same number of elements as the Go array. | ||||
| //     It does not support any custom format flags. | ||||
| // | ||||
| //   - A Go pointer is decoded based on the JSON kind and underlying Go type. | ||||
| //     If the input is a JSON null, then this stores a nil pointer. | ||||
| //     Otherwise, it allocates a new underlying value if the pointer is nil, | ||||
| //     and recursively JSON decodes into the underlying value. | ||||
| //     Format flags are forwarded to the decoding of the underlying type. | ||||
| // | ||||
| //   - A Go interface is decoded based on the JSON kind and underlying Go type. | ||||
| //     If the input is a JSON null, then this stores a nil interface value. | ||||
| //     Otherwise, a nil interface value of an empty interface type is initialized | ||||
| //     with a zero Go bool, string, float64, map[string]any, or []any if the | ||||
| //     input is a JSON boolean, string, number, object, or array, respectively. | ||||
| //     If the interface value is still nil, then this fails with a [SemanticError] | ||||
| //     since decoding could not determine an appropriate Go type to decode into. | ||||
| //     For example, unmarshaling into a nil io.Reader fails since | ||||
| //     there is no concrete type to populate the interface value with. | ||||
| //     Otherwise an underlying value exists and it recursively decodes | ||||
| //     the JSON input into it. It does not support any custom format flags. | ||||
| // | ||||
| //   - A Go [time.Time] is decoded from a JSON string containing the time | ||||
| //     formatted in RFC 3339 with nanosecond precision. | ||||
| //     If the format matches one of the format constants declared in | ||||
| //     the time package (e.g., RFC1123), then that format is used for parsing. | ||||
| //     If the format is "unix", "unixmilli", "unixmicro", or "unixnano", | ||||
| //     then the timestamp is decoded from a JSON number of the number of seconds | ||||
| //     (or milliseconds, microseconds, or nanoseconds) since the Unix epoch, | ||||
| //     which is January 1st, 1970 at 00:00:00 UTC. | ||||
| //     Otherwise, the format is used as-is with [time.Time.Parse] if non-empty. | ||||
| // | ||||
| //   - A Go [time.Duration] is decoded from a JSON string by | ||||
| //     passing the decoded string to [time.ParseDuration]. | ||||
| //     If the format is "sec", "milli", "micro", or "nano", | ||||
| //     then the duration is decoded from a JSON number of the number of seconds | ||||
| //     (or milliseconds, microseconds, or nanoseconds) in the duration. | ||||
| //     If the format is "units", it uses [time.ParseDuration]. | ||||
| // | ||||
| //   - All other Go types (e.g., complex numbers, channels, and functions) | ||||
| //     have no default representation and result in a [SemanticError]. | ||||
| // | ||||
| // In general, unmarshaling follows merge semantics (similar to RFC 7396) | ||||
| // where the decoded Go value replaces the destination value | ||||
| // for any JSON kind other than an object. | ||||
| // For JSON objects, the input object is merged into the destination value | ||||
| // where matching object members recursively apply merge semantics. | ||||
| func Unmarshal(in []byte, out any, opts ...Options) (err error) { | ||||
| 	dec := export.GetBufferedDecoder(in, opts...) | ||||
| 	defer export.PutBufferedDecoder(dec) | ||||
| 	xd := export.Decoder(dec) | ||||
| 	err = unmarshalFull(dec, out, &xd.Struct) | ||||
| 	if err != nil && xd.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { | ||||
| 		return internal.TransformUnmarshalError(out, err) | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // UnmarshalRead deserializes a Go value from an [io.Reader] according to the | ||||
| // provided unmarshal and decode options (while ignoring marshal or encode options). | ||||
| // The input must be a single JSON value with optional whitespace interspersed. | ||||
| // It consumes the entirety of [io.Reader] until [io.EOF] is encountered, | ||||
| // without reporting an error for EOF. The output must be a non-nil pointer. | ||||
| // See [Unmarshal] for details about the conversion of JSON into a Go value. | ||||
| func UnmarshalRead(in io.Reader, out any, opts ...Options) (err error) { | ||||
| 	dec := export.GetStreamingDecoder(in, opts...) | ||||
| 	defer export.PutStreamingDecoder(dec) | ||||
| 	xd := export.Decoder(dec) | ||||
| 	err = unmarshalFull(dec, out, &xd.Struct) | ||||
| 	if err != nil && xd.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { | ||||
| 		return internal.TransformUnmarshalError(out, err) | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func unmarshalFull(in *jsontext.Decoder, out any, uo *jsonopts.Struct) error { | ||||
| 	switch err := unmarshalDecode(in, out, uo); err { | ||||
| 	case nil: | ||||
| 		return export.Decoder(in).CheckEOF() | ||||
| 	case io.EOF: | ||||
| 		return io.ErrUnexpectedEOF | ||||
| 	default: | ||||
| 		return err | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // UnmarshalDecode deserializes a Go value from a [jsontext.Decoder] according to | ||||
| // the provided unmarshal options (while ignoring marshal, encode, or decode options). | ||||
| // Any unmarshal options already specified on the [jsontext.Decoder] | ||||
| // take lower precedence than the set of options provided by the caller. | ||||
| // Unlike [Unmarshal] and [UnmarshalRead], decode options are ignored because | ||||
| // they must have already been specified on the provided [jsontext.Decoder]. | ||||
| // | ||||
| // The input may be a stream of one or more JSON values, | ||||
| // where this only unmarshals the next JSON value in the stream. | ||||
| // The output must be a non-nil pointer. | ||||
| // See [Unmarshal] for details about the conversion of JSON into a Go value. | ||||
| func UnmarshalDecode(in *jsontext.Decoder, out any, opts ...Options) (err error) { | ||||
| 	xd := export.Decoder(in) | ||||
| 	if len(opts) > 0 { | ||||
| 		optsOriginal := xd.Struct | ||||
| 		defer func() { xd.Struct = optsOriginal }() | ||||
| 		xd.Struct.JoinWithoutCoderOptions(opts...) | ||||
| 	} | ||||
| 	err = unmarshalDecode(in, out, &xd.Struct) | ||||
| 	if err != nil && xd.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { | ||||
| 		return internal.TransformUnmarshalError(out, err) | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func unmarshalDecode(in *jsontext.Decoder, out any, uo *jsonopts.Struct) (err error) { | ||||
| 	v := reflect.ValueOf(out) | ||||
| 	if v.Kind() != reflect.Pointer || v.IsNil() { | ||||
| 		return &SemanticError{action: "unmarshal", GoType: reflect.TypeOf(out), Err: internal.ErrNonNilReference} | ||||
| 	} | ||||
| 	va := addressableValue{v.Elem(), false} // dereferenced pointer is always addressable | ||||
| 	t := va.Type() | ||||
|  | ||||
| 	// In legacy semantics, the entirety of the next JSON value | ||||
| 	// was validated before attempting to unmarshal it. | ||||
| 	if uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { | ||||
| 		if err := export.Decoder(in).CheckNextValue(); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Lookup and call the unmarshal function for this type. | ||||
| 	unmarshal := lookupArshaler(t).unmarshal | ||||
| 	if uo.Unmarshalers != nil { | ||||
| 		unmarshal, _ = uo.Unmarshalers.(*Unmarshalers).lookup(unmarshal, t) | ||||
| 	} | ||||
| 	if err := unmarshal(in, va, uo); err != nil { | ||||
| 		if !uo.Flags.Get(jsonflags.AllowDuplicateNames) { | ||||
| 			export.Decoder(in).Tokens.InvalidateDisabledNamespaces() | ||||
| 		} | ||||
| 		return err | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // addressableValue is a reflect.Value that is guaranteed to be addressable | ||||
| // such that calling the Addr and Set methods do not panic. | ||||
| // | ||||
| // There is no compile magic that enforces this property, | ||||
| // but rather the need to construct this type makes it easier to examine each | ||||
| // construction site to ensure that this property is upheld. | ||||
| type addressableValue struct { | ||||
| 	reflect.Value | ||||
|  | ||||
| 	// forcedAddr reports whether this value is addressable | ||||
| 	// only through the use of [newAddressableValue]. | ||||
| 	// This is only used for [jsonflags.CallMethodsWithLegacySemantics]. | ||||
| 	forcedAddr bool | ||||
| } | ||||
|  | ||||
| // newAddressableValue constructs a new addressable value of type t. | ||||
| func newAddressableValue(t reflect.Type) addressableValue { | ||||
| 	return addressableValue{reflect.New(t).Elem(), true} | ||||
| } | ||||
|  | ||||
| // TODO: Remove *jsonopts.Struct argument from [marshaler] and [unmarshaler]. | ||||
| // This can be directly accessed on the encoder or decoder. | ||||
|  | ||||
| // All marshal and unmarshal behavior is implemented using these signatures. | ||||
| // The *jsonopts.Struct argument is guaranteed to identical to or at least | ||||
| // a strict super-set of the options in Encoder.Struct or Decoder.Struct. | ||||
| // It is identical for Marshal, Unmarshal, MarshalWrite, and UnmarshalRead. | ||||
| // It is a super-set for MarshalEncode and UnmarshalDecode. | ||||
| type ( | ||||
| 	marshaler   = func(*jsontext.Encoder, addressableValue, *jsonopts.Struct) error | ||||
| 	unmarshaler = func(*jsontext.Decoder, addressableValue, *jsonopts.Struct) error | ||||
| ) | ||||
|  | ||||
| type arshaler struct { | ||||
| 	marshal    marshaler | ||||
| 	unmarshal  unmarshaler | ||||
| 	nonDefault bool | ||||
| } | ||||
|  | ||||
| var lookupArshalerCache sync.Map // map[reflect.Type]*arshaler | ||||
|  | ||||
| func lookupArshaler(t reflect.Type) *arshaler { | ||||
| 	if v, ok := lookupArshalerCache.Load(t); ok { | ||||
| 		return v.(*arshaler) | ||||
| 	} | ||||
|  | ||||
| 	fncs := makeDefaultArshaler(t) | ||||
| 	fncs = makeMethodArshaler(fncs, t) | ||||
| 	fncs = makeTimeArshaler(fncs, t) | ||||
|  | ||||
| 	// Use the last stored so that duplicate arshalers can be garbage collected. | ||||
| 	v, _ := lookupArshalerCache.LoadOrStore(t, fncs) | ||||
| 	return v.(*arshaler) | ||||
| } | ||||
|  | ||||
| var stringsPools = &sync.Pool{New: func() any { return new(stringSlice) }} | ||||
|  | ||||
| type stringSlice []string | ||||
|  | ||||
| // getStrings returns a non-nil pointer to a slice with length n. | ||||
| func getStrings(n int) *stringSlice { | ||||
| 	s := stringsPools.Get().(*stringSlice) | ||||
| 	if cap(*s) < n { | ||||
| 		*s = make([]string, n) | ||||
| 	} | ||||
| 	*s = (*s)[:n] | ||||
| 	return s | ||||
| } | ||||
|  | ||||
| func putStrings(s *stringSlice) { | ||||
| 	if cap(*s) > 1<<10 { | ||||
| 		*s = nil // avoid pinning arbitrarily large amounts of memory | ||||
| 	} | ||||
| 	stringsPools.Put(s) | ||||
| } | ||||
|  | ||||
| func (ss *stringSlice) Sort() { | ||||
| 	slices.SortFunc(*ss, func(x, y string) int { return strings.Compare(x, y) }) | ||||
| } | ||||
							
								
								
									
										281
									
								
								vendor/github.com/go-json-experiment/json/arshal_any.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										281
									
								
								vendor/github.com/go-json-experiment/json/arshal_any.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,281 @@ | ||||
| // Copyright 2022 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. | ||||
|  | ||||
| package json | ||||
|  | ||||
| import ( | ||||
| 	"cmp" | ||||
| 	"reflect" | ||||
| 	"strconv" | ||||
|  | ||||
| 	"github.com/go-json-experiment/json/internal" | ||||
| 	"github.com/go-json-experiment/json/internal/jsonflags" | ||||
| 	"github.com/go-json-experiment/json/internal/jsonopts" | ||||
| 	"github.com/go-json-experiment/json/internal/jsonwire" | ||||
| 	"github.com/go-json-experiment/json/jsontext" | ||||
| ) | ||||
|  | ||||
| // This file contains an optimized marshal and unmarshal implementation | ||||
| // for the any type. This type is often used when the Go program has | ||||
| // no knowledge of the JSON schema. This is a common enough occurrence | ||||
| // to justify the complexity of adding logic for this. | ||||
|  | ||||
| // marshalValueAny marshals a Go any as a JSON value. | ||||
| // This assumes that there are no special formatting directives | ||||
| // for any possible nested value. | ||||
| func marshalValueAny(enc *jsontext.Encoder, val any, mo *jsonopts.Struct) error { | ||||
| 	switch val := val.(type) { | ||||
| 	case nil: | ||||
| 		return enc.WriteToken(jsontext.Null) | ||||
| 	case bool: | ||||
| 		return enc.WriteToken(jsontext.Bool(val)) | ||||
| 	case string: | ||||
| 		return enc.WriteToken(jsontext.String(val)) | ||||
| 	case float64: | ||||
| 		return enc.WriteToken(jsontext.Float(val)) | ||||
| 	case map[string]any: | ||||
| 		return marshalObjectAny(enc, val, mo) | ||||
| 	case []any: | ||||
| 		return marshalArrayAny(enc, val, mo) | ||||
| 	default: | ||||
| 		v := newAddressableValue(reflect.TypeOf(val)) | ||||
| 		v.Set(reflect.ValueOf(val)) | ||||
| 		marshal := lookupArshaler(v.Type()).marshal | ||||
| 		if mo.Marshalers != nil { | ||||
| 			marshal, _ = mo.Marshalers.(*Marshalers).lookup(marshal, v.Type()) | ||||
| 		} | ||||
| 		return marshal(enc, v, mo) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // unmarshalValueAny unmarshals a JSON value as a Go any. | ||||
| // This assumes that there are no special formatting directives | ||||
| // for any possible nested value. | ||||
| // Duplicate names must be rejected since this does not implement merging. | ||||
| func unmarshalValueAny(dec *jsontext.Decoder, uo *jsonopts.Struct) (any, error) { | ||||
| 	switch k := dec.PeekKind(); k { | ||||
| 	case '{': | ||||
| 		return unmarshalObjectAny(dec, uo) | ||||
| 	case '[': | ||||
| 		return unmarshalArrayAny(dec, uo) | ||||
| 	default: | ||||
| 		xd := export.Decoder(dec) | ||||
| 		var flags jsonwire.ValueFlags | ||||
| 		val, err := xd.ReadValue(&flags) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		switch val.Kind() { | ||||
| 		case 'n': | ||||
| 			return nil, nil | ||||
| 		case 'f': | ||||
| 			return false, nil | ||||
| 		case 't': | ||||
| 			return true, nil | ||||
| 		case '"': | ||||
| 			val = jsonwire.UnquoteMayCopy(val, flags.IsVerbatim()) | ||||
| 			if xd.StringCache == nil { | ||||
| 				xd.StringCache = new(stringCache) | ||||
| 			} | ||||
| 			return makeString(xd.StringCache, val), nil | ||||
| 		case '0': | ||||
| 			if uo.Flags.Get(jsonflags.UnmarshalAnyWithRawNumber) { | ||||
| 				return internal.RawNumberOf(val), nil | ||||
| 			} | ||||
| 			fv, ok := jsonwire.ParseFloat(val, 64) | ||||
| 			if !ok { | ||||
| 				return fv, newUnmarshalErrorAfterWithValue(dec, float64Type, strconv.ErrRange) | ||||
| 			} | ||||
| 			return fv, nil | ||||
| 		default: | ||||
| 			panic("BUG: invalid kind: " + k.String()) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // marshalObjectAny marshals a Go map[string]any as a JSON object | ||||
| // (or as a JSON null if nil and [jsonflags.FormatNilMapAsNull]). | ||||
| func marshalObjectAny(enc *jsontext.Encoder, obj map[string]any, mo *jsonopts.Struct) error { | ||||
| 	// Check for cycles. | ||||
| 	xe := export.Encoder(enc) | ||||
| 	if xe.Tokens.Depth() > startDetectingCyclesAfter { | ||||
| 		v := reflect.ValueOf(obj) | ||||
| 		if err := visitPointer(&xe.SeenPointers, v); err != nil { | ||||
| 			return newMarshalErrorBefore(enc, anyType, err) | ||||
| 		} | ||||
| 		defer leavePointer(&xe.SeenPointers, v) | ||||
| 	} | ||||
|  | ||||
| 	// Handle empty maps. | ||||
| 	if len(obj) == 0 { | ||||
| 		if mo.Flags.Get(jsonflags.FormatNilMapAsNull) && obj == nil { | ||||
| 			return enc.WriteToken(jsontext.Null) | ||||
| 		} | ||||
| 		// Optimize for marshaling an empty map without any preceding whitespace. | ||||
| 		if !mo.Flags.Get(jsonflags.AnyWhitespace) && !xe.Tokens.Last.NeedObjectName() { | ||||
| 			xe.Buf = append(xe.Tokens.MayAppendDelim(xe.Buf, '{'), "{}"...) | ||||
| 			xe.Tokens.Last.Increment() | ||||
| 			if xe.NeedFlush() { | ||||
| 				return xe.Flush() | ||||
| 			} | ||||
| 			return nil | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if err := enc.WriteToken(jsontext.BeginObject); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	// A Go map guarantees that each entry has a unique key | ||||
| 	// The only possibility of duplicates is due to invalid UTF-8. | ||||
| 	if !mo.Flags.Get(jsonflags.AllowInvalidUTF8) { | ||||
| 		xe.Tokens.Last.DisableNamespace() | ||||
| 	} | ||||
| 	if !mo.Flags.Get(jsonflags.Deterministic) || len(obj) <= 1 { | ||||
| 		for name, val := range obj { | ||||
| 			if err := enc.WriteToken(jsontext.String(name)); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			if err := marshalValueAny(enc, val, mo); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 	} else { | ||||
| 		names := getStrings(len(obj)) | ||||
| 		var i int | ||||
| 		for name := range obj { | ||||
| 			(*names)[i] = name | ||||
| 			i++ | ||||
| 		} | ||||
| 		names.Sort() | ||||
| 		for _, name := range *names { | ||||
| 			if err := enc.WriteToken(jsontext.String(name)); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			if err := marshalValueAny(enc, obj[name], mo); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 		putStrings(names) | ||||
| 	} | ||||
| 	if err := enc.WriteToken(jsontext.EndObject); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // unmarshalObjectAny unmarshals a JSON object as a Go map[string]any. | ||||
| // It panics if not decoding a JSON object. | ||||
| func unmarshalObjectAny(dec *jsontext.Decoder, uo *jsonopts.Struct) (map[string]any, error) { | ||||
| 	switch tok, err := dec.ReadToken(); { | ||||
| 	case err != nil: | ||||
| 		return nil, err | ||||
| 	case tok.Kind() != '{': | ||||
| 		panic("BUG: invalid kind: " + tok.Kind().String()) | ||||
| 	} | ||||
| 	obj := make(map[string]any) | ||||
| 	// A Go map guarantees that each entry has a unique key | ||||
| 	// The only possibility of duplicates is due to invalid UTF-8. | ||||
| 	if !uo.Flags.Get(jsonflags.AllowInvalidUTF8) { | ||||
| 		export.Decoder(dec).Tokens.Last.DisableNamespace() | ||||
| 	} | ||||
| 	var errUnmarshal error | ||||
| 	for dec.PeekKind() != '}' { | ||||
| 		tok, err := dec.ReadToken() | ||||
| 		if err != nil { | ||||
| 			return obj, err | ||||
| 		} | ||||
| 		name := tok.String() | ||||
|  | ||||
| 		// Manually check for duplicate names. | ||||
| 		if _, ok := obj[name]; ok { | ||||
| 			// TODO: Unread the object name. | ||||
| 			name := export.Decoder(dec).PreviousTokenOrValue() | ||||
| 			err := newDuplicateNameError(dec.StackPointer(), nil, dec.InputOffset()-len64(name)) | ||||
| 			return obj, err | ||||
| 		} | ||||
|  | ||||
| 		val, err := unmarshalValueAny(dec, uo) | ||||
| 		obj[name] = val | ||||
| 		if err != nil { | ||||
| 			if isFatalError(err, uo.Flags) { | ||||
| 				return obj, err | ||||
| 			} | ||||
| 			errUnmarshal = cmp.Or(err, errUnmarshal) | ||||
| 		} | ||||
| 	} | ||||
| 	if _, err := dec.ReadToken(); err != nil { | ||||
| 		return obj, err | ||||
| 	} | ||||
| 	return obj, errUnmarshal | ||||
| } | ||||
|  | ||||
| // marshalArrayAny marshals a Go []any as a JSON array | ||||
| // (or as a JSON null if nil and [jsonflags.FormatNilSliceAsNull]). | ||||
| func marshalArrayAny(enc *jsontext.Encoder, arr []any, mo *jsonopts.Struct) error { | ||||
| 	// Check for cycles. | ||||
| 	xe := export.Encoder(enc) | ||||
| 	if xe.Tokens.Depth() > startDetectingCyclesAfter { | ||||
| 		v := reflect.ValueOf(arr) | ||||
| 		if err := visitPointer(&xe.SeenPointers, v); err != nil { | ||||
| 			return newMarshalErrorBefore(enc, sliceAnyType, err) | ||||
| 		} | ||||
| 		defer leavePointer(&xe.SeenPointers, v) | ||||
| 	} | ||||
|  | ||||
| 	// Handle empty slices. | ||||
| 	if len(arr) == 0 { | ||||
| 		if mo.Flags.Get(jsonflags.FormatNilSliceAsNull) && arr == nil { | ||||
| 			return enc.WriteToken(jsontext.Null) | ||||
| 		} | ||||
| 		// Optimize for marshaling an empty slice without any preceding whitespace. | ||||
| 		if !mo.Flags.Get(jsonflags.AnyWhitespace) && !xe.Tokens.Last.NeedObjectName() { | ||||
| 			xe.Buf = append(xe.Tokens.MayAppendDelim(xe.Buf, '['), "[]"...) | ||||
| 			xe.Tokens.Last.Increment() | ||||
| 			if xe.NeedFlush() { | ||||
| 				return xe.Flush() | ||||
| 			} | ||||
| 			return nil | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if err := enc.WriteToken(jsontext.BeginArray); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	for _, val := range arr { | ||||
| 		if err := marshalValueAny(enc, val, mo); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	if err := enc.WriteToken(jsontext.EndArray); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // unmarshalArrayAny unmarshals a JSON array as a Go []any. | ||||
| // It panics if not decoding a JSON array. | ||||
| func unmarshalArrayAny(dec *jsontext.Decoder, uo *jsonopts.Struct) ([]any, error) { | ||||
| 	switch tok, err := dec.ReadToken(); { | ||||
| 	case err != nil: | ||||
| 		return nil, err | ||||
| 	case tok.Kind() != '[': | ||||
| 		panic("BUG: invalid kind: " + tok.Kind().String()) | ||||
| 	} | ||||
| 	arr := []any{} | ||||
| 	var errUnmarshal error | ||||
| 	for dec.PeekKind() != ']' { | ||||
| 		val, err := unmarshalValueAny(dec, uo) | ||||
| 		arr = append(arr, val) | ||||
| 		if err != nil { | ||||
| 			if isFatalError(err, uo.Flags) { | ||||
| 				return arr, err | ||||
| 			} | ||||
| 			errUnmarshal = cmp.Or(errUnmarshal, err) | ||||
| 		} | ||||
| 	} | ||||
| 	if _, err := dec.ReadToken(); err != nil { | ||||
| 		return arr, err | ||||
| 	} | ||||
| 	return arr, errUnmarshal | ||||
| } | ||||
							
								
								
									
										1908
									
								
								vendor/github.com/go-json-experiment/json/arshal_default.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1908
									
								
								vendor/github.com/go-json-experiment/json/arshal_default.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										430
									
								
								vendor/github.com/go-json-experiment/json/arshal_funcs.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										430
									
								
								vendor/github.com/go-json-experiment/json/arshal_funcs.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,430 @@ | ||||
| // Copyright 2020 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. | ||||
|  | ||||
| package json | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"reflect" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/go-json-experiment/json/internal" | ||||
| 	"github.com/go-json-experiment/json/internal/jsonflags" | ||||
| 	"github.com/go-json-experiment/json/internal/jsonopts" | ||||
| 	"github.com/go-json-experiment/json/jsontext" | ||||
| ) | ||||
|  | ||||
| // SkipFunc may be returned by [MarshalToFunc] and [UnmarshalFromFunc] functions. | ||||
| // | ||||
| // Any function that returns SkipFunc must not cause observable side effects | ||||
| // on the provided [jsontext.Encoder] or [jsontext.Decoder]. | ||||
| // For example, it is permissible to call [jsontext.Decoder.PeekKind], | ||||
| // but not permissible to call [jsontext.Decoder.ReadToken] or | ||||
| // [jsontext.Encoder.WriteToken] since such methods mutate the state. | ||||
| var SkipFunc = errors.New("json: skip function") | ||||
|  | ||||
| var errSkipMutation = errors.New("must not read or write any tokens when skipping") | ||||
| var errNonSingularValue = errors.New("must read or write exactly one value") | ||||
|  | ||||
| // Marshalers is a list of functions that may override the marshal behavior | ||||
| // of specific types. Populate [WithMarshalers] to use it with | ||||
| // [Marshal], [MarshalWrite], or [MarshalEncode]. | ||||
| // A nil *Marshalers is equivalent to an empty list. | ||||
| // There are no exported fields or methods on Marshalers. | ||||
| type Marshalers = typedMarshalers | ||||
|  | ||||
| // JoinMarshalers constructs a flattened list of marshal functions. | ||||
| // If multiple functions in the list are applicable for a value of a given type, | ||||
| // then those earlier in the list take precedence over those that come later. | ||||
| // If a function returns [SkipFunc], then the next applicable function is called, | ||||
| // otherwise the default marshaling behavior is used. | ||||
| // | ||||
| // For example: | ||||
| // | ||||
| //	m1 := JoinMarshalers(f1, f2) | ||||
| //	m2 := JoinMarshalers(f0, m1, f3)     // equivalent to m3 | ||||
| //	m3 := JoinMarshalers(f0, f1, f2, f3) // equivalent to m2 | ||||
| func JoinMarshalers(ms ...*Marshalers) *Marshalers { | ||||
| 	return newMarshalers(ms...) | ||||
| } | ||||
|  | ||||
| // Unmarshalers is a list of functions that may override the unmarshal behavior | ||||
| // of specific types. Populate [WithUnmarshalers] to use it with | ||||
| // [Unmarshal], [UnmarshalRead], or [UnmarshalDecode]. | ||||
| // A nil *Unmarshalers is equivalent to an empty list. | ||||
| // There are no exported fields or methods on Unmarshalers. | ||||
| type Unmarshalers = typedUnmarshalers | ||||
|  | ||||
| // JoinUnmarshalers constructs a flattened list of unmarshal functions. | ||||
| // If multiple functions in the list are applicable for a value of a given type, | ||||
| // then those earlier in the list take precedence over those that come later. | ||||
| // If a function returns [SkipFunc], then the next applicable function is called, | ||||
| // otherwise the default unmarshaling behavior is used. | ||||
| // | ||||
| // For example: | ||||
| // | ||||
| //	u1 := JoinUnmarshalers(f1, f2) | ||||
| //	u2 := JoinUnmarshalers(f0, u1, f3)     // equivalent to u3 | ||||
| //	u3 := JoinUnmarshalers(f0, f1, f2, f3) // equivalent to u2 | ||||
| func JoinUnmarshalers(us ...*Unmarshalers) *Unmarshalers { | ||||
| 	return newUnmarshalers(us...) | ||||
| } | ||||
|  | ||||
| type typedMarshalers = typedArshalers[jsontext.Encoder] | ||||
| type typedUnmarshalers = typedArshalers[jsontext.Decoder] | ||||
| type typedArshalers[Coder any] struct { | ||||
| 	nonComparable | ||||
|  | ||||
| 	fncVals  []typedArshaler[Coder] | ||||
| 	fncCache sync.Map // map[reflect.Type]arshaler | ||||
|  | ||||
| 	// fromAny reports whether any of Go types used to represent arbitrary JSON | ||||
| 	// (i.e., any, bool, string, float64, map[string]any, or []any) matches | ||||
| 	// any of the provided type-specific arshalers. | ||||
| 	// | ||||
| 	// This bit of information is needed in arshal_default.go to determine | ||||
| 	// whether to use the specialized logic in arshal_any.go to handle | ||||
| 	// the any interface type. The logic in arshal_any.go does not support | ||||
| 	// type-specific arshal functions, so we must avoid using that logic | ||||
| 	// if this is true. | ||||
| 	fromAny bool | ||||
| } | ||||
| type typedMarshaler = typedArshaler[jsontext.Encoder] | ||||
| type typedUnmarshaler = typedArshaler[jsontext.Decoder] | ||||
| type typedArshaler[Coder any] struct { | ||||
| 	typ     reflect.Type | ||||
| 	fnc     func(*Coder, addressableValue, *jsonopts.Struct) error | ||||
| 	maySkip bool | ||||
| } | ||||
|  | ||||
| func newMarshalers(ms ...*Marshalers) *Marshalers       { return newTypedArshalers(ms...) } | ||||
| func newUnmarshalers(us ...*Unmarshalers) *Unmarshalers { return newTypedArshalers(us...) } | ||||
| func newTypedArshalers[Coder any](as ...*typedArshalers[Coder]) *typedArshalers[Coder] { | ||||
| 	var a typedArshalers[Coder] | ||||
| 	for _, a2 := range as { | ||||
| 		if a2 != nil { | ||||
| 			a.fncVals = append(a.fncVals, a2.fncVals...) | ||||
| 			a.fromAny = a.fromAny || a2.fromAny | ||||
| 		} | ||||
| 	} | ||||
| 	if len(a.fncVals) == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return &a | ||||
| } | ||||
|  | ||||
| func (a *typedArshalers[Coder]) lookup(fnc func(*Coder, addressableValue, *jsonopts.Struct) error, t reflect.Type) (func(*Coder, addressableValue, *jsonopts.Struct) error, bool) { | ||||
| 	if a == nil { | ||||
| 		return fnc, false | ||||
| 	} | ||||
| 	if v, ok := a.fncCache.Load(t); ok { | ||||
| 		if v == nil { | ||||
| 			return fnc, false | ||||
| 		} | ||||
| 		return v.(func(*Coder, addressableValue, *jsonopts.Struct) error), true | ||||
| 	} | ||||
|  | ||||
| 	// Collect a list of arshalers that can be called for this type. | ||||
| 	// This list may be longer than 1 since some arshalers can be skipped. | ||||
| 	var fncs []func(*Coder, addressableValue, *jsonopts.Struct) error | ||||
| 	for _, fncVal := range a.fncVals { | ||||
| 		if !castableTo(t, fncVal.typ) { | ||||
| 			continue | ||||
| 		} | ||||
| 		fncs = append(fncs, fncVal.fnc) | ||||
| 		if !fncVal.maySkip { | ||||
| 			break // subsequent arshalers will never be called | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if len(fncs) == 0 { | ||||
| 		a.fncCache.Store(t, nil) // nil to indicate that no funcs found | ||||
| 		return fnc, false | ||||
| 	} | ||||
|  | ||||
| 	// Construct an arshaler that may call every applicable arshaler. | ||||
| 	fncDefault := fnc | ||||
| 	fnc = func(c *Coder, v addressableValue, o *jsonopts.Struct) error { | ||||
| 		for _, fnc := range fncs { | ||||
| 			if err := fnc(c, v, o); err != SkipFunc { | ||||
| 				return err // may be nil or non-nil | ||||
| 			} | ||||
| 		} | ||||
| 		return fncDefault(c, v, o) | ||||
| 	} | ||||
|  | ||||
| 	// Use the first stored so duplicate work can be garbage collected. | ||||
| 	v, _ := a.fncCache.LoadOrStore(t, fnc) | ||||
| 	return v.(func(*Coder, addressableValue, *jsonopts.Struct) error), true | ||||
| } | ||||
|  | ||||
| // MarshalFunc constructs a type-specific marshaler that | ||||
| // specifies how to marshal values of type T. | ||||
| // T can be any type except a named pointer. | ||||
| // The function is always provided with a non-nil pointer value | ||||
| // if T is an interface or pointer type. | ||||
| // | ||||
| // The function must marshal exactly one JSON value. | ||||
| // The value of T must not be retained outside the function call. | ||||
| // It may not return [SkipFunc]. | ||||
| func MarshalFunc[T any](fn func(T) ([]byte, error)) *Marshalers { | ||||
| 	t := reflect.TypeFor[T]() | ||||
| 	assertCastableTo(t, true) | ||||
| 	typFnc := typedMarshaler{ | ||||
| 		typ: t, | ||||
| 		fnc: func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { | ||||
| 			val, err := fn(va.castTo(t).Interface().(T)) | ||||
| 			if err != nil { | ||||
| 				err = wrapSkipFunc(err, "marshal function of type func(T) ([]byte, error)") | ||||
| 				if mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { | ||||
| 					return internal.NewMarshalerError(va.Addr().Interface(), err, "MarshalFunc") // unlike unmarshal, always wrapped | ||||
| 				} | ||||
| 				err = newMarshalErrorBefore(enc, t, err) | ||||
| 				return collapseSemanticErrors(err) | ||||
| 			} | ||||
| 			if err := enc.WriteValue(val); err != nil { | ||||
| 				if mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { | ||||
| 					return internal.NewMarshalerError(va.Addr().Interface(), err, "MarshalFunc") // unlike unmarshal, always wrapped | ||||
| 				} | ||||
| 				if isSyntacticError(err) { | ||||
| 					err = newMarshalErrorBefore(enc, t, err) | ||||
| 				} | ||||
| 				return err | ||||
| 			} | ||||
| 			return nil | ||||
| 		}, | ||||
| 	} | ||||
| 	return &Marshalers{fncVals: []typedMarshaler{typFnc}, fromAny: castableToFromAny(t)} | ||||
| } | ||||
|  | ||||
| // MarshalToFunc constructs a type-specific marshaler that | ||||
| // specifies how to marshal values of type T. | ||||
| // T can be any type except a named pointer. | ||||
| // The function is always provided with a non-nil pointer value | ||||
| // if T is an interface or pointer type. | ||||
| // | ||||
| // The function must marshal exactly one JSON value by calling write methods | ||||
| // on the provided encoder. It may return [SkipFunc] such that marshaling can | ||||
| // move on to the next marshal function. However, no mutable method calls may | ||||
| // be called on the encoder if [SkipFunc] is returned. | ||||
| // The pointer to [jsontext.Encoder] and the value of T | ||||
| // must not be retained outside the function call. | ||||
| func MarshalToFunc[T any](fn func(*jsontext.Encoder, T) error) *Marshalers { | ||||
| 	t := reflect.TypeFor[T]() | ||||
| 	assertCastableTo(t, true) | ||||
| 	typFnc := typedMarshaler{ | ||||
| 		typ: t, | ||||
| 		fnc: func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { | ||||
| 			xe := export.Encoder(enc) | ||||
| 			prevDepth, prevLength := xe.Tokens.DepthLength() | ||||
| 			xe.Flags.Set(jsonflags.WithinArshalCall | 1) | ||||
| 			err := fn(enc, va.castTo(t).Interface().(T)) | ||||
| 			xe.Flags.Set(jsonflags.WithinArshalCall | 0) | ||||
| 			currDepth, currLength := xe.Tokens.DepthLength() | ||||
| 			if err == nil && (prevDepth != currDepth || prevLength+1 != currLength) { | ||||
| 				err = errNonSingularValue | ||||
| 			} | ||||
| 			if err != nil { | ||||
| 				if err == SkipFunc { | ||||
| 					if prevDepth == currDepth && prevLength == currLength { | ||||
| 						return SkipFunc | ||||
| 					} | ||||
| 					err = errSkipMutation | ||||
| 				} | ||||
| 				if mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { | ||||
| 					return internal.NewMarshalerError(va.Addr().Interface(), err, "MarshalToFunc") // unlike unmarshal, always wrapped | ||||
| 				} | ||||
| 				if !export.IsIOError(err) { | ||||
| 					err = newSemanticErrorWithPosition(enc, t, prevDepth, prevLength, err) | ||||
| 				} | ||||
| 				return err | ||||
| 			} | ||||
| 			return nil | ||||
| 		}, | ||||
| 		maySkip: true, | ||||
| 	} | ||||
| 	return &Marshalers{fncVals: []typedMarshaler{typFnc}, fromAny: castableToFromAny(t)} | ||||
| } | ||||
|  | ||||
| // UnmarshalFunc constructs a type-specific unmarshaler that | ||||
| // specifies how to unmarshal values of type T. | ||||
| // T must be an unnamed pointer or an interface type. | ||||
| // The function is always provided with a non-nil pointer value. | ||||
| // | ||||
| // The function must unmarshal exactly one JSON value. | ||||
| // The input []byte must not be mutated. | ||||
| // The input []byte and value T must not be retained outside the function call. | ||||
| // It may not return [SkipFunc]. | ||||
| func UnmarshalFunc[T any](fn func([]byte, T) error) *Unmarshalers { | ||||
| 	t := reflect.TypeFor[T]() | ||||
| 	assertCastableTo(t, false) | ||||
| 	typFnc := typedUnmarshaler{ | ||||
| 		typ: t, | ||||
| 		fnc: func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error { | ||||
| 			val, err := dec.ReadValue() | ||||
| 			if err != nil { | ||||
| 				return err // must be a syntactic or I/O error | ||||
| 			} | ||||
| 			err = fn(val, va.castTo(t).Interface().(T)) | ||||
| 			if err != nil { | ||||
| 				err = wrapSkipFunc(err, "unmarshal function of type func([]byte, T) error") | ||||
| 				if uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { | ||||
| 					return err // unlike marshal, never wrapped | ||||
| 				} | ||||
| 				err = newUnmarshalErrorAfter(dec, t, err) | ||||
| 				return collapseSemanticErrors(err) | ||||
| 			} | ||||
| 			return nil | ||||
| 		}, | ||||
| 	} | ||||
| 	return &Unmarshalers{fncVals: []typedUnmarshaler{typFnc}, fromAny: castableToFromAny(t)} | ||||
| } | ||||
|  | ||||
| // UnmarshalFromFunc constructs a type-specific unmarshaler that | ||||
| // specifies how to unmarshal values of type T. | ||||
| // T must be an unnamed pointer or an interface type. | ||||
| // The function is always provided with a non-nil pointer value. | ||||
| // | ||||
| // The function must unmarshal exactly one JSON value by calling read methods | ||||
| // on the provided decoder. It may return [SkipFunc] such that unmarshaling can | ||||
| // move on to the next unmarshal function. However, no mutable method calls may | ||||
| // be called on the decoder if [SkipFunc] is returned. | ||||
| // The pointer to [jsontext.Decoder] and the value of T | ||||
| // must not be retained outside the function call. | ||||
| func UnmarshalFromFunc[T any](fn func(*jsontext.Decoder, T) error) *Unmarshalers { | ||||
| 	t := reflect.TypeFor[T]() | ||||
| 	assertCastableTo(t, false) | ||||
| 	typFnc := typedUnmarshaler{ | ||||
| 		typ: t, | ||||
| 		fnc: func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error { | ||||
| 			xd := export.Decoder(dec) | ||||
| 			prevDepth, prevLength := xd.Tokens.DepthLength() | ||||
| 			xd.Flags.Set(jsonflags.WithinArshalCall | 1) | ||||
| 			err := fn(dec, va.castTo(t).Interface().(T)) | ||||
| 			xd.Flags.Set(jsonflags.WithinArshalCall | 0) | ||||
| 			currDepth, currLength := xd.Tokens.DepthLength() | ||||
| 			if err == nil && (prevDepth != currDepth || prevLength+1 != currLength) { | ||||
| 				err = errNonSingularValue | ||||
| 			} | ||||
| 			if err != nil { | ||||
| 				if err == SkipFunc { | ||||
| 					if prevDepth == currDepth && prevLength == currLength { | ||||
| 						return SkipFunc | ||||
| 					} | ||||
| 					err = errSkipMutation | ||||
| 				} | ||||
| 				if uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { | ||||
| 					if err2 := xd.SkipUntil(prevDepth, prevLength+1); err2 != nil { | ||||
| 						return err2 | ||||
| 					} | ||||
| 					return err // unlike marshal, never wrapped | ||||
| 				} | ||||
| 				if !isSyntacticError(err) && !export.IsIOError(err) { | ||||
| 					err = newSemanticErrorWithPosition(dec, t, prevDepth, prevLength, err) | ||||
| 				} | ||||
| 				return err | ||||
| 			} | ||||
| 			return nil | ||||
| 		}, | ||||
| 		maySkip: true, | ||||
| 	} | ||||
| 	return &Unmarshalers{fncVals: []typedUnmarshaler{typFnc}, fromAny: castableToFromAny(t)} | ||||
| } | ||||
|  | ||||
| // assertCastableTo asserts that "to" is a valid type to be casted to. | ||||
| // These are the Go types that type-specific arshalers may operate upon. | ||||
| // | ||||
| // Let AllTypes be the universal set of all possible Go types. | ||||
| // This function generally asserts that: | ||||
| // | ||||
| //	len([from for from in AllTypes if castableTo(from, to)]) > 0 | ||||
| // | ||||
| // otherwise it panics. | ||||
| // | ||||
| // As a special-case if marshal is false, then we forbid any non-pointer or | ||||
| // non-interface type since it is almost always a bug trying to unmarshal | ||||
| // into something where the end-user caller did not pass in an addressable value | ||||
| // since they will not observe the mutations. | ||||
| func assertCastableTo(to reflect.Type, marshal bool) { | ||||
| 	switch to.Kind() { | ||||
| 	case reflect.Interface: | ||||
| 		return | ||||
| 	case reflect.Pointer: | ||||
| 		// Only allow unnamed pointers to be consistent with the fact that | ||||
| 		// taking the address of a value produces an unnamed pointer type. | ||||
| 		if to.Name() == "" { | ||||
| 			return | ||||
| 		} | ||||
| 	default: | ||||
| 		// Technically, non-pointer types are permissible for unmarshal. | ||||
| 		// However, they are often a bug since the receiver would be immutable. | ||||
| 		// Thus, only allow them for marshaling. | ||||
| 		if marshal { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 	if marshal { | ||||
| 		panic(fmt.Sprintf("input type %v must be an interface type, an unnamed pointer type, or a non-pointer type", to)) | ||||
| 	} else { | ||||
| 		panic(fmt.Sprintf("input type %v must be an interface type or an unnamed pointer type", to)) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // castableTo checks whether values of type "from" can be casted to type "to". | ||||
| // Nil pointer or interface "from" values are never considered castable. | ||||
| // | ||||
| // This function must be kept in sync with addressableValue.castTo. | ||||
| func castableTo(from, to reflect.Type) bool { | ||||
| 	switch to.Kind() { | ||||
| 	case reflect.Interface: | ||||
| 		// TODO: This breaks when ordinary interfaces can have type sets | ||||
| 		// since interfaces now exist where only the value form of a type (T) | ||||
| 		// implements the interface, but not the pointer variant (*T). | ||||
| 		// See https://go.dev/issue/45346. | ||||
| 		return reflect.PointerTo(from).Implements(to) | ||||
| 	case reflect.Pointer: | ||||
| 		// Common case for unmarshaling. | ||||
| 		// From must be a concrete or interface type. | ||||
| 		return reflect.PointerTo(from) == to | ||||
| 	default: | ||||
| 		// Common case for marshaling. | ||||
| 		// From must be a concrete type. | ||||
| 		return from == to | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // castTo casts va to the specified type. | ||||
| // If the type is an interface, then the underlying type will always | ||||
| // be a non-nil pointer to a concrete type. | ||||
| // | ||||
| // Requirement: castableTo(va.Type(), to) must hold. | ||||
| func (va addressableValue) castTo(to reflect.Type) reflect.Value { | ||||
| 	switch to.Kind() { | ||||
| 	case reflect.Interface: | ||||
| 		return va.Addr().Convert(to) | ||||
| 	case reflect.Pointer: | ||||
| 		return va.Addr() | ||||
| 	default: | ||||
| 		return va.Value | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // castableToFromAny reports whether "to" can be casted to from any | ||||
| // of the dynamic types used to represent arbitrary JSON. | ||||
| func castableToFromAny(to reflect.Type) bool { | ||||
| 	for _, from := range []reflect.Type{anyType, boolType, stringType, float64Type, mapStringAnyType, sliceAnyType} { | ||||
| 		if castableTo(from, to) { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func wrapSkipFunc(err error, what string) error { | ||||
| 	if err == SkipFunc { | ||||
| 		return errors.New(what + " cannot be skipped") | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
							
								
								
									
										228
									
								
								vendor/github.com/go-json-experiment/json/arshal_inlined.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										228
									
								
								vendor/github.com/go-json-experiment/json/arshal_inlined.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,228 @@ | ||||
| // Copyright 2020 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. | ||||
|  | ||||
| package json | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"errors" | ||||
| 	"io" | ||||
| 	"reflect" | ||||
|  | ||||
| 	"github.com/go-json-experiment/json/internal/jsonflags" | ||||
| 	"github.com/go-json-experiment/json/internal/jsonopts" | ||||
| 	"github.com/go-json-experiment/json/internal/jsonwire" | ||||
| 	"github.com/go-json-experiment/json/jsontext" | ||||
| ) | ||||
|  | ||||
| // This package supports "inlining" a Go struct field, where the contents | ||||
| // of the serialized field (which must be a JSON object) are treated as if | ||||
| // they are part of the parent Go struct (which represents a JSON object). | ||||
| // | ||||
| // Generally, inlined fields are of a Go struct type, where the fields of the | ||||
| // nested struct are virtually hoisted up to the parent struct using rules | ||||
| // similar to how Go embedding works (but operating within the JSON namespace). | ||||
| // | ||||
| // However, inlined fields may also be of a Go map type with a string key or | ||||
| // a jsontext.Value. Such inlined fields are called "fallback" fields since they | ||||
| // represent any arbitrary JSON object member. Explicitly named fields take | ||||
| // precedence over the inlined fallback. Only one inlined fallback is allowed. | ||||
|  | ||||
| var errRawInlinedNotObject = errors.New("inlined raw value must be a JSON object") | ||||
|  | ||||
| var jsontextValueType = reflect.TypeFor[jsontext.Value]() | ||||
|  | ||||
| // marshalInlinedFallbackAll marshals all the members in an inlined fallback. | ||||
| func marshalInlinedFallbackAll(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct, f *structField, insertUnquotedName func([]byte) bool) error { | ||||
| 	v := addressableValue{va.Field(f.index0), va.forcedAddr} // addressable if struct value is addressable | ||||
| 	if len(f.index) > 0 { | ||||
| 		v = v.fieldByIndex(f.index, false) | ||||
| 		if !v.IsValid() { | ||||
| 			return nil // implies a nil inlined field | ||||
| 		} | ||||
| 	} | ||||
| 	v = v.indirect(false) | ||||
| 	if !v.IsValid() { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	if v.Type() == jsontextValueType { | ||||
| 		// TODO(https://go.dev/issue/62121): Use reflect.Value.AssertTo. | ||||
| 		b := *v.Addr().Interface().(*jsontext.Value) | ||||
| 		if len(b) == 0 { // TODO: Should this be nil? What if it were all whitespace? | ||||
| 			return nil | ||||
| 		} | ||||
|  | ||||
| 		dec := export.GetBufferedDecoder(b) | ||||
| 		defer export.PutBufferedDecoder(dec) | ||||
| 		xd := export.Decoder(dec) | ||||
| 		xd.Flags.Set(jsonflags.AllowDuplicateNames | jsonflags.AllowInvalidUTF8 | 1) | ||||
|  | ||||
| 		tok, err := dec.ReadToken() | ||||
| 		if err != nil { | ||||
| 			if err == io.EOF { | ||||
| 				err = io.ErrUnexpectedEOF | ||||
| 			} | ||||
| 			return newMarshalErrorBefore(enc, v.Type(), err) | ||||
| 		} | ||||
| 		if tok.Kind() != '{' { | ||||
| 			return newMarshalErrorBefore(enc, v.Type(), errRawInlinedNotObject) | ||||
| 		} | ||||
| 		for dec.PeekKind() != '}' { | ||||
| 			// Parse the JSON object name. | ||||
| 			var flags jsonwire.ValueFlags | ||||
| 			val, err := xd.ReadValue(&flags) | ||||
| 			if err != nil { | ||||
| 				return newMarshalErrorBefore(enc, v.Type(), err) | ||||
| 			} | ||||
| 			if insertUnquotedName != nil { | ||||
| 				name := jsonwire.UnquoteMayCopy(val, flags.IsVerbatim()) | ||||
| 				if !insertUnquotedName(name) { | ||||
| 					return newDuplicateNameError(enc.StackPointer().Parent(), val, enc.OutputOffset()) | ||||
| 				} | ||||
| 			} | ||||
| 			if err := enc.WriteValue(val); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
|  | ||||
| 			// Parse the JSON object value. | ||||
| 			val, err = xd.ReadValue(&flags) | ||||
| 			if err != nil { | ||||
| 				return newMarshalErrorBefore(enc, v.Type(), err) | ||||
| 			} | ||||
| 			if err := enc.WriteValue(val); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 		if _, err := dec.ReadToken(); err != nil { | ||||
| 			return newMarshalErrorBefore(enc, v.Type(), err) | ||||
| 		} | ||||
| 		if err := xd.CheckEOF(); err != nil { | ||||
| 			return newMarshalErrorBefore(enc, v.Type(), err) | ||||
| 		} | ||||
| 		return nil | ||||
| 	} else { | ||||
| 		m := v // must be a map[~string]V | ||||
| 		n := m.Len() | ||||
| 		if n == 0 { | ||||
| 			return nil | ||||
| 		} | ||||
| 		mk := newAddressableValue(m.Type().Key()) | ||||
| 		mv := newAddressableValue(m.Type().Elem()) | ||||
| 		marshalKey := func(mk addressableValue) error { | ||||
| 			b, err := jsonwire.AppendQuote(enc.UnusedBuffer(), mk.String(), &mo.Flags) | ||||
| 			if err != nil { | ||||
| 				return newMarshalErrorBefore(enc, m.Type().Key(), err) | ||||
| 			} | ||||
| 			if insertUnquotedName != nil { | ||||
| 				isVerbatim := bytes.IndexByte(b, '\\') < 0 | ||||
| 				name := jsonwire.UnquoteMayCopy(b, isVerbatim) | ||||
| 				if !insertUnquotedName(name) { | ||||
| 					return newDuplicateNameError(enc.StackPointer().Parent(), b, enc.OutputOffset()) | ||||
| 				} | ||||
| 			} | ||||
| 			return enc.WriteValue(b) | ||||
| 		} | ||||
| 		marshalVal := f.fncs.marshal | ||||
| 		if mo.Marshalers != nil { | ||||
| 			marshalVal, _ = mo.Marshalers.(*Marshalers).lookup(marshalVal, mv.Type()) | ||||
| 		} | ||||
| 		if !mo.Flags.Get(jsonflags.Deterministic) || n <= 1 { | ||||
| 			for iter := m.MapRange(); iter.Next(); { | ||||
| 				mk.SetIterKey(iter) | ||||
| 				if err := marshalKey(mk); err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 				mv.Set(iter.Value()) | ||||
| 				if err := marshalVal(enc, mv, mo); err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 			} | ||||
| 		} else { | ||||
| 			names := getStrings(n) | ||||
| 			for i, iter := 0, m.Value.MapRange(); i < n && iter.Next(); i++ { | ||||
| 				mk.SetIterKey(iter) | ||||
| 				(*names)[i] = mk.String() | ||||
| 			} | ||||
| 			names.Sort() | ||||
| 			for _, name := range *names { | ||||
| 				mk.SetString(name) | ||||
| 				if err := marshalKey(mk); err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 				// TODO(https://go.dev/issue/57061): Use mv.SetMapIndexOf. | ||||
| 				mv.Set(m.MapIndex(mk.Value)) | ||||
| 				if err := marshalVal(enc, mv, mo); err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 			} | ||||
| 			putStrings(names) | ||||
| 		} | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // unmarshalInlinedFallbackNext unmarshals only the next member in an inlined fallback. | ||||
| func unmarshalInlinedFallbackNext(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct, f *structField, quotedName, unquotedName []byte) error { | ||||
| 	v := addressableValue{va.Field(f.index0), va.forcedAddr} // addressable if struct value is addressable | ||||
| 	if len(f.index) > 0 { | ||||
| 		v = v.fieldByIndex(f.index, true) | ||||
| 	} | ||||
| 	v = v.indirect(true) | ||||
|  | ||||
| 	if v.Type() == jsontextValueType { | ||||
| 		b := v.Addr().Interface().(*jsontext.Value) | ||||
| 		if len(*b) == 0 { // TODO: Should this be nil? What if it were all whitespace? | ||||
| 			*b = append(*b, '{') | ||||
| 		} else { | ||||
| 			*b = jsonwire.TrimSuffixWhitespace(*b) | ||||
| 			if jsonwire.HasSuffixByte(*b, '}') { | ||||
| 				// TODO: When merging into an object for the first time, | ||||
| 				// should we verify that it is valid? | ||||
| 				*b = jsonwire.TrimSuffixByte(*b, '}') | ||||
| 				*b = jsonwire.TrimSuffixWhitespace(*b) | ||||
| 				if !jsonwire.HasSuffixByte(*b, ',') && !jsonwire.HasSuffixByte(*b, '{') { | ||||
| 					*b = append(*b, ',') | ||||
| 				} | ||||
| 			} else { | ||||
| 				return newUnmarshalErrorAfterWithSkipping(dec, uo, v.Type(), errRawInlinedNotObject) | ||||
| 			} | ||||
| 		} | ||||
| 		*b = append(*b, quotedName...) | ||||
| 		*b = append(*b, ':') | ||||
| 		val, err := dec.ReadValue() | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		*b = append(*b, val...) | ||||
| 		*b = append(*b, '}') | ||||
| 		return nil | ||||
| 	} else { | ||||
| 		name := string(unquotedName) // TODO: Intern this? | ||||
|  | ||||
| 		m := v // must be a map[~string]V | ||||
| 		if m.IsNil() { | ||||
| 			m.Set(reflect.MakeMap(m.Type())) | ||||
| 		} | ||||
| 		mk := reflect.ValueOf(name) | ||||
| 		if mkt := m.Type().Key(); mkt != stringType { | ||||
| 			mk = mk.Convert(mkt) | ||||
| 		} | ||||
| 		mv := newAddressableValue(m.Type().Elem()) // TODO: Cache across calls? | ||||
| 		if v2 := m.MapIndex(mk); v2.IsValid() { | ||||
| 			mv.Set(v2) | ||||
| 		} | ||||
|  | ||||
| 		unmarshal := f.fncs.unmarshal | ||||
| 		if uo.Unmarshalers != nil { | ||||
| 			unmarshal, _ = uo.Unmarshalers.(*Unmarshalers).lookup(unmarshal, mv.Type()) | ||||
| 		} | ||||
| 		err := unmarshal(dec, mv, uo) | ||||
| 		m.SetMapIndex(mk, mv.Value) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										335
									
								
								vendor/github.com/go-json-experiment/json/arshal_methods.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										335
									
								
								vendor/github.com/go-json-experiment/json/arshal_methods.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,335 @@ | ||||
| // Copyright 2020 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. | ||||
|  | ||||
| package json | ||||
|  | ||||
| import ( | ||||
| 	"encoding" | ||||
| 	"errors" | ||||
| 	"reflect" | ||||
|  | ||||
| 	"github.com/go-json-experiment/json/internal" | ||||
| 	"github.com/go-json-experiment/json/internal/jsonflags" | ||||
| 	"github.com/go-json-experiment/json/internal/jsonopts" | ||||
| 	"github.com/go-json-experiment/json/internal/jsonwire" | ||||
| 	"github.com/go-json-experiment/json/jsontext" | ||||
| ) | ||||
|  | ||||
| var errNonStringValue = errors.New("JSON value must be string type") | ||||
|  | ||||
| // Interfaces for custom serialization. | ||||
| var ( | ||||
| 	jsonMarshalerType       = reflect.TypeFor[Marshaler]() | ||||
| 	jsonMarshalerToType     = reflect.TypeFor[MarshalerTo]() | ||||
| 	jsonUnmarshalerType     = reflect.TypeFor[Unmarshaler]() | ||||
| 	jsonUnmarshalerFromType = reflect.TypeFor[UnmarshalerFrom]() | ||||
| 	textAppenderType        = reflect.TypeFor[encoding.TextAppender]() | ||||
| 	textMarshalerType       = reflect.TypeFor[encoding.TextMarshaler]() | ||||
| 	textUnmarshalerType     = reflect.TypeFor[encoding.TextUnmarshaler]() | ||||
|  | ||||
| 	allMarshalerTypes   = []reflect.Type{jsonMarshalerToType, jsonMarshalerType, textAppenderType, textMarshalerType} | ||||
| 	allUnmarshalerTypes = []reflect.Type{jsonUnmarshalerFromType, jsonUnmarshalerType, textUnmarshalerType} | ||||
| 	allMethodTypes      = append(allMarshalerTypes, allUnmarshalerTypes...) | ||||
| ) | ||||
|  | ||||
| // Marshaler is implemented by types that can marshal themselves. | ||||
| // It is recommended that types implement [MarshalerTo] unless the implementation | ||||
| // is trying to avoid a hard dependency on the "jsontext" package. | ||||
| // | ||||
| // It is recommended that implementations return a buffer that is safe | ||||
| // for the caller to retain and potentially mutate. | ||||
| type Marshaler interface { | ||||
| 	MarshalJSON() ([]byte, error) | ||||
| } | ||||
|  | ||||
| // MarshalerTo is implemented by types that can marshal themselves. | ||||
| // It is recommended that types implement MarshalerTo instead of [Marshaler] | ||||
| // since this is both more performant and flexible. | ||||
| // If a type implements both Marshaler and MarshalerTo, | ||||
| // then MarshalerTo takes precedence. In such a case, both implementations | ||||
| // should aim to have equivalent behavior for the default marshal options. | ||||
| // | ||||
| // The implementation must write only one JSON value to the Encoder and | ||||
| // must not retain the pointer to [jsontext.Encoder]. | ||||
| type MarshalerTo interface { | ||||
| 	MarshalJSONTo(*jsontext.Encoder) error | ||||
|  | ||||
| 	// TODO: Should users call the MarshalEncode function or | ||||
| 	// should/can they call this method directly? Does it matter? | ||||
| } | ||||
|  | ||||
| // Unmarshaler is implemented by types that can unmarshal themselves. | ||||
| // It is recommended that types implement [UnmarshalerFrom] unless the implementation | ||||
| // is trying to avoid a hard dependency on the "jsontext" package. | ||||
| // | ||||
| // The input can be assumed to be a valid encoding of a JSON value | ||||
| // if called from unmarshal functionality in this package. | ||||
| // UnmarshalJSON must copy the JSON data if it is retained after returning. | ||||
| // It is recommended that UnmarshalJSON implement merge semantics when | ||||
| // unmarshaling into a pre-populated value. | ||||
| // | ||||
| // Implementations must not retain or mutate the input []byte. | ||||
| type Unmarshaler interface { | ||||
| 	UnmarshalJSON([]byte) error | ||||
| } | ||||
|  | ||||
| // UnmarshalerFrom is implemented by types that can unmarshal themselves. | ||||
| // It is recommended that types implement UnmarshalerFrom instead of [Unmarshaler] | ||||
| // since this is both more performant and flexible. | ||||
| // If a type implements both Unmarshaler and UnmarshalerFrom, | ||||
| // then UnmarshalerFrom takes precedence. In such a case, both implementations | ||||
| // should aim to have equivalent behavior for the default unmarshal options. | ||||
| // | ||||
| // The implementation must read only one JSON value from the Decoder. | ||||
| // It is recommended that UnmarshalJSONFrom implement merge semantics when | ||||
| // unmarshaling into a pre-populated value. | ||||
| // | ||||
| // Implementations must not retain the pointer to [jsontext.Decoder]. | ||||
| type UnmarshalerFrom interface { | ||||
| 	UnmarshalJSONFrom(*jsontext.Decoder) error | ||||
|  | ||||
| 	// TODO: Should users call the UnmarshalDecode function or | ||||
| 	// should/can they call this method directly? Does it matter? | ||||
| } | ||||
|  | ||||
| func makeMethodArshaler(fncs *arshaler, t reflect.Type) *arshaler { | ||||
| 	// Avoid injecting method arshaler on the pointer or interface version | ||||
| 	// to avoid ever calling the method on a nil pointer or interface receiver. | ||||
| 	// Let it be injected on the value receiver (which is always addressable). | ||||
| 	if t.Kind() == reflect.Pointer || t.Kind() == reflect.Interface { | ||||
| 		return fncs | ||||
| 	} | ||||
|  | ||||
| 	if needAddr, ok := implements(t, textMarshalerType); ok { | ||||
| 		fncs.nonDefault = true | ||||
| 		prevMarshal := fncs.marshal | ||||
| 		fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { | ||||
| 			if mo.Flags.Get(jsonflags.CallMethodsWithLegacySemantics) && | ||||
| 				(needAddr && va.forcedAddr) { | ||||
| 				return prevMarshal(enc, va, mo) | ||||
| 			} | ||||
| 			marshaler := va.Addr().Interface().(encoding.TextMarshaler) | ||||
| 			if err := export.Encoder(enc).AppendRaw('"', false, func(b []byte) ([]byte, error) { | ||||
| 				b2, err := marshaler.MarshalText() | ||||
| 				return append(b, b2...), err | ||||
| 			}); err != nil { | ||||
| 				err = wrapSkipFunc(err, "marshal method") | ||||
| 				if mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { | ||||
| 					return internal.NewMarshalerError(va.Addr().Interface(), err, "MarshalText") // unlike unmarshal, always wrapped | ||||
| 				} | ||||
| 				if !isSemanticError(err) && !export.IsIOError(err) { | ||||
| 					err = newMarshalErrorBefore(enc, t, err) | ||||
| 				} | ||||
| 				return err | ||||
| 			} | ||||
| 			return nil | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if needAddr, ok := implements(t, textAppenderType); ok { | ||||
| 		fncs.nonDefault = true | ||||
| 		prevMarshal := fncs.marshal | ||||
| 		fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) (err error) { | ||||
| 			if mo.Flags.Get(jsonflags.CallMethodsWithLegacySemantics) && | ||||
| 				(needAddr && va.forcedAddr) { | ||||
| 				return prevMarshal(enc, va, mo) | ||||
| 			} | ||||
| 			appender := va.Addr().Interface().(encoding.TextAppender) | ||||
| 			if err := export.Encoder(enc).AppendRaw('"', false, appender.AppendText); err != nil { | ||||
| 				err = wrapSkipFunc(err, "append method") | ||||
| 				if mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { | ||||
| 					return internal.NewMarshalerError(va.Addr().Interface(), err, "AppendText") // unlike unmarshal, always wrapped | ||||
| 				} | ||||
| 				if !isSemanticError(err) && !export.IsIOError(err) { | ||||
| 					err = newMarshalErrorBefore(enc, t, err) | ||||
| 				} | ||||
| 				return err | ||||
| 			} | ||||
| 			return nil | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if needAddr, ok := implements(t, jsonMarshalerType); ok { | ||||
| 		fncs.nonDefault = true | ||||
| 		prevMarshal := fncs.marshal | ||||
| 		fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { | ||||
| 			if mo.Flags.Get(jsonflags.CallMethodsWithLegacySemantics) && | ||||
| 				((needAddr && va.forcedAddr) || export.Encoder(enc).Tokens.Last.NeedObjectName()) { | ||||
| 				return prevMarshal(enc, va, mo) | ||||
| 			} | ||||
| 			marshaler := va.Addr().Interface().(Marshaler) | ||||
| 			val, err := marshaler.MarshalJSON() | ||||
| 			if err != nil { | ||||
| 				err = wrapSkipFunc(err, "marshal method") | ||||
| 				if mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { | ||||
| 					return internal.NewMarshalerError(va.Addr().Interface(), err, "MarshalJSON") // unlike unmarshal, always wrapped | ||||
| 				} | ||||
| 				err = newMarshalErrorBefore(enc, t, err) | ||||
| 				return collapseSemanticErrors(err) | ||||
| 			} | ||||
| 			if err := enc.WriteValue(val); err != nil { | ||||
| 				if mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { | ||||
| 					return internal.NewMarshalerError(va.Addr().Interface(), err, "MarshalJSON") // unlike unmarshal, always wrapped | ||||
| 				} | ||||
| 				if isSyntacticError(err) { | ||||
| 					err = newMarshalErrorBefore(enc, t, err) | ||||
| 				} | ||||
| 				return err | ||||
| 			} | ||||
| 			return nil | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if needAddr, ok := implements(t, jsonMarshalerToType); ok { | ||||
| 		fncs.nonDefault = true | ||||
| 		prevMarshal := fncs.marshal | ||||
| 		fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { | ||||
| 			if mo.Flags.Get(jsonflags.CallMethodsWithLegacySemantics) && | ||||
| 				((needAddr && va.forcedAddr) || export.Encoder(enc).Tokens.Last.NeedObjectName()) { | ||||
| 				return prevMarshal(enc, va, mo) | ||||
| 			} | ||||
| 			xe := export.Encoder(enc) | ||||
| 			prevDepth, prevLength := xe.Tokens.DepthLength() | ||||
| 			xe.Flags.Set(jsonflags.WithinArshalCall | 1) | ||||
| 			err := va.Addr().Interface().(MarshalerTo).MarshalJSONTo(enc) | ||||
| 			xe.Flags.Set(jsonflags.WithinArshalCall | 0) | ||||
| 			currDepth, currLength := xe.Tokens.DepthLength() | ||||
| 			if (prevDepth != currDepth || prevLength+1 != currLength) && err == nil { | ||||
| 				err = errNonSingularValue | ||||
| 			} | ||||
| 			if err != nil { | ||||
| 				err = wrapSkipFunc(err, "marshal method") | ||||
| 				if mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { | ||||
| 					return internal.NewMarshalerError(va.Addr().Interface(), err, "MarshalJSONTo") // unlike unmarshal, always wrapped | ||||
| 				} | ||||
| 				if !export.IsIOError(err) { | ||||
| 					err = newSemanticErrorWithPosition(enc, t, prevDepth, prevLength, err) | ||||
| 				} | ||||
| 				return err | ||||
| 			} | ||||
| 			return nil | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if _, ok := implements(t, textUnmarshalerType); ok { | ||||
| 		fncs.nonDefault = true | ||||
| 		fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error { | ||||
| 			xd := export.Decoder(dec) | ||||
| 			var flags jsonwire.ValueFlags | ||||
| 			val, err := xd.ReadValue(&flags) | ||||
| 			if err != nil { | ||||
| 				return err // must be a syntactic or I/O error | ||||
| 			} | ||||
| 			if val.Kind() == 'n' { | ||||
| 				if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) { | ||||
| 					va.SetZero() | ||||
| 				} | ||||
| 				return nil | ||||
| 			} | ||||
| 			if val.Kind() != '"' { | ||||
| 				return newUnmarshalErrorAfter(dec, t, errNonStringValue) | ||||
| 			} | ||||
| 			s := jsonwire.UnquoteMayCopy(val, flags.IsVerbatim()) | ||||
| 			unmarshaler := va.Addr().Interface().(encoding.TextUnmarshaler) | ||||
| 			if err := unmarshaler.UnmarshalText(s); err != nil { | ||||
| 				err = wrapSkipFunc(err, "unmarshal method") | ||||
| 				if uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { | ||||
| 					return err // unlike marshal, never wrapped | ||||
| 				} | ||||
| 				if !isSemanticError(err) && !isSyntacticError(err) && !export.IsIOError(err) { | ||||
| 					err = newUnmarshalErrorAfter(dec, t, err) | ||||
| 				} | ||||
| 				return err | ||||
| 			} | ||||
| 			return nil | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if _, ok := implements(t, jsonUnmarshalerType); ok { | ||||
| 		fncs.nonDefault = true | ||||
| 		prevUnmarshal := fncs.unmarshal | ||||
| 		fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error { | ||||
| 			if uo.Flags.Get(jsonflags.CallMethodsWithLegacySemantics) && | ||||
| 				export.Decoder(dec).Tokens.Last.NeedObjectName() { | ||||
| 				return prevUnmarshal(dec, va, uo) | ||||
| 			} | ||||
| 			val, err := dec.ReadValue() | ||||
| 			if err != nil { | ||||
| 				return err // must be a syntactic or I/O error | ||||
| 			} | ||||
| 			unmarshaler := va.Addr().Interface().(Unmarshaler) | ||||
| 			if err := unmarshaler.UnmarshalJSON(val); err != nil { | ||||
| 				err = wrapSkipFunc(err, "unmarshal method") | ||||
| 				if uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { | ||||
| 					return err // unlike marshal, never wrapped | ||||
| 				} | ||||
| 				err = newUnmarshalErrorAfter(dec, t, err) | ||||
| 				return collapseSemanticErrors(err) | ||||
| 			} | ||||
| 			return nil | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if _, ok := implements(t, jsonUnmarshalerFromType); ok { | ||||
| 		fncs.nonDefault = true | ||||
| 		prevUnmarshal := fncs.unmarshal | ||||
| 		fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error { | ||||
| 			if uo.Flags.Get(jsonflags.CallMethodsWithLegacySemantics) && | ||||
| 				export.Decoder(dec).Tokens.Last.NeedObjectName() { | ||||
| 				return prevUnmarshal(dec, va, uo) | ||||
| 			} | ||||
| 			xd := export.Decoder(dec) | ||||
| 			prevDepth, prevLength := xd.Tokens.DepthLength() | ||||
| 			xd.Flags.Set(jsonflags.WithinArshalCall | 1) | ||||
| 			err := va.Addr().Interface().(UnmarshalerFrom).UnmarshalJSONFrom(dec) | ||||
| 			xd.Flags.Set(jsonflags.WithinArshalCall | 0) | ||||
| 			currDepth, currLength := xd.Tokens.DepthLength() | ||||
| 			if (prevDepth != currDepth || prevLength+1 != currLength) && err == nil { | ||||
| 				err = errNonSingularValue | ||||
| 			} | ||||
| 			if err != nil { | ||||
| 				err = wrapSkipFunc(err, "unmarshal method") | ||||
| 				if uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { | ||||
| 					if err2 := xd.SkipUntil(prevDepth, prevLength+1); err2 != nil { | ||||
| 						return err2 | ||||
| 					} | ||||
| 					return err // unlike marshal, never wrapped | ||||
| 				} | ||||
| 				if !isSyntacticError(err) && !export.IsIOError(err) { | ||||
| 					err = newSemanticErrorWithPosition(dec, t, prevDepth, prevLength, err) | ||||
| 				} | ||||
| 				return err | ||||
| 			} | ||||
| 			return nil | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return fncs | ||||
| } | ||||
|  | ||||
| // implementsAny is like t.Implements(ifaceType) for a list of interfaces, | ||||
| // but checks whether either t or reflect.PointerTo(t) implements the interface. | ||||
| func implementsAny(t reflect.Type, ifaceTypes ...reflect.Type) bool { | ||||
| 	for _, ifaceType := range ifaceTypes { | ||||
| 		if _, ok := implements(t, ifaceType); ok { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // implements is like t.Implements(ifaceType) but checks whether | ||||
| // either t or reflect.PointerTo(t) implements the interface. | ||||
| // It also reports whether the value needs to be addressed | ||||
| // in order to satisfy the interface. | ||||
| func implements(t, ifaceType reflect.Type) (needAddr, ok bool) { | ||||
| 	switch { | ||||
| 	case t.Implements(ifaceType): | ||||
| 		return false, true | ||||
| 	case reflect.PointerTo(t).Implements(ifaceType): | ||||
| 		return true, true | ||||
| 	default: | ||||
| 		return false, false | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										598
									
								
								vendor/github.com/go-json-experiment/json/arshal_time.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										598
									
								
								vendor/github.com/go-json-experiment/json/arshal_time.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,598 @@ | ||||
| // Copyright 2020 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. | ||||
|  | ||||
| package json | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"cmp" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"math" | ||||
| 	"math/bits" | ||||
| 	"reflect" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/go-json-experiment/json/internal" | ||||
| 	"github.com/go-json-experiment/json/internal/jsonflags" | ||||
| 	"github.com/go-json-experiment/json/internal/jsonopts" | ||||
| 	"github.com/go-json-experiment/json/internal/jsonwire" | ||||
| 	"github.com/go-json-experiment/json/jsontext" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	timeDurationType = reflect.TypeFor[time.Duration]() | ||||
| 	timeTimeType     = reflect.TypeFor[time.Time]() | ||||
| ) | ||||
|  | ||||
| func makeTimeArshaler(fncs *arshaler, t reflect.Type) *arshaler { | ||||
| 	// Ideally, time types would implement MarshalerTo and UnmarshalerFrom, | ||||
| 	// but that would incur a dependency on package json from package time. | ||||
| 	// Given how widely used time is, it is more acceptable that we incur a | ||||
| 	// dependency on time from json. | ||||
| 	// | ||||
| 	// Injecting the arshaling functionality like this will not be identical | ||||
| 	// to actually declaring methods on the time types since embedding of the | ||||
| 	// time types will not be able to forward this functionality. | ||||
| 	switch t { | ||||
| 	case timeDurationType: | ||||
| 		fncs.nonDefault = true | ||||
| 		marshalNano := fncs.marshal | ||||
| 		fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { | ||||
| 			xe := export.Encoder(enc) | ||||
| 			var m durationArshaler | ||||
| 			if mo.Format != "" && mo.FormatDepth == xe.Tokens.Depth() { | ||||
| 				if !m.initFormat(mo.Format) { | ||||
| 					return newInvalidFormatError(enc, t, mo) | ||||
| 				} | ||||
| 			} else if mo.Flags.Get(jsonflags.FormatTimeWithLegacySemantics) { | ||||
| 				return marshalNano(enc, va, mo) | ||||
| 			} | ||||
|  | ||||
| 			// TODO(https://go.dev/issue/62121): Use reflect.Value.AssertTo. | ||||
| 			m.td = *va.Addr().Interface().(*time.Duration) | ||||
| 			k := stringOrNumberKind(!m.isNumeric() || xe.Tokens.Last.NeedObjectName() || mo.Flags.Get(jsonflags.StringifyNumbers)) | ||||
| 			if err := xe.AppendRaw(k, true, m.appendMarshal); err != nil { | ||||
| 				if !isSyntacticError(err) && !export.IsIOError(err) { | ||||
| 					err = newMarshalErrorBefore(enc, t, err) | ||||
| 				} | ||||
| 				return err | ||||
| 			} | ||||
| 			return nil | ||||
| 		} | ||||
| 		unmarshalNano := fncs.unmarshal | ||||
| 		fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error { | ||||
| 			xd := export.Decoder(dec) | ||||
| 			var u durationArshaler | ||||
| 			if uo.Format != "" && uo.FormatDepth == xd.Tokens.Depth() { | ||||
| 				if !u.initFormat(uo.Format) { | ||||
| 					return newInvalidFormatError(dec, t, uo) | ||||
| 				} | ||||
| 			} else if uo.Flags.Get(jsonflags.FormatTimeWithLegacySemantics) { | ||||
| 				return unmarshalNano(dec, va, uo) | ||||
| 			} | ||||
|  | ||||
| 			stringify := !u.isNumeric() || xd.Tokens.Last.NeedObjectName() || uo.Flags.Get(jsonflags.StringifyNumbers) | ||||
| 			var flags jsonwire.ValueFlags | ||||
| 			td := va.Addr().Interface().(*time.Duration) | ||||
| 			val, err := xd.ReadValue(&flags) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			switch k := val.Kind(); k { | ||||
| 			case 'n': | ||||
| 				if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) { | ||||
| 					*td = time.Duration(0) | ||||
| 				} | ||||
| 				return nil | ||||
| 			case '"': | ||||
| 				if !stringify { | ||||
| 					break | ||||
| 				} | ||||
| 				val = jsonwire.UnquoteMayCopy(val, flags.IsVerbatim()) | ||||
| 				if err := u.unmarshal(val); err != nil { | ||||
| 					return newUnmarshalErrorAfter(dec, t, err) | ||||
| 				} | ||||
| 				*td = u.td | ||||
| 				return nil | ||||
| 			case '0': | ||||
| 				if stringify { | ||||
| 					break | ||||
| 				} | ||||
| 				if err := u.unmarshal(val); err != nil { | ||||
| 					return newUnmarshalErrorAfter(dec, t, err) | ||||
| 				} | ||||
| 				*td = u.td | ||||
| 				return nil | ||||
| 			} | ||||
| 			return newUnmarshalErrorAfter(dec, t, nil) | ||||
| 		} | ||||
| 	case timeTimeType: | ||||
| 		fncs.nonDefault = true | ||||
| 		fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) (err error) { | ||||
| 			xe := export.Encoder(enc) | ||||
| 			var m timeArshaler | ||||
| 			if mo.Format != "" && mo.FormatDepth == xe.Tokens.Depth() { | ||||
| 				if !m.initFormat(mo.Format) { | ||||
| 					return newInvalidFormatError(enc, t, mo) | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			// TODO(https://go.dev/issue/62121): Use reflect.Value.AssertTo. | ||||
| 			m.tt = *va.Addr().Interface().(*time.Time) | ||||
| 			k := stringOrNumberKind(!m.isNumeric() || xe.Tokens.Last.NeedObjectName() || mo.Flags.Get(jsonflags.StringifyNumbers)) | ||||
| 			if err := xe.AppendRaw(k, !m.hasCustomFormat(), m.appendMarshal); err != nil { | ||||
| 				if mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { | ||||
| 					return internal.NewMarshalerError(va.Addr().Interface(), err, "MarshalJSON") // unlike unmarshal, always wrapped | ||||
| 				} | ||||
| 				if !isSyntacticError(err) && !export.IsIOError(err) { | ||||
| 					err = newMarshalErrorBefore(enc, t, err) | ||||
| 				} | ||||
| 				return err | ||||
| 			} | ||||
| 			return nil | ||||
| 		} | ||||
| 		fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) (err error) { | ||||
| 			xd := export.Decoder(dec) | ||||
| 			var u timeArshaler | ||||
| 			if uo.Format != "" && uo.FormatDepth == xd.Tokens.Depth() { | ||||
| 				if !u.initFormat(uo.Format) { | ||||
| 					return newInvalidFormatError(dec, t, uo) | ||||
| 				} | ||||
| 			} else if uo.Flags.Get(jsonflags.FormatTimeWithLegacySemantics) { | ||||
| 				u.looseRFC3339 = true | ||||
| 			} | ||||
|  | ||||
| 			stringify := !u.isNumeric() || xd.Tokens.Last.NeedObjectName() || uo.Flags.Get(jsonflags.StringifyNumbers) | ||||
| 			var flags jsonwire.ValueFlags | ||||
| 			tt := va.Addr().Interface().(*time.Time) | ||||
| 			val, err := xd.ReadValue(&flags) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			switch k := val.Kind(); k { | ||||
| 			case 'n': | ||||
| 				if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) { | ||||
| 					*tt = time.Time{} | ||||
| 				} | ||||
| 				return nil | ||||
| 			case '"': | ||||
| 				if !stringify { | ||||
| 					break | ||||
| 				} | ||||
| 				val = jsonwire.UnquoteMayCopy(val, flags.IsVerbatim()) | ||||
| 				if err := u.unmarshal(val); err != nil { | ||||
| 					if uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { | ||||
| 						return err // unlike marshal, never wrapped | ||||
| 					} | ||||
| 					return newUnmarshalErrorAfter(dec, t, err) | ||||
| 				} | ||||
| 				*tt = u.tt | ||||
| 				return nil | ||||
| 			case '0': | ||||
| 				if stringify { | ||||
| 					break | ||||
| 				} | ||||
| 				if err := u.unmarshal(val); err != nil { | ||||
| 					if uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { | ||||
| 						return err // unlike marshal, never wrapped | ||||
| 					} | ||||
| 					return newUnmarshalErrorAfter(dec, t, err) | ||||
| 				} | ||||
| 				*tt = u.tt | ||||
| 				return nil | ||||
| 			} | ||||
| 			return newUnmarshalErrorAfter(dec, t, nil) | ||||
| 		} | ||||
| 	} | ||||
| 	return fncs | ||||
| } | ||||
|  | ||||
| type durationArshaler struct { | ||||
| 	td time.Duration | ||||
|  | ||||
| 	// base records the representation where: | ||||
| 	//   - 0 uses time.Duration.String | ||||
| 	//   - 1e0, 1e3, 1e6, or 1e9 use a decimal encoding of the duration as | ||||
| 	//     nanoseconds, microseconds, milliseconds, or seconds. | ||||
| 	base uint64 | ||||
| } | ||||
|  | ||||
| func (a *durationArshaler) initFormat(format string) (ok bool) { | ||||
| 	switch format { | ||||
| 	case "units": | ||||
| 		a.base = 0 | ||||
| 	case "sec": | ||||
| 		a.base = 1e9 | ||||
| 	case "milli": | ||||
| 		a.base = 1e6 | ||||
| 	case "micro": | ||||
| 		a.base = 1e3 | ||||
| 	case "nano": | ||||
| 		a.base = 1e0 | ||||
| 	default: | ||||
| 		return false | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| func (a *durationArshaler) isNumeric() bool { | ||||
| 	return a.base != 0 && a.base != 60 | ||||
| } | ||||
|  | ||||
| func (a *durationArshaler) appendMarshal(b []byte) ([]byte, error) { | ||||
| 	switch a.base { | ||||
| 	case 0: | ||||
| 		return append(b, a.td.String()...), nil | ||||
| 	default: | ||||
| 		return appendDurationBase10(b, a.td, a.base), nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (a *durationArshaler) unmarshal(b []byte) (err error) { | ||||
| 	switch a.base { | ||||
| 	case 0: | ||||
| 		a.td, err = time.ParseDuration(string(b)) | ||||
| 	default: | ||||
| 		a.td, err = parseDurationBase10(b, a.base) | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| type timeArshaler struct { | ||||
| 	tt time.Time | ||||
|  | ||||
| 	// base records the representation where: | ||||
| 	//   - 0 uses RFC 3339 encoding of the timestamp | ||||
| 	//   - 1e0, 1e3, 1e6, or 1e9 use a decimal encoding of the timestamp as | ||||
| 	//     seconds, milliseconds, microseconds, or nanoseconds since Unix epoch. | ||||
| 	//   - math.MaxUint uses time.Time.Format to encode the timestamp | ||||
| 	base   uint64 | ||||
| 	format string // time format passed to time.Parse | ||||
|  | ||||
| 	looseRFC3339 bool | ||||
| } | ||||
|  | ||||
| func (a *timeArshaler) initFormat(format string) bool { | ||||
| 	// We assume that an exported constant in the time package will | ||||
| 	// always start with an uppercase ASCII letter. | ||||
| 	if len(format) == 0 { | ||||
| 		return false | ||||
| 	} | ||||
| 	a.base = math.MaxUint // implies custom format | ||||
| 	if c := format[0]; !('a' <= c && c <= 'z') && !('A' <= c && c <= 'Z') { | ||||
| 		a.format = format | ||||
| 		return true | ||||
| 	} | ||||
| 	switch format { | ||||
| 	case "ANSIC": | ||||
| 		a.format = time.ANSIC | ||||
| 	case "UnixDate": | ||||
| 		a.format = time.UnixDate | ||||
| 	case "RubyDate": | ||||
| 		a.format = time.RubyDate | ||||
| 	case "RFC822": | ||||
| 		a.format = time.RFC822 | ||||
| 	case "RFC822Z": | ||||
| 		a.format = time.RFC822Z | ||||
| 	case "RFC850": | ||||
| 		a.format = time.RFC850 | ||||
| 	case "RFC1123": | ||||
| 		a.format = time.RFC1123 | ||||
| 	case "RFC1123Z": | ||||
| 		a.format = time.RFC1123Z | ||||
| 	case "RFC3339": | ||||
| 		a.base = 0 | ||||
| 		a.format = time.RFC3339 | ||||
| 	case "RFC3339Nano": | ||||
| 		a.base = 0 | ||||
| 		a.format = time.RFC3339Nano | ||||
| 	case "Kitchen": | ||||
| 		a.format = time.Kitchen | ||||
| 	case "Stamp": | ||||
| 		a.format = time.Stamp | ||||
| 	case "StampMilli": | ||||
| 		a.format = time.StampMilli | ||||
| 	case "StampMicro": | ||||
| 		a.format = time.StampMicro | ||||
| 	case "StampNano": | ||||
| 		a.format = time.StampNano | ||||
| 	case "DateTime": | ||||
| 		a.format = time.DateTime | ||||
| 	case "DateOnly": | ||||
| 		a.format = time.DateOnly | ||||
| 	case "TimeOnly": | ||||
| 		a.format = time.TimeOnly | ||||
| 	case "unix": | ||||
| 		a.base = 1e0 | ||||
| 	case "unixmilli": | ||||
| 		a.base = 1e3 | ||||
| 	case "unixmicro": | ||||
| 		a.base = 1e6 | ||||
| 	case "unixnano": | ||||
| 		a.base = 1e9 | ||||
| 	default: | ||||
| 		// Reject any Go identifier in case new constants are supported. | ||||
| 		if strings.TrimFunc(format, isLetterOrDigit) == "" { | ||||
| 			return false | ||||
| 		} | ||||
| 		a.format = format | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| func (a *timeArshaler) isNumeric() bool { | ||||
| 	return int(a.base) > 0 | ||||
| } | ||||
|  | ||||
| func (a *timeArshaler) hasCustomFormat() bool { | ||||
| 	return a.base == math.MaxUint | ||||
| } | ||||
|  | ||||
| func (a *timeArshaler) appendMarshal(b []byte) ([]byte, error) { | ||||
| 	switch a.base { | ||||
| 	case 0: | ||||
| 		format := cmp.Or(a.format, time.RFC3339Nano) | ||||
| 		n0 := len(b) | ||||
| 		b = a.tt.AppendFormat(b, format) | ||||
| 		// Not all Go timestamps can be represented as valid RFC 3339. | ||||
| 		// Explicitly check for these edge cases. | ||||
| 		// See https://go.dev/issue/4556 and https://go.dev/issue/54580. | ||||
| 		switch b := b[n0:]; { | ||||
| 		case b[len("9999")] != '-': // year must be exactly 4 digits wide | ||||
| 			return b, errors.New("year outside of range [0,9999]") | ||||
| 		case b[len(b)-1] != 'Z': | ||||
| 			c := b[len(b)-len("Z07:00")] | ||||
| 			if ('0' <= c && c <= '9') || parseDec2(b[len(b)-len("07:00"):]) >= 24 { | ||||
| 				return b, errors.New("timezone hour outside of range [0,23]") | ||||
| 			} | ||||
| 		} | ||||
| 		return b, nil | ||||
| 	case math.MaxUint: | ||||
| 		return a.tt.AppendFormat(b, a.format), nil | ||||
| 	default: | ||||
| 		return appendTimeUnix(b, a.tt, a.base), nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (a *timeArshaler) unmarshal(b []byte) (err error) { | ||||
| 	switch a.base { | ||||
| 	case 0: | ||||
| 		// Use time.Time.UnmarshalText to avoid possible string allocation. | ||||
| 		if err := a.tt.UnmarshalText(b); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		// TODO(https://go.dev/issue/57912): | ||||
| 		// RFC 3339 specifies the grammar for a valid timestamp. | ||||
| 		// However, the parsing functionality in "time" is too loose and | ||||
| 		// incorrectly accepts invalid timestamps as valid. | ||||
| 		// Remove these manual checks when "time" checks it for us. | ||||
| 		newParseError := func(layout, value, layoutElem, valueElem, message string) error { | ||||
| 			return &time.ParseError{Layout: layout, Value: value, LayoutElem: layoutElem, ValueElem: valueElem, Message: message} | ||||
| 		} | ||||
| 		switch { | ||||
| 		case a.looseRFC3339: | ||||
| 			return nil | ||||
| 		case b[len("2006-01-02T")+1] == ':': // hour must be two digits | ||||
| 			return newParseError(time.RFC3339, string(b), "15", string(b[len("2006-01-02T"):][:1]), "") | ||||
| 		case b[len("2006-01-02T15:04:05")] == ',': // sub-second separator must be a period | ||||
| 			return newParseError(time.RFC3339, string(b), ".", ",", "") | ||||
| 		case b[len(b)-1] != 'Z': | ||||
| 			switch { | ||||
| 			case parseDec2(b[len(b)-len("07:00"):]) >= 24: // timezone hour must be in range | ||||
| 				return newParseError(time.RFC3339, string(b), "Z07:00", string(b[len(b)-len("Z07:00"):]), ": timezone hour out of range") | ||||
| 			case parseDec2(b[len(b)-len("00"):]) >= 60: // timezone minute must be in range | ||||
| 				return newParseError(time.RFC3339, string(b), "Z07:00", string(b[len(b)-len("Z07:00"):]), ": timezone minute out of range") | ||||
| 			} | ||||
| 		} | ||||
| 		return nil | ||||
| 	case math.MaxUint: | ||||
| 		a.tt, err = time.Parse(a.format, string(b)) | ||||
| 		return err | ||||
| 	default: | ||||
| 		a.tt, err = parseTimeUnix(b, a.base) | ||||
| 		return err | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // appendDurationBase10 appends d formatted as a decimal fractional number, | ||||
| // where pow10 is a power-of-10 used to scale down the number. | ||||
| func appendDurationBase10(b []byte, d time.Duration, pow10 uint64) []byte { | ||||
| 	b, n := mayAppendDurationSign(b, d)            // append sign | ||||
| 	whole, frac := bits.Div64(0, n, uint64(pow10)) // compute whole and frac fields | ||||
| 	b = strconv.AppendUint(b, whole, 10)           // append whole field | ||||
| 	return appendFracBase10(b, frac, pow10)        // append frac field | ||||
| } | ||||
|  | ||||
| // parseDurationBase10 parses d from a decimal fractional number, | ||||
| // where pow10 is a power-of-10 used to scale up the number. | ||||
| func parseDurationBase10(b []byte, pow10 uint64) (time.Duration, error) { | ||||
| 	suffix, neg := consumeSign(b)                            // consume sign | ||||
| 	wholeBytes, fracBytes := bytesCutByte(suffix, '.', true) // consume whole and frac fields | ||||
| 	whole, okWhole := jsonwire.ParseUint(wholeBytes)         // parse whole field; may overflow | ||||
| 	frac, okFrac := parseFracBase10(fracBytes, pow10)        // parse frac field | ||||
| 	hi, lo := bits.Mul64(whole, uint64(pow10))               // overflow if hi > 0 | ||||
| 	sum, co := bits.Add64(lo, uint64(frac), 0)               // overflow if co > 0 | ||||
| 	switch d := mayApplyDurationSign(sum, neg); {            // overflow if neg != (d < 0) | ||||
| 	case (!okWhole && whole != math.MaxUint64) || !okFrac: | ||||
| 		return 0, fmt.Errorf("invalid duration %q: %w", b, strconv.ErrSyntax) | ||||
| 	case !okWhole || hi > 0 || co > 0 || neg != (d < 0): | ||||
| 		return 0, fmt.Errorf("invalid duration %q: %w", b, strconv.ErrRange) | ||||
| 	default: | ||||
| 		return d, nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // mayAppendDurationSign appends a negative sign if n is negative. | ||||
| func mayAppendDurationSign(b []byte, d time.Duration) ([]byte, uint64) { | ||||
| 	if d < 0 { | ||||
| 		b = append(b, '-') | ||||
| 		d *= -1 | ||||
| 	} | ||||
| 	return b, uint64(d) | ||||
| } | ||||
|  | ||||
| // mayApplyDurationSign inverts n if neg is specified. | ||||
| func mayApplyDurationSign(n uint64, neg bool) time.Duration { | ||||
| 	if neg { | ||||
| 		return -1 * time.Duration(n) | ||||
| 	} else { | ||||
| 		return +1 * time.Duration(n) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // appendTimeUnix appends t formatted as a decimal fractional number, | ||||
| // where pow10 is a power-of-10 used to scale up the number. | ||||
| func appendTimeUnix(b []byte, t time.Time, pow10 uint64) []byte { | ||||
| 	sec, nsec := t.Unix(), int64(t.Nanosecond()) | ||||
| 	if sec < 0 { | ||||
| 		b = append(b, '-') | ||||
| 		sec, nsec = negateSecNano(sec, nsec) | ||||
| 	} | ||||
| 	switch { | ||||
| 	case pow10 == 1e0: // fast case where units is in seconds | ||||
| 		b = strconv.AppendUint(b, uint64(sec), 10) | ||||
| 		return appendFracBase10(b, uint64(nsec), 1e9) | ||||
| 	case uint64(sec) < 1e9: // intermediate case where units is not seconds, but no overflow | ||||
| 		b = strconv.AppendUint(b, uint64(sec)*uint64(pow10)+uint64(uint64(nsec)/(1e9/pow10)), 10) | ||||
| 		return appendFracBase10(b, (uint64(nsec)*pow10)%1e9, 1e9) | ||||
| 	default: // slow case where units is not seconds and overflow would occur | ||||
| 		b = strconv.AppendUint(b, uint64(sec), 10) | ||||
| 		b = appendPaddedBase10(b, uint64(nsec)/(1e9/pow10), pow10) | ||||
| 		return appendFracBase10(b, (uint64(nsec)*pow10)%1e9, 1e9) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // parseTimeUnix parses t formatted as a decimal fractional number, | ||||
| // where pow10 is a power-of-10 used to scale down the number. | ||||
| func parseTimeUnix(b []byte, pow10 uint64) (time.Time, error) { | ||||
| 	suffix, neg := consumeSign(b)                            // consume sign | ||||
| 	wholeBytes, fracBytes := bytesCutByte(suffix, '.', true) // consume whole and frac fields | ||||
| 	whole, okWhole := jsonwire.ParseUint(wholeBytes)         // parse whole field; may overflow | ||||
| 	frac, okFrac := parseFracBase10(fracBytes, 1e9/pow10)    // parse frac field | ||||
| 	var sec, nsec int64 | ||||
| 	switch { | ||||
| 	case pow10 == 1e0: // fast case where units is in seconds | ||||
| 		sec = int64(whole) // check overflow later after negation | ||||
| 		nsec = int64(frac) // cannot overflow | ||||
| 	case okWhole: // intermediate case where units is not seconds, but no overflow | ||||
| 		sec = int64(whole / pow10)                     // check overflow later after negation | ||||
| 		nsec = int64((whole%pow10)*(1e9/pow10) + frac) // cannot overflow | ||||
| 	case !okWhole && whole == math.MaxUint64: // slow case where units is not seconds and overflow occurred | ||||
| 		width := int(math.Log10(float64(pow10)))                                // compute len(strconv.Itoa(pow10-1)) | ||||
| 		whole, okWhole = jsonwire.ParseUint(wholeBytes[:len(wholeBytes)-width]) // parse the upper whole field | ||||
| 		mid, _ := parsePaddedBase10(wholeBytes[len(wholeBytes)-width:], pow10)  // parse the lower whole field | ||||
| 		sec = int64(whole)                                                      // check overflow later after negation | ||||
| 		nsec = int64(mid*(1e9/pow10) + frac)                                    // cannot overflow | ||||
| 	} | ||||
| 	if neg { | ||||
| 		sec, nsec = negateSecNano(sec, nsec) | ||||
| 	} | ||||
| 	switch t := time.Unix(sec, nsec).UTC(); { | ||||
| 	case (!okWhole && whole != math.MaxUint64) || !okFrac: | ||||
| 		return time.Time{}, fmt.Errorf("invalid time %q: %w", b, strconv.ErrSyntax) | ||||
| 	case !okWhole || neg != (t.Unix() < 0): | ||||
| 		return time.Time{}, fmt.Errorf("invalid time %q: %w", b, strconv.ErrRange) | ||||
| 	default: | ||||
| 		return t, nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // negateSecNano negates a Unix timestamp, where nsec must be within [0, 1e9). | ||||
| func negateSecNano(sec, nsec int64) (int64, int64) { | ||||
| 	sec = ^sec               // twos-complement negation (i.e., -1*sec + 1) | ||||
| 	nsec = -nsec + 1e9       // negate nsec and add 1e9 (which is the extra +1 from sec negation) | ||||
| 	sec += int64(nsec / 1e9) // handle possible overflow of nsec if it started as zero | ||||
| 	nsec %= 1e9              // ensure nsec stays within [0, 1e9) | ||||
| 	return sec, nsec | ||||
| } | ||||
|  | ||||
| // appendFracBase10 appends the fraction of n/max10, | ||||
| // where max10 is a power-of-10 that is larger than n. | ||||
| func appendFracBase10(b []byte, n, max10 uint64) []byte { | ||||
| 	if n == 0 { | ||||
| 		return b | ||||
| 	} | ||||
| 	return bytes.TrimRight(appendPaddedBase10(append(b, '.'), n, max10), "0") | ||||
| } | ||||
|  | ||||
| // parseFracBase10 parses the fraction of n/max10, | ||||
| // where max10 is a power-of-10 that is larger than n. | ||||
| func parseFracBase10(b []byte, max10 uint64) (n uint64, ok bool) { | ||||
| 	switch { | ||||
| 	case len(b) == 0: | ||||
| 		return 0, true | ||||
| 	case len(b) < len(".0") || b[0] != '.': | ||||
| 		return 0, false | ||||
| 	} | ||||
| 	return parsePaddedBase10(b[len("."):], max10) | ||||
| } | ||||
|  | ||||
| // appendPaddedBase10 appends a zero-padded encoding of n, | ||||
| // where max10 is a power-of-10 that is larger than n. | ||||
| func appendPaddedBase10(b []byte, n, max10 uint64) []byte { | ||||
| 	if n < max10/10 { | ||||
| 		// Formatting of n is shorter than log10(max10), | ||||
| 		// so add max10/10 to ensure the length is equal to log10(max10). | ||||
| 		i := len(b) | ||||
| 		b = strconv.AppendUint(b, n+max10/10, 10) | ||||
| 		b[i]-- // subtract the addition of max10/10 | ||||
| 		return b | ||||
| 	} | ||||
| 	return strconv.AppendUint(b, n, 10) | ||||
| } | ||||
|  | ||||
| // parsePaddedBase10 parses b as the zero-padded encoding of n, | ||||
| // where max10 is a power-of-10 that is larger than n. | ||||
| // Truncated suffix is treated as implicit zeros. | ||||
| // Extended suffix is ignored, but verified to contain only digits. | ||||
| func parsePaddedBase10(b []byte, max10 uint64) (n uint64, ok bool) { | ||||
| 	pow10 := uint64(1) | ||||
| 	for pow10 < max10 { | ||||
| 		n *= 10 | ||||
| 		if len(b) > 0 { | ||||
| 			if b[0] < '0' || '9' < b[0] { | ||||
| 				return n, false | ||||
| 			} | ||||
| 			n += uint64(b[0] - '0') | ||||
| 			b = b[1:] | ||||
| 		} | ||||
| 		pow10 *= 10 | ||||
| 	} | ||||
| 	if len(b) > 0 && len(bytes.TrimRight(b, "0123456789")) > 0 { | ||||
| 		return n, false // trailing characters are not digits | ||||
| 	} | ||||
| 	return n, true | ||||
| } | ||||
|  | ||||
| // consumeSign consumes an optional leading negative sign. | ||||
| func consumeSign(b []byte) ([]byte, bool) { | ||||
| 	if len(b) > 0 && b[0] == '-' { | ||||
| 		return b[len("-"):], true | ||||
| 	} | ||||
| 	return b, false | ||||
| } | ||||
|  | ||||
| // bytesCutByte is similar to bytes.Cut(b, []byte{c}), | ||||
| // except c may optionally be included as part of the suffix. | ||||
| func bytesCutByte(b []byte, c byte, include bool) ([]byte, []byte) { | ||||
| 	if i := bytes.IndexByte(b, c); i >= 0 { | ||||
| 		if include { | ||||
| 			return b[:i], b[i:] | ||||
| 		} | ||||
| 		return b[:i], b[i+1:] | ||||
| 	} | ||||
| 	return b, nil | ||||
| } | ||||
|  | ||||
| // parseDec2 parses b as an unsigned, base-10, 2-digit number. | ||||
| // The result is undefined if digits are not base-10. | ||||
| func parseDec2(b []byte) byte { | ||||
| 	if len(b) < 2 { | ||||
| 		return 0 | ||||
| 	} | ||||
| 	return 10*(b[0]-'0') + (b[1] - '0') | ||||
| } | ||||
							
								
								
									
										168
									
								
								vendor/github.com/go-json-experiment/json/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										168
									
								
								vendor/github.com/go-json-experiment/json/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,168 @@ | ||||
| // Copyright 2020 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. | ||||
|  | ||||
| // Package json implements semantic processing of JSON as specified in RFC 8259. | ||||
| // JSON is a simple data interchange format that can represent | ||||
| // primitive data types such as booleans, strings, and numbers, | ||||
| // in addition to structured data types such as objects and arrays. | ||||
| // | ||||
| // [Marshal] and [Unmarshal] encode and decode Go values | ||||
| // to/from JSON text contained within a []byte. | ||||
| // [MarshalWrite] and [UnmarshalRead] operate on JSON text | ||||
| // by writing to or reading from an [io.Writer] or [io.Reader]. | ||||
| // [MarshalEncode] and [UnmarshalDecode] operate on JSON text | ||||
| // by encoding to or decoding from a [jsontext.Encoder] or [jsontext.Decoder]. | ||||
| // [Options] may be passed to each of the marshal or unmarshal functions | ||||
| // to configure the semantic behavior of marshaling and unmarshaling | ||||
| // (i.e., alter how JSON data is understood as Go data and vice versa). | ||||
| // [jsontext.Options] may also be passed to the marshal or unmarshal functions | ||||
| // to configure the syntactic behavior of encoding or decoding. | ||||
| // | ||||
| // The data types of JSON are mapped to/from the data types of Go based on | ||||
| // the closest logical equivalent between the two type systems. For example, | ||||
| // a JSON boolean corresponds with a Go bool, | ||||
| // a JSON string corresponds with a Go string, | ||||
| // a JSON number corresponds with a Go int, uint or float, | ||||
| // a JSON array corresponds with a Go slice or array, and | ||||
| // a JSON object corresponds with a Go struct or map. | ||||
| // See the documentation on [Marshal] and [Unmarshal] for a comprehensive list | ||||
| // of how the JSON and Go type systems correspond. | ||||
| // | ||||
| // Arbitrary Go types can customize their JSON representation by implementing | ||||
| // [Marshaler], [MarshalerTo], [Unmarshaler], or [UnmarshalerFrom]. | ||||
| // This provides authors of Go types with control over how their types are | ||||
| // serialized as JSON. Alternatively, users can implement functions that match | ||||
| // [MarshalFunc], [MarshalToFunc], [UnmarshalFunc], or [UnmarshalFromFunc] | ||||
| // to specify the JSON representation for arbitrary types. | ||||
| // This provides callers of JSON functionality with control over | ||||
| // how any arbitrary type is serialized as JSON. | ||||
| // | ||||
| // # JSON Representation of Go structs | ||||
| // | ||||
| // A Go struct is naturally represented as a JSON object, | ||||
| // where each Go struct field corresponds with a JSON object member. | ||||
| // When marshaling, all Go struct fields are recursively encoded in depth-first | ||||
| // order as JSON object members except those that are ignored or omitted. | ||||
| // When unmarshaling, JSON object members are recursively decoded | ||||
| // into the corresponding Go struct fields. | ||||
| // Object members that do not match any struct fields, | ||||
| // also known as “unknown members”, are ignored by default or rejected | ||||
| // if [RejectUnknownMembers] is specified. | ||||
| // | ||||
| // The representation of each struct field can be customized in the | ||||
| // "json" struct field tag, where the tag is a comma separated list of options. | ||||
| // As a special case, if the entire tag is `json:"-"`, | ||||
| // then the field is ignored with regard to its JSON representation. | ||||
| // Some options also have equivalent behavior controlled by a caller-specified [Options]. | ||||
| // Field-specified options take precedence over caller-specified options. | ||||
| // | ||||
| // The first option is the JSON object name override for the Go struct field. | ||||
| // If the name is not specified, then the Go struct field name | ||||
| // is used as the JSON object name. JSON names containing commas or quotes, | ||||
| // or names identical to "" or "-", can be specified using | ||||
| // a single-quoted string literal, where the syntax is identical to | ||||
| // the Go grammar for a double-quoted string literal, | ||||
| // but instead uses single quotes as the delimiters. | ||||
| // By default, unmarshaling uses case-sensitive matching to identify | ||||
| // the Go struct field associated with a JSON object name. | ||||
| // | ||||
| // After the name, the following tag options are supported: | ||||
| // | ||||
| //   - omitzero: When marshaling, the "omitzero" option specifies that | ||||
| //     the struct field should be omitted if the field value is zero | ||||
| //     as determined by the "IsZero() bool" method if present, | ||||
| //     otherwise based on whether the field is the zero Go value. | ||||
| //     This option has no effect when unmarshaling. | ||||
| // | ||||
| //   - omitempty: When marshaling, the "omitempty" option specifies that | ||||
| //     the struct field should be omitted if the field value would have been | ||||
| //     encoded as a JSON null, empty string, empty object, or empty array. | ||||
| //     This option has no effect when unmarshaling. | ||||
| // | ||||
| //   - string: The "string" option specifies that [StringifyNumbers] | ||||
| //     be set when marshaling or unmarshaling a struct field value. | ||||
| //     This causes numeric types to be encoded as a JSON number | ||||
| //     within a JSON string, and to be decoded from a JSON string | ||||
| //     containing the JSON number without any surrounding whitespace. | ||||
| //     This extra level of encoding is often necessary since | ||||
| //     many JSON parsers cannot precisely represent 64-bit integers. | ||||
| // | ||||
| //   - case: When unmarshaling, the "case" option specifies how | ||||
| //     JSON object names are matched with the JSON name for Go struct fields. | ||||
| //     The option is a key-value pair specified as "case:value" where | ||||
| //     the value must either be 'ignore' or 'strict'. | ||||
| //     The 'ignore' value specifies that matching is case-insensitive | ||||
| //     where dashes and underscores are also ignored. If multiple fields match, | ||||
| //     the first declared field in breadth-first order takes precedence. | ||||
| //     The 'strict' value specifies that matching is case-sensitive. | ||||
| //     This takes precedence over the [MatchCaseInsensitiveNames] option. | ||||
| // | ||||
| //   - inline: The "inline" option specifies that | ||||
| //     the JSON representable content of this field type is to be promoted | ||||
| //     as if they were specified in the parent struct. | ||||
| //     It is the JSON equivalent of Go struct embedding. | ||||
| //     A Go embedded field is implicitly inlined unless an explicit JSON name | ||||
| //     is specified. The inlined field must be a Go struct | ||||
| //     (that does not implement any JSON methods), [jsontext.Value], | ||||
| //     map[~string]T, or an unnamed pointer to such types. When marshaling, | ||||
| //     inlined fields from a pointer type are omitted if it is nil. | ||||
| //     Inlined fields of type [jsontext.Value] and map[~string]T are called | ||||
| //     “inlined fallbacks” as they can represent all possible | ||||
| //     JSON object members not directly handled by the parent struct. | ||||
| //     Only one inlined fallback field may be specified in a struct, | ||||
| //     while many non-fallback fields may be specified. This option | ||||
| //     must not be specified with any other option (including the JSON name). | ||||
| // | ||||
| //   - unknown: The "unknown" option is a specialized variant | ||||
| //     of the inlined fallback to indicate that this Go struct field | ||||
| //     contains any number of unknown JSON object members. The field type must | ||||
| //     be a [jsontext.Value], map[~string]T, or an unnamed pointer to such types. | ||||
| //     If [DiscardUnknownMembers] is specified when marshaling, | ||||
| //     the contents of this field are ignored. | ||||
| //     If [RejectUnknownMembers] is specified when unmarshaling, | ||||
| //     any unknown object members are rejected regardless of whether | ||||
| //     an inlined fallback with the "unknown" option exists. This option | ||||
| //     must not be specified with any other option (including the JSON name). | ||||
| // | ||||
| //   - format: The "format" option specifies a format flag | ||||
| //     used to specialize the formatting of the field value. | ||||
| //     The option is a key-value pair specified as "format:value" where | ||||
| //     the value must be either a literal consisting of letters and numbers | ||||
| //     (e.g., "format:RFC3339") or a single-quoted string literal | ||||
| //     (e.g., "format:'2006-01-02'"). The interpretation of the format flag | ||||
| //     is determined by the struct field type. | ||||
| // | ||||
| // The "omitzero" and "omitempty" options are mostly semantically identical. | ||||
| // The former is defined in terms of the Go type system, | ||||
| // while the latter in terms of the JSON type system. | ||||
| // Consequently they behave differently in some circumstances. | ||||
| // For example, only a nil slice or map is omitted under "omitzero", while | ||||
| // an empty slice or map is omitted under "omitempty" regardless of nilness. | ||||
| // The "omitzero" option is useful for types with a well-defined zero value | ||||
| // (e.g., [net/netip.Addr]) or have an IsZero method (e.g., [time.Time.IsZero]). | ||||
| // | ||||
| // Every Go struct corresponds to a list of JSON representable fields | ||||
| // which is constructed by performing a breadth-first search over | ||||
| // all struct fields (excluding unexported or ignored fields), | ||||
| // where the search recursively descends into inlined structs. | ||||
| // The set of non-inlined fields in a struct must have unique JSON names. | ||||
| // If multiple fields all have the same JSON name, then the one | ||||
| // at shallowest depth takes precedence and the other fields at deeper depths | ||||
| // are excluded from the list of JSON representable fields. | ||||
| // If multiple fields at the shallowest depth have the same JSON name, | ||||
| // but exactly one is explicitly tagged with a JSON name, | ||||
| // then that field takes precedence and all others are excluded from the list. | ||||
| // This is analogous to Go visibility rules for struct field selection | ||||
| // with embedded struct types. | ||||
| // | ||||
| // Marshaling or unmarshaling a non-empty struct | ||||
| // without any JSON representable fields results in a [SemanticError]. | ||||
| // Unexported fields must not have any `json` tags except for `json:"-"`. | ||||
| package json | ||||
|  | ||||
| // requireKeyedLiterals can be embedded in a struct to require keyed literals. | ||||
| type requireKeyedLiterals struct{} | ||||
|  | ||||
| // nonComparable can be embedded in a struct to prevent comparability. | ||||
| type nonComparable [0]func() | ||||
							
								
								
									
										418
									
								
								vendor/github.com/go-json-experiment/json/errors.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										418
									
								
								vendor/github.com/go-json-experiment/json/errors.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,418 @@ | ||||
| // Copyright 2020 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. | ||||
|  | ||||
| package json | ||||
|  | ||||
| import ( | ||||
| 	"cmp" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"reflect" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/go-json-experiment/json/internal/jsonflags" | ||||
| 	"github.com/go-json-experiment/json/internal/jsonopts" | ||||
| 	"github.com/go-json-experiment/json/internal/jsonwire" | ||||
| 	"github.com/go-json-experiment/json/jsontext" | ||||
| ) | ||||
|  | ||||
| // ErrUnknownName indicates that a JSON object member could not be | ||||
| // unmarshaled because the name is not known to the target Go struct. | ||||
| // This error is directly wrapped within a [SemanticError] when produced. | ||||
| // | ||||
| // The name of an unknown JSON object member can be extracted as: | ||||
| // | ||||
| //	err := ... | ||||
| //	var serr json.SemanticError | ||||
| //	if errors.As(err, &serr) && serr.Err == json.ErrUnknownName { | ||||
| //		ptr := serr.JSONPointer // JSON pointer to unknown name | ||||
| //		name := ptr.LastToken() // unknown name itself | ||||
| //		... | ||||
| //	} | ||||
| // | ||||
| // This error is only returned if [RejectUnknownMembers] is true. | ||||
| var ErrUnknownName = errors.New("unknown object member name") | ||||
|  | ||||
| const errorPrefix = "json: " | ||||
|  | ||||
| func isSemanticError(err error) bool { | ||||
| 	_, ok := err.(*SemanticError) | ||||
| 	return ok | ||||
| } | ||||
|  | ||||
| func isSyntacticError(err error) bool { | ||||
| 	_, ok := err.(*jsontext.SyntacticError) | ||||
| 	return ok | ||||
| } | ||||
|  | ||||
| // isFatalError reports whether this error must terminate asharling. | ||||
| // All errors are considered fatal unless operating under | ||||
| // [jsonflags.ReportErrorsWithLegacySemantics] in which case only | ||||
| // syntactic errors and I/O errors are considered fatal. | ||||
| func isFatalError(err error, flags jsonflags.Flags) bool { | ||||
| 	return !flags.Get(jsonflags.ReportErrorsWithLegacySemantics) || | ||||
| 		isSyntacticError(err) || export.IsIOError(err) | ||||
| } | ||||
|  | ||||
| // SemanticError describes an error determining the meaning | ||||
| // of JSON data as Go data or vice-versa. | ||||
| // | ||||
| // The contents of this error as produced by this package may change over time. | ||||
| type SemanticError struct { | ||||
| 	requireKeyedLiterals | ||||
| 	nonComparable | ||||
|  | ||||
| 	action string // either "marshal" or "unmarshal" | ||||
|  | ||||
| 	// ByteOffset indicates that an error occurred after this byte offset. | ||||
| 	ByteOffset int64 | ||||
| 	// JSONPointer indicates that an error occurred within this JSON value | ||||
| 	// as indicated using the JSON Pointer notation (see RFC 6901). | ||||
| 	JSONPointer jsontext.Pointer | ||||
|  | ||||
| 	// JSONKind is the JSON kind that could not be handled. | ||||
| 	JSONKind jsontext.Kind // may be zero if unknown | ||||
| 	// JSONValue is the JSON number or string that could not be unmarshaled. | ||||
| 	// It is not populated during marshaling. | ||||
| 	JSONValue jsontext.Value // may be nil if irrelevant or unknown | ||||
| 	// GoType is the Go type that could not be handled. | ||||
| 	GoType reflect.Type // may be nil if unknown | ||||
|  | ||||
| 	// Err is the underlying error. | ||||
| 	Err error // may be nil | ||||
| } | ||||
|  | ||||
| // coder is implemented by [jsontext.Encoder] or [jsontext.Decoder]. | ||||
| type coder interface{ StackPointer() jsontext.Pointer } | ||||
|  | ||||
| // newInvalidFormatError wraps err in a SemanticError because | ||||
| // the current type t cannot handle the provided options format. | ||||
| // This error must be called before producing or consuming the next value. | ||||
| // | ||||
| // If [jsonflags.ReportErrorsWithLegacySemantics] is specified, | ||||
| // then this automatically skips the next value when unmarshaling | ||||
| // to ensure that the value is fully consumed. | ||||
| func newInvalidFormatError(c coder, t reflect.Type, o *jsonopts.Struct) error { | ||||
| 	err := fmt.Errorf("invalid format flag %q", o.Format) | ||||
| 	switch c := c.(type) { | ||||
| 	case *jsontext.Encoder: | ||||
| 		err = newMarshalErrorBefore(c, t, err) | ||||
| 	case *jsontext.Decoder: | ||||
| 		err = newUnmarshalErrorBeforeWithSkipping(c, o, t, err) | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // newMarshalErrorBefore wraps err in a SemanticError assuming that e | ||||
| // is positioned right before the next token or value, which causes an error. | ||||
| func newMarshalErrorBefore(e *jsontext.Encoder, t reflect.Type, err error) error { | ||||
| 	return &SemanticError{action: "marshal", GoType: t, Err: err, | ||||
| 		ByteOffset:  e.OutputOffset() + int64(export.Encoder(e).CountNextDelimWhitespace()), | ||||
| 		JSONPointer: jsontext.Pointer(export.Encoder(e).AppendStackPointer(nil, +1))} | ||||
| } | ||||
|  | ||||
| // newUnmarshalErrorBefore wraps err in a SemanticError assuming that d | ||||
| // is positioned right before the next token or value, which causes an error. | ||||
| // It does not record the next JSON kind as this error is used to indicate | ||||
| // the receiving Go value is invalid to unmarshal into (and not a JSON error). | ||||
| func newUnmarshalErrorBefore(d *jsontext.Decoder, t reflect.Type, err error) error { | ||||
| 	return &SemanticError{action: "unmarshal", GoType: t, Err: err, | ||||
| 		ByteOffset:  d.InputOffset() + int64(export.Decoder(d).CountNextDelimWhitespace()), | ||||
| 		JSONPointer: jsontext.Pointer(export.Decoder(d).AppendStackPointer(nil, +1))} | ||||
| } | ||||
|  | ||||
| // newUnmarshalErrorBeforeWithSkipping is like [newUnmarshalErrorBefore], | ||||
| // but automatically skips the next value if | ||||
| // [jsonflags.ReportErrorsWithLegacySemantics] is specified. | ||||
| func newUnmarshalErrorBeforeWithSkipping(d *jsontext.Decoder, o *jsonopts.Struct, t reflect.Type, err error) error { | ||||
| 	err = newUnmarshalErrorBefore(d, t, err) | ||||
| 	if o.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { | ||||
| 		if err2 := export.Decoder(d).SkipValue(); err2 != nil { | ||||
| 			return err2 | ||||
| 		} | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // newUnmarshalErrorAfter wraps err in a SemanticError assuming that d | ||||
| // is positioned right after the previous token or value, which caused an error. | ||||
| func newUnmarshalErrorAfter(d *jsontext.Decoder, t reflect.Type, err error) error { | ||||
| 	tokOrVal := export.Decoder(d).PreviousTokenOrValue() | ||||
| 	return &SemanticError{action: "unmarshal", GoType: t, Err: err, | ||||
| 		ByteOffset:  d.InputOffset() - int64(len(tokOrVal)), | ||||
| 		JSONPointer: jsontext.Pointer(export.Decoder(d).AppendStackPointer(nil, -1)), | ||||
| 		JSONKind:    jsontext.Value(tokOrVal).Kind()} | ||||
| } | ||||
|  | ||||
| // newUnmarshalErrorAfter wraps err in a SemanticError assuming that d | ||||
| // is positioned right after the previous token or value, which caused an error. | ||||
| // It also stores a copy of the last JSON value if it is a string or number. | ||||
| func newUnmarshalErrorAfterWithValue(d *jsontext.Decoder, t reflect.Type, err error) error { | ||||
| 	serr := newUnmarshalErrorAfter(d, t, err).(*SemanticError) | ||||
| 	if serr.JSONKind == '"' || serr.JSONKind == '0' { | ||||
| 		serr.JSONValue = jsontext.Value(export.Decoder(d).PreviousTokenOrValue()).Clone() | ||||
| 	} | ||||
| 	return serr | ||||
| } | ||||
|  | ||||
| // newUnmarshalErrorAfterWithSkipping is like [newUnmarshalErrorAfter], | ||||
| // but automatically skips the remainder of the current value if | ||||
| // [jsonflags.ReportErrorsWithLegacySemantics] is specified. | ||||
| func newUnmarshalErrorAfterWithSkipping(d *jsontext.Decoder, o *jsonopts.Struct, t reflect.Type, err error) error { | ||||
| 	err = newUnmarshalErrorAfter(d, t, err) | ||||
| 	if o.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { | ||||
| 		if err2 := export.Decoder(d).SkipValueRemainder(); err2 != nil { | ||||
| 			return err2 | ||||
| 		} | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // newSemanticErrorWithPosition wraps err in a SemanticError assuming that | ||||
| // the error occurred at the provided depth, and length. | ||||
| // If err is already a SemanticError, then position information is only | ||||
| // injected if it is currently unpopulated. | ||||
| // | ||||
| // If the position is unpopulated, it is ambiguous where the error occurred | ||||
| // in the user code, whether it was before or after the current position. | ||||
| // For the byte offset, we assume that the error occurred before the last read | ||||
| // token or value when decoding, or before the next value when encoding. | ||||
| // For the JSON pointer, we point to the parent object or array unless | ||||
| // we can be certain that it happened with an object member. | ||||
| // | ||||
| // This is used to annotate errors returned by user-provided | ||||
| // v2 MarshalJSON or UnmarshalJSON methods or functions. | ||||
| func newSemanticErrorWithPosition(c coder, t reflect.Type, prevDepth int, prevLength int64, err error) error { | ||||
| 	serr, _ := err.(*SemanticError) | ||||
| 	if serr == nil { | ||||
| 		serr = &SemanticError{Err: err} | ||||
| 	} | ||||
| 	var currDepth int | ||||
| 	var currLength int64 | ||||
| 	var coderState interface{ AppendStackPointer([]byte, int) []byte } | ||||
| 	var offset int64 | ||||
| 	switch c := c.(type) { | ||||
| 	case *jsontext.Encoder: | ||||
| 		e := export.Encoder(c) | ||||
| 		serr.action = cmp.Or(serr.action, "marshal") | ||||
| 		currDepth, currLength = e.Tokens.DepthLength() | ||||
| 		offset = c.OutputOffset() + int64(export.Encoder(c).CountNextDelimWhitespace()) | ||||
| 		coderState = e | ||||
| 	case *jsontext.Decoder: | ||||
| 		d := export.Decoder(c) | ||||
| 		serr.action = cmp.Or(serr.action, "unmarshal") | ||||
| 		currDepth, currLength = d.Tokens.DepthLength() | ||||
| 		tokOrVal := d.PreviousTokenOrValue() | ||||
| 		offset = c.InputOffset() - int64(len(tokOrVal)) | ||||
| 		if (prevDepth == currDepth && prevLength == currLength) || len(tokOrVal) == 0 { | ||||
| 			// If no Read method was called in the user-defined method or | ||||
| 			// if the Peek method was called, then use the offset of the next value. | ||||
| 			offset = c.InputOffset() + int64(export.Decoder(c).CountNextDelimWhitespace()) | ||||
| 		} | ||||
| 		coderState = d | ||||
| 	} | ||||
| 	serr.ByteOffset = cmp.Or(serr.ByteOffset, offset) | ||||
| 	if serr.JSONPointer == "" { | ||||
| 		where := 0 // default to ambiguous positioning | ||||
| 		switch { | ||||
| 		case prevDepth == currDepth && prevLength+0 == currLength: | ||||
| 			where = +1 | ||||
| 		case prevDepth == currDepth && prevLength+1 == currLength: | ||||
| 			where = -1 | ||||
| 		} | ||||
| 		serr.JSONPointer = jsontext.Pointer(coderState.AppendStackPointer(nil, where)) | ||||
| 	} | ||||
| 	serr.GoType = cmp.Or(serr.GoType, t) | ||||
| 	return serr | ||||
| } | ||||
|  | ||||
| // collapseSemanticErrors collapses double SemanticErrors at the outer levels | ||||
| // into a single SemanticError by preserving the inner error, | ||||
| // but prepending the ByteOffset and JSONPointer with the outer error. | ||||
| // | ||||
| // For example: | ||||
| // | ||||
| //	collapseSemanticErrors(&SemanticError{ | ||||
| //		ByteOffset:  len64(`[0,{"alpha":[0,1,`), | ||||
| //		JSONPointer: "/1/alpha/2", | ||||
| //		GoType:      reflect.TypeFor[outerType](), | ||||
| //		Err: &SemanticError{ | ||||
| //			ByteOffset:  len64(`{"foo":"bar","fizz":[0,`), | ||||
| //			JSONPointer: "/fizz/1", | ||||
| //			GoType:      reflect.TypeFor[innerType](), | ||||
| //			Err:         ..., | ||||
| //		}, | ||||
| //	}) | ||||
| // | ||||
| // results in: | ||||
| // | ||||
| //	&SemanticError{ | ||||
| //		ByteOffset:  len64(`[0,{"alpha":[0,1,`) + len64(`{"foo":"bar","fizz":[0,`), | ||||
| //		JSONPointer: "/1/alpha/2" + "/fizz/1", | ||||
| //		GoType:      reflect.TypeFor[innerType](), | ||||
| //		Err:         ..., | ||||
| //	} | ||||
| // | ||||
| // This is used to annotate errors returned by user-provided | ||||
| // v1 MarshalJSON or UnmarshalJSON methods with precise position information | ||||
| // if they themselves happened to return a SemanticError. | ||||
| // Since MarshalJSON and UnmarshalJSON are not operating on the root JSON value, | ||||
| // their positioning must be relative to the nested JSON value | ||||
| // returned by UnmarshalJSON or passed to MarshalJSON. | ||||
| // Therefore, we can construct an absolute position by concatenating | ||||
| // the outer with the inner positions. | ||||
| // | ||||
| // Note that we do not use collapseSemanticErrors with user-provided functions | ||||
| // that take in an [jsontext.Encoder] or [jsontext.Decoder] since they contain | ||||
| // methods to report position relative to the root JSON value. | ||||
| // We assume user-constructed errors are correctly precise about position. | ||||
| func collapseSemanticErrors(err error) error { | ||||
| 	if serr1, ok := err.(*SemanticError); ok { | ||||
| 		if serr2, ok := serr1.Err.(*SemanticError); ok { | ||||
| 			serr2.ByteOffset = serr1.ByteOffset + serr2.ByteOffset | ||||
| 			serr2.JSONPointer = serr1.JSONPointer + serr2.JSONPointer | ||||
| 			*serr1 = *serr2 | ||||
| 		} | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // errorModalVerb is a modal verb like "cannot" or "unable to". | ||||
| // | ||||
| // Once per process, Hyrum-proof the error message by deliberately | ||||
| // switching between equivalent renderings of the same error message. | ||||
| // The randomization is tied to the Hyrum-proofing already applied | ||||
| // on map iteration in Go. | ||||
| var errorModalVerb = sync.OnceValue(func() string { | ||||
| 	for phrase := range map[string]struct{}{"cannot": {}, "unable to": {}} { | ||||
| 		return phrase // use whichever phrase we get in the first iteration | ||||
| 	} | ||||
| 	return "" | ||||
| }) | ||||
|  | ||||
| func (e *SemanticError) Error() string { | ||||
| 	var sb strings.Builder | ||||
| 	sb.WriteString(errorPrefix) | ||||
| 	sb.WriteString(errorModalVerb()) | ||||
|  | ||||
| 	// Format action. | ||||
| 	var preposition string | ||||
| 	switch e.action { | ||||
| 	case "marshal": | ||||
| 		sb.WriteString(" marshal") | ||||
| 		preposition = " from" | ||||
| 	case "unmarshal": | ||||
| 		sb.WriteString(" unmarshal") | ||||
| 		preposition = " into" | ||||
| 	default: | ||||
| 		sb.WriteString(" handle") | ||||
| 		preposition = " with" | ||||
| 	} | ||||
|  | ||||
| 	// Format JSON kind. | ||||
| 	switch e.JSONKind { | ||||
| 	case 'n': | ||||
| 		sb.WriteString(" JSON null") | ||||
| 	case 'f', 't': | ||||
| 		sb.WriteString(" JSON boolean") | ||||
| 	case '"': | ||||
| 		sb.WriteString(" JSON string") | ||||
| 	case '0': | ||||
| 		sb.WriteString(" JSON number") | ||||
| 	case '{', '}': | ||||
| 		sb.WriteString(" JSON object") | ||||
| 	case '[', ']': | ||||
| 		sb.WriteString(" JSON array") | ||||
| 	default: | ||||
| 		if e.action == "" { | ||||
| 			preposition = "" | ||||
| 		} | ||||
| 	} | ||||
| 	if len(e.JSONValue) > 0 && len(e.JSONValue) < 100 { | ||||
| 		sb.WriteByte(' ') | ||||
| 		sb.Write(e.JSONValue) | ||||
| 	} | ||||
|  | ||||
| 	// Format Go type. | ||||
| 	if e.GoType != nil { | ||||
| 		typeString := e.GoType.String() | ||||
| 		if len(typeString) > 100 { | ||||
| 			// An excessively long type string most likely occurs for | ||||
| 			// an anonymous struct declaration with many fields. | ||||
| 			// Reduce the noise by just printing the kind, | ||||
| 			// and optionally prepending it with the package name | ||||
| 			// if the struct happens to include an unexported field. | ||||
| 			typeString = e.GoType.Kind().String() | ||||
| 			if e.GoType.Kind() == reflect.Struct && e.GoType.Name() == "" { | ||||
| 				for i := range e.GoType.NumField() { | ||||
| 					if pkgPath := e.GoType.Field(i).PkgPath; pkgPath != "" { | ||||
| 						typeString = pkgPath[strings.LastIndexByte(pkgPath, '/')+len("/"):] + ".struct" | ||||
| 						break | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		sb.WriteString(preposition) | ||||
| 		sb.WriteString(" Go ") | ||||
| 		sb.WriteString(typeString) | ||||
| 	} | ||||
|  | ||||
| 	// Special handling for unknown names. | ||||
| 	if e.Err == ErrUnknownName { | ||||
| 		sb.WriteString(": ") | ||||
| 		sb.WriteString(ErrUnknownName.Error()) | ||||
| 		sb.WriteString(" ") | ||||
| 		sb.WriteString(strconv.Quote(e.JSONPointer.LastToken())) | ||||
| 		if parent := e.JSONPointer.Parent(); parent != "" { | ||||
| 			sb.WriteString(" within ") | ||||
| 			sb.WriteString(strconv.Quote(jsonwire.TruncatePointer(string(parent), 100))) | ||||
| 		} | ||||
| 		return sb.String() | ||||
| 	} | ||||
|  | ||||
| 	// Format where. | ||||
| 	// Avoid printing if it overlaps with a wrapped SyntacticError. | ||||
| 	switch serr, _ := e.Err.(*jsontext.SyntacticError); { | ||||
| 	case e.JSONPointer != "": | ||||
| 		if serr == nil || !e.JSONPointer.Contains(serr.JSONPointer) { | ||||
| 			sb.WriteString(" within ") | ||||
| 			sb.WriteString(strconv.Quote(jsonwire.TruncatePointer(string(e.JSONPointer), 100))) | ||||
| 		} | ||||
| 	case e.ByteOffset > 0: | ||||
| 		if serr == nil || !(e.ByteOffset <= serr.ByteOffset) { | ||||
| 			sb.WriteString(" after offset ") | ||||
| 			sb.WriteString(strconv.FormatInt(e.ByteOffset, 10)) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Format underlying error. | ||||
| 	if e.Err != nil { | ||||
| 		errString := e.Err.Error() | ||||
| 		if isSyntacticError(e.Err) { | ||||
| 			errString = strings.TrimPrefix(errString, "jsontext: ") | ||||
| 		} | ||||
| 		sb.WriteString(": ") | ||||
| 		sb.WriteString(errString) | ||||
| 	} | ||||
|  | ||||
| 	return sb.String() | ||||
| } | ||||
|  | ||||
| func (e *SemanticError) Unwrap() error { | ||||
| 	return e.Err | ||||
| } | ||||
|  | ||||
| func newDuplicateNameError(ptr jsontext.Pointer, quotedName []byte, offset int64) error { | ||||
| 	if quotedName != nil { | ||||
| 		name, _ := jsonwire.AppendUnquote(nil, quotedName) | ||||
| 		ptr = ptr.AppendToken(string(name)) | ||||
| 	} | ||||
| 	return &jsontext.SyntacticError{ | ||||
| 		ByteOffset:  offset, | ||||
| 		JSONPointer: ptr, | ||||
| 		Err:         jsontext.ErrDuplicateName, | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										644
									
								
								vendor/github.com/go-json-experiment/json/fields.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										644
									
								
								vendor/github.com/go-json-experiment/json/fields.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,644 @@ | ||||
| // Copyright 2021 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. | ||||
|  | ||||
| package json | ||||
|  | ||||
| import ( | ||||
| 	"cmp" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"reflect" | ||||
| 	"slices" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"unicode" | ||||
| 	"unicode/utf8" | ||||
|  | ||||
| 	"github.com/go-json-experiment/json/internal/jsonflags" | ||||
| 	"github.com/go-json-experiment/json/internal/jsonwire" | ||||
| ) | ||||
|  | ||||
| type isZeroer interface { | ||||
| 	IsZero() bool | ||||
| } | ||||
|  | ||||
| var isZeroerType = reflect.TypeFor[isZeroer]() | ||||
|  | ||||
| type structFields struct { | ||||
| 	flattened       []structField // listed in depth-first ordering | ||||
| 	byActualName    map[string]*structField | ||||
| 	byFoldedName    map[string][]*structField | ||||
| 	inlinedFallback *structField | ||||
| } | ||||
|  | ||||
| // reindex recomputes index to avoid bounds check during runtime. | ||||
| // | ||||
| // During the construction of each [structField] in [makeStructFields], | ||||
| // the index field is 0-indexed. However, before it returns, | ||||
| // the 0th field is stored in index0 and index stores the remainder. | ||||
| func (sf *structFields) reindex() { | ||||
| 	reindex := func(f *structField) { | ||||
| 		f.index0 = f.index[0] | ||||
| 		f.index = f.index[1:] | ||||
| 		if len(f.index) == 0 { | ||||
| 			f.index = nil // avoid pinning the backing slice | ||||
| 		} | ||||
| 	} | ||||
| 	for i := range sf.flattened { | ||||
| 		reindex(&sf.flattened[i]) | ||||
| 	} | ||||
| 	if sf.inlinedFallback != nil { | ||||
| 		reindex(sf.inlinedFallback) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // lookupByFoldedName looks up name by a case-insensitive match | ||||
| // that also ignores the presence of dashes and underscores. | ||||
| func (fs *structFields) lookupByFoldedName(name []byte) []*structField { | ||||
| 	return fs.byFoldedName[string(foldName(name))] | ||||
| } | ||||
|  | ||||
| type structField struct { | ||||
| 	id      int   // unique numeric ID in breadth-first ordering | ||||
| 	index0  int   // 0th index into a struct according to [reflect.Type.FieldByIndex] | ||||
| 	index   []int // 1st index and remainder according to [reflect.Type.FieldByIndex] | ||||
| 	typ     reflect.Type | ||||
| 	fncs    *arshaler | ||||
| 	isZero  func(addressableValue) bool | ||||
| 	isEmpty func(addressableValue) bool | ||||
| 	fieldOptions | ||||
| } | ||||
|  | ||||
| var errNoExportedFields = errors.New("Go struct has no exported fields") | ||||
|  | ||||
| func makeStructFields(root reflect.Type) (fs structFields, serr *SemanticError) { | ||||
| 	orErrorf := func(serr *SemanticError, t reflect.Type, f string, a ...any) *SemanticError { | ||||
| 		return cmp.Or(serr, &SemanticError{GoType: t, Err: fmt.Errorf(f, a...)}) | ||||
| 	} | ||||
|  | ||||
| 	// Setup a queue for a breath-first search. | ||||
| 	var queueIndex int | ||||
| 	type queueEntry struct { | ||||
| 		typ           reflect.Type | ||||
| 		index         []int | ||||
| 		visitChildren bool // whether to recursively visit inlined field in this struct | ||||
| 	} | ||||
| 	queue := []queueEntry{{root, nil, true}} | ||||
| 	seen := map[reflect.Type]bool{root: true} | ||||
|  | ||||
| 	// Perform a breadth-first search over all reachable fields. | ||||
| 	// This ensures that len(f.index) will be monotonically increasing. | ||||
| 	var allFields, inlinedFallbacks []structField | ||||
| 	for queueIndex < len(queue) { | ||||
| 		qe := queue[queueIndex] | ||||
| 		queueIndex++ | ||||
|  | ||||
| 		t := qe.typ | ||||
| 		inlinedFallbackIndex := -1         // index of last inlined fallback field in current struct | ||||
| 		namesIndex := make(map[string]int) // index of each field with a given JSON object name in current struct | ||||
| 		var hasAnyJSONTag bool             // whether any Go struct field has a `json` tag | ||||
| 		var hasAnyJSONField bool           // whether any JSON serializable fields exist in current struct | ||||
| 		for i := range t.NumField() { | ||||
| 			sf := t.Field(i) | ||||
| 			_, hasTag := sf.Tag.Lookup("json") | ||||
| 			hasAnyJSONTag = hasAnyJSONTag || hasTag | ||||
| 			options, ignored, err := parseFieldOptions(sf) | ||||
| 			if err != nil { | ||||
| 				serr = cmp.Or(serr, &SemanticError{GoType: t, Err: err}) | ||||
| 			} | ||||
| 			if ignored { | ||||
| 				continue | ||||
| 			} | ||||
| 			hasAnyJSONField = true | ||||
| 			f := structField{ | ||||
| 				// Allocate a new slice (len=N+1) to hold both | ||||
| 				// the parent index (len=N) and the current index (len=1). | ||||
| 				// Do this to avoid clobbering the memory of the parent index. | ||||
| 				index:        append(append(make([]int, 0, len(qe.index)+1), qe.index...), i), | ||||
| 				typ:          sf.Type, | ||||
| 				fieldOptions: options, | ||||
| 			} | ||||
| 			if sf.Anonymous && !f.hasName { | ||||
| 				if indirectType(f.typ).Kind() != reflect.Struct { | ||||
| 					serr = orErrorf(serr, t, "embedded Go struct field %s of non-struct type must be explicitly given a JSON name", sf.Name) | ||||
| 				} else { | ||||
| 					f.inline = true // implied by use of Go embedding without an explicit name | ||||
| 				} | ||||
| 			} | ||||
| 			if f.inline || f.unknown { | ||||
| 				// Handle an inlined field that serializes to/from | ||||
| 				// zero or more JSON object members. | ||||
|  | ||||
| 				switch f.fieldOptions { | ||||
| 				case fieldOptions{name: f.name, quotedName: f.quotedName, inline: true}: | ||||
| 				case fieldOptions{name: f.name, quotedName: f.quotedName, unknown: true}: | ||||
| 				case fieldOptions{name: f.name, quotedName: f.quotedName, inline: true, unknown: true}: | ||||
| 					serr = orErrorf(serr, t, "Go struct field %s cannot have both `inline` and `unknown` specified", sf.Name) | ||||
| 					f.inline = false // let `unknown` take precedence | ||||
| 				default: | ||||
| 					serr = orErrorf(serr, t, "Go struct field %s cannot have any options other than `inline` or `unknown` specified", sf.Name) | ||||
| 					if f.hasName { | ||||
| 						continue // invalid inlined field; treat as ignored | ||||
| 					} | ||||
| 					f.fieldOptions = fieldOptions{name: f.name, quotedName: f.quotedName, inline: f.inline, unknown: f.unknown} | ||||
| 					if f.inline && f.unknown { | ||||
| 						f.inline = false // let `unknown` take precedence | ||||
| 					} | ||||
| 				} | ||||
|  | ||||
| 				// Reject any types with custom serialization otherwise | ||||
| 				// it becomes impossible to know what sub-fields to inline. | ||||
| 				tf := indirectType(f.typ) | ||||
| 				if implementsAny(tf, allMethodTypes...) && tf != jsontextValueType { | ||||
| 					serr = orErrorf(serr, t, "inlined Go struct field %s of type %s must not implement marshal or unmarshal methods", sf.Name, tf) | ||||
| 				} | ||||
|  | ||||
| 				// Handle an inlined field that serializes to/from | ||||
| 				// a finite number of JSON object members backed by a Go struct. | ||||
| 				if tf.Kind() == reflect.Struct { | ||||
| 					if f.unknown { | ||||
| 						serr = orErrorf(serr, t, "inlined Go struct field %s of type %s with `unknown` tag must be a Go map of string key or a jsontext.Value", sf.Name, tf) | ||||
| 						continue // invalid inlined field; treat as ignored | ||||
| 					} | ||||
| 					if qe.visitChildren { | ||||
| 						queue = append(queue, queueEntry{tf, f.index, !seen[tf]}) | ||||
| 					} | ||||
| 					seen[tf] = true | ||||
| 					continue | ||||
| 				} else if !sf.IsExported() { | ||||
| 					serr = orErrorf(serr, t, "inlined Go struct field %s is not exported", sf.Name) | ||||
| 					continue // invalid inlined field; treat as ignored | ||||
| 				} | ||||
|  | ||||
| 				// Handle an inlined field that serializes to/from any number of | ||||
| 				// JSON object members back by a Go map or jsontext.Value. | ||||
| 				switch { | ||||
| 				case tf == jsontextValueType: | ||||
| 					f.fncs = nil // specially handled in arshal_inlined.go | ||||
| 				case tf.Kind() == reflect.Map && tf.Key().Kind() == reflect.String: | ||||
| 					if implementsAny(tf.Key(), allMethodTypes...) { | ||||
| 						serr = orErrorf(serr, t, "inlined map field %s of type %s must have a string key that does not implement marshal or unmarshal methods", sf.Name, tf) | ||||
| 						continue // invalid inlined field; treat as ignored | ||||
| 					} | ||||
| 					f.fncs = lookupArshaler(tf.Elem()) | ||||
| 				default: | ||||
| 					serr = orErrorf(serr, t, "inlined Go struct field %s of type %s must be a Go struct, Go map of string key, or jsontext.Value", sf.Name, tf) | ||||
| 					continue // invalid inlined field; treat as ignored | ||||
| 				} | ||||
|  | ||||
| 				// Reject multiple inlined fallback fields within the same struct. | ||||
| 				if inlinedFallbackIndex >= 0 { | ||||
| 					serr = orErrorf(serr, t, "inlined Go struct fields %s and %s cannot both be a Go map or jsontext.Value", t.Field(inlinedFallbackIndex).Name, sf.Name) | ||||
| 					// Still append f to inlinedFallbacks as there is still a | ||||
| 					// check for a dominant inlined fallback before returning. | ||||
| 				} | ||||
| 				inlinedFallbackIndex = i | ||||
|  | ||||
| 				inlinedFallbacks = append(inlinedFallbacks, f) | ||||
| 			} else { | ||||
| 				// Handle normal Go struct field that serializes to/from | ||||
| 				// a single JSON object member. | ||||
|  | ||||
| 				// Unexported fields cannot be serialized except for | ||||
| 				// embedded fields of a struct type, | ||||
| 				// which might promote exported fields of their own. | ||||
| 				if !sf.IsExported() { | ||||
| 					tf := indirectType(f.typ) | ||||
| 					if !(sf.Anonymous && tf.Kind() == reflect.Struct) { | ||||
| 						serr = orErrorf(serr, t, "Go struct field %s is not exported", sf.Name) | ||||
| 						continue | ||||
| 					} | ||||
| 					// Unfortunately, methods on the unexported field | ||||
| 					// still cannot be called. | ||||
| 					if implementsAny(tf, allMethodTypes...) || | ||||
| 						(f.omitzero && implementsAny(tf, isZeroerType)) { | ||||
| 						serr = orErrorf(serr, t, "Go struct field %s is not exported for method calls", sf.Name) | ||||
| 						continue | ||||
| 					} | ||||
| 				} | ||||
|  | ||||
| 				// Provide a function that uses a type's IsZero method. | ||||
| 				switch { | ||||
| 				case sf.Type.Kind() == reflect.Interface && sf.Type.Implements(isZeroerType): | ||||
| 					f.isZero = func(va addressableValue) bool { | ||||
| 						// Avoid panics calling IsZero on a nil interface or | ||||
| 						// non-nil interface with nil pointer. | ||||
| 						return va.IsNil() || (va.Elem().Kind() == reflect.Pointer && va.Elem().IsNil()) || va.Interface().(isZeroer).IsZero() | ||||
| 					} | ||||
| 				case sf.Type.Kind() == reflect.Pointer && sf.Type.Implements(isZeroerType): | ||||
| 					f.isZero = func(va addressableValue) bool { | ||||
| 						// Avoid panics calling IsZero on nil pointer. | ||||
| 						return va.IsNil() || va.Interface().(isZeroer).IsZero() | ||||
| 					} | ||||
| 				case sf.Type.Implements(isZeroerType): | ||||
| 					f.isZero = func(va addressableValue) bool { return va.Interface().(isZeroer).IsZero() } | ||||
| 				case reflect.PointerTo(sf.Type).Implements(isZeroerType): | ||||
| 					f.isZero = func(va addressableValue) bool { return va.Addr().Interface().(isZeroer).IsZero() } | ||||
| 				} | ||||
|  | ||||
| 				// Provide a function that can determine whether the value would | ||||
| 				// serialize as an empty JSON value. | ||||
| 				switch sf.Type.Kind() { | ||||
| 				case reflect.String, reflect.Map, reflect.Array, reflect.Slice: | ||||
| 					f.isEmpty = func(va addressableValue) bool { return va.Len() == 0 } | ||||
| 				case reflect.Pointer, reflect.Interface: | ||||
| 					f.isEmpty = func(va addressableValue) bool { return va.IsNil() } | ||||
| 				} | ||||
|  | ||||
| 				// Reject multiple fields with same name within the same struct. | ||||
| 				if j, ok := namesIndex[f.name]; ok { | ||||
| 					serr = orErrorf(serr, t, "Go struct fields %s and %s conflict over JSON object name %q", t.Field(j).Name, sf.Name, f.name) | ||||
| 					// Still append f to allFields as there is still a | ||||
| 					// check for a dominant field before returning. | ||||
| 				} | ||||
| 				namesIndex[f.name] = i | ||||
|  | ||||
| 				f.id = len(allFields) | ||||
| 				f.fncs = lookupArshaler(sf.Type) | ||||
| 				allFields = append(allFields, f) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		// NOTE: New users to the json package are occasionally surprised that | ||||
| 		// unexported fields are ignored. This occurs by necessity due to our | ||||
| 		// inability to directly introspect such fields with Go reflection | ||||
| 		// without the use of unsafe. | ||||
| 		// | ||||
| 		// To reduce friction here, refuse to serialize any Go struct that | ||||
| 		// has no JSON serializable fields, has at least one Go struct field, | ||||
| 		// and does not have any `json` tags present. For example, | ||||
| 		// errors returned by errors.New would fail to serialize. | ||||
| 		isEmptyStruct := t.NumField() == 0 | ||||
| 		if !isEmptyStruct && !hasAnyJSONTag && !hasAnyJSONField { | ||||
| 			serr = cmp.Or(serr, &SemanticError{GoType: t, Err: errNoExportedFields}) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Sort the fields by exact name (breaking ties by depth and | ||||
| 	// then by presence of an explicitly provided JSON name). | ||||
| 	// Select the dominant field from each set of fields with the same name. | ||||
| 	// If multiple fields have the same name, then the dominant field | ||||
| 	// is the one that exists alone at the shallowest depth, | ||||
| 	// or the one that is uniquely tagged with a JSON name. | ||||
| 	// Otherwise, no dominant field exists for the set. | ||||
| 	flattened := allFields[:0] | ||||
| 	slices.SortStableFunc(allFields, func(x, y structField) int { | ||||
| 		return cmp.Or( | ||||
| 			strings.Compare(x.name, y.name), | ||||
| 			cmp.Compare(len(x.index), len(y.index)), | ||||
| 			boolsCompare(!x.hasName, !y.hasName)) | ||||
| 	}) | ||||
| 	for len(allFields) > 0 { | ||||
| 		n := 1 // number of fields with the same exact name | ||||
| 		for n < len(allFields) && allFields[n-1].name == allFields[n].name { | ||||
| 			n++ | ||||
| 		} | ||||
| 		if n == 1 || len(allFields[0].index) != len(allFields[1].index) || allFields[0].hasName != allFields[1].hasName { | ||||
| 			flattened = append(flattened, allFields[0]) // only keep field if there is a dominant field | ||||
| 		} | ||||
| 		allFields = allFields[n:] | ||||
| 	} | ||||
|  | ||||
| 	// Sort the fields according to a breadth-first ordering | ||||
| 	// so that we can re-number IDs with the smallest possible values. | ||||
| 	// This optimizes use of uintSet such that it fits in the 64-entry bit set. | ||||
| 	slices.SortFunc(flattened, func(x, y structField) int { | ||||
| 		return cmp.Compare(x.id, y.id) | ||||
| 	}) | ||||
| 	for i := range flattened { | ||||
| 		flattened[i].id = i | ||||
| 	} | ||||
|  | ||||
| 	// Sort the fields according to a depth-first ordering | ||||
| 	// as the typical order that fields are marshaled. | ||||
| 	slices.SortFunc(flattened, func(x, y structField) int { | ||||
| 		return slices.Compare(x.index, y.index) | ||||
| 	}) | ||||
|  | ||||
| 	// Compute the mapping of fields in the byActualName map. | ||||
| 	// Pre-fold all names so that we can lookup folded names quickly. | ||||
| 	fs = structFields{ | ||||
| 		flattened:    flattened, | ||||
| 		byActualName: make(map[string]*structField, len(flattened)), | ||||
| 		byFoldedName: make(map[string][]*structField, len(flattened)), | ||||
| 	} | ||||
| 	for i, f := range fs.flattened { | ||||
| 		foldedName := string(foldName([]byte(f.name))) | ||||
| 		fs.byActualName[f.name] = &fs.flattened[i] | ||||
| 		fs.byFoldedName[foldedName] = append(fs.byFoldedName[foldedName], &fs.flattened[i]) | ||||
| 	} | ||||
| 	for foldedName, fields := range fs.byFoldedName { | ||||
| 		if len(fields) > 1 { | ||||
| 			// The precedence order for conflicting ignoreCase names | ||||
| 			// is by breadth-first order, rather than depth-first order. | ||||
| 			slices.SortFunc(fields, func(x, y *structField) int { | ||||
| 				return cmp.Compare(x.id, y.id) | ||||
| 			}) | ||||
| 			fs.byFoldedName[foldedName] = fields | ||||
| 		} | ||||
| 	} | ||||
| 	if n := len(inlinedFallbacks); n == 1 || (n > 1 && len(inlinedFallbacks[0].index) != len(inlinedFallbacks[1].index)) { | ||||
| 		fs.inlinedFallback = &inlinedFallbacks[0] // dominant inlined fallback field | ||||
| 	} | ||||
| 	fs.reindex() | ||||
| 	return fs, serr | ||||
| } | ||||
|  | ||||
| // indirectType unwraps one level of pointer indirection | ||||
| // similar to how Go only allows embedding either T or *T, | ||||
| // but not **T or P (which is a named pointer). | ||||
| func indirectType(t reflect.Type) reflect.Type { | ||||
| 	if t.Kind() == reflect.Pointer && t.Name() == "" { | ||||
| 		t = t.Elem() | ||||
| 	} | ||||
| 	return t | ||||
| } | ||||
|  | ||||
| // matchFoldedName matches a case-insensitive name depending on the options. | ||||
| // It assumes that foldName(f.name) == foldName(name). | ||||
| // | ||||
| // Case-insensitive matching is used if the `case:ignore` tag option is specified | ||||
| // or the MatchCaseInsensitiveNames call option is specified | ||||
| // (and the `case:strict` tag option is not specified). | ||||
| // Functionally, the `case:ignore` and `case:strict` tag options take precedence. | ||||
| // | ||||
| // The v1 definition of case-insensitivity operated under strings.EqualFold | ||||
| // and would strictly compare dashes and underscores, | ||||
| // while the v2 definition would ignore the presence of dashes and underscores. | ||||
| // Thus, if the MatchCaseSensitiveDelimiter call option is specified, | ||||
| // the match is further restricted to using strings.EqualFold. | ||||
| func (f *structField) matchFoldedName(name []byte, flags *jsonflags.Flags) bool { | ||||
| 	if f.casing == caseIgnore || (flags.Get(jsonflags.MatchCaseInsensitiveNames) && f.casing != caseStrict) { | ||||
| 		if !flags.Get(jsonflags.MatchCaseSensitiveDelimiter) || strings.EqualFold(string(name), f.name) { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| const ( | ||||
| 	caseIgnore = 1 | ||||
| 	caseStrict = 2 | ||||
| ) | ||||
|  | ||||
| type fieldOptions struct { | ||||
| 	name           string | ||||
| 	quotedName     string // quoted name per RFC 8785, section 3.2.2.2. | ||||
| 	hasName        bool | ||||
| 	nameNeedEscape bool | ||||
| 	casing         int8 // either 0, caseIgnore, or caseStrict | ||||
| 	inline         bool | ||||
| 	unknown        bool | ||||
| 	omitzero       bool | ||||
| 	omitempty      bool | ||||
| 	string         bool | ||||
| 	format         string | ||||
| } | ||||
|  | ||||
| // parseFieldOptions parses the `json` tag in a Go struct field as | ||||
| // a structured set of options configuring parameters such as | ||||
| // the JSON member name and other features. | ||||
| func parseFieldOptions(sf reflect.StructField) (out fieldOptions, ignored bool, err error) { | ||||
| 	tag, hasTag := sf.Tag.Lookup("json") | ||||
|  | ||||
| 	// Check whether this field is explicitly ignored. | ||||
| 	if tag == "-" { | ||||
| 		return fieldOptions{}, true, nil | ||||
| 	} | ||||
|  | ||||
| 	// Check whether this field is unexported and not embedded, | ||||
| 	// which Go reflection cannot mutate for the sake of serialization. | ||||
| 	// | ||||
| 	// An embedded field of an unexported type is still capable of | ||||
| 	// forwarding exported fields, which may be JSON serialized. | ||||
| 	// This technically operates on the edge of what is permissible by | ||||
| 	// the Go language, but the most recent decision is to permit this. | ||||
| 	// | ||||
| 	// See https://go.dev/issue/24153 and https://go.dev/issue/32772. | ||||
| 	if !sf.IsExported() && !sf.Anonymous { | ||||
| 		// Tag options specified on an unexported field suggests user error. | ||||
| 		if hasTag { | ||||
| 			err = cmp.Or(err, fmt.Errorf("unexported Go struct field %s cannot have non-ignored `json:%q` tag", sf.Name, tag)) | ||||
| 		} | ||||
| 		return fieldOptions{}, true, err | ||||
| 	} | ||||
|  | ||||
| 	// Determine the JSON member name for this Go field. A user-specified name | ||||
| 	// may be provided as either an identifier or a single-quoted string. | ||||
| 	// The single-quoted string allows arbitrary characters in the name. | ||||
| 	// See https://go.dev/issue/2718 and https://go.dev/issue/3546. | ||||
| 	out.name = sf.Name // always starts with an uppercase character | ||||
| 	if len(tag) > 0 && !strings.HasPrefix(tag, ",") { | ||||
| 		// For better compatibility with v1, accept almost any unescaped name. | ||||
| 		n := len(tag) - len(strings.TrimLeftFunc(tag, func(r rune) bool { | ||||
| 			return !strings.ContainsRune(",\\'\"`", r) // reserve comma, backslash, and quotes | ||||
| 		})) | ||||
| 		name := tag[:n] | ||||
|  | ||||
| 		// If the next character is not a comma, then the name is either | ||||
| 		// malformed (if n > 0) or a single-quoted name. | ||||
| 		// In either case, call consumeTagOption to handle it further. | ||||
| 		var err2 error | ||||
| 		if !strings.HasPrefix(tag[n:], ",") && len(name) != len(tag) { | ||||
| 			name, n, err2 = consumeTagOption(tag) | ||||
| 			if err2 != nil { | ||||
| 				err = cmp.Or(err, fmt.Errorf("Go struct field %s has malformed `json` tag: %v", sf.Name, err2)) | ||||
| 			} | ||||
| 		} | ||||
| 		if !utf8.ValidString(name) { | ||||
| 			err = cmp.Or(err, fmt.Errorf("Go struct field %s has JSON object name %q with invalid UTF-8", sf.Name, name)) | ||||
| 			name = string([]rune(name)) // replace invalid UTF-8 with utf8.RuneError | ||||
| 		} | ||||
| 		if err2 == nil { | ||||
| 			out.hasName = true | ||||
| 			out.name = name | ||||
| 		} | ||||
| 		tag = tag[n:] | ||||
| 	} | ||||
| 	b, _ := jsonwire.AppendQuote(nil, out.name, &jsonflags.Flags{}) | ||||
| 	out.quotedName = string(b) | ||||
| 	out.nameNeedEscape = jsonwire.NeedEscape(out.name) | ||||
|  | ||||
| 	// Handle any additional tag options (if any). | ||||
| 	var wasFormat bool | ||||
| 	seenOpts := make(map[string]bool) | ||||
| 	for len(tag) > 0 { | ||||
| 		// Consume comma delimiter. | ||||
| 		if tag[0] != ',' { | ||||
| 			err = cmp.Or(err, fmt.Errorf("Go struct field %s has malformed `json` tag: invalid character %q before next option (expecting ',')", sf.Name, tag[0])) | ||||
| 		} else { | ||||
| 			tag = tag[len(","):] | ||||
| 			if len(tag) == 0 { | ||||
| 				err = cmp.Or(err, fmt.Errorf("Go struct field %s has malformed `json` tag: invalid trailing ',' character", sf.Name)) | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		// Consume and process the tag option. | ||||
| 		opt, n, err2 := consumeTagOption(tag) | ||||
| 		if err2 != nil { | ||||
| 			err = cmp.Or(err, fmt.Errorf("Go struct field %s has malformed `json` tag: %v", sf.Name, err2)) | ||||
| 		} | ||||
| 		rawOpt := tag[:n] | ||||
| 		tag = tag[n:] | ||||
| 		switch { | ||||
| 		case wasFormat: | ||||
| 			err = cmp.Or(err, fmt.Errorf("Go struct field %s has `format` tag option that was not specified last", sf.Name)) | ||||
| 		case strings.HasPrefix(rawOpt, "'") && strings.TrimFunc(opt, isLetterOrDigit) == "": | ||||
| 			err = cmp.Or(err, fmt.Errorf("Go struct field %s has unnecessarily quoted appearance of `%s` tag option; specify `%s` instead", sf.Name, rawOpt, opt)) | ||||
| 		} | ||||
| 		switch opt { | ||||
| 		case "case": | ||||
| 			if !strings.HasPrefix(tag, ":") { | ||||
| 				err = cmp.Or(err, fmt.Errorf("Go struct field %s is missing value for `case` tag option; specify `case:ignore` or `case:strict` instead", sf.Name)) | ||||
| 				break | ||||
| 			} | ||||
| 			tag = tag[len(":"):] | ||||
| 			opt, n, err2 := consumeTagOption(tag) | ||||
| 			if err2 != nil { | ||||
| 				err = cmp.Or(err, fmt.Errorf("Go struct field %s has malformed value for `case` tag option: %v", sf.Name, err2)) | ||||
| 				break | ||||
| 			} | ||||
| 			rawOpt := tag[:n] | ||||
| 			tag = tag[n:] | ||||
| 			if strings.HasPrefix(rawOpt, "'") { | ||||
| 				err = cmp.Or(err, fmt.Errorf("Go struct field %s has unnecessarily quoted appearance of `case:%s` tag option; specify `case:%s` instead", sf.Name, rawOpt, opt)) | ||||
| 			} | ||||
| 			switch opt { | ||||
| 			case "ignore": | ||||
| 				out.casing |= caseIgnore | ||||
| 			case "strict": | ||||
| 				out.casing |= caseStrict | ||||
| 			default: | ||||
| 				err = cmp.Or(err, fmt.Errorf("Go struct field %s has unknown `case:%s` tag value", sf.Name, rawOpt)) | ||||
| 			} | ||||
| 		case "inline": | ||||
| 			out.inline = true | ||||
| 		case "unknown": | ||||
| 			out.unknown = true | ||||
| 		case "omitzero": | ||||
| 			out.omitzero = true | ||||
| 		case "omitempty": | ||||
| 			out.omitempty = true | ||||
| 		case "string": | ||||
| 			out.string = true | ||||
| 		case "format": | ||||
| 			if !strings.HasPrefix(tag, ":") { | ||||
| 				err = cmp.Or(err, fmt.Errorf("Go struct field %s is missing value for `format` tag option", sf.Name)) | ||||
| 				break | ||||
| 			} | ||||
| 			tag = tag[len(":"):] | ||||
| 			opt, n, err2 := consumeTagOption(tag) | ||||
| 			if err2 != nil { | ||||
| 				err = cmp.Or(err, fmt.Errorf("Go struct field %s has malformed value for `format` tag option: %v", sf.Name, err2)) | ||||
| 				break | ||||
| 			} | ||||
| 			tag = tag[n:] | ||||
| 			out.format = opt | ||||
| 			wasFormat = true | ||||
| 		default: | ||||
| 			// Reject keys that resemble one of the supported options. | ||||
| 			// This catches invalid mutants such as "omitEmpty" or "omit_empty". | ||||
| 			normOpt := strings.ReplaceAll(strings.ToLower(opt), "_", "") | ||||
| 			switch normOpt { | ||||
| 			case "case", "inline", "unknown", "omitzero", "omitempty", "string", "format": | ||||
| 				err = cmp.Or(err, fmt.Errorf("Go struct field %s has invalid appearance of `%s` tag option; specify `%s` instead", sf.Name, opt, normOpt)) | ||||
| 			} | ||||
|  | ||||
| 			// NOTE: Everything else is ignored. This does not mean it is | ||||
| 			// forward compatible to insert arbitrary tag options since | ||||
| 			// a future version of this package may understand that tag. | ||||
| 		} | ||||
|  | ||||
| 		// Reject duplicates. | ||||
| 		switch { | ||||
| 		case out.casing == caseIgnore|caseStrict: | ||||
| 			err = cmp.Or(err, fmt.Errorf("Go struct field %s cannot have both `case:ignore` and `case:strict` tag options", sf.Name)) | ||||
| 		case seenOpts[opt]: | ||||
| 			err = cmp.Or(err, fmt.Errorf("Go struct field %s has duplicate appearance of `%s` tag option", sf.Name, rawOpt)) | ||||
| 		} | ||||
| 		seenOpts[opt] = true | ||||
| 	} | ||||
| 	return out, false, err | ||||
| } | ||||
|  | ||||
| // consumeTagOption consumes the next option, | ||||
| // which is either a Go identifier or a single-quoted string. | ||||
| // If the next option is invalid, it returns all of in until the next comma, | ||||
| // and reports an error. | ||||
| func consumeTagOption(in string) (string, int, error) { | ||||
| 	// For legacy compatibility with v1, assume options are comma-separated. | ||||
| 	i := strings.IndexByte(in, ',') | ||||
| 	if i < 0 { | ||||
| 		i = len(in) | ||||
| 	} | ||||
|  | ||||
| 	switch r, _ := utf8.DecodeRuneInString(in); { | ||||
| 	// Option as a Go identifier. | ||||
| 	case r == '_' || unicode.IsLetter(r): | ||||
| 		n := len(in) - len(strings.TrimLeftFunc(in, isLetterOrDigit)) | ||||
| 		return in[:n], n, nil | ||||
| 	// Option as a single-quoted string. | ||||
| 	case r == '\'': | ||||
| 		// The grammar is nearly identical to a double-quoted Go string literal, | ||||
| 		// but uses single quotes as the terminators. The reason for a custom | ||||
| 		// grammar is because both backtick and double quotes cannot be used | ||||
| 		// verbatim in a struct tag. | ||||
| 		// | ||||
| 		// Convert a single-quoted string to a double-quote string and rely on | ||||
| 		// strconv.Unquote to handle the rest. | ||||
| 		var inEscape bool | ||||
| 		b := []byte{'"'} | ||||
| 		n := len(`'`) | ||||
| 		for len(in) > n { | ||||
| 			r, rn := utf8.DecodeRuneInString(in[n:]) | ||||
| 			switch { | ||||
| 			case inEscape: | ||||
| 				if r == '\'' { | ||||
| 					b = b[:len(b)-1] // remove escape character: `\'` => `'` | ||||
| 				} | ||||
| 				inEscape = false | ||||
| 			case r == '\\': | ||||
| 				inEscape = true | ||||
| 			case r == '"': | ||||
| 				b = append(b, '\\') // insert escape character: `"` => `\"` | ||||
| 			case r == '\'': | ||||
| 				b = append(b, '"') | ||||
| 				n += len(`'`) | ||||
| 				out, err := strconv.Unquote(string(b)) | ||||
| 				if err != nil { | ||||
| 					return in[:i], i, fmt.Errorf("invalid single-quoted string: %s", in[:n]) | ||||
| 				} | ||||
| 				return out, n, nil | ||||
| 			} | ||||
| 			b = append(b, in[n:][:rn]...) | ||||
| 			n += rn | ||||
| 		} | ||||
| 		if n > 10 { | ||||
| 			n = 10 // limit the amount of context printed in the error | ||||
| 		} | ||||
| 		return in[:i], i, fmt.Errorf("single-quoted string not terminated: %s...", in[:n]) | ||||
| 	case len(in) == 0: | ||||
| 		return in[:i], i, io.ErrUnexpectedEOF | ||||
| 	default: | ||||
| 		return in[:i], i, fmt.Errorf("invalid character %q at start of option (expecting Unicode letter or single quote)", r) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func isLetterOrDigit(r rune) bool { | ||||
| 	return r == '_' || unicode.IsLetter(r) || unicode.IsNumber(r) | ||||
| } | ||||
|  | ||||
| // boolsCompare compares x and y, ordering false before true. | ||||
| func boolsCompare(x, y bool) int { | ||||
| 	switch { | ||||
| 	case !x && y: | ||||
| 		return -1 | ||||
| 	default: | ||||
| 		return 0 | ||||
| 	case x && !y: | ||||
| 		return +1 | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										56
									
								
								vendor/github.com/go-json-experiment/json/fold.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								vendor/github.com/go-json-experiment/json/fold.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | ||||
| // Copyright 2020 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. | ||||
|  | ||||
| package json | ||||
|  | ||||
| import ( | ||||
| 	"unicode" | ||||
| 	"unicode/utf8" | ||||
| ) | ||||
|  | ||||
| // foldName returns a folded string such that foldName(x) == foldName(y) | ||||
| // is similar to strings.EqualFold(x, y), but ignores underscore and dashes. | ||||
| // This allows foldName to match common naming conventions. | ||||
| func foldName(in []byte) []byte { | ||||
| 	// This is inlinable to take advantage of "function outlining". | ||||
| 	// See https://blog.filippo.io/efficient-go-apis-with-the-inliner/ | ||||
| 	var arr [32]byte // large enough for most JSON names | ||||
| 	return appendFoldedName(arr[:0], in) | ||||
| } | ||||
| func appendFoldedName(out, in []byte) []byte { | ||||
| 	for i := 0; i < len(in); { | ||||
| 		// Handle single-byte ASCII. | ||||
| 		if c := in[i]; c < utf8.RuneSelf { | ||||
| 			if c != '_' && c != '-' { | ||||
| 				if 'a' <= c && c <= 'z' { | ||||
| 					c -= 'a' - 'A' | ||||
| 				} | ||||
| 				out = append(out, c) | ||||
| 			} | ||||
| 			i++ | ||||
| 			continue | ||||
| 		} | ||||
| 		// Handle multi-byte Unicode. | ||||
| 		r, n := utf8.DecodeRune(in[i:]) | ||||
| 		out = utf8.AppendRune(out, foldRune(r)) | ||||
| 		i += n | ||||
| 	} | ||||
| 	return out | ||||
| } | ||||
|  | ||||
| // foldRune is a variation on unicode.SimpleFold that returns the same rune | ||||
| // for all runes in the same fold set. | ||||
| // | ||||
| // Invariant: | ||||
| // | ||||
| //	foldRune(x) == foldRune(y) ⇔ strings.EqualFold(string(x), string(y)) | ||||
| func foldRune(r rune) rune { | ||||
| 	for { | ||||
| 		r2 := unicode.SimpleFold(r) | ||||
| 		if r2 <= r { | ||||
| 			return r2 // smallest character in the fold set | ||||
| 		} | ||||
| 		r = r2 | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										86
									
								
								vendor/github.com/go-json-experiment/json/intern.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								vendor/github.com/go-json-experiment/json/intern.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,86 @@ | ||||
| // Copyright 2022 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. | ||||
|  | ||||
| package json | ||||
|  | ||||
| import ( | ||||
| 	"encoding/binary" | ||||
| 	"math/bits" | ||||
| ) | ||||
|  | ||||
| // stringCache is a cache for strings converted from a []byte. | ||||
| type stringCache = [256]string // 256*unsafe.Sizeof(string("")) => 4KiB | ||||
|  | ||||
| // makeString returns the string form of b. | ||||
| // It returns a pre-allocated string from c if present, otherwise | ||||
| // it allocates a new string, inserts it into the cache, and returns it. | ||||
| func makeString(c *stringCache, b []byte) string { | ||||
| 	const ( | ||||
| 		minCachedLen = 2   // single byte strings are already interned by the runtime | ||||
| 		maxCachedLen = 256 // large enough for UUIDs, IPv6 addresses, SHA-256 checksums, etc. | ||||
| 	) | ||||
| 	if c == nil || len(b) < minCachedLen || len(b) > maxCachedLen { | ||||
| 		return string(b) | ||||
| 	} | ||||
|  | ||||
| 	// Compute a hash from the fixed-width prefix and suffix of the string. | ||||
| 	// This ensures hashing a string is a constant time operation. | ||||
| 	var h uint32 | ||||
| 	switch { | ||||
| 	case len(b) >= 8: | ||||
| 		lo := binary.LittleEndian.Uint64(b[:8]) | ||||
| 		hi := binary.LittleEndian.Uint64(b[len(b)-8:]) | ||||
| 		h = hash64(uint32(lo), uint32(lo>>32)) ^ hash64(uint32(hi), uint32(hi>>32)) | ||||
| 	case len(b) >= 4: | ||||
| 		lo := binary.LittleEndian.Uint32(b[:4]) | ||||
| 		hi := binary.LittleEndian.Uint32(b[len(b)-4:]) | ||||
| 		h = hash64(lo, hi) | ||||
| 	case len(b) >= 2: | ||||
| 		lo := binary.LittleEndian.Uint16(b[:2]) | ||||
| 		hi := binary.LittleEndian.Uint16(b[len(b)-2:]) | ||||
| 		h = hash64(uint32(lo), uint32(hi)) | ||||
| 	} | ||||
|  | ||||
| 	// Check the cache for the string. | ||||
| 	i := h % uint32(len(*c)) | ||||
| 	if s := (*c)[i]; s == string(b) { | ||||
| 		return s | ||||
| 	} | ||||
| 	s := string(b) | ||||
| 	(*c)[i] = s | ||||
| 	return s | ||||
| } | ||||
|  | ||||
| // hash64 returns the hash of two uint32s as a single uint32. | ||||
| func hash64(lo, hi uint32) uint32 { | ||||
| 	// If avalanche=true, this is identical to XXH32 hash on a 8B string: | ||||
| 	//	var b [8]byte | ||||
| 	//	binary.LittleEndian.PutUint32(b[:4], lo) | ||||
| 	//	binary.LittleEndian.PutUint32(b[4:], hi) | ||||
| 	//	return xxhash.Sum32(b[:]) | ||||
| 	const ( | ||||
| 		prime1 = 0x9e3779b1 | ||||
| 		prime2 = 0x85ebca77 | ||||
| 		prime3 = 0xc2b2ae3d | ||||
| 		prime4 = 0x27d4eb2f | ||||
| 		prime5 = 0x165667b1 | ||||
| 	) | ||||
| 	h := prime5 + uint32(8) | ||||
| 	h += lo * prime3 | ||||
| 	h = bits.RotateLeft32(h, 17) * prime4 | ||||
| 	h += hi * prime3 | ||||
| 	h = bits.RotateLeft32(h, 17) * prime4 | ||||
| 	// Skip final mix (avalanche) step of XXH32 for performance reasons. | ||||
| 	// Empirical testing shows that the improvements in unbiased distribution | ||||
| 	// does not outweigh the extra cost in computational complexity. | ||||
| 	const avalanche = false | ||||
| 	if avalanche { | ||||
| 		h ^= h >> 15 | ||||
| 		h *= prime2 | ||||
| 		h ^= h >> 13 | ||||
| 		h *= prime3 | ||||
| 		h ^= h >> 16 | ||||
| 	} | ||||
| 	return h | ||||
| } | ||||
							
								
								
									
										39
									
								
								vendor/github.com/go-json-experiment/json/internal/internal.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								vendor/github.com/go-json-experiment/json/internal/internal.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| // Copyright 2023 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. | ||||
|  | ||||
| package internal | ||||
|  | ||||
| import "errors" | ||||
|  | ||||
| // NotForPublicUse is a marker type that an API is for internal use only. | ||||
| // It does not perfectly prevent usage of that API, but helps to restrict usage. | ||||
| // Anything with this marker is not covered by the Go compatibility agreement. | ||||
| type NotForPublicUse struct{} | ||||
|  | ||||
| // AllowInternalUse is passed from "json" to "jsontext" to authenticate | ||||
| // that the caller can have access to internal functionality. | ||||
| var AllowInternalUse NotForPublicUse | ||||
|  | ||||
| // Sentinel error values internally shared between jsonv1 and jsonv2. | ||||
| var ( | ||||
| 	ErrCycle           = errors.New("encountered a cycle") | ||||
| 	ErrNonNilReference = errors.New("value must be passed as a non-nil pointer reference") | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	// TransformMarshalError converts a v2 error into a v1 error. | ||||
| 	// It is called only at the top-level of a Marshal function. | ||||
| 	TransformMarshalError func(any, error) error | ||||
| 	// NewMarshalerError constructs a jsonv1.MarshalerError. | ||||
| 	// It is called after a user-defined Marshal method/function fails. | ||||
| 	NewMarshalerError func(any, error, string) error | ||||
| 	// TransformUnmarshalError converts a v2 error into a v1 error. | ||||
| 	// It is called only at the top-level of a Unmarshal function. | ||||
| 	TransformUnmarshalError func(any, error) error | ||||
|  | ||||
| 	// NewRawNumber returns new(jsonv1.Number). | ||||
| 	NewRawNumber func() any | ||||
| 	// RawNumberOf returns jsonv1.Number(b). | ||||
| 	RawNumberOf func(b []byte) any | ||||
| ) | ||||
							
								
								
									
										203
									
								
								vendor/github.com/go-json-experiment/json/internal/jsonflags/flags.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										203
									
								
								vendor/github.com/go-json-experiment/json/internal/jsonflags/flags.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,203 @@ | ||||
| // Copyright 2023 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. | ||||
|  | ||||
| // jsonflags implements all the optional boolean flags. | ||||
| // These flags are shared across both "json", "jsontext", and "jsonopts". | ||||
| package jsonflags | ||||
|  | ||||
| import "github.com/go-json-experiment/json/internal" | ||||
|  | ||||
| // Bools represents zero or more boolean flags, all set to true or false. | ||||
| // The least-significant bit is the boolean value of all flags in the set. | ||||
| // The remaining bits identify which particular flags. | ||||
| // | ||||
| // In common usage, this is OR'd with 0 or 1. For example: | ||||
| //   - (AllowInvalidUTF8 | 0) means "AllowInvalidUTF8 is false" | ||||
| //   - (Multiline | Indent | 1) means "Multiline and Indent are true" | ||||
| type Bools uint64 | ||||
|  | ||||
| func (Bools) JSONOptions(internal.NotForPublicUse) {} | ||||
|  | ||||
| const ( | ||||
| 	// AllFlags is the set of all flags. | ||||
| 	AllFlags = AllCoderFlags | AllArshalV2Flags | AllArshalV1Flags | ||||
|  | ||||
| 	// AllCoderFlags is the set of all encoder/decoder flags. | ||||
| 	AllCoderFlags = (maxCoderFlag - 1) - initFlag | ||||
|  | ||||
| 	// AllArshalV2Flags is the set of all v2 marshal/unmarshal flags. | ||||
| 	AllArshalV2Flags = (maxArshalV2Flag - 1) - (maxCoderFlag - 1) | ||||
|  | ||||
| 	// AllArshalV1Flags is the set of all v1 marshal/unmarshal flags. | ||||
| 	AllArshalV1Flags = (maxArshalV1Flag - 1) - (maxArshalV2Flag - 1) | ||||
|  | ||||
| 	// NonBooleanFlags is the set of non-boolean flags, | ||||
| 	// where the value is some other concrete Go type. | ||||
| 	// The value of the flag is stored within jsonopts.Struct. | ||||
| 	NonBooleanFlags = 0 | | ||||
| 		Indent | | ||||
| 		IndentPrefix | | ||||
| 		ByteLimit | | ||||
| 		DepthLimit | | ||||
| 		Marshalers | | ||||
| 		Unmarshalers | ||||
|  | ||||
| 	// DefaultV1Flags is the set of booleans flags that default to true under | ||||
| 	// v1 semantics. None of the non-boolean flags differ between v1 and v2. | ||||
| 	DefaultV1Flags = 0 | | ||||
| 		AllowDuplicateNames | | ||||
| 		AllowInvalidUTF8 | | ||||
| 		EscapeForHTML | | ||||
| 		EscapeForJS | | ||||
| 		EscapeInvalidUTF8 | | ||||
| 		PreserveRawStrings | | ||||
| 		Deterministic | | ||||
| 		FormatNilMapAsNull | | ||||
| 		FormatNilSliceAsNull | | ||||
| 		MatchCaseInsensitiveNames | | ||||
| 		CallMethodsWithLegacySemantics | | ||||
| 		FormatBytesWithLegacySemantics | | ||||
| 		FormatTimeWithLegacySemantics | | ||||
| 		MatchCaseSensitiveDelimiter | | ||||
| 		MergeWithLegacySemantics | | ||||
| 		OmitEmptyWithLegacyDefinition | | ||||
| 		ReportErrorsWithLegacySemantics | | ||||
| 		StringifyWithLegacySemantics | | ||||
| 		UnmarshalArrayFromAnyLength | ||||
|  | ||||
| 	// AnyWhitespace reports whether the encoded output might have any whitespace. | ||||
| 	AnyWhitespace = Multiline | SpaceAfterColon | SpaceAfterComma | ||||
|  | ||||
| 	// WhitespaceFlags is the set of flags related to whitespace formatting. | ||||
| 	// In contrast to AnyWhitespace, this includes Indent and IndentPrefix | ||||
| 	// as those settings take no effect if Multiline is false. | ||||
| 	WhitespaceFlags = AnyWhitespace | Indent | IndentPrefix | ||||
|  | ||||
| 	// AnyEscape is the set of flags related to escaping in a JSON string. | ||||
| 	AnyEscape = EscapeForHTML | EscapeForJS | EscapeInvalidUTF8 | ||||
|  | ||||
| 	// CanonicalizeNumbers is the set of flags related to raw number canonicalization. | ||||
| 	CanonicalizeNumbers = CanonicalizeRawInts | CanonicalizeRawFloats | ||||
| ) | ||||
|  | ||||
| // Encoder and decoder flags. | ||||
| const ( | ||||
| 	initFlag Bools = 1 << iota // reserved for the boolean value itself | ||||
|  | ||||
| 	AllowDuplicateNames   // encode or decode | ||||
| 	AllowInvalidUTF8      // encode or decode | ||||
| 	WithinArshalCall      // encode or decode; for internal use by json.Marshal and json.Unmarshal | ||||
| 	OmitTopLevelNewline   // encode only; for internal use by json.Marshal and json.MarshalWrite | ||||
| 	PreserveRawStrings    // encode only | ||||
| 	CanonicalizeRawInts   // encode only | ||||
| 	CanonicalizeRawFloats // encode only | ||||
| 	ReorderRawObjects     // encode only | ||||
| 	EscapeForHTML         // encode only | ||||
| 	EscapeForJS           // encode only | ||||
| 	EscapeInvalidUTF8     // encode only; only exposed in v1 | ||||
| 	Multiline             // encode only | ||||
| 	SpaceAfterColon       // encode only | ||||
| 	SpaceAfterComma       // encode only | ||||
| 	Indent                // encode only; non-boolean flag | ||||
| 	IndentPrefix          // encode only; non-boolean flag | ||||
| 	ByteLimit             // encode or decode; non-boolean flag | ||||
| 	DepthLimit            // encode or decode; non-boolean flag | ||||
|  | ||||
| 	maxCoderFlag | ||||
| ) | ||||
|  | ||||
| // Marshal and Unmarshal flags (for v2). | ||||
| const ( | ||||
| 	_ Bools = (maxCoderFlag >> 1) << iota | ||||
|  | ||||
| 	StringifyNumbers          // marshal or unmarshal | ||||
| 	Deterministic             // marshal only | ||||
| 	FormatNilMapAsNull        // marshal only | ||||
| 	FormatNilSliceAsNull      // marshal only | ||||
| 	OmitZeroStructFields      // marshal only | ||||
| 	MatchCaseInsensitiveNames // marshal or unmarshal | ||||
| 	DiscardUnknownMembers     // marshal only | ||||
| 	RejectUnknownMembers      // unmarshal only | ||||
| 	Marshalers                // marshal only; non-boolean flag | ||||
| 	Unmarshalers              // unmarshal only; non-boolean flag | ||||
|  | ||||
| 	maxArshalV2Flag | ||||
| ) | ||||
|  | ||||
| // Marshal and Unmarshal flags (for v1). | ||||
| const ( | ||||
| 	_ Bools = (maxArshalV2Flag >> 1) << iota | ||||
|  | ||||
| 	CallMethodsWithLegacySemantics  // marshal or unmarshal | ||||
| 	FormatBytesWithLegacySemantics  // marshal or unmarshal | ||||
| 	FormatTimeWithLegacySemantics   // marshal or unmarshal | ||||
| 	MatchCaseSensitiveDelimiter     // marshal or unmarshal | ||||
| 	MergeWithLegacySemantics        // unmarshal | ||||
| 	OmitEmptyWithLegacyDefinition   // marshal | ||||
| 	ReportErrorsWithLegacySemantics // marshal or unmarshal | ||||
| 	StringifyWithLegacySemantics    // marshal or unmarshal | ||||
| 	StringifyBoolsAndStrings        // marshal or unmarshal; for internal use by jsonv2.makeStructArshaler | ||||
| 	UnmarshalAnyWithRawNumber       // unmarshal; for internal use by jsonv1.Decoder.UseNumber | ||||
| 	UnmarshalArrayFromAnyLength     // unmarshal | ||||
|  | ||||
| 	maxArshalV1Flag | ||||
| ) | ||||
|  | ||||
| // Flags is a set of boolean flags. | ||||
| // If the presence bit is zero, then the value bit must also be zero. | ||||
| // The least-significant bit of both fields is always zero. | ||||
| // | ||||
| // Unlike Bools, which can represent a set of bools that are all true or false, | ||||
| // Flags represents a set of bools, each individually may be true or false. | ||||
| type Flags struct{ Presence, Values uint64 } | ||||
|  | ||||
| // Join joins two sets of flags such that the latter takes precedence. | ||||
| func (dst *Flags) Join(src Flags) { | ||||
| 	// Copy over all source presence bits over to the destination (using OR), | ||||
| 	// then invert the source presence bits to clear out source value (using AND-NOT), | ||||
| 	// then copy over source value bits over to the destination (using OR). | ||||
| 	//	e.g., dst := Flags{Presence: 0b_1100_0011, Value: 0b_1000_0011} | ||||
| 	//	e.g., src := Flags{Presence: 0b_0101_1010, Value: 0b_1001_0010} | ||||
| 	dst.Presence |= src.Presence // e.g., 0b_1100_0011 | 0b_0101_1010 -> 0b_110_11011 | ||||
| 	dst.Values &= ^src.Presence  // e.g., 0b_1000_0011 & 0b_1010_0101 -> 0b_100_00001 | ||||
| 	dst.Values |= src.Values     // e.g., 0b_1000_0001 | 0b_1001_0010 -> 0b_100_10011 | ||||
| } | ||||
|  | ||||
| // Set sets both the presence and value for the provided bool (or set of bools). | ||||
| func (fs *Flags) Set(f Bools) { | ||||
| 	// Select out the bits for the flag identifiers (everything except LSB), | ||||
| 	// then set the presence for all the identifier bits (using OR), | ||||
| 	// then invert the identifier bits to clear out the values (using AND-NOT), | ||||
| 	// then copy over all the identifier bits to the value if LSB is 1. | ||||
| 	//	e.g., fs := Flags{Presence: 0b_0101_0010, Value: 0b_0001_0010} | ||||
| 	//	e.g., f := 0b_1001_0001 | ||||
| 	id := uint64(f) &^ uint64(1)  // e.g., 0b_1001_0001 & 0b_1111_1110 -> 0b_1001_0000 | ||||
| 	fs.Presence |= id             // e.g., 0b_0101_0010 | 0b_1001_0000 -> 0b_1101_0011 | ||||
| 	fs.Values &= ^id              // e.g., 0b_0001_0010 & 0b_0110_1111 -> 0b_0000_0010 | ||||
| 	fs.Values |= uint64(f&1) * id // e.g., 0b_0000_0010 | 0b_1001_0000 -> 0b_1001_0010 | ||||
| } | ||||
|  | ||||
| // Get reports whether the bool (or any of the bools) is true. | ||||
| // This is generally only used with a singular bool. | ||||
| // The value bit of f (i.e., the LSB) is ignored. | ||||
| func (fs Flags) Get(f Bools) bool { | ||||
| 	return fs.Values&uint64(f) > 0 | ||||
| } | ||||
|  | ||||
| // Has reports whether the bool (or any of the bools) is set. | ||||
| // The value bit of f (i.e., the LSB) is ignored. | ||||
| func (fs Flags) Has(f Bools) bool { | ||||
| 	return fs.Presence&uint64(f) > 0 | ||||
| } | ||||
|  | ||||
| // Clear clears both the presence and value for the provided bool or bools. | ||||
| // The value bit of f (i.e., the LSB) is ignored. | ||||
| func (fs *Flags) Clear(f Bools) { | ||||
| 	// Invert f to produce a mask to clear all bits in f (using AND). | ||||
| 	//	e.g., fs := Flags{Presence: 0b_0101_0010, Value: 0b_0001_0010} | ||||
| 	//	e.g., f := 0b_0001_1000 | ||||
| 	mask := uint64(^f)  // e.g., 0b_0001_1000 -> 0b_1110_0111 | ||||
| 	fs.Presence &= mask // e.g., 0b_0101_0010 &  0b_1110_0111 -> 0b_0100_0010 | ||||
| 	fs.Values &= mask   // e.g., 0b_0001_0010 &  0b_1110_0111 -> 0b_0000_0010 | ||||
| } | ||||
							
								
								
									
										200
									
								
								vendor/github.com/go-json-experiment/json/internal/jsonopts/options.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										200
									
								
								vendor/github.com/go-json-experiment/json/internal/jsonopts/options.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,200 @@ | ||||
| // Copyright 2023 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. | ||||
|  | ||||
| package jsonopts | ||||
|  | ||||
| import ( | ||||
| 	"github.com/go-json-experiment/json/internal" | ||||
| 	"github.com/go-json-experiment/json/internal/jsonflags" | ||||
| ) | ||||
|  | ||||
| // Options is the common options type shared across json packages. | ||||
| type Options interface { | ||||
| 	// JSONOptions is exported so related json packages can implement Options. | ||||
| 	JSONOptions(internal.NotForPublicUse) | ||||
| } | ||||
|  | ||||
| // Struct is the combination of all options in struct form. | ||||
| // This is efficient to pass down the call stack and to query. | ||||
| type Struct struct { | ||||
| 	Flags jsonflags.Flags | ||||
|  | ||||
| 	CoderValues | ||||
| 	ArshalValues | ||||
| } | ||||
|  | ||||
| type CoderValues struct { | ||||
| 	Indent       string // jsonflags.Indent | ||||
| 	IndentPrefix string // jsonflags.IndentPrefix | ||||
| 	ByteLimit    int64  // jsonflags.ByteLimit | ||||
| 	DepthLimit   int    // jsonflags.DepthLimit | ||||
| } | ||||
|  | ||||
| type ArshalValues struct { | ||||
| 	// The Marshalers and Unmarshalers fields use the any type to avoid a | ||||
| 	// concrete dependency on *json.Marshalers and *json.Unmarshalers, | ||||
| 	// which would in turn create a dependency on the "reflect" package. | ||||
|  | ||||
| 	Marshalers   any // jsonflags.Marshalers | ||||
| 	Unmarshalers any // jsonflags.Unmarshalers | ||||
|  | ||||
| 	Format      string | ||||
| 	FormatDepth int | ||||
| } | ||||
|  | ||||
| // DefaultOptionsV2 is the set of all options that define default v2 behavior. | ||||
| var DefaultOptionsV2 = Struct{ | ||||
| 	Flags: jsonflags.Flags{ | ||||
| 		Presence: uint64(jsonflags.AllFlags & ^jsonflags.WhitespaceFlags), | ||||
| 		Values:   uint64(0), | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| // DefaultOptionsV1 is the set of all options that define default v1 behavior. | ||||
| var DefaultOptionsV1 = Struct{ | ||||
| 	Flags: jsonflags.Flags{ | ||||
| 		Presence: uint64(jsonflags.AllFlags & ^jsonflags.WhitespaceFlags), | ||||
| 		Values:   uint64(jsonflags.DefaultV1Flags), | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| func (*Struct) JSONOptions(internal.NotForPublicUse) {} | ||||
|  | ||||
| // GetUnknownOption is injected by the "json" package to handle Options | ||||
| // declared in that package so that "jsonopts" can handle them. | ||||
| var GetUnknownOption = func(*Struct, Options) (any, bool) { panic("unknown option") } | ||||
|  | ||||
| func GetOption[T any](opts Options, setter func(T) Options) (T, bool) { | ||||
| 	// Collapse the options to *Struct to simplify lookup. | ||||
| 	structOpts, ok := opts.(*Struct) | ||||
| 	if !ok { | ||||
| 		var structOpts2 Struct | ||||
| 		structOpts2.Join(opts) | ||||
| 		structOpts = &structOpts2 | ||||
| 	} | ||||
|  | ||||
| 	// Lookup the option based on the return value of the setter. | ||||
| 	var zero T | ||||
| 	switch opt := setter(zero).(type) { | ||||
| 	case jsonflags.Bools: | ||||
| 		v := structOpts.Flags.Get(opt) | ||||
| 		ok := structOpts.Flags.Has(opt) | ||||
| 		return any(v).(T), ok | ||||
| 	case Indent: | ||||
| 		if !structOpts.Flags.Has(jsonflags.Indent) { | ||||
| 			return zero, false | ||||
| 		} | ||||
| 		return any(structOpts.Indent).(T), true | ||||
| 	case IndentPrefix: | ||||
| 		if !structOpts.Flags.Has(jsonflags.IndentPrefix) { | ||||
| 			return zero, false | ||||
| 		} | ||||
| 		return any(structOpts.IndentPrefix).(T), true | ||||
| 	case ByteLimit: | ||||
| 		if !structOpts.Flags.Has(jsonflags.ByteLimit) { | ||||
| 			return zero, false | ||||
| 		} | ||||
| 		return any(structOpts.ByteLimit).(T), true | ||||
| 	case DepthLimit: | ||||
| 		if !structOpts.Flags.Has(jsonflags.DepthLimit) { | ||||
| 			return zero, false | ||||
| 		} | ||||
| 		return any(structOpts.DepthLimit).(T), true | ||||
| 	default: | ||||
| 		v, ok := GetUnknownOption(structOpts, opt) | ||||
| 		return v.(T), ok | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // JoinUnknownOption is injected by the "json" package to handle Options | ||||
| // declared in that package so that "jsonopts" can handle them. | ||||
| var JoinUnknownOption = func(*Struct, Options) { panic("unknown option") } | ||||
|  | ||||
| func (dst *Struct) Join(srcs ...Options) { | ||||
| 	dst.join(false, srcs...) | ||||
| } | ||||
|  | ||||
| func (dst *Struct) JoinWithoutCoderOptions(srcs ...Options) { | ||||
| 	dst.join(true, srcs...) | ||||
| } | ||||
|  | ||||
| func (dst *Struct) join(excludeCoderOptions bool, srcs ...Options) { | ||||
| 	for _, src := range srcs { | ||||
| 		switch src := src.(type) { | ||||
| 		case nil: | ||||
| 			continue | ||||
| 		case jsonflags.Bools: | ||||
| 			if excludeCoderOptions { | ||||
| 				src &= ^jsonflags.AllCoderFlags | ||||
| 			} | ||||
| 			dst.Flags.Set(src) | ||||
| 		case Indent: | ||||
| 			if excludeCoderOptions { | ||||
| 				continue | ||||
| 			} | ||||
| 			dst.Flags.Set(jsonflags.Multiline | jsonflags.Indent | 1) | ||||
| 			dst.Indent = string(src) | ||||
| 		case IndentPrefix: | ||||
| 			if excludeCoderOptions { | ||||
| 				continue | ||||
| 			} | ||||
| 			dst.Flags.Set(jsonflags.Multiline | jsonflags.IndentPrefix | 1) | ||||
| 			dst.IndentPrefix = string(src) | ||||
| 		case ByteLimit: | ||||
| 			if excludeCoderOptions { | ||||
| 				continue | ||||
| 			} | ||||
| 			dst.Flags.Set(jsonflags.ByteLimit | 1) | ||||
| 			dst.ByteLimit = int64(src) | ||||
| 		case DepthLimit: | ||||
| 			if excludeCoderOptions { | ||||
| 				continue | ||||
| 			} | ||||
| 			dst.Flags.Set(jsonflags.DepthLimit | 1) | ||||
| 			dst.DepthLimit = int(src) | ||||
| 		case *Struct: | ||||
| 			srcFlags := src.Flags // shallow copy the flags | ||||
| 			if excludeCoderOptions { | ||||
| 				srcFlags.Clear(jsonflags.AllCoderFlags) | ||||
| 			} | ||||
| 			dst.Flags.Join(srcFlags) | ||||
| 			if srcFlags.Has(jsonflags.NonBooleanFlags) { | ||||
| 				if srcFlags.Has(jsonflags.Indent) { | ||||
| 					dst.Indent = src.Indent | ||||
| 				} | ||||
| 				if srcFlags.Has(jsonflags.IndentPrefix) { | ||||
| 					dst.IndentPrefix = src.IndentPrefix | ||||
| 				} | ||||
| 				if srcFlags.Has(jsonflags.ByteLimit) { | ||||
| 					dst.ByteLimit = src.ByteLimit | ||||
| 				} | ||||
| 				if srcFlags.Has(jsonflags.DepthLimit) { | ||||
| 					dst.DepthLimit = src.DepthLimit | ||||
| 				} | ||||
| 				if srcFlags.Has(jsonflags.Marshalers) { | ||||
| 					dst.Marshalers = src.Marshalers | ||||
| 				} | ||||
| 				if srcFlags.Has(jsonflags.Unmarshalers) { | ||||
| 					dst.Unmarshalers = src.Unmarshalers | ||||
| 				} | ||||
| 			} | ||||
| 		default: | ||||
| 			JoinUnknownOption(dst, src) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type ( | ||||
| 	Indent       string // jsontext.WithIndent | ||||
| 	IndentPrefix string // jsontext.WithIndentPrefix | ||||
| 	ByteLimit    int64  // jsontext.WithByteLimit | ||||
| 	DepthLimit   int    // jsontext.WithDepthLimit | ||||
| 	// type for jsonflags.Marshalers declared in "json" package | ||||
| 	// type for jsonflags.Unmarshalers declared in "json" package | ||||
| ) | ||||
|  | ||||
| func (Indent) JSONOptions(internal.NotForPublicUse)       {} | ||||
| func (IndentPrefix) JSONOptions(internal.NotForPublicUse) {} | ||||
| func (ByteLimit) JSONOptions(internal.NotForPublicUse)    {} | ||||
| func (DepthLimit) JSONOptions(internal.NotForPublicUse)   {} | ||||
							
								
								
									
										627
									
								
								vendor/github.com/go-json-experiment/json/internal/jsonwire/decode.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										627
									
								
								vendor/github.com/go-json-experiment/json/internal/jsonwire/decode.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,627 @@ | ||||
| // Copyright 2023 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. | ||||
|  | ||||
| package jsonwire | ||||
|  | ||||
| import ( | ||||
| 	"io" | ||||
| 	"math" | ||||
| 	"slices" | ||||
| 	"strconv" | ||||
| 	"unicode/utf16" | ||||
| 	"unicode/utf8" | ||||
| ) | ||||
|  | ||||
| type ValueFlags uint | ||||
|  | ||||
| const ( | ||||
| 	_ ValueFlags = (1 << iota) / 2 // powers of two starting with zero | ||||
|  | ||||
| 	stringNonVerbatim  // string cannot be naively treated as valid UTF-8 | ||||
| 	stringNonCanonical // string not formatted according to RFC 8785, section 3.2.2.2. | ||||
| 	// TODO: Track whether a number is a non-integer? | ||||
| ) | ||||
|  | ||||
| func (f *ValueFlags) Join(f2 ValueFlags) { *f |= f2 } | ||||
| func (f ValueFlags) IsVerbatim() bool    { return f&stringNonVerbatim == 0 } | ||||
| func (f ValueFlags) IsCanonical() bool   { return f&stringNonCanonical == 0 } | ||||
|  | ||||
| // ConsumeWhitespace consumes leading JSON whitespace per RFC 7159, section 2. | ||||
| func ConsumeWhitespace(b []byte) (n int) { | ||||
| 	// NOTE: The arguments and logic are kept simple to keep this inlinable. | ||||
| 	for len(b) > n && (b[n] == ' ' || b[n] == '\t' || b[n] == '\r' || b[n] == '\n') { | ||||
| 		n++ | ||||
| 	} | ||||
| 	return n | ||||
| } | ||||
|  | ||||
| // ConsumeNull consumes the next JSON null literal per RFC 7159, section 3. | ||||
| // It returns 0 if it is invalid, in which case consumeLiteral should be used. | ||||
| func ConsumeNull(b []byte) int { | ||||
| 	// NOTE: The arguments and logic are kept simple to keep this inlinable. | ||||
| 	const literal = "null" | ||||
| 	if len(b) >= len(literal) && string(b[:len(literal)]) == literal { | ||||
| 		return len(literal) | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| // ConsumeFalse consumes the next JSON false literal per RFC 7159, section 3. | ||||
| // It returns 0 if it is invalid, in which case consumeLiteral should be used. | ||||
| func ConsumeFalse(b []byte) int { | ||||
| 	// NOTE: The arguments and logic are kept simple to keep this inlinable. | ||||
| 	const literal = "false" | ||||
| 	if len(b) >= len(literal) && string(b[:len(literal)]) == literal { | ||||
| 		return len(literal) | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| // ConsumeTrue consumes the next JSON true literal per RFC 7159, section 3. | ||||
| // It returns 0 if it is invalid, in which case consumeLiteral should be used. | ||||
| func ConsumeTrue(b []byte) int { | ||||
| 	// NOTE: The arguments and logic are kept simple to keep this inlinable. | ||||
| 	const literal = "true" | ||||
| 	if len(b) >= len(literal) && string(b[:len(literal)]) == literal { | ||||
| 		return len(literal) | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| // ConsumeLiteral consumes the next JSON literal per RFC 7159, section 3. | ||||
| // If the input appears truncated, it returns io.ErrUnexpectedEOF. | ||||
| func ConsumeLiteral(b []byte, lit string) (n int, err error) { | ||||
| 	for i := 0; i < len(b) && i < len(lit); i++ { | ||||
| 		if b[i] != lit[i] { | ||||
| 			return i, NewInvalidCharacterError(b[i:], "in literal "+lit+" (expecting "+strconv.QuoteRune(rune(lit[i]))+")") | ||||
| 		} | ||||
| 	} | ||||
| 	if len(b) < len(lit) { | ||||
| 		return len(b), io.ErrUnexpectedEOF | ||||
| 	} | ||||
| 	return len(lit), nil | ||||
| } | ||||
|  | ||||
| // ConsumeSimpleString consumes the next JSON string per RFC 7159, section 7 | ||||
| // but is limited to the grammar for an ASCII string without escape sequences. | ||||
| // It returns 0 if it is invalid or more complicated than a simple string, | ||||
| // in which case consumeString should be called. | ||||
| // | ||||
| // It rejects '<', '>', and '&' for compatibility reasons since these were | ||||
| // always escaped in the v1 implementation. Thus, if this function reports | ||||
| // non-zero then we know that the string would be encoded the same way | ||||
| // under both v1 or v2 escape semantics. | ||||
| func ConsumeSimpleString(b []byte) (n int) { | ||||
| 	// NOTE: The arguments and logic are kept simple to keep this inlinable. | ||||
| 	if len(b) > 0 && b[0] == '"' { | ||||
| 		n++ | ||||
| 		for len(b) > n && b[n] < utf8.RuneSelf && escapeASCII[b[n]] == 0 { | ||||
| 			n++ | ||||
| 		} | ||||
| 		if uint(len(b)) > uint(n) && b[n] == '"' { | ||||
| 			n++ | ||||
| 			return n | ||||
| 		} | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| // ConsumeString consumes the next JSON string per RFC 7159, section 7. | ||||
| // If validateUTF8 is false, then this allows the presence of invalid UTF-8 | ||||
| // characters within the string itself. | ||||
| // It reports the number of bytes consumed and whether an error was encountered. | ||||
| // If the input appears truncated, it returns io.ErrUnexpectedEOF. | ||||
| func ConsumeString(flags *ValueFlags, b []byte, validateUTF8 bool) (n int, err error) { | ||||
| 	return ConsumeStringResumable(flags, b, 0, validateUTF8) | ||||
| } | ||||
|  | ||||
| // ConsumeStringResumable is identical to consumeString but supports resuming | ||||
| // from a previous call that returned io.ErrUnexpectedEOF. | ||||
| func ConsumeStringResumable(flags *ValueFlags, b []byte, resumeOffset int, validateUTF8 bool) (n int, err error) { | ||||
| 	// Consume the leading double quote. | ||||
| 	switch { | ||||
| 	case resumeOffset > 0: | ||||
| 		n = resumeOffset // already handled the leading quote | ||||
| 	case uint(len(b)) == 0: | ||||
| 		return n, io.ErrUnexpectedEOF | ||||
| 	case b[0] == '"': | ||||
| 		n++ | ||||
| 	default: | ||||
| 		return n, NewInvalidCharacterError(b[n:], `at start of string (expecting '"')`) | ||||
| 	} | ||||
|  | ||||
| 	// Consume every character in the string. | ||||
| 	for uint(len(b)) > uint(n) { | ||||
| 		// Optimize for long sequences of unescaped characters. | ||||
| 		noEscape := func(c byte) bool { | ||||
| 			return c < utf8.RuneSelf && ' ' <= c && c != '\\' && c != '"' | ||||
| 		} | ||||
| 		for uint(len(b)) > uint(n) && noEscape(b[n]) { | ||||
| 			n++ | ||||
| 		} | ||||
| 		if uint(len(b)) <= uint(n) { | ||||
| 			return n, io.ErrUnexpectedEOF | ||||
| 		} | ||||
|  | ||||
| 		// Check for terminating double quote. | ||||
| 		if b[n] == '"' { | ||||
| 			n++ | ||||
| 			return n, nil | ||||
| 		} | ||||
|  | ||||
| 		switch r, rn := utf8.DecodeRune(b[n:]); { | ||||
| 		// Handle UTF-8 encoded byte sequence. | ||||
| 		// Due to specialized handling of ASCII above, we know that | ||||
| 		// all normal sequences at this point must be 2 bytes or larger. | ||||
| 		case rn > 1: | ||||
| 			n += rn | ||||
| 		// Handle escape sequence. | ||||
| 		case r == '\\': | ||||
| 			flags.Join(stringNonVerbatim) | ||||
| 			resumeOffset = n | ||||
| 			if uint(len(b)) < uint(n+2) { | ||||
| 				return resumeOffset, io.ErrUnexpectedEOF | ||||
| 			} | ||||
| 			switch r := b[n+1]; r { | ||||
| 			case '/': | ||||
| 				// Forward slash is the only character with 3 representations. | ||||
| 				// Per RFC 8785, section 3.2.2.2., this must not be escaped. | ||||
| 				flags.Join(stringNonCanonical) | ||||
| 				n += 2 | ||||
| 			case '"', '\\', 'b', 'f', 'n', 'r', 't': | ||||
| 				n += 2 | ||||
| 			case 'u': | ||||
| 				if uint(len(b)) < uint(n+6) { | ||||
| 					if hasEscapedUTF16Prefix(b[n:], false) { | ||||
| 						return resumeOffset, io.ErrUnexpectedEOF | ||||
| 					} | ||||
| 					flags.Join(stringNonCanonical) | ||||
| 					return n, NewInvalidEscapeSequenceError(b[n:]) | ||||
| 				} | ||||
| 				v1, ok := parseHexUint16(b[n+2 : n+6]) | ||||
| 				if !ok { | ||||
| 					flags.Join(stringNonCanonical) | ||||
| 					return n, NewInvalidEscapeSequenceError(b[n : n+6]) | ||||
| 				} | ||||
| 				// Only certain control characters can use the \uFFFF notation | ||||
| 				// for canonical formatting (per RFC 8785, section 3.2.2.2.). | ||||
| 				switch v1 { | ||||
| 				// \uFFFF notation not permitted for these characters. | ||||
| 				case '\b', '\f', '\n', '\r', '\t': | ||||
| 					flags.Join(stringNonCanonical) | ||||
| 				default: | ||||
| 					// \uFFFF notation only permitted for control characters. | ||||
| 					if v1 >= ' ' { | ||||
| 						flags.Join(stringNonCanonical) | ||||
| 					} else { | ||||
| 						// \uFFFF notation must be lower case. | ||||
| 						for _, c := range b[n+2 : n+6] { | ||||
| 							if 'A' <= c && c <= 'F' { | ||||
| 								flags.Join(stringNonCanonical) | ||||
| 							} | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 				n += 6 | ||||
|  | ||||
| 				r := rune(v1) | ||||
| 				if validateUTF8 && utf16.IsSurrogate(r) { | ||||
| 					if uint(len(b)) < uint(n+6) { | ||||
| 						if hasEscapedUTF16Prefix(b[n:], true) { | ||||
| 							return resumeOffset, io.ErrUnexpectedEOF | ||||
| 						} | ||||
| 						flags.Join(stringNonCanonical) | ||||
| 						return n - 6, NewInvalidEscapeSequenceError(b[n-6:]) | ||||
| 					} else if v2, ok := parseHexUint16(b[n+2 : n+6]); b[n] != '\\' || b[n+1] != 'u' || !ok { | ||||
| 						flags.Join(stringNonCanonical) | ||||
| 						return n - 6, NewInvalidEscapeSequenceError(b[n-6 : n+6]) | ||||
| 					} else if r = utf16.DecodeRune(rune(v1), rune(v2)); r == utf8.RuneError { | ||||
| 						flags.Join(stringNonCanonical) | ||||
| 						return n - 6, NewInvalidEscapeSequenceError(b[n-6 : n+6]) | ||||
| 					} else { | ||||
| 						n += 6 | ||||
| 					} | ||||
| 				} | ||||
| 			default: | ||||
| 				flags.Join(stringNonCanonical) | ||||
| 				return n, NewInvalidEscapeSequenceError(b[n : n+2]) | ||||
| 			} | ||||
| 		// Handle invalid UTF-8. | ||||
| 		case r == utf8.RuneError: | ||||
| 			if !utf8.FullRune(b[n:]) { | ||||
| 				return n, io.ErrUnexpectedEOF | ||||
| 			} | ||||
| 			flags.Join(stringNonVerbatim | stringNonCanonical) | ||||
| 			if validateUTF8 { | ||||
| 				return n, ErrInvalidUTF8 | ||||
| 			} | ||||
| 			n++ | ||||
| 		// Handle invalid control characters. | ||||
| 		case r < ' ': | ||||
| 			flags.Join(stringNonVerbatim | stringNonCanonical) | ||||
| 			return n, NewInvalidCharacterError(b[n:], "in string (expecting non-control character)") | ||||
| 		default: | ||||
| 			panic("BUG: unhandled character " + QuoteRune(b[n:])) | ||||
| 		} | ||||
| 	} | ||||
| 	return n, io.ErrUnexpectedEOF | ||||
| } | ||||
|  | ||||
| // AppendUnquote appends the unescaped form of a JSON string in src to dst. | ||||
| // Any invalid UTF-8 within the string will be replaced with utf8.RuneError, | ||||
| // but the error will be specified as having encountered such an error. | ||||
| // The input must be an entire JSON string with no surrounding whitespace. | ||||
| func AppendUnquote[Bytes ~[]byte | ~string](dst []byte, src Bytes) (v []byte, err error) { | ||||
| 	dst = slices.Grow(dst, len(src)) | ||||
|  | ||||
| 	// Consume the leading double quote. | ||||
| 	var i, n int | ||||
| 	switch { | ||||
| 	case uint(len(src)) == 0: | ||||
| 		return dst, io.ErrUnexpectedEOF | ||||
| 	case src[0] == '"': | ||||
| 		i, n = 1, 1 | ||||
| 	default: | ||||
| 		return dst, NewInvalidCharacterError(src, `at start of string (expecting '"')`) | ||||
| 	} | ||||
|  | ||||
| 	// Consume every character in the string. | ||||
| 	for uint(len(src)) > uint(n) { | ||||
| 		// Optimize for long sequences of unescaped characters. | ||||
| 		noEscape := func(c byte) bool { | ||||
| 			return c < utf8.RuneSelf && ' ' <= c && c != '\\' && c != '"' | ||||
| 		} | ||||
| 		for uint(len(src)) > uint(n) && noEscape(src[n]) { | ||||
| 			n++ | ||||
| 		} | ||||
| 		if uint(len(src)) <= uint(n) { | ||||
| 			dst = append(dst, src[i:n]...) | ||||
| 			return dst, io.ErrUnexpectedEOF | ||||
| 		} | ||||
|  | ||||
| 		// Check for terminating double quote. | ||||
| 		if src[n] == '"' { | ||||
| 			dst = append(dst, src[i:n]...) | ||||
| 			n++ | ||||
| 			if n < len(src) { | ||||
| 				err = NewInvalidCharacterError(src[n:], "after string value") | ||||
| 			} | ||||
| 			return dst, err | ||||
| 		} | ||||
|  | ||||
| 		switch r, rn := utf8.DecodeRuneInString(string(truncateMaxUTF8(src[n:]))); { | ||||
| 		// Handle UTF-8 encoded byte sequence. | ||||
| 		// Due to specialized handling of ASCII above, we know that | ||||
| 		// all normal sequences at this point must be 2 bytes or larger. | ||||
| 		case rn > 1: | ||||
| 			n += rn | ||||
| 		// Handle escape sequence. | ||||
| 		case r == '\\': | ||||
| 			dst = append(dst, src[i:n]...) | ||||
|  | ||||
| 			// Handle escape sequence. | ||||
| 			if uint(len(src)) < uint(n+2) { | ||||
| 				return dst, io.ErrUnexpectedEOF | ||||
| 			} | ||||
| 			switch r := src[n+1]; r { | ||||
| 			case '"', '\\', '/': | ||||
| 				dst = append(dst, r) | ||||
| 				n += 2 | ||||
| 			case 'b': | ||||
| 				dst = append(dst, '\b') | ||||
| 				n += 2 | ||||
| 			case 'f': | ||||
| 				dst = append(dst, '\f') | ||||
| 				n += 2 | ||||
| 			case 'n': | ||||
| 				dst = append(dst, '\n') | ||||
| 				n += 2 | ||||
| 			case 'r': | ||||
| 				dst = append(dst, '\r') | ||||
| 				n += 2 | ||||
| 			case 't': | ||||
| 				dst = append(dst, '\t') | ||||
| 				n += 2 | ||||
| 			case 'u': | ||||
| 				if uint(len(src)) < uint(n+6) { | ||||
| 					if hasEscapedUTF16Prefix(src[n:], false) { | ||||
| 						return dst, io.ErrUnexpectedEOF | ||||
| 					} | ||||
| 					return dst, NewInvalidEscapeSequenceError(src[n:]) | ||||
| 				} | ||||
| 				v1, ok := parseHexUint16(src[n+2 : n+6]) | ||||
| 				if !ok { | ||||
| 					return dst, NewInvalidEscapeSequenceError(src[n : n+6]) | ||||
| 				} | ||||
| 				n += 6 | ||||
|  | ||||
| 				// Check whether this is a surrogate half. | ||||
| 				r := rune(v1) | ||||
| 				if utf16.IsSurrogate(r) { | ||||
| 					r = utf8.RuneError // assume failure unless the following succeeds | ||||
| 					if uint(len(src)) < uint(n+6) { | ||||
| 						if hasEscapedUTF16Prefix(src[n:], true) { | ||||
| 							return utf8.AppendRune(dst, r), io.ErrUnexpectedEOF | ||||
| 						} | ||||
| 						err = NewInvalidEscapeSequenceError(src[n-6:]) | ||||
| 					} else if v2, ok := parseHexUint16(src[n+2 : n+6]); src[n] != '\\' || src[n+1] != 'u' || !ok { | ||||
| 						err = NewInvalidEscapeSequenceError(src[n-6 : n+6]) | ||||
| 					} else if r = utf16.DecodeRune(rune(v1), rune(v2)); r == utf8.RuneError { | ||||
| 						err = NewInvalidEscapeSequenceError(src[n-6 : n+6]) | ||||
| 					} else { | ||||
| 						n += 6 | ||||
| 					} | ||||
| 				} | ||||
|  | ||||
| 				dst = utf8.AppendRune(dst, r) | ||||
| 			default: | ||||
| 				return dst, NewInvalidEscapeSequenceError(src[n : n+2]) | ||||
| 			} | ||||
| 			i = n | ||||
| 		// Handle invalid UTF-8. | ||||
| 		case r == utf8.RuneError: | ||||
| 			dst = append(dst, src[i:n]...) | ||||
| 			if !utf8.FullRuneInString(string(truncateMaxUTF8(src[n:]))) { | ||||
| 				return dst, io.ErrUnexpectedEOF | ||||
| 			} | ||||
| 			// NOTE: An unescaped string may be longer than the escaped string | ||||
| 			// because invalid UTF-8 bytes are being replaced. | ||||
| 			dst = append(dst, "\uFFFD"...) | ||||
| 			n += rn | ||||
| 			i = n | ||||
| 			err = ErrInvalidUTF8 | ||||
| 		// Handle invalid control characters. | ||||
| 		case r < ' ': | ||||
| 			dst = append(dst, src[i:n]...) | ||||
| 			return dst, NewInvalidCharacterError(src[n:], "in string (expecting non-control character)") | ||||
| 		default: | ||||
| 			panic("BUG: unhandled character " + QuoteRune(src[n:])) | ||||
| 		} | ||||
| 	} | ||||
| 	dst = append(dst, src[i:n]...) | ||||
| 	return dst, io.ErrUnexpectedEOF | ||||
| } | ||||
|  | ||||
| // hasEscapedUTF16Prefix reports whether b is possibly | ||||
| // the truncated prefix of a \uFFFF escape sequence. | ||||
| func hasEscapedUTF16Prefix[Bytes ~[]byte | ~string](b Bytes, lowerSurrogateHalf bool) bool { | ||||
| 	for i := range len(b) { | ||||
| 		switch c := b[i]; { | ||||
| 		case i == 0 && c != '\\': | ||||
| 			return false | ||||
| 		case i == 1 && c != 'u': | ||||
| 			return false | ||||
| 		case i == 2 && lowerSurrogateHalf && c != 'd' && c != 'D': | ||||
| 			return false // not within ['\uDC00':'\uDFFF'] | ||||
| 		case i == 3 && lowerSurrogateHalf && !('c' <= c && c <= 'f') && !('C' <= c && c <= 'F'): | ||||
| 			return false // not within ['\uDC00':'\uDFFF'] | ||||
| 		case i >= 2 && i < 6 && !('0' <= c && c <= '9') && !('a' <= c && c <= 'f') && !('A' <= c && c <= 'F'): | ||||
| 			return false | ||||
| 		} | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| // UnquoteMayCopy returns the unescaped form of b. | ||||
| // If there are no escaped characters, the output is simply a subslice of | ||||
| // the input with the surrounding quotes removed. | ||||
| // Otherwise, a new buffer is allocated for the output. | ||||
| // It assumes the input is valid. | ||||
| func UnquoteMayCopy(b []byte, isVerbatim bool) []byte { | ||||
| 	// NOTE: The arguments and logic are kept simple to keep this inlinable. | ||||
| 	if isVerbatim { | ||||
| 		return b[len(`"`) : len(b)-len(`"`)] | ||||
| 	} | ||||
| 	b, _ = AppendUnquote(nil, b) | ||||
| 	return b | ||||
| } | ||||
|  | ||||
| // ConsumeSimpleNumber consumes the next JSON number per RFC 7159, section 6 | ||||
| // but is limited to the grammar for a positive integer. | ||||
| // It returns 0 if it is invalid or more complicated than a simple integer, | ||||
| // in which case consumeNumber should be called. | ||||
| func ConsumeSimpleNumber(b []byte) (n int) { | ||||
| 	// NOTE: The arguments and logic are kept simple to keep this inlinable. | ||||
| 	if len(b) > 0 { | ||||
| 		if b[0] == '0' { | ||||
| 			n++ | ||||
| 		} else if '1' <= b[0] && b[0] <= '9' { | ||||
| 			n++ | ||||
| 			for len(b) > n && ('0' <= b[n] && b[n] <= '9') { | ||||
| 				n++ | ||||
| 			} | ||||
| 		} else { | ||||
| 			return 0 | ||||
| 		} | ||||
| 		if uint(len(b)) <= uint(n) || (b[n] != '.' && b[n] != 'e' && b[n] != 'E') { | ||||
| 			return n | ||||
| 		} | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| type ConsumeNumberState uint | ||||
|  | ||||
| const ( | ||||
| 	consumeNumberInit ConsumeNumberState = iota | ||||
| 	beforeIntegerDigits | ||||
| 	withinIntegerDigits | ||||
| 	beforeFractionalDigits | ||||
| 	withinFractionalDigits | ||||
| 	beforeExponentDigits | ||||
| 	withinExponentDigits | ||||
| ) | ||||
|  | ||||
| // ConsumeNumber consumes the next JSON number per RFC 7159, section 6. | ||||
| // It reports the number of bytes consumed and whether an error was encountered. | ||||
| // If the input appears truncated, it returns io.ErrUnexpectedEOF. | ||||
| // | ||||
| // Note that JSON numbers are not self-terminating. | ||||
| // If the entire input is consumed, then the caller needs to consider whether | ||||
| // there may be subsequent unread data that may still be part of this number. | ||||
| func ConsumeNumber(b []byte) (n int, err error) { | ||||
| 	n, _, err = ConsumeNumberResumable(b, 0, consumeNumberInit) | ||||
| 	return n, err | ||||
| } | ||||
|  | ||||
| // ConsumeNumberResumable is identical to consumeNumber but supports resuming | ||||
| // from a previous call that returned io.ErrUnexpectedEOF. | ||||
| func ConsumeNumberResumable(b []byte, resumeOffset int, state ConsumeNumberState) (n int, _ ConsumeNumberState, err error) { | ||||
| 	// Jump to the right state when resuming from a partial consumption. | ||||
| 	n = resumeOffset | ||||
| 	if state > consumeNumberInit { | ||||
| 		switch state { | ||||
| 		case withinIntegerDigits, withinFractionalDigits, withinExponentDigits: | ||||
| 			// Consume leading digits. | ||||
| 			for uint(len(b)) > uint(n) && ('0' <= b[n] && b[n] <= '9') { | ||||
| 				n++ | ||||
| 			} | ||||
| 			if uint(len(b)) <= uint(n) { | ||||
| 				return n, state, nil // still within the same state | ||||
| 			} | ||||
| 			state++ // switches "withinX" to "beforeY" where Y is the state after X | ||||
| 		} | ||||
| 		switch state { | ||||
| 		case beforeIntegerDigits: | ||||
| 			goto beforeInteger | ||||
| 		case beforeFractionalDigits: | ||||
| 			goto beforeFractional | ||||
| 		case beforeExponentDigits: | ||||
| 			goto beforeExponent | ||||
| 		default: | ||||
| 			return n, state, nil | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Consume required integer component (with optional minus sign). | ||||
| beforeInteger: | ||||
| 	resumeOffset = n | ||||
| 	if uint(len(b)) > 0 && b[0] == '-' { | ||||
| 		n++ | ||||
| 	} | ||||
| 	switch { | ||||
| 	case uint(len(b)) <= uint(n): | ||||
| 		return resumeOffset, beforeIntegerDigits, io.ErrUnexpectedEOF | ||||
| 	case b[n] == '0': | ||||
| 		n++ | ||||
| 		state = beforeFractionalDigits | ||||
| 	case '1' <= b[n] && b[n] <= '9': | ||||
| 		n++ | ||||
| 		for uint(len(b)) > uint(n) && ('0' <= b[n] && b[n] <= '9') { | ||||
| 			n++ | ||||
| 		} | ||||
| 		state = withinIntegerDigits | ||||
| 	default: | ||||
| 		return n, state, NewInvalidCharacterError(b[n:], "in number (expecting digit)") | ||||
| 	} | ||||
|  | ||||
| 	// Consume optional fractional component. | ||||
| beforeFractional: | ||||
| 	if uint(len(b)) > uint(n) && b[n] == '.' { | ||||
| 		resumeOffset = n | ||||
| 		n++ | ||||
| 		switch { | ||||
| 		case uint(len(b)) <= uint(n): | ||||
| 			return resumeOffset, beforeFractionalDigits, io.ErrUnexpectedEOF | ||||
| 		case '0' <= b[n] && b[n] <= '9': | ||||
| 			n++ | ||||
| 		default: | ||||
| 			return n, state, NewInvalidCharacterError(b[n:], "in number (expecting digit)") | ||||
| 		} | ||||
| 		for uint(len(b)) > uint(n) && ('0' <= b[n] && b[n] <= '9') { | ||||
| 			n++ | ||||
| 		} | ||||
| 		state = withinFractionalDigits | ||||
| 	} | ||||
|  | ||||
| 	// Consume optional exponent component. | ||||
| beforeExponent: | ||||
| 	if uint(len(b)) > uint(n) && (b[n] == 'e' || b[n] == 'E') { | ||||
| 		resumeOffset = n | ||||
| 		n++ | ||||
| 		if uint(len(b)) > uint(n) && (b[n] == '-' || b[n] == '+') { | ||||
| 			n++ | ||||
| 		} | ||||
| 		switch { | ||||
| 		case uint(len(b)) <= uint(n): | ||||
| 			return resumeOffset, beforeExponentDigits, io.ErrUnexpectedEOF | ||||
| 		case '0' <= b[n] && b[n] <= '9': | ||||
| 			n++ | ||||
| 		default: | ||||
| 			return n, state, NewInvalidCharacterError(b[n:], "in number (expecting digit)") | ||||
| 		} | ||||
| 		for uint(len(b)) > uint(n) && ('0' <= b[n] && b[n] <= '9') { | ||||
| 			n++ | ||||
| 		} | ||||
| 		state = withinExponentDigits | ||||
| 	} | ||||
|  | ||||
| 	return n, state, nil | ||||
| } | ||||
|  | ||||
| // parseHexUint16 is similar to strconv.ParseUint, | ||||
| // but operates directly on []byte and is optimized for base-16. | ||||
| // See https://go.dev/issue/42429. | ||||
| func parseHexUint16[Bytes ~[]byte | ~string](b Bytes) (v uint16, ok bool) { | ||||
| 	if len(b) != 4 { | ||||
| 		return 0, false | ||||
| 	} | ||||
| 	for i := range 4 { | ||||
| 		c := b[i] | ||||
| 		switch { | ||||
| 		case '0' <= c && c <= '9': | ||||
| 			c = c - '0' | ||||
| 		case 'a' <= c && c <= 'f': | ||||
| 			c = 10 + c - 'a' | ||||
| 		case 'A' <= c && c <= 'F': | ||||
| 			c = 10 + c - 'A' | ||||
| 		default: | ||||
| 			return 0, false | ||||
| 		} | ||||
| 		v = v*16 + uint16(c) | ||||
| 	} | ||||
| 	return v, true | ||||
| } | ||||
|  | ||||
| // ParseUint parses b as a decimal unsigned integer according to | ||||
| // a strict subset of the JSON number grammar, returning the value if valid. | ||||
| // It returns (0, false) if there is a syntax error and | ||||
| // returns (math.MaxUint64, false) if there is an overflow. | ||||
| func ParseUint(b []byte) (v uint64, ok bool) { | ||||
| 	const unsafeWidth = 20 // len(fmt.Sprint(uint64(math.MaxUint64))) | ||||
| 	var n int | ||||
| 	for ; len(b) > n && ('0' <= b[n] && b[n] <= '9'); n++ { | ||||
| 		v = 10*v + uint64(b[n]-'0') | ||||
| 	} | ||||
| 	switch { | ||||
| 	case n == 0 || len(b) != n || (b[0] == '0' && string(b) != "0"): | ||||
| 		return 0, false | ||||
| 	case n >= unsafeWidth && (b[0] != '1' || v < 1e19 || n > unsafeWidth): | ||||
| 		return math.MaxUint64, false | ||||
| 	} | ||||
| 	return v, true | ||||
| } | ||||
|  | ||||
| // ParseFloat parses a floating point number according to the Go float grammar. | ||||
| // Note that the JSON number grammar is a strict subset. | ||||
| // | ||||
| // If the number overflows the finite representation of a float, | ||||
| // then we return MaxFloat since any finite value will always be infinitely | ||||
| // more accurate at representing another finite value than an infinite value. | ||||
| func ParseFloat(b []byte, bits int) (v float64, ok bool) { | ||||
| 	fv, err := strconv.ParseFloat(string(b), bits) | ||||
| 	if math.IsInf(fv, 0) { | ||||
| 		switch { | ||||
| 		case bits == 32 && math.IsInf(fv, +1): | ||||
| 			fv = +math.MaxFloat32 | ||||
| 		case bits == 64 && math.IsInf(fv, +1): | ||||
| 			fv = +math.MaxFloat64 | ||||
| 		case bits == 32 && math.IsInf(fv, -1): | ||||
| 			fv = -math.MaxFloat32 | ||||
| 		case bits == 64 && math.IsInf(fv, -1): | ||||
| 			fv = -math.MaxFloat64 | ||||
| 		} | ||||
| 	} | ||||
| 	return fv, err == nil | ||||
| } | ||||
							
								
								
									
										292
									
								
								vendor/github.com/go-json-experiment/json/internal/jsonwire/encode.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										292
									
								
								vendor/github.com/go-json-experiment/json/internal/jsonwire/encode.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,292 @@ | ||||
| // Copyright 2023 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. | ||||
|  | ||||
| package jsonwire | ||||
|  | ||||
| import ( | ||||
| 	"math" | ||||
| 	"slices" | ||||
| 	"strconv" | ||||
| 	"unicode/utf16" | ||||
| 	"unicode/utf8" | ||||
|  | ||||
| 	"github.com/go-json-experiment/json/internal/jsonflags" | ||||
| ) | ||||
|  | ||||
| // escapeASCII reports whether the ASCII character needs to be escaped. | ||||
| // It conservatively assumes EscapeForHTML. | ||||
| var escapeASCII = [...]uint8{ | ||||
| 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // escape control characters | ||||
| 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // escape control characters | ||||
| 	0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, // escape '"' and '&' | ||||
| 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, // escape '<' and '>' | ||||
| 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||||
| 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, // escape '\\' | ||||
| 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||||
| 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||||
| } | ||||
|  | ||||
| // NeedEscape reports whether src needs escaping of any characters. | ||||
| // It conservatively assumes EscapeForHTML and EscapeForJS. | ||||
| // It reports true for inputs with invalid UTF-8. | ||||
| func NeedEscape[Bytes ~[]byte | ~string](src Bytes) bool { | ||||
| 	var i int | ||||
| 	for uint(len(src)) > uint(i) { | ||||
| 		if c := src[i]; c < utf8.RuneSelf { | ||||
| 			if escapeASCII[c] > 0 { | ||||
| 				return true | ||||
| 			} | ||||
| 			i++ | ||||
| 		} else { | ||||
| 			r, rn := utf8.DecodeRuneInString(string(truncateMaxUTF8(src[i:]))) | ||||
| 			if r == utf8.RuneError || r == '\u2028' || r == '\u2029' { | ||||
| 				return true | ||||
| 			} | ||||
| 			i += rn | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // AppendQuote appends src to dst as a JSON string per RFC 7159, section 7. | ||||
| // | ||||
| // It takes in flags and respects the following: | ||||
| //   - EscapeForHTML escapes '<', '>', and '&'. | ||||
| //   - EscapeForJS escapes '\u2028' and '\u2029'. | ||||
| //   - AllowInvalidUTF8 avoids reporting an error for invalid UTF-8. | ||||
| // | ||||
| // Regardless of whether AllowInvalidUTF8 is specified, | ||||
| // invalid bytes are replaced with the Unicode replacement character ('\ufffd'). | ||||
| // If no escape flags are set, then the shortest representable form is used, | ||||
| // which is also the canonical form for strings (RFC 8785, section 3.2.2.2). | ||||
| func AppendQuote[Bytes ~[]byte | ~string](dst []byte, src Bytes, flags *jsonflags.Flags) ([]byte, error) { | ||||
| 	var i, n int | ||||
| 	var hasInvalidUTF8 bool | ||||
| 	dst = slices.Grow(dst, len(`"`)+len(src)+len(`"`)) | ||||
| 	dst = append(dst, '"') | ||||
| 	for uint(len(src)) > uint(n) { | ||||
| 		if c := src[n]; c < utf8.RuneSelf { | ||||
| 			// Handle single-byte ASCII. | ||||
| 			n++ | ||||
| 			if escapeASCII[c] == 0 { | ||||
| 				continue // no escaping possibly needed | ||||
| 			} | ||||
| 			// Handle escaping of single-byte ASCII. | ||||
| 			if !(c == '<' || c == '>' || c == '&') || flags.Get(jsonflags.EscapeForHTML) { | ||||
| 				dst = append(dst, src[i:n-1]...) | ||||
| 				dst = appendEscapedASCII(dst, c) | ||||
| 				i = n | ||||
| 			} | ||||
| 		} else { | ||||
| 			// Handle multi-byte Unicode. | ||||
| 			r, rn := utf8.DecodeRuneInString(string(truncateMaxUTF8(src[n:]))) | ||||
| 			n += rn | ||||
| 			if r != utf8.RuneError && r != '\u2028' && r != '\u2029' { | ||||
| 				continue // no escaping possibly needed | ||||
| 			} | ||||
| 			// Handle escaping of multi-byte Unicode. | ||||
| 			switch { | ||||
| 			case isInvalidUTF8(r, rn): | ||||
| 				hasInvalidUTF8 = true | ||||
| 				dst = append(dst, src[i:n-rn]...) | ||||
| 				if flags.Get(jsonflags.EscapeInvalidUTF8) { | ||||
| 					dst = append(dst, `\ufffd`...) | ||||
| 				} else { | ||||
| 					dst = append(dst, "\ufffd"...) | ||||
| 				} | ||||
| 				i = n | ||||
| 			case (r == '\u2028' || r == '\u2029') && flags.Get(jsonflags.EscapeForJS): | ||||
| 				dst = append(dst, src[i:n-rn]...) | ||||
| 				dst = appendEscapedUnicode(dst, r) | ||||
| 				i = n | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	dst = append(dst, src[i:n]...) | ||||
| 	dst = append(dst, '"') | ||||
| 	if hasInvalidUTF8 && !flags.Get(jsonflags.AllowInvalidUTF8) { | ||||
| 		return dst, ErrInvalidUTF8 | ||||
| 	} | ||||
| 	return dst, nil | ||||
| } | ||||
|  | ||||
| func appendEscapedASCII(dst []byte, c byte) []byte { | ||||
| 	switch c { | ||||
| 	case '"', '\\': | ||||
| 		dst = append(dst, '\\', c) | ||||
| 	case '\b': | ||||
| 		dst = append(dst, "\\b"...) | ||||
| 	case '\f': | ||||
| 		dst = append(dst, "\\f"...) | ||||
| 	case '\n': | ||||
| 		dst = append(dst, "\\n"...) | ||||
| 	case '\r': | ||||
| 		dst = append(dst, "\\r"...) | ||||
| 	case '\t': | ||||
| 		dst = append(dst, "\\t"...) | ||||
| 	default: | ||||
| 		dst = appendEscapedUTF16(dst, uint16(c)) | ||||
| 	} | ||||
| 	return dst | ||||
| } | ||||
|  | ||||
| func appendEscapedUnicode(dst []byte, r rune) []byte { | ||||
| 	if r1, r2 := utf16.EncodeRune(r); r1 != '\ufffd' && r2 != '\ufffd' { | ||||
| 		dst = appendEscapedUTF16(dst, uint16(r1)) | ||||
| 		dst = appendEscapedUTF16(dst, uint16(r2)) | ||||
| 	} else { | ||||
| 		dst = appendEscapedUTF16(dst, uint16(r)) | ||||
| 	} | ||||
| 	return dst | ||||
| } | ||||
|  | ||||
| func appendEscapedUTF16(dst []byte, x uint16) []byte { | ||||
| 	const hex = "0123456789abcdef" | ||||
| 	return append(dst, '\\', 'u', hex[(x>>12)&0xf], hex[(x>>8)&0xf], hex[(x>>4)&0xf], hex[(x>>0)&0xf]) | ||||
| } | ||||
|  | ||||
| // ReformatString consumes a JSON string from src and appends it to dst, | ||||
| // reformatting it if necessary according to the specified flags. | ||||
| // It returns the appended output and the number of consumed input bytes. | ||||
| func ReformatString(dst, src []byte, flags *jsonflags.Flags) ([]byte, int, error) { | ||||
| 	// TODO: Should this update ValueFlags as input? | ||||
| 	var valFlags ValueFlags | ||||
| 	n, err := ConsumeString(&valFlags, src, !flags.Get(jsonflags.AllowInvalidUTF8)) | ||||
| 	if err != nil { | ||||
| 		return dst, n, err | ||||
| 	} | ||||
|  | ||||
| 	// If the output requires no special escapes, and the input | ||||
| 	// is already in canonical form or should be preserved verbatim, | ||||
| 	// then directly copy the input to the output. | ||||
| 	if !flags.Get(jsonflags.AnyEscape) && | ||||
| 		(valFlags.IsCanonical() || flags.Get(jsonflags.PreserveRawStrings)) { | ||||
| 		dst = append(dst, src[:n]...) // copy the string verbatim | ||||
| 		return dst, n, nil | ||||
| 	} | ||||
|  | ||||
| 	// Under [jsonflags.PreserveRawStrings], any pre-escaped sequences | ||||
| 	// remain escaped, however we still need to respect the | ||||
| 	// [jsonflags.EscapeForHTML] and [jsonflags.EscapeForJS] options. | ||||
| 	if flags.Get(jsonflags.PreserveRawStrings) { | ||||
| 		var i, lastAppendIndex int | ||||
| 		for i < n { | ||||
| 			if c := src[i]; c < utf8.RuneSelf { | ||||
| 				if (c == '<' || c == '>' || c == '&') && flags.Get(jsonflags.EscapeForHTML) { | ||||
| 					dst = append(dst, src[lastAppendIndex:i]...) | ||||
| 					dst = appendEscapedASCII(dst, c) | ||||
| 					lastAppendIndex = i + 1 | ||||
| 				} | ||||
| 				i++ | ||||
| 			} else { | ||||
| 				r, rn := utf8.DecodeRune(truncateMaxUTF8(src[i:])) | ||||
| 				if (r == '\u2028' || r == '\u2029') && flags.Get(jsonflags.EscapeForJS) { | ||||
| 					dst = append(dst, src[lastAppendIndex:i]...) | ||||
| 					dst = appendEscapedUnicode(dst, r) | ||||
| 					lastAppendIndex = i + rn | ||||
| 				} | ||||
| 				i += rn | ||||
| 			} | ||||
| 		} | ||||
| 		return append(dst, src[lastAppendIndex:n]...), n, nil | ||||
| 	} | ||||
|  | ||||
| 	// The input contains characters that might need escaping, | ||||
| 	// unnecessary escape sequences, or invalid UTF-8. | ||||
| 	// Perform a round-trip unquote and quote to properly reformat | ||||
| 	// these sequences according the current flags. | ||||
| 	b, _ := AppendUnquote(nil, src[:n]) | ||||
| 	dst, _ = AppendQuote(dst, b, flags) | ||||
| 	return dst, n, nil | ||||
| } | ||||
|  | ||||
| // AppendFloat appends src to dst as a JSON number per RFC 7159, section 6. | ||||
| // It formats numbers similar to the ES6 number-to-string conversion. | ||||
| // See https://go.dev/issue/14135. | ||||
| // | ||||
| // The output is identical to ECMA-262, 6th edition, section 7.1.12.1 and with | ||||
| // RFC 8785, section 3.2.2.3 for 64-bit floating-point numbers except for -0, | ||||
| // which is formatted as -0 instead of just 0. | ||||
| // | ||||
| // For 32-bit floating-point numbers, | ||||
| // the output is a 32-bit equivalent of the algorithm. | ||||
| // Note that ECMA-262 specifies no algorithm for 32-bit numbers. | ||||
| func AppendFloat(dst []byte, src float64, bits int) []byte { | ||||
| 	if bits == 32 { | ||||
| 		src = float64(float32(src)) | ||||
| 	} | ||||
|  | ||||
| 	abs := math.Abs(src) | ||||
| 	fmt := byte('f') | ||||
| 	if abs != 0 { | ||||
| 		if bits == 64 && (float64(abs) < 1e-6 || float64(abs) >= 1e21) || | ||||
| 			bits == 32 && (float32(abs) < 1e-6 || float32(abs) >= 1e21) { | ||||
| 			fmt = 'e' | ||||
| 		} | ||||
| 	} | ||||
| 	dst = strconv.AppendFloat(dst, src, fmt, -1, bits) | ||||
| 	if fmt == 'e' { | ||||
| 		// Clean up e-09 to e-9. | ||||
| 		n := len(dst) | ||||
| 		if n >= 4 && dst[n-4] == 'e' && dst[n-3] == '-' && dst[n-2] == '0' { | ||||
| 			dst[n-2] = dst[n-1] | ||||
| 			dst = dst[:n-1] | ||||
| 		} | ||||
| 	} | ||||
| 	return dst | ||||
| } | ||||
|  | ||||
| // ReformatNumber consumes a JSON string from src and appends it to dst, | ||||
| // canonicalizing it if specified. | ||||
| // It returns the appended output and the number of consumed input bytes. | ||||
| func ReformatNumber(dst, src []byte, flags *jsonflags.Flags) ([]byte, int, error) { | ||||
| 	n, err := ConsumeNumber(src) | ||||
| 	if err != nil { | ||||
| 		return dst, n, err | ||||
| 	} | ||||
| 	if !flags.Get(jsonflags.CanonicalizeNumbers) { | ||||
| 		dst = append(dst, src[:n]...) // copy the number verbatim | ||||
| 		return dst, n, nil | ||||
| 	} | ||||
|  | ||||
| 	// Identify the kind of number. | ||||
| 	var isFloat bool | ||||
| 	for _, c := range src[:n] { | ||||
| 		if c == '.' || c == 'e' || c == 'E' { | ||||
| 			isFloat = true // has fraction or exponent | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Check if need to canonicalize this kind of number. | ||||
| 	switch { | ||||
| 	case string(src[:n]) == "-0": | ||||
| 		break // canonicalize -0 as 0 regardless of kind | ||||
| 	case isFloat: | ||||
| 		if !flags.Get(jsonflags.CanonicalizeRawFloats) { | ||||
| 			dst = append(dst, src[:n]...) // copy the number verbatim | ||||
| 			return dst, n, nil | ||||
| 		} | ||||
| 	default: | ||||
| 		// As an optimization, we can copy integer numbers below 2⁵³ verbatim | ||||
| 		// since the canonical form is always identical. | ||||
| 		const maxExactIntegerDigits = 16 // len(strconv.AppendUint(nil, 1<<53, 10)) | ||||
| 		if !flags.Get(jsonflags.CanonicalizeRawInts) || n < maxExactIntegerDigits { | ||||
| 			dst = append(dst, src[:n]...) // copy the number verbatim | ||||
| 			return dst, n, nil | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Parse and reformat the number (which uses a canonical format). | ||||
| 	fv, _ := strconv.ParseFloat(string(src[:n]), 64) | ||||
| 	switch { | ||||
| 	case fv == 0: | ||||
| 		fv = 0 // normalize negative zero as just zero | ||||
| 	case math.IsInf(fv, +1): | ||||
| 		fv = +math.MaxFloat64 | ||||
| 	case math.IsInf(fv, -1): | ||||
| 		fv = -math.MaxFloat64 | ||||
| 	} | ||||
| 	return AppendFloat(dst, fv, 64), n, nil | ||||
| } | ||||
							
								
								
									
										215
									
								
								vendor/github.com/go-json-experiment/json/internal/jsonwire/wire.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										215
									
								
								vendor/github.com/go-json-experiment/json/internal/jsonwire/wire.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,215 @@ | ||||
| // Copyright 2023 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. | ||||
|  | ||||
| // Package jsonwire implements stateless functionality for handling JSON text. | ||||
| package jsonwire | ||||
|  | ||||
| import ( | ||||
| 	"cmp" | ||||
| 	"errors" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"unicode" | ||||
| 	"unicode/utf16" | ||||
| 	"unicode/utf8" | ||||
| ) | ||||
|  | ||||
| // TrimSuffixWhitespace trims JSON from the end of b. | ||||
| func TrimSuffixWhitespace(b []byte) []byte { | ||||
| 	// NOTE: The arguments and logic are kept simple to keep this inlinable. | ||||
| 	n := len(b) - 1 | ||||
| 	for n >= 0 && (b[n] == ' ' || b[n] == '\t' || b[n] == '\r' || b[n] == '\n') { | ||||
| 		n-- | ||||
| 	} | ||||
| 	return b[:n+1] | ||||
| } | ||||
|  | ||||
| // TrimSuffixString trims a valid JSON string at the end of b. | ||||
| // The behavior is undefined if there is not a valid JSON string present. | ||||
| func TrimSuffixString(b []byte) []byte { | ||||
| 	// NOTE: The arguments and logic are kept simple to keep this inlinable. | ||||
| 	if len(b) > 0 && b[len(b)-1] == '"' { | ||||
| 		b = b[:len(b)-1] | ||||
| 	} | ||||
| 	for len(b) >= 2 && !(b[len(b)-1] == '"' && b[len(b)-2] != '\\') { | ||||
| 		b = b[:len(b)-1] // trim all characters except an unescaped quote | ||||
| 	} | ||||
| 	if len(b) > 0 && b[len(b)-1] == '"' { | ||||
| 		b = b[:len(b)-1] | ||||
| 	} | ||||
| 	return b | ||||
| } | ||||
|  | ||||
| // HasSuffixByte reports whether b ends with c. | ||||
| func HasSuffixByte(b []byte, c byte) bool { | ||||
| 	// NOTE: The arguments and logic are kept simple to keep this inlinable. | ||||
| 	return len(b) > 0 && b[len(b)-1] == c | ||||
| } | ||||
|  | ||||
| // TrimSuffixByte removes c from the end of b if it is present. | ||||
| func TrimSuffixByte(b []byte, c byte) []byte { | ||||
| 	// NOTE: The arguments and logic are kept simple to keep this inlinable. | ||||
| 	if len(b) > 0 && b[len(b)-1] == c { | ||||
| 		return b[:len(b)-1] | ||||
| 	} | ||||
| 	return b | ||||
| } | ||||
|  | ||||
| // QuoteRune quotes the first rune in the input. | ||||
| func QuoteRune[Bytes ~[]byte | ~string](b Bytes) string { | ||||
| 	r, n := utf8.DecodeRuneInString(string(truncateMaxUTF8(b))) | ||||
| 	if r == utf8.RuneError && n == 1 { | ||||
| 		return `'\x` + strconv.FormatUint(uint64(b[0]), 16) + `'` | ||||
| 	} | ||||
| 	return strconv.QuoteRune(r) | ||||
| } | ||||
|  | ||||
| // CompareUTF16 lexicographically compares x to y according | ||||
| // to the UTF-16 codepoints of the UTF-8 encoded input strings. | ||||
| // This implements the ordering specified in RFC 8785, section 3.2.3. | ||||
| func CompareUTF16[Bytes ~[]byte | ~string](x, y Bytes) int { | ||||
| 	// NOTE: This is an optimized, mostly allocation-free implementation | ||||
| 	// of CompareUTF16Simple in wire_test.go. FuzzCompareUTF16 verifies that the | ||||
| 	// two implementations agree on the result of comparing any two strings. | ||||
| 	isUTF16Self := func(r rune) bool { | ||||
| 		return ('\u0000' <= r && r <= '\uD7FF') || ('\uE000' <= r && r <= '\uFFFF') | ||||
| 	} | ||||
|  | ||||
| 	for { | ||||
| 		if len(x) == 0 || len(y) == 0 { | ||||
| 			return cmp.Compare(len(x), len(y)) | ||||
| 		} | ||||
|  | ||||
| 		// ASCII fast-path. | ||||
| 		if x[0] < utf8.RuneSelf || y[0] < utf8.RuneSelf { | ||||
| 			if x[0] != y[0] { | ||||
| 				return cmp.Compare(x[0], y[0]) | ||||
| 			} | ||||
| 			x, y = x[1:], y[1:] | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		// Decode next pair of runes as UTF-8. | ||||
| 		rx, nx := utf8.DecodeRuneInString(string(truncateMaxUTF8(x))) | ||||
| 		ry, ny := utf8.DecodeRuneInString(string(truncateMaxUTF8(y))) | ||||
|  | ||||
| 		selfx := isUTF16Self(rx) | ||||
| 		selfy := isUTF16Self(ry) | ||||
| 		switch { | ||||
| 		// The x rune is a single UTF-16 codepoint, while | ||||
| 		// the y rune is a surrogate pair of UTF-16 codepoints. | ||||
| 		case selfx && !selfy: | ||||
| 			ry, _ = utf16.EncodeRune(ry) | ||||
| 		// The y rune is a single UTF-16 codepoint, while | ||||
| 		// the x rune is a surrogate pair of UTF-16 codepoints. | ||||
| 		case selfy && !selfx: | ||||
| 			rx, _ = utf16.EncodeRune(rx) | ||||
| 		} | ||||
| 		if rx != ry { | ||||
| 			return cmp.Compare(rx, ry) | ||||
| 		} | ||||
|  | ||||
| 		// Check for invalid UTF-8, in which case, | ||||
| 		// we just perform a byte-for-byte comparison. | ||||
| 		if isInvalidUTF8(rx, nx) || isInvalidUTF8(ry, ny) { | ||||
| 			if x[0] != y[0] { | ||||
| 				return cmp.Compare(x[0], y[0]) | ||||
| 			} | ||||
| 		} | ||||
| 		x, y = x[nx:], y[ny:] | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // truncateMaxUTF8 truncates b such it contains at least one rune. | ||||
| // | ||||
| // The utf8 package currently lacks generic variants, which complicates | ||||
| // generic functions that operates on either []byte or string. | ||||
| // As a hack, we always call the utf8 function operating on strings, | ||||
| // but always truncate the input such that the result is identical. | ||||
| // | ||||
| // Example usage: | ||||
| // | ||||
| //	utf8.DecodeRuneInString(string(truncateMaxUTF8(b))) | ||||
| // | ||||
| // Converting a []byte to a string is stack allocated since | ||||
| // truncateMaxUTF8 guarantees that the []byte is short. | ||||
| func truncateMaxUTF8[Bytes ~[]byte | ~string](b Bytes) Bytes { | ||||
| 	// TODO(https://go.dev/issue/56948): Remove this function and | ||||
| 	// instead directly call generic utf8 functions wherever used. | ||||
| 	if len(b) > utf8.UTFMax { | ||||
| 		return b[:utf8.UTFMax] | ||||
| 	} | ||||
| 	return b | ||||
| } | ||||
|  | ||||
| // TODO(https://go.dev/issue/70547): Use utf8.ErrInvalid instead. | ||||
| var ErrInvalidUTF8 = errors.New("invalid UTF-8") | ||||
|  | ||||
| func NewInvalidCharacterError[Bytes ~[]byte | ~string](prefix Bytes, where string) error { | ||||
| 	what := QuoteRune(prefix) | ||||
| 	return errors.New("invalid character " + what + " " + where) | ||||
| } | ||||
|  | ||||
| func NewInvalidEscapeSequenceError[Bytes ~[]byte | ~string](what Bytes) error { | ||||
| 	label := "escape sequence" | ||||
| 	if len(what) > 6 { | ||||
| 		label = "surrogate pair" | ||||
| 	} | ||||
| 	needEscape := strings.IndexFunc(string(what), func(r rune) bool { | ||||
| 		return r == '`' || r == utf8.RuneError || unicode.IsSpace(r) || !unicode.IsPrint(r) | ||||
| 	}) >= 0 | ||||
| 	if needEscape { | ||||
| 		return errors.New("invalid " + label + " " + strconv.Quote(string(what)) + " in string") | ||||
| 	} else { | ||||
| 		return errors.New("invalid " + label + " `" + string(what) + "` in string") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // TruncatePointer optionally truncates the JSON pointer, | ||||
| // enforcing that the length roughly does not exceed n. | ||||
| func TruncatePointer(s string, n int) string { | ||||
| 	if len(s) <= n { | ||||
| 		return s | ||||
| 	} | ||||
| 	i := n / 2 | ||||
| 	j := len(s) - n/2 | ||||
|  | ||||
| 	// Avoid truncating a name if there are multiple names present. | ||||
| 	if k := strings.LastIndexByte(s[:i], '/'); k > 0 { | ||||
| 		i = k | ||||
| 	} | ||||
| 	if k := strings.IndexByte(s[j:], '/'); k >= 0 { | ||||
| 		j += k + len("/") | ||||
| 	} | ||||
|  | ||||
| 	// Avoid truncation in the middle of a UTF-8 rune. | ||||
| 	for i > 0 && isInvalidUTF8(utf8.DecodeLastRuneInString(s[:i])) { | ||||
| 		i-- | ||||
| 	} | ||||
| 	for j < len(s) && isInvalidUTF8(utf8.DecodeRuneInString(s[j:])) { | ||||
| 		j++ | ||||
| 	} | ||||
|  | ||||
| 	// Determine the right middle fragment to use. | ||||
| 	var middle string | ||||
| 	switch strings.Count(s[i:j], "/") { | ||||
| 	case 0: | ||||
| 		middle = "…" | ||||
| 	case 1: | ||||
| 		middle = "…/…" | ||||
| 	default: | ||||
| 		middle = "…/…/…" | ||||
| 	} | ||||
| 	if strings.HasPrefix(s[i:j], "/") && middle != "…" { | ||||
| 		middle = strings.TrimPrefix(middle, "…") | ||||
| 	} | ||||
| 	if strings.HasSuffix(s[i:j], "/") && middle != "…" { | ||||
| 		middle = strings.TrimSuffix(middle, "…") | ||||
| 	} | ||||
| 	return s[:i] + middle + s[j:] | ||||
| } | ||||
|  | ||||
| func isInvalidUTF8(r rune, rn int) bool { | ||||
| 	return r == utf8.RuneError && rn == 1 | ||||
| } | ||||
							
								
								
									
										1166
									
								
								vendor/github.com/go-json-experiment/json/jsontext/decode.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1166
									
								
								vendor/github.com/go-json-experiment/json/jsontext/decode.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										105
									
								
								vendor/github.com/go-json-experiment/json/jsontext/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								vendor/github.com/go-json-experiment/json/jsontext/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,105 @@ | ||||
| // Copyright 2023 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. | ||||
|  | ||||
| // Package jsontext implements syntactic processing of JSON | ||||
| // as specified in RFC 4627, RFC 7159, RFC 7493, RFC 8259, and RFC 8785. | ||||
| // JSON is a simple data interchange format that can represent | ||||
| // primitive data types such as booleans, strings, and numbers, | ||||
| // in addition to structured data types such as objects and arrays. | ||||
| // | ||||
| // The [Encoder] and [Decoder] types are used to encode or decode | ||||
| // a stream of JSON tokens or values. | ||||
| // | ||||
| // # Tokens and Values | ||||
| // | ||||
| // A JSON token refers to the basic structural elements of JSON: | ||||
| // | ||||
| //   - a JSON literal (i.e., null, true, or false) | ||||
| //   - a JSON string (e.g., "hello, world!") | ||||
| //   - a JSON number (e.g., 123.456) | ||||
| //   - a start or end delimiter for a JSON object (i.e., '{' or '}') | ||||
| //   - a start or end delimiter for a JSON array (i.e., '[' or ']') | ||||
| // | ||||
| // A JSON token is represented by the [Token] type in Go. Technically, | ||||
| // there are two additional structural characters (i.e., ':' and ','), | ||||
| // but there is no [Token] representation for them since their presence | ||||
| // can be inferred by the structure of the JSON grammar itself. | ||||
| // For example, there must always be an implicit colon between | ||||
| // the name and value of a JSON object member. | ||||
| // | ||||
| // A JSON value refers to a complete unit of JSON data: | ||||
| // | ||||
| //   - a JSON literal, string, or number | ||||
| //   - a JSON object (e.g., `{"name":"value"}`) | ||||
| //   - a JSON array (e.g., `[1,2,3,]`) | ||||
| // | ||||
| // A JSON value is represented by the [Value] type in Go and is a []byte | ||||
| // containing the raw textual representation of the value. There is some overlap | ||||
| // between tokens and values as both contain literals, strings, and numbers. | ||||
| // However, only a value can represent the entirety of a JSON object or array. | ||||
| // | ||||
| // The [Encoder] and [Decoder] types contain methods to read or write the next | ||||
| // [Token] or [Value] in a sequence. They maintain a state machine to validate | ||||
| // whether the sequence of JSON tokens and/or values produces a valid JSON. | ||||
| // [Options] may be passed to the [NewEncoder] or [NewDecoder] constructors | ||||
| // to configure the syntactic behavior of encoding and decoding. | ||||
| // | ||||
| // # Terminology | ||||
| // | ||||
| // The terms "encode" and "decode" are used for syntactic functionality | ||||
| // that is concerned with processing JSON based on its grammar, and | ||||
| // the terms "marshal" and "unmarshal" are used for semantic functionality | ||||
| // that determines the meaning of JSON values as Go values and vice-versa. | ||||
| // This package (i.e., [jsontext]) deals with JSON at a syntactic layer, | ||||
| // while [encoding/json/v2] deals with JSON at a semantic layer. | ||||
| // The goal is to provide a clear distinction between functionality that | ||||
| // is purely concerned with encoding versus that of marshaling. | ||||
| // For example, one can directly encode a stream of JSON tokens without | ||||
| // needing to marshal a concrete Go value representing them. | ||||
| // Similarly, one can decode a stream of JSON tokens without | ||||
| // needing to unmarshal them into a concrete Go value. | ||||
| // | ||||
| // This package uses JSON terminology when discussing JSON, which may differ | ||||
| // from related concepts in Go or elsewhere in computing literature. | ||||
| // | ||||
| //   - a JSON "object" refers to an unordered collection of name/value members. | ||||
| //   - a JSON "array" refers to an ordered sequence of elements. | ||||
| //   - a JSON "value" refers to either a literal (i.e., null, false, or true), | ||||
| //     string, number, object, or array. | ||||
| // | ||||
| // See RFC 8259 for more information. | ||||
| // | ||||
| // # Specifications | ||||
| // | ||||
| // Relevant specifications include RFC 4627, RFC 7159, RFC 7493, RFC 8259, | ||||
| // and RFC 8785. Each RFC is generally a stricter subset of another RFC. | ||||
| // In increasing order of strictness: | ||||
| // | ||||
| //   - RFC 4627 and RFC 7159 do not require (but recommend) the use of UTF-8 | ||||
| //     and also do not require (but recommend) that object names be unique. | ||||
| //   - RFC 8259 requires the use of UTF-8, | ||||
| //     but does not require (but recommends) that object names be unique. | ||||
| //   - RFC 7493 requires the use of UTF-8 | ||||
| //     and also requires that object names be unique. | ||||
| //   - RFC 8785 defines a canonical representation. It requires the use of UTF-8 | ||||
| //     and also requires that object names be unique and in a specific ordering. | ||||
| //     It specifies exactly how strings and numbers must be formatted. | ||||
| // | ||||
| // The primary difference between RFC 4627 and RFC 7159 is that the former | ||||
| // restricted top-level values to only JSON objects and arrays, while | ||||
| // RFC 7159 and subsequent RFCs permit top-level values to additionally be | ||||
| // JSON nulls, booleans, strings, or numbers. | ||||
| // | ||||
| // By default, this package operates on RFC 7493, but can be configured | ||||
| // to operate according to the other RFC specifications. | ||||
| // RFC 7493 is a stricter subset of RFC 8259 and fully compliant with it. | ||||
| // In particular, it makes specific choices about behavior that RFC 8259 | ||||
| // leaves as undefined in order to ensure greater interoperability. | ||||
| package jsontext | ||||
|  | ||||
| // requireKeyedLiterals can be embedded in a struct to require keyed literals. | ||||
| type requireKeyedLiterals struct{} | ||||
|  | ||||
| // nonComparable can be embedded in a struct to prevent comparability. | ||||
| type nonComparable [0]func() | ||||
							
								
								
									
										970
									
								
								vendor/github.com/go-json-experiment/json/jsontext/encode.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										970
									
								
								vendor/github.com/go-json-experiment/json/jsontext/encode.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,970 @@ | ||||
| // Copyright 2020 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. | ||||
|  | ||||
| package jsontext | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"io" | ||||
| 	"math/bits" | ||||
|  | ||||
| 	"github.com/go-json-experiment/json/internal/jsonflags" | ||||
| 	"github.com/go-json-experiment/json/internal/jsonopts" | ||||
| 	"github.com/go-json-experiment/json/internal/jsonwire" | ||||
| ) | ||||
|  | ||||
| // Encoder is a streaming encoder from raw JSON tokens and values. | ||||
| // It is used to write a stream of top-level JSON values, | ||||
| // each terminated with a newline character. | ||||
| // | ||||
| // [Encoder.WriteToken] and [Encoder.WriteValue] calls may be interleaved. | ||||
| // For example, the following JSON value: | ||||
| // | ||||
| //	{"name":"value","array":[null,false,true,3.14159],"object":{"k":"v"}} | ||||
| // | ||||
| // can be composed with the following calls (ignoring errors for brevity): | ||||
| // | ||||
| //	e.WriteToken(BeginObject)        // { | ||||
| //	e.WriteToken(String("name"))     // "name" | ||||
| //	e.WriteToken(String("value"))    // "value" | ||||
| //	e.WriteValue(Value(`"array"`))   // "array" | ||||
| //	e.WriteToken(BeginArray)         // [ | ||||
| //	e.WriteToken(Null)               // null | ||||
| //	e.WriteToken(False)              // false | ||||
| //	e.WriteValue(Value("true"))      // true | ||||
| //	e.WriteToken(Float(3.14159))     // 3.14159 | ||||
| //	e.WriteToken(EndArray)           // ] | ||||
| //	e.WriteValue(Value(`"object"`))  // "object" | ||||
| //	e.WriteValue(Value(`{"k":"v"}`)) // {"k":"v"} | ||||
| //	e.WriteToken(EndObject)          // } | ||||
| // | ||||
| // The above is one of many possible sequence of calls and | ||||
| // may not represent the most sensible method to call for any given token/value. | ||||
| // For example, it is probably more common to call [Encoder.WriteToken] with a string | ||||
| // for object names. | ||||
| type Encoder struct { | ||||
| 	s encoderState | ||||
| } | ||||
|  | ||||
| // encoderState is the low-level state of Encoder. | ||||
| // It has exported fields and method for use by the "json" package. | ||||
| type encoderState struct { | ||||
| 	state | ||||
| 	encodeBuffer | ||||
| 	jsonopts.Struct | ||||
|  | ||||
| 	SeenPointers map[any]struct{} // only used when marshaling; identical to json.seenPointers | ||||
| } | ||||
|  | ||||
| // encodeBuffer is a buffer split into 2 segments: | ||||
| // | ||||
| //   - buf[0:len(buf)]        // written (but unflushed) portion of the buffer | ||||
| //   - buf[len(buf):cap(buf)] // unused portion of the buffer | ||||
| type encodeBuffer struct { | ||||
| 	Buf []byte // may alias wr if it is a bytes.Buffer | ||||
|  | ||||
| 	// baseOffset is added to len(buf) to obtain the absolute offset | ||||
| 	// relative to the start of io.Writer stream. | ||||
| 	baseOffset int64 | ||||
|  | ||||
| 	wr io.Writer | ||||
|  | ||||
| 	// maxValue is the approximate maximum Value size passed to WriteValue. | ||||
| 	maxValue int | ||||
| 	// unusedCache is the buffer returned by the UnusedBuffer method. | ||||
| 	unusedCache []byte | ||||
| 	// bufStats is statistics about buffer utilization. | ||||
| 	// It is only used with pooled encoders in pools.go. | ||||
| 	bufStats bufferStatistics | ||||
| } | ||||
|  | ||||
| // NewEncoder constructs a new streaming encoder writing to w | ||||
| // configured with the provided options. | ||||
| // It flushes the internal buffer when the buffer is sufficiently full or | ||||
| // when a top-level value has been written. | ||||
| // | ||||
| // If w is a [bytes.Buffer], then the encoder appends directly into the buffer | ||||
| // without copying the contents from an intermediate buffer. | ||||
| func NewEncoder(w io.Writer, opts ...Options) *Encoder { | ||||
| 	e := new(Encoder) | ||||
| 	e.Reset(w, opts...) | ||||
| 	return e | ||||
| } | ||||
|  | ||||
| // Reset resets an encoder such that it is writing afresh to w and | ||||
| // configured with the provided options. Reset must not be called on | ||||
| // a Encoder passed to the [encoding/json/v2.MarshalerTo.MarshalJSONTo] method | ||||
| // or the [encoding/json/v2.MarshalToFunc] function. | ||||
| func (e *Encoder) Reset(w io.Writer, opts ...Options) { | ||||
| 	switch { | ||||
| 	case e == nil: | ||||
| 		panic("jsontext: invalid nil Encoder") | ||||
| 	case w == nil: | ||||
| 		panic("jsontext: invalid nil io.Writer") | ||||
| 	case e.s.Flags.Get(jsonflags.WithinArshalCall): | ||||
| 		panic("jsontext: cannot reset Encoder passed to json.MarshalerTo") | ||||
| 	} | ||||
| 	e.s.reset(nil, w, opts...) | ||||
| } | ||||
|  | ||||
| func (e *encoderState) reset(b []byte, w io.Writer, opts ...Options) { | ||||
| 	e.state.reset() | ||||
| 	e.encodeBuffer = encodeBuffer{Buf: b, wr: w, bufStats: e.bufStats} | ||||
| 	if bb, ok := w.(*bytes.Buffer); ok && bb != nil { | ||||
| 		e.Buf = bb.Bytes()[bb.Len():] // alias the unused buffer of bb | ||||
| 	} | ||||
| 	opts2 := jsonopts.Struct{} // avoid mutating e.Struct in case it is part of opts | ||||
| 	opts2.Join(opts...) | ||||
| 	e.Struct = opts2 | ||||
| 	if e.Flags.Get(jsonflags.Multiline) { | ||||
| 		if !e.Flags.Has(jsonflags.SpaceAfterColon) { | ||||
| 			e.Flags.Set(jsonflags.SpaceAfterColon | 1) | ||||
| 		} | ||||
| 		if !e.Flags.Has(jsonflags.SpaceAfterComma) { | ||||
| 			e.Flags.Set(jsonflags.SpaceAfterComma | 0) | ||||
| 		} | ||||
| 		if !e.Flags.Has(jsonflags.Indent) { | ||||
| 			e.Flags.Set(jsonflags.Indent | 1) | ||||
| 			e.Indent = "\t" | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Options returns the options used to construct the decoder and | ||||
| // may additionally contain semantic options passed to a | ||||
| // [encoding/json/v2.MarshalEncode] call. | ||||
| // | ||||
| // If operating within | ||||
| // a [encoding/json/v2.MarshalerTo.MarshalJSONTo] method call or | ||||
| // a [encoding/json/v2.MarshalToFunc] function call, | ||||
| // then the returned options are only valid within the call. | ||||
| func (e *Encoder) Options() Options { | ||||
| 	return &e.s.Struct | ||||
| } | ||||
|  | ||||
| // NeedFlush determines whether to flush at this point. | ||||
| func (e *encoderState) NeedFlush() bool { | ||||
| 	// NOTE: This function is carefully written to be inlinable. | ||||
|  | ||||
| 	// Avoid flushing if e.wr is nil since there is no underlying writer. | ||||
| 	// Flush if less than 25% of the capacity remains. | ||||
| 	// Flushing at some constant fraction ensures that the buffer stops growing | ||||
| 	// so long as the largest Token or Value fits within that unused capacity. | ||||
| 	return e.wr != nil && (e.Tokens.Depth() == 1 || len(e.Buf) > 3*cap(e.Buf)/4) | ||||
| } | ||||
|  | ||||
| // Flush flushes the buffer to the underlying io.Writer. | ||||
| // It may append a trailing newline after the top-level value. | ||||
| func (e *encoderState) Flush() error { | ||||
| 	if e.wr == nil || e.avoidFlush() { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	// In streaming mode, always emit a newline after the top-level value. | ||||
| 	if e.Tokens.Depth() == 1 && !e.Flags.Get(jsonflags.OmitTopLevelNewline) { | ||||
| 		e.Buf = append(e.Buf, '\n') | ||||
| 	} | ||||
|  | ||||
| 	// Inform objectNameStack that we are about to flush the buffer content. | ||||
| 	e.Names.copyQuotedBuffer(e.Buf) | ||||
|  | ||||
| 	// Specialize bytes.Buffer for better performance. | ||||
| 	if bb, ok := e.wr.(*bytes.Buffer); ok { | ||||
| 		// If e.buf already aliases the internal buffer of bb, | ||||
| 		// then the Write call simply increments the internal offset, | ||||
| 		// otherwise Write operates as expected. | ||||
| 		// See https://go.dev/issue/42986. | ||||
| 		n, _ := bb.Write(e.Buf) // never fails unless bb is nil | ||||
| 		e.baseOffset += int64(n) | ||||
|  | ||||
| 		// If the internal buffer of bytes.Buffer is too small, | ||||
| 		// append operations elsewhere in the Encoder may grow the buffer. | ||||
| 		// This would be semantically correct, but hurts performance. | ||||
| 		// As such, ensure 25% of the current length is always available | ||||
| 		// to reduce the probability that other appends must allocate. | ||||
| 		if avail := bb.Available(); avail < bb.Len()/4 { | ||||
| 			bb.Grow(avail + 1) | ||||
| 		} | ||||
|  | ||||
| 		e.Buf = bb.AvailableBuffer() | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	// Flush the internal buffer to the underlying io.Writer. | ||||
| 	n, err := e.wr.Write(e.Buf) | ||||
| 	e.baseOffset += int64(n) | ||||
| 	if err != nil { | ||||
| 		// In the event of an error, preserve the unflushed portion. | ||||
| 		// Thus, write errors aren't fatal so long as the io.Writer | ||||
| 		// maintains consistent state after errors. | ||||
| 		if n > 0 { | ||||
| 			e.Buf = e.Buf[:copy(e.Buf, e.Buf[n:])] | ||||
| 		} | ||||
| 		return &ioError{action: "write", err: err} | ||||
| 	} | ||||
| 	e.Buf = e.Buf[:0] | ||||
|  | ||||
| 	// Check whether to grow the buffer. | ||||
| 	// Note that cap(e.buf) may already exceed maxBufferSize since | ||||
| 	// an append elsewhere already grew it to store a large token. | ||||
| 	const maxBufferSize = 4 << 10 | ||||
| 	const growthSizeFactor = 2 // higher value is faster | ||||
| 	const growthRateFactor = 2 // higher value is slower | ||||
| 	// By default, grow if below the maximum buffer size. | ||||
| 	grow := cap(e.Buf) <= maxBufferSize/growthSizeFactor | ||||
| 	// Growing can be expensive, so only grow | ||||
| 	// if a sufficient number of bytes have been processed. | ||||
| 	grow = grow && int64(cap(e.Buf)) < e.previousOffsetEnd()/growthRateFactor | ||||
| 	if grow { | ||||
| 		e.Buf = make([]byte, 0, cap(e.Buf)*growthSizeFactor) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
| func (d *encodeBuffer) offsetAt(pos int) int64   { return d.baseOffset + int64(pos) } | ||||
| func (e *encodeBuffer) previousOffsetEnd() int64 { return e.baseOffset + int64(len(e.Buf)) } | ||||
| func (e *encodeBuffer) unflushedBuffer() []byte  { return e.Buf } | ||||
|  | ||||
| // avoidFlush indicates whether to avoid flushing to ensure there is always | ||||
| // enough in the buffer to unwrite the last object member if it were empty. | ||||
| func (e *encoderState) avoidFlush() bool { | ||||
| 	switch { | ||||
| 	case e.Tokens.Last.Length() == 0: | ||||
| 		// Never flush after BeginObject or BeginArray since we don't know yet | ||||
| 		// if the object or array will end up being empty. | ||||
| 		return true | ||||
| 	case e.Tokens.Last.needObjectValue(): | ||||
| 		// Never flush before the object value since we don't know yet | ||||
| 		// if the object value will end up being empty. | ||||
| 		return true | ||||
| 	case e.Tokens.Last.NeedObjectName() && len(e.Buf) >= 2: | ||||
| 		// Never flush after the object value if it does turn out to be empty. | ||||
| 		switch string(e.Buf[len(e.Buf)-2:]) { | ||||
| 		case `ll`, `""`, `{}`, `[]`: // last two bytes of every empty value | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // UnwriteEmptyObjectMember unwrites the last object member if it is empty | ||||
| // and reports whether it performed an unwrite operation. | ||||
| func (e *encoderState) UnwriteEmptyObjectMember(prevName *string) bool { | ||||
| 	if last := e.Tokens.Last; !last.isObject() || !last.NeedObjectName() || last.Length() == 0 { | ||||
| 		panic("BUG: must be called on an object after writing a value") | ||||
| 	} | ||||
|  | ||||
| 	// The flushing logic is modified to never flush a trailing empty value. | ||||
| 	// The encoder never writes trailing whitespace eagerly. | ||||
| 	b := e.unflushedBuffer() | ||||
|  | ||||
| 	// Detect whether the last value was empty. | ||||
| 	var n int | ||||
| 	if len(b) >= 3 { | ||||
| 		switch string(b[len(b)-2:]) { | ||||
| 		case "ll": // last two bytes of `null` | ||||
| 			n = len(`null`) | ||||
| 		case `""`: | ||||
| 			// It is possible for a non-empty string to have `""` as a suffix | ||||
| 			// if the second to the last quote was escaped. | ||||
| 			if b[len(b)-3] == '\\' { | ||||
| 				return false // e.g., `"\""` is not empty | ||||
| 			} | ||||
| 			n = len(`""`) | ||||
| 		case `{}`: | ||||
| 			n = len(`{}`) | ||||
| 		case `[]`: | ||||
| 			n = len(`[]`) | ||||
| 		} | ||||
| 	} | ||||
| 	if n == 0 { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	// Unwrite the value, whitespace, colon, name, whitespace, and comma. | ||||
| 	b = b[:len(b)-n] | ||||
| 	b = jsonwire.TrimSuffixWhitespace(b) | ||||
| 	b = jsonwire.TrimSuffixByte(b, ':') | ||||
| 	b = jsonwire.TrimSuffixString(b) | ||||
| 	b = jsonwire.TrimSuffixWhitespace(b) | ||||
| 	b = jsonwire.TrimSuffixByte(b, ',') | ||||
| 	e.Buf = b // store back truncated unflushed buffer | ||||
|  | ||||
| 	// Undo state changes. | ||||
| 	e.Tokens.Last.decrement() // for object member value | ||||
| 	e.Tokens.Last.decrement() // for object member name | ||||
| 	if !e.Flags.Get(jsonflags.AllowDuplicateNames) { | ||||
| 		if e.Tokens.Last.isActiveNamespace() { | ||||
| 			e.Namespaces.Last().removeLast() | ||||
| 		} | ||||
| 	} | ||||
| 	e.Names.clearLast() | ||||
| 	if prevName != nil { | ||||
| 		e.Names.copyQuotedBuffer(e.Buf) // required by objectNameStack.replaceLastUnquotedName | ||||
| 		e.Names.replaceLastUnquotedName(*prevName) | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| // UnwriteOnlyObjectMemberName unwrites the only object member name | ||||
| // and returns the unquoted name. | ||||
| func (e *encoderState) UnwriteOnlyObjectMemberName() string { | ||||
| 	if last := e.Tokens.Last; !last.isObject() || last.Length() != 1 { | ||||
| 		panic("BUG: must be called on an object after writing first name") | ||||
| 	} | ||||
|  | ||||
| 	// Unwrite the name and whitespace. | ||||
| 	b := jsonwire.TrimSuffixString(e.Buf) | ||||
| 	isVerbatim := bytes.IndexByte(e.Buf[len(b):], '\\') < 0 | ||||
| 	name := string(jsonwire.UnquoteMayCopy(e.Buf[len(b):], isVerbatim)) | ||||
| 	e.Buf = jsonwire.TrimSuffixWhitespace(b) | ||||
|  | ||||
| 	// Undo state changes. | ||||
| 	e.Tokens.Last.decrement() | ||||
| 	if !e.Flags.Get(jsonflags.AllowDuplicateNames) { | ||||
| 		if e.Tokens.Last.isActiveNamespace() { | ||||
| 			e.Namespaces.Last().removeLast() | ||||
| 		} | ||||
| 	} | ||||
| 	e.Names.clearLast() | ||||
| 	return name | ||||
| } | ||||
|  | ||||
| // WriteToken writes the next token and advances the internal write offset. | ||||
| // | ||||
| // The provided token kind must be consistent with the JSON grammar. | ||||
| // For example, it is an error to provide a number when the encoder | ||||
| // is expecting an object name (which is always a string), or | ||||
| // to provide an end object delimiter when the encoder is finishing an array. | ||||
| // If the provided token is invalid, then it reports a [SyntacticError] and | ||||
| // the internal state remains unchanged. The offset reported | ||||
| // in [SyntacticError] will be relative to the [Encoder.OutputOffset]. | ||||
| func (e *Encoder) WriteToken(t Token) error { | ||||
| 	return e.s.WriteToken(t) | ||||
| } | ||||
| func (e *encoderState) WriteToken(t Token) error { | ||||
| 	k := t.Kind() | ||||
| 	b := e.Buf // use local variable to avoid mutating e in case of error | ||||
|  | ||||
| 	// Append any delimiters or optional whitespace. | ||||
| 	b = e.Tokens.MayAppendDelim(b, k) | ||||
| 	if e.Flags.Get(jsonflags.AnyWhitespace) { | ||||
| 		b = e.appendWhitespace(b, k) | ||||
| 	} | ||||
| 	pos := len(b) // offset before the token | ||||
|  | ||||
| 	// Append the token to the output and to the state machine. | ||||
| 	var err error | ||||
| 	switch k { | ||||
| 	case 'n': | ||||
| 		b = append(b, "null"...) | ||||
| 		err = e.Tokens.appendLiteral() | ||||
| 	case 'f': | ||||
| 		b = append(b, "false"...) | ||||
| 		err = e.Tokens.appendLiteral() | ||||
| 	case 't': | ||||
| 		b = append(b, "true"...) | ||||
| 		err = e.Tokens.appendLiteral() | ||||
| 	case '"': | ||||
| 		if b, err = t.appendString(b, &e.Flags); err != nil { | ||||
| 			break | ||||
| 		} | ||||
| 		if e.Tokens.Last.NeedObjectName() { | ||||
| 			if !e.Flags.Get(jsonflags.AllowDuplicateNames) { | ||||
| 				if !e.Tokens.Last.isValidNamespace() { | ||||
| 					err = errInvalidNamespace | ||||
| 					break | ||||
| 				} | ||||
| 				if e.Tokens.Last.isActiveNamespace() && !e.Namespaces.Last().insertQuoted(b[pos:], false) { | ||||
| 					err = wrapWithObjectName(ErrDuplicateName, b[pos:]) | ||||
| 					break | ||||
| 				} | ||||
| 			} | ||||
| 			e.Names.ReplaceLastQuotedOffset(pos) // only replace if insertQuoted succeeds | ||||
| 		} | ||||
| 		err = e.Tokens.appendString() | ||||
| 	case '0': | ||||
| 		if b, err = t.appendNumber(b, &e.Flags); err != nil { | ||||
| 			break | ||||
| 		} | ||||
| 		err = e.Tokens.appendNumber() | ||||
| 	case '{': | ||||
| 		b = append(b, '{') | ||||
| 		if err = e.Tokens.pushObject(); err != nil { | ||||
| 			break | ||||
| 		} | ||||
| 		e.Names.push() | ||||
| 		if !e.Flags.Get(jsonflags.AllowDuplicateNames) { | ||||
| 			e.Namespaces.push() | ||||
| 		} | ||||
| 	case '}': | ||||
| 		b = append(b, '}') | ||||
| 		if err = e.Tokens.popObject(); err != nil { | ||||
| 			break | ||||
| 		} | ||||
| 		e.Names.pop() | ||||
| 		if !e.Flags.Get(jsonflags.AllowDuplicateNames) { | ||||
| 			e.Namespaces.pop() | ||||
| 		} | ||||
| 	case '[': | ||||
| 		b = append(b, '[') | ||||
| 		err = e.Tokens.pushArray() | ||||
| 	case ']': | ||||
| 		b = append(b, ']') | ||||
| 		err = e.Tokens.popArray() | ||||
| 	default: | ||||
| 		err = errInvalidToken | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return wrapSyntacticError(e, err, pos, +1) | ||||
| 	} | ||||
|  | ||||
| 	// Finish off the buffer and store it back into e. | ||||
| 	e.Buf = b | ||||
| 	if e.NeedFlush() { | ||||
| 		return e.Flush() | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // AppendRaw appends either a raw string (without double quotes) or number. | ||||
| // Specify safeASCII if the string output is guaranteed to be ASCII | ||||
| // without any characters (including '<', '>', and '&') that need escaping, | ||||
| // otherwise this will validate whether the string needs escaping. | ||||
| // The appended bytes for a JSON number must be valid. | ||||
| // | ||||
| // This is a specialized implementation of Encoder.WriteValue | ||||
| // that allows appending directly into the buffer. | ||||
| // It is only called from marshal logic in the "json" package. | ||||
| func (e *encoderState) AppendRaw(k Kind, safeASCII bool, appendFn func([]byte) ([]byte, error)) error { | ||||
| 	b := e.Buf // use local variable to avoid mutating e in case of error | ||||
|  | ||||
| 	// Append any delimiters or optional whitespace. | ||||
| 	b = e.Tokens.MayAppendDelim(b, k) | ||||
| 	if e.Flags.Get(jsonflags.AnyWhitespace) { | ||||
| 		b = e.appendWhitespace(b, k) | ||||
| 	} | ||||
| 	pos := len(b) // offset before the token | ||||
|  | ||||
| 	var err error | ||||
| 	switch k { | ||||
| 	case '"': | ||||
| 		// Append directly into the encoder buffer by assuming that | ||||
| 		// most of the time none of the characters need escaping. | ||||
| 		b = append(b, '"') | ||||
| 		if b, err = appendFn(b); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		b = append(b, '"') | ||||
|  | ||||
| 		// Check whether we need to escape the string and if necessary | ||||
| 		// copy it to a scratch buffer and then escape it back. | ||||
| 		isVerbatim := safeASCII || !jsonwire.NeedEscape(b[pos+len(`"`):len(b)-len(`"`)]) | ||||
| 		if !isVerbatim { | ||||
| 			var err error | ||||
| 			b2 := append(e.unusedCache, b[pos+len(`"`):len(b)-len(`"`)]...) | ||||
| 			b, err = jsonwire.AppendQuote(b[:pos], string(b2), &e.Flags) | ||||
| 			e.unusedCache = b2[:0] | ||||
| 			if err != nil { | ||||
| 				return wrapSyntacticError(e, err, pos, +1) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		// Update the state machine. | ||||
| 		if e.Tokens.Last.NeedObjectName() { | ||||
| 			if !e.Flags.Get(jsonflags.AllowDuplicateNames) { | ||||
| 				if !e.Tokens.Last.isValidNamespace() { | ||||
| 					return wrapSyntacticError(e, err, pos, +1) | ||||
| 				} | ||||
| 				if e.Tokens.Last.isActiveNamespace() && !e.Namespaces.Last().insertQuoted(b[pos:], isVerbatim) { | ||||
| 					err = wrapWithObjectName(ErrDuplicateName, b[pos:]) | ||||
| 					return wrapSyntacticError(e, err, pos, +1) | ||||
| 				} | ||||
| 			} | ||||
| 			e.Names.ReplaceLastQuotedOffset(pos) // only replace if insertQuoted succeeds | ||||
| 		} | ||||
| 		if err := e.Tokens.appendString(); err != nil { | ||||
| 			return wrapSyntacticError(e, err, pos, +1) | ||||
| 		} | ||||
| 	case '0': | ||||
| 		if b, err = appendFn(b); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		if err := e.Tokens.appendNumber(); err != nil { | ||||
| 			return wrapSyntacticError(e, err, pos, +1) | ||||
| 		} | ||||
| 	default: | ||||
| 		panic("BUG: invalid kind") | ||||
| 	} | ||||
|  | ||||
| 	// Finish off the buffer and store it back into e. | ||||
| 	e.Buf = b | ||||
| 	if e.NeedFlush() { | ||||
| 		return e.Flush() | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // WriteValue writes the next raw value and advances the internal write offset. | ||||
| // The Encoder does not simply copy the provided value verbatim, but | ||||
| // parses it to ensure that it is syntactically valid and reformats it | ||||
| // according to how the Encoder is configured to format whitespace and strings. | ||||
| // If [AllowInvalidUTF8] is specified, then any invalid UTF-8 is mangled | ||||
| // as the Unicode replacement character, U+FFFD. | ||||
| // | ||||
| // The provided value kind must be consistent with the JSON grammar | ||||
| // (see examples on [Encoder.WriteToken]). If the provided value is invalid, | ||||
| // then it reports a [SyntacticError] and the internal state remains unchanged. | ||||
| // The offset reported in [SyntacticError] will be relative to the | ||||
| // [Encoder.OutputOffset] plus the offset into v of any encountered syntax error. | ||||
| func (e *Encoder) WriteValue(v Value) error { | ||||
| 	return e.s.WriteValue(v) | ||||
| } | ||||
| func (e *encoderState) WriteValue(v Value) error { | ||||
| 	e.maxValue |= len(v) // bitwise OR is a fast approximation of max | ||||
|  | ||||
| 	k := v.Kind() | ||||
| 	b := e.Buf // use local variable to avoid mutating e in case of error | ||||
|  | ||||
| 	// Append any delimiters or optional whitespace. | ||||
| 	b = e.Tokens.MayAppendDelim(b, k) | ||||
| 	if e.Flags.Get(jsonflags.AnyWhitespace) { | ||||
| 		b = e.appendWhitespace(b, k) | ||||
| 	} | ||||
| 	pos := len(b) // offset before the value | ||||
|  | ||||
| 	// Append the value the output. | ||||
| 	var n int | ||||
| 	n += jsonwire.ConsumeWhitespace(v[n:]) | ||||
| 	b, m, err := e.reformatValue(b, v[n:], e.Tokens.Depth()) | ||||
| 	if err != nil { | ||||
| 		return wrapSyntacticError(e, err, pos+n+m, +1) | ||||
| 	} | ||||
| 	n += m | ||||
| 	n += jsonwire.ConsumeWhitespace(v[n:]) | ||||
| 	if len(v) > n { | ||||
| 		err = jsonwire.NewInvalidCharacterError(v[n:], "after top-level value") | ||||
| 		return wrapSyntacticError(e, err, pos+n, 0) | ||||
| 	} | ||||
|  | ||||
| 	// Append the kind to the state machine. | ||||
| 	switch k { | ||||
| 	case 'n', 'f', 't': | ||||
| 		err = e.Tokens.appendLiteral() | ||||
| 	case '"': | ||||
| 		if e.Tokens.Last.NeedObjectName() { | ||||
| 			if !e.Flags.Get(jsonflags.AllowDuplicateNames) { | ||||
| 				if !e.Tokens.Last.isValidNamespace() { | ||||
| 					err = errInvalidNamespace | ||||
| 					break | ||||
| 				} | ||||
| 				if e.Tokens.Last.isActiveNamespace() && !e.Namespaces.Last().insertQuoted(b[pos:], false) { | ||||
| 					err = wrapWithObjectName(ErrDuplicateName, b[pos:]) | ||||
| 					break | ||||
| 				} | ||||
| 			} | ||||
| 			e.Names.ReplaceLastQuotedOffset(pos) // only replace if insertQuoted succeeds | ||||
| 		} | ||||
| 		err = e.Tokens.appendString() | ||||
| 	case '0': | ||||
| 		err = e.Tokens.appendNumber() | ||||
| 	case '{': | ||||
| 		if err = e.Tokens.pushObject(); err != nil { | ||||
| 			break | ||||
| 		} | ||||
| 		if err = e.Tokens.popObject(); err != nil { | ||||
| 			panic("BUG: popObject should never fail immediately after pushObject: " + err.Error()) | ||||
| 		} | ||||
| 		if e.Flags.Get(jsonflags.ReorderRawObjects) { | ||||
| 			mustReorderObjects(b[pos:]) | ||||
| 		} | ||||
| 	case '[': | ||||
| 		if err = e.Tokens.pushArray(); err != nil { | ||||
| 			break | ||||
| 		} | ||||
| 		if err = e.Tokens.popArray(); err != nil { | ||||
| 			panic("BUG: popArray should never fail immediately after pushArray: " + err.Error()) | ||||
| 		} | ||||
| 		if e.Flags.Get(jsonflags.ReorderRawObjects) { | ||||
| 			mustReorderObjects(b[pos:]) | ||||
| 		} | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return wrapSyntacticError(e, err, pos, +1) | ||||
| 	} | ||||
|  | ||||
| 	// Finish off the buffer and store it back into e. | ||||
| 	e.Buf = b | ||||
| 	if e.NeedFlush() { | ||||
| 		return e.Flush() | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // CountNextDelimWhitespace counts the number of bytes of delimiter and | ||||
| // whitespace bytes assuming the upcoming token is a JSON value. | ||||
| // This method is used for error reporting at the semantic layer. | ||||
| func (e *encoderState) CountNextDelimWhitespace() (n int) { | ||||
| 	const next = Kind('"') // arbitrary kind as next JSON value | ||||
| 	delim := e.Tokens.needDelim(next) | ||||
| 	if delim > 0 { | ||||
| 		n += len(",") | len(":") | ||||
| 	} | ||||
| 	if delim == ':' { | ||||
| 		if e.Flags.Get(jsonflags.SpaceAfterColon) { | ||||
| 			n += len(" ") | ||||
| 		} | ||||
| 	} else { | ||||
| 		if delim == ',' && e.Flags.Get(jsonflags.SpaceAfterComma) { | ||||
| 			n += len(" ") | ||||
| 		} | ||||
| 		if e.Flags.Get(jsonflags.Multiline) { | ||||
| 			if m := e.Tokens.NeedIndent(next); m > 0 { | ||||
| 				n += len("\n") + len(e.IndentPrefix) + (m-1)*len(e.Indent) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return n | ||||
| } | ||||
|  | ||||
| // appendWhitespace appends whitespace that immediately precedes the next token. | ||||
| func (e *encoderState) appendWhitespace(b []byte, next Kind) []byte { | ||||
| 	if delim := e.Tokens.needDelim(next); delim == ':' { | ||||
| 		if e.Flags.Get(jsonflags.SpaceAfterColon) { | ||||
| 			b = append(b, ' ') | ||||
| 		} | ||||
| 	} else { | ||||
| 		if delim == ',' && e.Flags.Get(jsonflags.SpaceAfterComma) { | ||||
| 			b = append(b, ' ') | ||||
| 		} | ||||
| 		if e.Flags.Get(jsonflags.Multiline) { | ||||
| 			b = e.AppendIndent(b, e.Tokens.NeedIndent(next)) | ||||
| 		} | ||||
| 	} | ||||
| 	return b | ||||
| } | ||||
|  | ||||
| // AppendIndent appends the appropriate number of indentation characters | ||||
| // for the current nested level, n. | ||||
| func (e *encoderState) AppendIndent(b []byte, n int) []byte { | ||||
| 	if n == 0 { | ||||
| 		return b | ||||
| 	} | ||||
| 	b = append(b, '\n') | ||||
| 	b = append(b, e.IndentPrefix...) | ||||
| 	for ; n > 1; n-- { | ||||
| 		b = append(b, e.Indent...) | ||||
| 	} | ||||
| 	return b | ||||
| } | ||||
|  | ||||
| // reformatValue parses a JSON value from the start of src and | ||||
| // appends it to the end of dst, reformatting whitespace and strings as needed. | ||||
| // It returns the extended dst buffer and the number of consumed input bytes. | ||||
| func (e *encoderState) reformatValue(dst []byte, src Value, depth int) ([]byte, int, error) { | ||||
| 	// TODO: Should this update ValueFlags as input? | ||||
| 	if len(src) == 0 { | ||||
| 		return dst, 0, io.ErrUnexpectedEOF | ||||
| 	} | ||||
| 	switch k := Kind(src[0]).normalize(); k { | ||||
| 	case 'n': | ||||
| 		if jsonwire.ConsumeNull(src) == 0 { | ||||
| 			n, err := jsonwire.ConsumeLiteral(src, "null") | ||||
| 			return dst, n, err | ||||
| 		} | ||||
| 		return append(dst, "null"...), len("null"), nil | ||||
| 	case 'f': | ||||
| 		if jsonwire.ConsumeFalse(src) == 0 { | ||||
| 			n, err := jsonwire.ConsumeLiteral(src, "false") | ||||
| 			return dst, n, err | ||||
| 		} | ||||
| 		return append(dst, "false"...), len("false"), nil | ||||
| 	case 't': | ||||
| 		if jsonwire.ConsumeTrue(src) == 0 { | ||||
| 			n, err := jsonwire.ConsumeLiteral(src, "true") | ||||
| 			return dst, n, err | ||||
| 		} | ||||
| 		return append(dst, "true"...), len("true"), nil | ||||
| 	case '"': | ||||
| 		if n := jsonwire.ConsumeSimpleString(src); n > 0 { | ||||
| 			dst = append(dst, src[:n]...) // copy simple strings verbatim | ||||
| 			return dst, n, nil | ||||
| 		} | ||||
| 		return jsonwire.ReformatString(dst, src, &e.Flags) | ||||
| 	case '0': | ||||
| 		if n := jsonwire.ConsumeSimpleNumber(src); n > 0 && !e.Flags.Get(jsonflags.CanonicalizeNumbers) { | ||||
| 			dst = append(dst, src[:n]...) // copy simple numbers verbatim | ||||
| 			return dst, n, nil | ||||
| 		} | ||||
| 		return jsonwire.ReformatNumber(dst, src, &e.Flags) | ||||
| 	case '{': | ||||
| 		return e.reformatObject(dst, src, depth) | ||||
| 	case '[': | ||||
| 		return e.reformatArray(dst, src, depth) | ||||
| 	default: | ||||
| 		return dst, 0, jsonwire.NewInvalidCharacterError(src, "at start of value") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // reformatObject parses a JSON object from the start of src and | ||||
| // appends it to the end of src, reformatting whitespace and strings as needed. | ||||
| // It returns the extended dst buffer and the number of consumed input bytes. | ||||
| func (e *encoderState) reformatObject(dst []byte, src Value, depth int) ([]byte, int, error) { | ||||
| 	// Append object start. | ||||
| 	if len(src) == 0 || src[0] != '{' { | ||||
| 		panic("BUG: reformatObject must be called with a buffer that starts with '{'") | ||||
| 	} else if depth == maxNestingDepth+1 { | ||||
| 		return dst, 0, errMaxDepth | ||||
| 	} | ||||
| 	dst = append(dst, '{') | ||||
| 	n := len("{") | ||||
|  | ||||
| 	// Append (possible) object end. | ||||
| 	n += jsonwire.ConsumeWhitespace(src[n:]) | ||||
| 	if uint(len(src)) <= uint(n) { | ||||
| 		return dst, n, io.ErrUnexpectedEOF | ||||
| 	} | ||||
| 	if src[n] == '}' { | ||||
| 		dst = append(dst, '}') | ||||
| 		n += len("}") | ||||
| 		return dst, n, nil | ||||
| 	} | ||||
|  | ||||
| 	var err error | ||||
| 	var names *objectNamespace | ||||
| 	if !e.Flags.Get(jsonflags.AllowDuplicateNames) { | ||||
| 		e.Namespaces.push() | ||||
| 		defer e.Namespaces.pop() | ||||
| 		names = e.Namespaces.Last() | ||||
| 	} | ||||
| 	depth++ | ||||
| 	for { | ||||
| 		// Append optional newline and indentation. | ||||
| 		if e.Flags.Get(jsonflags.Multiline) { | ||||
| 			dst = e.AppendIndent(dst, depth) | ||||
| 		} | ||||
|  | ||||
| 		// Append object name. | ||||
| 		n += jsonwire.ConsumeWhitespace(src[n:]) | ||||
| 		if uint(len(src)) <= uint(n) { | ||||
| 			return dst, n, io.ErrUnexpectedEOF | ||||
| 		} | ||||
| 		m := jsonwire.ConsumeSimpleString(src[n:]) | ||||
| 		isVerbatim := m > 0 | ||||
| 		if isVerbatim { | ||||
| 			dst = append(dst, src[n:n+m]...) | ||||
| 		} else { | ||||
| 			dst, m, err = jsonwire.ReformatString(dst, src[n:], &e.Flags) | ||||
| 			if err != nil { | ||||
| 				return dst, n + m, err | ||||
| 			} | ||||
| 		} | ||||
| 		quotedName := src[n : n+m] | ||||
| 		if !e.Flags.Get(jsonflags.AllowDuplicateNames) && !names.insertQuoted(quotedName, isVerbatim) { | ||||
| 			return dst, n, wrapWithObjectName(ErrDuplicateName, quotedName) | ||||
| 		} | ||||
| 		n += m | ||||
|  | ||||
| 		// Append colon. | ||||
| 		n += jsonwire.ConsumeWhitespace(src[n:]) | ||||
| 		if uint(len(src)) <= uint(n) { | ||||
| 			return dst, n, wrapWithObjectName(io.ErrUnexpectedEOF, quotedName) | ||||
| 		} | ||||
| 		if src[n] != ':' { | ||||
| 			err = jsonwire.NewInvalidCharacterError(src[n:], "after object name (expecting ':')") | ||||
| 			return dst, n, wrapWithObjectName(err, quotedName) | ||||
| 		} | ||||
| 		dst = append(dst, ':') | ||||
| 		n += len(":") | ||||
| 		if e.Flags.Get(jsonflags.SpaceAfterColon) { | ||||
| 			dst = append(dst, ' ') | ||||
| 		} | ||||
|  | ||||
| 		// Append object value. | ||||
| 		n += jsonwire.ConsumeWhitespace(src[n:]) | ||||
| 		if uint(len(src)) <= uint(n) { | ||||
| 			return dst, n, wrapWithObjectName(io.ErrUnexpectedEOF, quotedName) | ||||
| 		} | ||||
| 		dst, m, err = e.reformatValue(dst, src[n:], depth) | ||||
| 		if err != nil { | ||||
| 			return dst, n + m, wrapWithObjectName(err, quotedName) | ||||
| 		} | ||||
| 		n += m | ||||
|  | ||||
| 		// Append comma or object end. | ||||
| 		n += jsonwire.ConsumeWhitespace(src[n:]) | ||||
| 		if uint(len(src)) <= uint(n) { | ||||
| 			return dst, n, io.ErrUnexpectedEOF | ||||
| 		} | ||||
| 		switch src[n] { | ||||
| 		case ',': | ||||
| 			dst = append(dst, ',') | ||||
| 			if e.Flags.Get(jsonflags.SpaceAfterComma) { | ||||
| 				dst = append(dst, ' ') | ||||
| 			} | ||||
| 			n += len(",") | ||||
| 			continue | ||||
| 		case '}': | ||||
| 			if e.Flags.Get(jsonflags.Multiline) { | ||||
| 				dst = e.AppendIndent(dst, depth-1) | ||||
| 			} | ||||
| 			dst = append(dst, '}') | ||||
| 			n += len("}") | ||||
| 			return dst, n, nil | ||||
| 		default: | ||||
| 			return dst, n, jsonwire.NewInvalidCharacterError(src[n:], "after object value (expecting ',' or '}')") | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // reformatArray parses a JSON array from the start of src and | ||||
| // appends it to the end of dst, reformatting whitespace and strings as needed. | ||||
| // It returns the extended dst buffer and the number of consumed input bytes. | ||||
| func (e *encoderState) reformatArray(dst []byte, src Value, depth int) ([]byte, int, error) { | ||||
| 	// Append array start. | ||||
| 	if len(src) == 0 || src[0] != '[' { | ||||
| 		panic("BUG: reformatArray must be called with a buffer that starts with '['") | ||||
| 	} else if depth == maxNestingDepth+1 { | ||||
| 		return dst, 0, errMaxDepth | ||||
| 	} | ||||
| 	dst = append(dst, '[') | ||||
| 	n := len("[") | ||||
|  | ||||
| 	// Append (possible) array end. | ||||
| 	n += jsonwire.ConsumeWhitespace(src[n:]) | ||||
| 	if uint(len(src)) <= uint(n) { | ||||
| 		return dst, n, io.ErrUnexpectedEOF | ||||
| 	} | ||||
| 	if src[n] == ']' { | ||||
| 		dst = append(dst, ']') | ||||
| 		n += len("]") | ||||
| 		return dst, n, nil | ||||
| 	} | ||||
|  | ||||
| 	var idx int64 | ||||
| 	var err error | ||||
| 	depth++ | ||||
| 	for { | ||||
| 		// Append optional newline and indentation. | ||||
| 		if e.Flags.Get(jsonflags.Multiline) { | ||||
| 			dst = e.AppendIndent(dst, depth) | ||||
| 		} | ||||
|  | ||||
| 		// Append array value. | ||||
| 		n += jsonwire.ConsumeWhitespace(src[n:]) | ||||
| 		if uint(len(src)) <= uint(n) { | ||||
| 			return dst, n, io.ErrUnexpectedEOF | ||||
| 		} | ||||
| 		var m int | ||||
| 		dst, m, err = e.reformatValue(dst, src[n:], depth) | ||||
| 		if err != nil { | ||||
| 			return dst, n + m, wrapWithArrayIndex(err, idx) | ||||
| 		} | ||||
| 		n += m | ||||
|  | ||||
| 		// Append comma or array end. | ||||
| 		n += jsonwire.ConsumeWhitespace(src[n:]) | ||||
| 		if uint(len(src)) <= uint(n) { | ||||
| 			return dst, n, io.ErrUnexpectedEOF | ||||
| 		} | ||||
| 		switch src[n] { | ||||
| 		case ',': | ||||
| 			dst = append(dst, ',') | ||||
| 			if e.Flags.Get(jsonflags.SpaceAfterComma) { | ||||
| 				dst = append(dst, ' ') | ||||
| 			} | ||||
| 			n += len(",") | ||||
| 			idx++ | ||||
| 			continue | ||||
| 		case ']': | ||||
| 			if e.Flags.Get(jsonflags.Multiline) { | ||||
| 				dst = e.AppendIndent(dst, depth-1) | ||||
| 			} | ||||
| 			dst = append(dst, ']') | ||||
| 			n += len("]") | ||||
| 			return dst, n, nil | ||||
| 		default: | ||||
| 			return dst, n, jsonwire.NewInvalidCharacterError(src[n:], "after array value (expecting ',' or ']')") | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // OutputOffset returns the current output byte offset. It gives the location | ||||
| // of the next byte immediately after the most recently written token or value. | ||||
| // The number of bytes actually written to the underlying [io.Writer] may be less | ||||
| // than this offset due to internal buffering effects. | ||||
| func (e *Encoder) OutputOffset() int64 { | ||||
| 	return e.s.previousOffsetEnd() | ||||
| } | ||||
|  | ||||
| // UnusedBuffer returns a zero-length buffer with a possible non-zero capacity. | ||||
| // This buffer is intended to be used to populate a [Value] | ||||
| // being passed to an immediately succeeding [Encoder.WriteValue] call. | ||||
| // | ||||
| // Example usage: | ||||
| // | ||||
| //	b := d.UnusedBuffer() | ||||
| //	b = append(b, '"') | ||||
| //	b = appendString(b, v) // append the string formatting of v | ||||
| //	b = append(b, '"') | ||||
| //	... := d.WriteValue(b) | ||||
| // | ||||
| // It is the user's responsibility to ensure that the value is valid JSON. | ||||
| func (e *Encoder) UnusedBuffer() []byte { | ||||
| 	// NOTE: We don't return e.buf[len(e.buf):cap(e.buf)] since WriteValue would | ||||
| 	// need to take special care to avoid mangling the data while reformatting. | ||||
| 	// WriteValue can't easily identify whether the input Value aliases e.buf | ||||
| 	// without using unsafe.Pointer. Thus, we just return a different buffer. | ||||
| 	// Should this ever alias e.buf, we need to consider how it operates with | ||||
| 	// the specialized performance optimization for bytes.Buffer. | ||||
| 	n := 1 << bits.Len(uint(e.s.maxValue|63)) // fast approximation for max length | ||||
| 	if cap(e.s.unusedCache) < n { | ||||
| 		e.s.unusedCache = make([]byte, 0, n) | ||||
| 	} | ||||
| 	return e.s.unusedCache | ||||
| } | ||||
|  | ||||
| // StackDepth returns the depth of the state machine for written JSON data. | ||||
| // Each level on the stack represents a nested JSON object or array. | ||||
| // It is incremented whenever an [BeginObject] or [BeginArray] token is encountered | ||||
| // and decremented whenever an [EndObject] or [EndArray] token is encountered. | ||||
| // The depth is zero-indexed, where zero represents the top-level JSON value. | ||||
| func (e *Encoder) StackDepth() int { | ||||
| 	// NOTE: Keep in sync with Decoder.StackDepth. | ||||
| 	return e.s.Tokens.Depth() - 1 | ||||
| } | ||||
|  | ||||
| // StackIndex returns information about the specified stack level. | ||||
| // It must be a number between 0 and [Encoder.StackDepth], inclusive. | ||||
| // For each level, it reports the kind: | ||||
| // | ||||
| //   - 0 for a level of zero, | ||||
| //   - '{' for a level representing a JSON object, and | ||||
| //   - '[' for a level representing a JSON array. | ||||
| // | ||||
| // It also reports the length of that JSON object or array. | ||||
| // Each name and value in a JSON object is counted separately, | ||||
| // so the effective number of members would be half the length. | ||||
| // A complete JSON object must have an even length. | ||||
| func (e *Encoder) StackIndex(i int) (Kind, int64) { | ||||
| 	// NOTE: Keep in sync with Decoder.StackIndex. | ||||
| 	switch s := e.s.Tokens.index(i); { | ||||
| 	case i > 0 && s.isObject(): | ||||
| 		return '{', s.Length() | ||||
| 	case i > 0 && s.isArray(): | ||||
| 		return '[', s.Length() | ||||
| 	default: | ||||
| 		return 0, s.Length() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // StackPointer returns a JSON Pointer (RFC 6901) to the most recently written value. | ||||
| func (e *Encoder) StackPointer() Pointer { | ||||
| 	return Pointer(e.s.AppendStackPointer(nil, -1)) | ||||
| } | ||||
|  | ||||
| func (e *encoderState) AppendStackPointer(b []byte, where int) []byte { | ||||
| 	e.Names.copyQuotedBuffer(e.Buf) | ||||
| 	return e.state.appendStackPointer(b, where) | ||||
| } | ||||
							
								
								
									
										180
									
								
								vendor/github.com/go-json-experiment/json/jsontext/errors.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										180
									
								
								vendor/github.com/go-json-experiment/json/jsontext/errors.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,180 @@ | ||||
| // Copyright 2020 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. | ||||
|  | ||||
| package jsontext | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"io" | ||||
| 	"strconv" | ||||
|  | ||||
| 	"github.com/go-json-experiment/json/internal/jsonwire" | ||||
| ) | ||||
|  | ||||
| const errorPrefix = "jsontext: " | ||||
|  | ||||
| type ioError struct { | ||||
| 	action string // either "read" or "write" | ||||
| 	err    error | ||||
| } | ||||
|  | ||||
| func (e *ioError) Error() string { | ||||
| 	return errorPrefix + e.action + " error: " + e.err.Error() | ||||
| } | ||||
| func (e *ioError) Unwrap() error { | ||||
| 	return e.err | ||||
| } | ||||
|  | ||||
| // SyntacticError is a description of a syntactic error that occurred when | ||||
| // encoding or decoding JSON according to the grammar. | ||||
| // | ||||
| // The contents of this error as produced by this package may change over time. | ||||
| type SyntacticError struct { | ||||
| 	requireKeyedLiterals | ||||
| 	nonComparable | ||||
|  | ||||
| 	// ByteOffset indicates that an error occurred after this byte offset. | ||||
| 	ByteOffset int64 | ||||
| 	// JSONPointer indicates that an error occurred within this JSON value | ||||
| 	// as indicated using the JSON Pointer notation (see RFC 6901). | ||||
| 	JSONPointer Pointer | ||||
|  | ||||
| 	// Err is the underlying error. | ||||
| 	Err error | ||||
| } | ||||
|  | ||||
| // wrapSyntacticError wraps an error and annotates it with a precise location | ||||
| // using the provided [encoderState] or [decoderState]. | ||||
| // If err is an [ioError] or [io.EOF], then it is not wrapped. | ||||
| // | ||||
| // It takes a relative offset pos that can be resolved into | ||||
| // an absolute offset using state.offsetAt. | ||||
| // | ||||
| // It takes a where that specify how the JSON pointer is derived. | ||||
| // If the underlying error is a [pointerSuffixError], | ||||
| // then the suffix is appended to the derived pointer. | ||||
| func wrapSyntacticError(state interface { | ||||
| 	offsetAt(pos int) int64 | ||||
| 	AppendStackPointer(b []byte, where int) []byte | ||||
| }, err error, pos, where int) error { | ||||
| 	if _, ok := err.(*ioError); err == io.EOF || ok { | ||||
| 		return err | ||||
| 	} | ||||
| 	offset := state.offsetAt(pos) | ||||
| 	ptr := state.AppendStackPointer(nil, where) | ||||
| 	if serr, ok := err.(*pointerSuffixError); ok { | ||||
| 		ptr = serr.appendPointer(ptr) | ||||
| 		err = serr.error | ||||
| 	} | ||||
| 	if d, ok := state.(*decoderState); ok && err == errMismatchDelim { | ||||
| 		where := "at start of value" | ||||
| 		if len(d.Tokens.Stack) > 0 && d.Tokens.Last.Length() > 0 { | ||||
| 			switch { | ||||
| 			case d.Tokens.Last.isArray(): | ||||
| 				where = "after array element (expecting ',' or ']')" | ||||
| 				ptr = []byte(Pointer(ptr).Parent()) // problem is with parent array | ||||
| 			case d.Tokens.Last.isObject(): | ||||
| 				where = "after object value (expecting ',' or '}')" | ||||
| 				ptr = []byte(Pointer(ptr).Parent()) // problem is with parent object | ||||
| 			} | ||||
| 		} | ||||
| 		err = jsonwire.NewInvalidCharacterError(d.buf[pos:], where) | ||||
| 	} | ||||
| 	return &SyntacticError{ByteOffset: offset, JSONPointer: Pointer(ptr), Err: err} | ||||
| } | ||||
|  | ||||
| func (e *SyntacticError) Error() string { | ||||
| 	pointer := e.JSONPointer | ||||
| 	offset := e.ByteOffset | ||||
| 	b := []byte(errorPrefix) | ||||
| 	if e.Err != nil { | ||||
| 		b = append(b, e.Err.Error()...) | ||||
| 		if e.Err == ErrDuplicateName { | ||||
| 			b = strconv.AppendQuote(append(b, ' '), pointer.LastToken()) | ||||
| 			pointer = pointer.Parent() | ||||
| 			offset = 0 // not useful to print offset for duplicate names | ||||
| 		} | ||||
| 	} else { | ||||
| 		b = append(b, "syntactic error"...) | ||||
| 	} | ||||
| 	if pointer != "" { | ||||
| 		b = strconv.AppendQuote(append(b, " within "...), jsonwire.TruncatePointer(string(pointer), 100)) | ||||
| 	} | ||||
| 	if offset > 0 { | ||||
| 		b = strconv.AppendInt(append(b, " after offset "...), offset, 10) | ||||
| 	} | ||||
| 	return string(b) | ||||
| } | ||||
|  | ||||
| func (e *SyntacticError) Unwrap() error { | ||||
| 	return e.Err | ||||
| } | ||||
|  | ||||
| // pointerSuffixError represents a JSON pointer suffix to be appended | ||||
| // to [SyntacticError.JSONPointer]. It is an internal error type | ||||
| // used within this package and does not appear in the public API. | ||||
| // | ||||
| // This type is primarily used to annotate errors in Encoder.WriteValue | ||||
| // and Decoder.ReadValue with precise positions. | ||||
| // At the time WriteValue or ReadValue is called, a JSON pointer to the | ||||
| // upcoming value can be constructed using the Encoder/Decoder state. | ||||
| // However, tracking pointers within values during normal operation | ||||
| // would incur a performance penalty in the error-free case. | ||||
| // | ||||
| // To provide precise error locations without this overhead, | ||||
| // the error is wrapped with object names or array indices | ||||
| // as the call stack is popped when an error occurs. | ||||
| // Since this happens in reverse order, pointerSuffixError holds | ||||
| // the pointer in reverse and is only later reversed when appending to | ||||
| // the pointer prefix. | ||||
| // | ||||
| // For example, if the encoder is at "/alpha/bravo/charlie" | ||||
| // and an error occurs in WriteValue at "/xray/yankee/zulu", then | ||||
| // the final pointer should be "/alpha/bravo/charlie/xray/yankee/zulu". | ||||
| // | ||||
| // As pointerSuffixError is populated during the error return path, | ||||
| // it first contains "/zulu", then "/zulu/yankee", | ||||
| // and finally "/zulu/yankee/xray". | ||||
| // These tokens are reversed and concatenated to "/alpha/bravo/charlie" | ||||
| // to form the full pointer. | ||||
| type pointerSuffixError struct { | ||||
| 	error | ||||
|  | ||||
| 	// reversePointer is a JSON pointer, but with each token in reverse order. | ||||
| 	reversePointer []byte | ||||
| } | ||||
|  | ||||
| // wrapWithObjectName wraps err with a JSON object name access, | ||||
| // which must be a valid quoted JSON string. | ||||
| func wrapWithObjectName(err error, quotedName []byte) error { | ||||
| 	serr, _ := err.(*pointerSuffixError) | ||||
| 	if serr == nil { | ||||
| 		serr = &pointerSuffixError{error: err} | ||||
| 	} | ||||
| 	name := jsonwire.UnquoteMayCopy(quotedName, false) | ||||
| 	serr.reversePointer = appendEscapePointerName(append(serr.reversePointer, '/'), name) | ||||
| 	return serr | ||||
| } | ||||
|  | ||||
| // wrapWithArrayIndex wraps err with a JSON array index access. | ||||
| func wrapWithArrayIndex(err error, index int64) error { | ||||
| 	serr, _ := err.(*pointerSuffixError) | ||||
| 	if serr == nil { | ||||
| 		serr = &pointerSuffixError{error: err} | ||||
| 	} | ||||
| 	serr.reversePointer = strconv.AppendUint(append(serr.reversePointer, '/'), uint64(index), 10) | ||||
| 	return serr | ||||
| } | ||||
|  | ||||
| // appendPointer appends the path encoded in e to the end of pointer. | ||||
| func (e *pointerSuffixError) appendPointer(pointer []byte) []byte { | ||||
| 	// Copy each token in reversePointer to the end of pointer in reverse order. | ||||
| 	// Double reversal means that the appended suffix is now in forward order. | ||||
| 	bi, bo := e.reversePointer, pointer | ||||
| 	for len(bi) > 0 { | ||||
| 		i := bytes.LastIndexByte(bi, '/') | ||||
| 		bi, bo = bi[:i], append(bo, bi[i:]...) | ||||
| 	} | ||||
| 	return bo | ||||
| } | ||||
							
								
								
									
										75
									
								
								vendor/github.com/go-json-experiment/json/jsontext/export.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								vendor/github.com/go-json-experiment/json/jsontext/export.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,75 @@ | ||||
| // Copyright 2023 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. | ||||
|  | ||||
| package jsontext | ||||
|  | ||||
| import ( | ||||
| 	"io" | ||||
|  | ||||
| 	"github.com/go-json-experiment/json/internal" | ||||
| ) | ||||
|  | ||||
| // Internal is for internal use only. | ||||
| // This is exempt from the Go compatibility agreement. | ||||
| var Internal exporter | ||||
|  | ||||
| type exporter struct{} | ||||
|  | ||||
| // Export exposes internal functionality from "jsontext" to "json". | ||||
| // This cannot be dynamically called by other packages since | ||||
| // they cannot obtain a reference to the internal.AllowInternalUse value. | ||||
| func (exporter) Export(p *internal.NotForPublicUse) export { | ||||
| 	if p != &internal.AllowInternalUse { | ||||
| 		panic("unauthorized call to Export") | ||||
| 	} | ||||
| 	return export{} | ||||
| } | ||||
|  | ||||
| // The export type exposes functionality to packages with visibility to | ||||
| // the internal.AllowInternalUse variable. The "json" package uses this | ||||
| // to modify low-level state in the Encoder and Decoder types. | ||||
| // It mutates the state directly instead of calling ReadToken or WriteToken | ||||
| // since this is more performant. The public APIs need to track state to ensure | ||||
| // that users are constructing a valid JSON value, but the "json" implementation | ||||
| // guarantees that it emits valid JSON by the structure of the code itself. | ||||
| type export struct{} | ||||
|  | ||||
| // Encoder returns a pointer to the underlying encoderState. | ||||
| func (export) Encoder(e *Encoder) *encoderState { return &e.s } | ||||
|  | ||||
| // Decoder returns a pointer to the underlying decoderState. | ||||
| func (export) Decoder(d *Decoder) *decoderState { return &d.s } | ||||
|  | ||||
| func (export) GetBufferedEncoder(o ...Options) *Encoder { | ||||
| 	return getBufferedEncoder(o...) | ||||
| } | ||||
| func (export) PutBufferedEncoder(e *Encoder) { | ||||
| 	putBufferedEncoder(e) | ||||
| } | ||||
|  | ||||
| func (export) GetStreamingEncoder(w io.Writer, o ...Options) *Encoder { | ||||
| 	return getStreamingEncoder(w, o...) | ||||
| } | ||||
| func (export) PutStreamingEncoder(e *Encoder) { | ||||
| 	putStreamingEncoder(e) | ||||
| } | ||||
|  | ||||
| func (export) GetBufferedDecoder(b []byte, o ...Options) *Decoder { | ||||
| 	return getBufferedDecoder(b, o...) | ||||
| } | ||||
| func (export) PutBufferedDecoder(d *Decoder) { | ||||
| 	putBufferedDecoder(d) | ||||
| } | ||||
|  | ||||
| func (export) GetStreamingDecoder(r io.Reader, o ...Options) *Decoder { | ||||
| 	return getStreamingDecoder(r, o...) | ||||
| } | ||||
| func (export) PutStreamingDecoder(d *Decoder) { | ||||
| 	putStreamingDecoder(d) | ||||
| } | ||||
|  | ||||
| func (export) IsIOError(err error) bool { | ||||
| 	_, ok := err.(*ioError) | ||||
| 	return ok | ||||
| } | ||||
							
								
								
									
										301
									
								
								vendor/github.com/go-json-experiment/json/jsontext/options.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										301
									
								
								vendor/github.com/go-json-experiment/json/jsontext/options.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,301 @@ | ||||
| // Copyright 2023 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. | ||||
|  | ||||
| package jsontext | ||||
|  | ||||
| import ( | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/go-json-experiment/json/internal/jsonflags" | ||||
| 	"github.com/go-json-experiment/json/internal/jsonopts" | ||||
| 	"github.com/go-json-experiment/json/internal/jsonwire" | ||||
| ) | ||||
|  | ||||
| // Options configures [NewEncoder], [Encoder.Reset], [NewDecoder], | ||||
| // and [Decoder.Reset] with specific features. | ||||
| // Each function takes in a variadic list of options, where properties | ||||
| // set in latter options override the value of previously set properties. | ||||
| // | ||||
| // There is a single Options type, which is used with both encoding and decoding. | ||||
| // Some options affect both operations, while others only affect one operation: | ||||
| // | ||||
| //   - [AllowDuplicateNames] affects encoding and decoding | ||||
| //   - [AllowInvalidUTF8] affects encoding and decoding | ||||
| //   - [EscapeForHTML] affects encoding only | ||||
| //   - [EscapeForJS] affects encoding only | ||||
| //   - [PreserveRawStrings] affects encoding only | ||||
| //   - [CanonicalizeRawInts] affects encoding only | ||||
| //   - [CanonicalizeRawFloats] affects encoding only | ||||
| //   - [ReorderRawObjects] affects encoding only | ||||
| //   - [SpaceAfterColon] affects encoding only | ||||
| //   - [SpaceAfterComma] affects encoding only | ||||
| //   - [Multiline] affects encoding only | ||||
| //   - [WithIndent] affects encoding only | ||||
| //   - [WithIndentPrefix] affects encoding only | ||||
| // | ||||
| // Options that do not affect a particular operation are ignored. | ||||
| // | ||||
| // The Options type is identical to [encoding/json.Options] and | ||||
| // [encoding/json/v2.Options]. Options from the other packages may | ||||
| // be passed to functionality in this package, but are ignored. | ||||
| // Options from this package may be used with the other packages. | ||||
| type Options = jsonopts.Options | ||||
|  | ||||
| // AllowDuplicateNames specifies that JSON objects may contain | ||||
| // duplicate member names. Disabling the duplicate name check may provide | ||||
| // performance benefits, but breaks compliance with RFC 7493, section 2.3. | ||||
| // The input or output will still be compliant with RFC 8259, | ||||
| // which leaves the handling of duplicate names as unspecified behavior. | ||||
| // | ||||
| // This affects either encoding or decoding. | ||||
| func AllowDuplicateNames(v bool) Options { | ||||
| 	if v { | ||||
| 		return jsonflags.AllowDuplicateNames | 1 | ||||
| 	} else { | ||||
| 		return jsonflags.AllowDuplicateNames | 0 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // AllowInvalidUTF8 specifies that JSON strings may contain invalid UTF-8, | ||||
| // which will be mangled as the Unicode replacement character, U+FFFD. | ||||
| // This causes the encoder or decoder to break compliance with | ||||
| // RFC 7493, section 2.1, and RFC 8259, section 8.1. | ||||
| // | ||||
| // This affects either encoding or decoding. | ||||
| func AllowInvalidUTF8(v bool) Options { | ||||
| 	if v { | ||||
| 		return jsonflags.AllowInvalidUTF8 | 1 | ||||
| 	} else { | ||||
| 		return jsonflags.AllowInvalidUTF8 | 0 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // EscapeForHTML specifies that '<', '>', and '&' characters within JSON strings | ||||
| // should be escaped as a hexadecimal Unicode codepoint (e.g., \u003c) so that | ||||
| // the output is safe to embed within HTML. | ||||
| // | ||||
| // This only affects encoding and is ignored when decoding. | ||||
| func EscapeForHTML(v bool) Options { | ||||
| 	if v { | ||||
| 		return jsonflags.EscapeForHTML | 1 | ||||
| 	} else { | ||||
| 		return jsonflags.EscapeForHTML | 0 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // EscapeForJS specifies that U+2028 and U+2029 characters within JSON strings | ||||
| // should be escaped as a hexadecimal Unicode codepoint (e.g., \u2028) so that | ||||
| // the output is valid to embed within JavaScript. See RFC 8259, section 12. | ||||
| // | ||||
| // This only affects encoding and is ignored when decoding. | ||||
| func EscapeForJS(v bool) Options { | ||||
| 	if v { | ||||
| 		return jsonflags.EscapeForJS | 1 | ||||
| 	} else { | ||||
| 		return jsonflags.EscapeForJS | 0 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // PreserveRawStrings specifies that when encoding a raw JSON string in a | ||||
| // [Token] or [Value], pre-escaped sequences | ||||
| // in a JSON string are preserved to the output. | ||||
| // However, raw strings still respect [EscapeForHTML] and [EscapeForJS] | ||||
| // such that the relevant characters are escaped. | ||||
| // If [AllowInvalidUTF8] is enabled, bytes of invalid UTF-8 | ||||
| // are preserved to the output. | ||||
| // | ||||
| // This only affects encoding and is ignored when decoding. | ||||
| func PreserveRawStrings(v bool) Options { | ||||
| 	if v { | ||||
| 		return jsonflags.PreserveRawStrings | 1 | ||||
| 	} else { | ||||
| 		return jsonflags.PreserveRawStrings | 0 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // CanonicalizeRawInts specifies that when encoding a raw JSON | ||||
| // integer number (i.e., a number without a fraction and exponent) in a | ||||
| // [Token] or [Value], the number is canonicalized | ||||
| // according to RFC 8785, section 3.2.2.3. As a special case, | ||||
| // the number -0 is canonicalized as 0. | ||||
| // | ||||
| // JSON numbers are treated as IEEE 754 double precision numbers. | ||||
| // Any numbers with precision beyond what is representable by that form | ||||
| // will lose their precision when canonicalized. For example, | ||||
| // integer values beyond ±2⁵³ will lose their precision. | ||||
| // For example, 1234567890123456789 is formatted as 1234567890123456800. | ||||
| // | ||||
| // This only affects encoding and is ignored when decoding. | ||||
| func CanonicalizeRawInts(v bool) Options { | ||||
| 	if v { | ||||
| 		return jsonflags.CanonicalizeRawInts | 1 | ||||
| 	} else { | ||||
| 		return jsonflags.CanonicalizeRawInts | 0 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // CanonicalizeRawFloats specifies that when encoding a raw JSON | ||||
| // floating-point number (i.e., a number with a fraction or exponent) in a | ||||
| // [Token] or [Value], the number is canonicalized | ||||
| // according to RFC 8785, section 3.2.2.3. As a special case, | ||||
| // the number -0 is canonicalized as 0. | ||||
| // | ||||
| // JSON numbers are treated as IEEE 754 double precision numbers. | ||||
| // It is safe to canonicalize a serialized single precision number and | ||||
| // parse it back as a single precision number and expect the same value. | ||||
| // If a number exceeds ±1.7976931348623157e+308, which is the maximum | ||||
| // finite number, then it saturated at that value and formatted as such. | ||||
| // | ||||
| // This only affects encoding and is ignored when decoding. | ||||
| func CanonicalizeRawFloats(v bool) Options { | ||||
| 	if v { | ||||
| 		return jsonflags.CanonicalizeRawFloats | 1 | ||||
| 	} else { | ||||
| 		return jsonflags.CanonicalizeRawFloats | 0 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // ReorderRawObjects specifies that when encoding a raw JSON object in a | ||||
| // [Value], the object members are reordered according to | ||||
| // RFC 8785, section 3.2.3. | ||||
| // | ||||
| // This only affects encoding and is ignored when decoding. | ||||
| func ReorderRawObjects(v bool) Options { | ||||
| 	if v { | ||||
| 		return jsonflags.ReorderRawObjects | 1 | ||||
| 	} else { | ||||
| 		return jsonflags.ReorderRawObjects | 0 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // SpaceAfterColon specifies that the JSON output should emit a space character | ||||
| // after each colon separator following a JSON object name. | ||||
| // If false, then no space character appears after the colon separator. | ||||
| // | ||||
| // This only affects encoding and is ignored when decoding. | ||||
| func SpaceAfterColon(v bool) Options { | ||||
| 	if v { | ||||
| 		return jsonflags.SpaceAfterColon | 1 | ||||
| 	} else { | ||||
| 		return jsonflags.SpaceAfterColon | 0 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // SpaceAfterComma specifies that the JSON output should emit a space character | ||||
| // after each comma separator following a JSON object value or array element. | ||||
| // If false, then no space character appears after the comma separator. | ||||
| // | ||||
| // This only affects encoding and is ignored when decoding. | ||||
| func SpaceAfterComma(v bool) Options { | ||||
| 	if v { | ||||
| 		return jsonflags.SpaceAfterComma | 1 | ||||
| 	} else { | ||||
| 		return jsonflags.SpaceAfterComma | 0 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Multiline specifies that the JSON output should expand to multiple lines, | ||||
| // where every JSON object member or JSON array element appears on | ||||
| // a new, indented line according to the nesting depth. | ||||
| // | ||||
| // If [SpaceAfterColon] is not specified, then the default is true. | ||||
| // If [SpaceAfterComma] is not specified, then the default is false. | ||||
| // If [WithIndent] is not specified, then the default is "\t". | ||||
| // | ||||
| // If set to false, then the output is a single-line, | ||||
| // where the only whitespace emitted is determined by the current | ||||
| // values of [SpaceAfterColon] and [SpaceAfterComma]. | ||||
| // | ||||
| // This only affects encoding and is ignored when decoding. | ||||
| func Multiline(v bool) Options { | ||||
| 	if v { | ||||
| 		return jsonflags.Multiline | 1 | ||||
| 	} else { | ||||
| 		return jsonflags.Multiline | 0 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WithIndent specifies that the encoder should emit multiline output | ||||
| // where each element in a JSON object or array begins on a new, indented line | ||||
| // beginning with the indent prefix (see [WithIndentPrefix]) | ||||
| // followed by one or more copies of indent according to the nesting depth. | ||||
| // The indent must only be composed of space or tab characters. | ||||
| // | ||||
| // If the intent to emit indented output without a preference for | ||||
| // the particular indent string, then use [Multiline] instead. | ||||
| // | ||||
| // This only affects encoding and is ignored when decoding. | ||||
| // Use of this option implies [Multiline] being set to true. | ||||
| func WithIndent(indent string) Options { | ||||
| 	// Fast-path: Return a constant for common indents, which avoids allocating. | ||||
| 	// These are derived from analyzing the Go module proxy on 2023-07-01. | ||||
| 	switch indent { | ||||
| 	case "\t": | ||||
| 		return jsonopts.Indent("\t") // ~14k usages | ||||
| 	case "    ": | ||||
| 		return jsonopts.Indent("    ") // ~18k usages | ||||
| 	case "   ": | ||||
| 		return jsonopts.Indent("   ") // ~1.7k usages | ||||
| 	case "  ": | ||||
| 		return jsonopts.Indent("  ") // ~52k usages | ||||
| 	case " ": | ||||
| 		return jsonopts.Indent(" ") // ~12k usages | ||||
| 	case "": | ||||
| 		return jsonopts.Indent("") // ~1.5k usages | ||||
| 	} | ||||
|  | ||||
| 	// Otherwise, allocate for this unique value. | ||||
| 	if s := strings.Trim(indent, " \t"); len(s) > 0 { | ||||
| 		panic("json: invalid character " + jsonwire.QuoteRune(s) + " in indent") | ||||
| 	} | ||||
| 	return jsonopts.Indent(indent) | ||||
| } | ||||
|  | ||||
| // WithIndentPrefix specifies that the encoder should emit multiline output | ||||
| // where each element in a JSON object or array begins on a new, indented line | ||||
| // beginning with the indent prefix followed by one or more copies of indent | ||||
| // (see [WithIndent]) according to the nesting depth. | ||||
| // The prefix must only be composed of space or tab characters. | ||||
| // | ||||
| // This only affects encoding and is ignored when decoding. | ||||
| // Use of this option implies [Multiline] being set to true. | ||||
| func WithIndentPrefix(prefix string) Options { | ||||
| 	if s := strings.Trim(prefix, " \t"); len(s) > 0 { | ||||
| 		panic("json: invalid character " + jsonwire.QuoteRune(s) + " in indent prefix") | ||||
| 	} | ||||
| 	return jsonopts.IndentPrefix(prefix) | ||||
| } | ||||
|  | ||||
| /* | ||||
| // TODO(https://go.dev/issue/56733): Implement WithByteLimit and WithDepthLimit. | ||||
|  | ||||
| // WithByteLimit sets a limit on the number of bytes of input or output bytes | ||||
| // that may be consumed or produced for each top-level JSON value. | ||||
| // If a [Decoder] or [Encoder] method call would need to consume/produce | ||||
| // more than a total of n bytes to make progress on the top-level JSON value, | ||||
| // then the call will report an error. | ||||
| // Whitespace before and within the top-level value are counted against the limit. | ||||
| // Whitespace after a top-level value are counted against the limit | ||||
| // for the next top-level value. | ||||
| // | ||||
| // A non-positive limit is equivalent to no limit at all. | ||||
| // If unspecified, the default limit is no limit at all. | ||||
| // This affects either encoding or decoding. | ||||
| func WithByteLimit(n int64) Options { | ||||
| 	return jsonopts.ByteLimit(max(n, 0)) | ||||
| } | ||||
|  | ||||
| // WithDepthLimit sets a limit on the maximum depth of JSON nesting | ||||
| // that may be consumed or produced for each top-level JSON value. | ||||
| // If a [Decoder] or [Encoder] method call would need to consume or produce | ||||
| // a depth greater than n to make progress on the top-level JSON value, | ||||
| // then the call will report an error. | ||||
| // | ||||
| // A non-positive limit is equivalent to no limit at all. | ||||
| // If unspecified, the default limit is 10000. | ||||
| // This affects either encoding or decoding. | ||||
| func WithDepthLimit(n int) Options { | ||||
| 	return jsonopts.DepthLimit(max(n, 0)) | ||||
| } | ||||
| */ | ||||
							
								
								
									
										150
									
								
								vendor/github.com/go-json-experiment/json/jsontext/pools.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								vendor/github.com/go-json-experiment/json/jsontext/pools.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,150 @@ | ||||
| // Copyright 2020 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. | ||||
|  | ||||
| package jsontext | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"io" | ||||
| 	"math/bits" | ||||
| 	"sync" | ||||
| ) | ||||
|  | ||||
| // TODO(https://go.dev/issue/47657): Use sync.PoolOf. | ||||
|  | ||||
| var ( | ||||
| 	// This owns the internal buffer since there is no io.Writer to output to. | ||||
| 	// Since the buffer can get arbitrarily large in normal usage, | ||||
| 	// there is statistical tracking logic to determine whether to recycle | ||||
| 	// the internal buffer or not based on a history of utilization. | ||||
| 	bufferedEncoderPool = &sync.Pool{New: func() any { return new(Encoder) }} | ||||
|  | ||||
| 	// This owns the internal buffer, but it is only used to temporarily store | ||||
| 	// buffered JSON before flushing it to the underlying io.Writer. | ||||
| 	// In a sufficiently efficient streaming mode, we do not expect the buffer | ||||
| 	// to grow arbitrarily large. Thus, we avoid recycling large buffers. | ||||
| 	streamingEncoderPool = &sync.Pool{New: func() any { return new(Encoder) }} | ||||
|  | ||||
| 	// This does not own the internal buffer since | ||||
| 	// it is taken directly from the provided bytes.Buffer. | ||||
| 	bytesBufferEncoderPool = &sync.Pool{New: func() any { return new(Encoder) }} | ||||
| ) | ||||
|  | ||||
| // bufferStatistics is statistics to track buffer utilization. | ||||
| // It is used to determine whether to recycle a buffer or not | ||||
| // to avoid https://go.dev/issue/23199. | ||||
| type bufferStatistics struct { | ||||
| 	strikes int // number of times the buffer was under-utilized | ||||
| 	prevLen int // length of previous buffer | ||||
| } | ||||
|  | ||||
| func getBufferedEncoder(opts ...Options) *Encoder { | ||||
| 	e := bufferedEncoderPool.Get().(*Encoder) | ||||
| 	if e.s.Buf == nil { | ||||
| 		// Round up to nearest 2ⁿ to make best use of malloc size classes. | ||||
| 		// See runtime/sizeclasses.go on Go1.15. | ||||
| 		// Logical OR with 63 to ensure 64 as the minimum buffer size. | ||||
| 		n := 1 << bits.Len(uint(e.s.bufStats.prevLen|63)) | ||||
| 		e.s.Buf = make([]byte, 0, n) | ||||
| 	} | ||||
| 	e.s.reset(e.s.Buf[:0], nil, opts...) | ||||
| 	return e | ||||
| } | ||||
| func putBufferedEncoder(e *Encoder) { | ||||
| 	// Recycle large buffers only if sufficiently utilized. | ||||
| 	// If a buffer is under-utilized enough times sequentially, | ||||
| 	// then it is discarded, ensuring that a single large buffer | ||||
| 	// won't be kept alive by a continuous stream of small usages. | ||||
| 	// | ||||
| 	// The worst case utilization is computed as: | ||||
| 	//	MIN_UTILIZATION_THRESHOLD / (1 + MAX_NUM_STRIKES) | ||||
| 	// | ||||
| 	// For the constants chosen below, this is (25%)/(1+4) ⇒ 5%. | ||||
| 	// This may seem low, but it ensures a lower bound on | ||||
| 	// the absolute worst-case utilization. Without this check, | ||||
| 	// this would be theoretically 0%, which is infinitely worse. | ||||
| 	// | ||||
| 	// See https://go.dev/issue/27735. | ||||
| 	switch { | ||||
| 	case cap(e.s.Buf) <= 4<<10: // always recycle buffers smaller than 4KiB | ||||
| 		e.s.bufStats.strikes = 0 | ||||
| 	case cap(e.s.Buf)/4 <= len(e.s.Buf): // at least 25% utilization | ||||
| 		e.s.bufStats.strikes = 0 | ||||
| 	case e.s.bufStats.strikes < 4: // at most 4 strikes | ||||
| 		e.s.bufStats.strikes++ | ||||
| 	default: // discard the buffer; too large and too often under-utilized | ||||
| 		e.s.bufStats.strikes = 0 | ||||
| 		e.s.bufStats.prevLen = len(e.s.Buf) // heuristic for size to allocate next time | ||||
| 		e.s.Buf = nil | ||||
| 	} | ||||
| 	bufferedEncoderPool.Put(e) | ||||
| } | ||||
|  | ||||
| func getStreamingEncoder(w io.Writer, opts ...Options) *Encoder { | ||||
| 	if _, ok := w.(*bytes.Buffer); ok { | ||||
| 		e := bytesBufferEncoderPool.Get().(*Encoder) | ||||
| 		e.s.reset(nil, w, opts...) // buffer taken from bytes.Buffer | ||||
| 		return e | ||||
| 	} else { | ||||
| 		e := streamingEncoderPool.Get().(*Encoder) | ||||
| 		e.s.reset(e.s.Buf[:0], w, opts...) // preserve existing buffer | ||||
| 		return e | ||||
| 	} | ||||
| } | ||||
| func putStreamingEncoder(e *Encoder) { | ||||
| 	if _, ok := e.s.wr.(*bytes.Buffer); ok { | ||||
| 		bytesBufferEncoderPool.Put(e) | ||||
| 	} else { | ||||
| 		if cap(e.s.Buf) > 64<<10 { | ||||
| 			e.s.Buf = nil // avoid pinning arbitrarily large amounts of memory | ||||
| 		} | ||||
| 		streamingEncoderPool.Put(e) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| var ( | ||||
| 	// This does not own the internal buffer since it is externally provided. | ||||
| 	bufferedDecoderPool = &sync.Pool{New: func() any { return new(Decoder) }} | ||||
|  | ||||
| 	// This owns the internal buffer, but it is only used to temporarily store | ||||
| 	// buffered JSON fetched from the underlying io.Reader. | ||||
| 	// In a sufficiently efficient streaming mode, we do not expect the buffer | ||||
| 	// to grow arbitrarily large. Thus, we avoid recycling large buffers. | ||||
| 	streamingDecoderPool = &sync.Pool{New: func() any { return new(Decoder) }} | ||||
|  | ||||
| 	// This does not own the internal buffer since | ||||
| 	// it is taken directly from the provided bytes.Buffer. | ||||
| 	bytesBufferDecoderPool = bufferedDecoderPool | ||||
| ) | ||||
|  | ||||
| func getBufferedDecoder(b []byte, opts ...Options) *Decoder { | ||||
| 	d := bufferedDecoderPool.Get().(*Decoder) | ||||
| 	d.s.reset(b, nil, opts...) | ||||
| 	return d | ||||
| } | ||||
| func putBufferedDecoder(d *Decoder) { | ||||
| 	bufferedDecoderPool.Put(d) | ||||
| } | ||||
|  | ||||
| func getStreamingDecoder(r io.Reader, opts ...Options) *Decoder { | ||||
| 	if _, ok := r.(*bytes.Buffer); ok { | ||||
| 		d := bytesBufferDecoderPool.Get().(*Decoder) | ||||
| 		d.s.reset(nil, r, opts...) // buffer taken from bytes.Buffer | ||||
| 		return d | ||||
| 	} else { | ||||
| 		d := streamingDecoderPool.Get().(*Decoder) | ||||
| 		d.s.reset(d.s.buf[:0], r, opts...) // preserve existing buffer | ||||
| 		return d | ||||
| 	} | ||||
| } | ||||
| func putStreamingDecoder(d *Decoder) { | ||||
| 	if _, ok := d.s.rd.(*bytes.Buffer); ok { | ||||
| 		bytesBufferDecoderPool.Put(d) | ||||
| 	} else { | ||||
| 		if cap(d.s.buf) > 64<<10 { | ||||
| 			d.s.buf = nil // avoid pinning arbitrarily large amounts of memory | ||||
| 		} | ||||
| 		streamingDecoderPool.Put(d) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										39
									
								
								vendor/github.com/go-json-experiment/json/jsontext/quote.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								vendor/github.com/go-json-experiment/json/jsontext/quote.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| // Copyright 2023 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. | ||||
|  | ||||
| package jsontext | ||||
|  | ||||
| import ( | ||||
| 	"github.com/go-json-experiment/json/internal/jsonflags" | ||||
| 	"github.com/go-json-experiment/json/internal/jsonwire" | ||||
| ) | ||||
|  | ||||
| // AppendQuote appends a double-quoted JSON string literal representing src | ||||
| // to dst and returns the extended buffer. | ||||
| // It uses the minimal string representation per RFC 8785, section 3.2.2.2. | ||||
| // Invalid UTF-8 bytes are replaced with the Unicode replacement character | ||||
| // and an error is returned at the end indicating the presence of invalid UTF-8. | ||||
| // The dst must not overlap with the src. | ||||
| func AppendQuote[Bytes ~[]byte | ~string](dst []byte, src Bytes) ([]byte, error) { | ||||
| 	dst, err := jsonwire.AppendQuote(dst, src, &jsonflags.Flags{}) | ||||
| 	if err != nil { | ||||
| 		err = &SyntacticError{Err: err} | ||||
| 	} | ||||
| 	return dst, err | ||||
| } | ||||
|  | ||||
| // AppendUnquote appends the decoded interpretation of src as a | ||||
| // double-quoted JSON string literal to dst and returns the extended buffer. | ||||
| // The input src must be a JSON string without any surrounding whitespace. | ||||
| // Invalid UTF-8 bytes are replaced with the Unicode replacement character | ||||
| // and an error is returned at the end indicating the presence of invalid UTF-8. | ||||
| // Any trailing bytes after the JSON string literal results in an error. | ||||
| // The dst must not overlap with the src. | ||||
| func AppendUnquote[Bytes ~[]byte | ~string](dst []byte, src Bytes) ([]byte, error) { | ||||
| 	dst, err := jsonwire.AppendUnquote(dst, src) | ||||
| 	if err != nil { | ||||
| 		err = &SyntacticError{Err: err} | ||||
| 	} | ||||
| 	return dst, err | ||||
| } | ||||
							
								
								
									
										826
									
								
								vendor/github.com/go-json-experiment/json/jsontext/state.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										826
									
								
								vendor/github.com/go-json-experiment/json/jsontext/state.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,826 @@ | ||||
| // Copyright 2020 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. | ||||
|  | ||||
| package jsontext | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"iter" | ||||
| 	"math" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"unicode/utf8" | ||||
|  | ||||
| 	"github.com/go-json-experiment/json/internal/jsonwire" | ||||
| ) | ||||
|  | ||||
| // ErrDuplicateName indicates that a JSON token could not be | ||||
| // encoded or decoded because it results in a duplicate JSON object name. | ||||
| // This error is directly wrapped within a [SyntacticError] when produced. | ||||
| // | ||||
| // The name of a duplicate JSON object member can be extracted as: | ||||
| // | ||||
| //	err := ... | ||||
| //	var serr jsontext.SyntacticError | ||||
| //	if errors.As(err, &serr) && serr.Err == jsontext.ErrDuplicateName { | ||||
| //		ptr := serr.JSONPointer // JSON pointer to duplicate name | ||||
| //		name := ptr.LastToken() // duplicate name itself | ||||
| //		... | ||||
| //	} | ||||
| // | ||||
| // This error is only returned if [AllowDuplicateNames] is false. | ||||
| var ErrDuplicateName = errors.New("duplicate object member name") | ||||
|  | ||||
| // ErrNonStringName indicates that a JSON token could not be | ||||
| // encoded or decoded because it is not a string, | ||||
| // as required for JSON object names according to RFC 8259, section 4. | ||||
| // This error is directly wrapped within a [SyntacticError] when produced. | ||||
| var ErrNonStringName = errors.New("object member name must be a string") | ||||
|  | ||||
| var ( | ||||
| 	errMissingValue  = errors.New("missing value after object name") | ||||
| 	errMismatchDelim = errors.New("mismatching structural token for object or array") | ||||
| 	errMaxDepth      = errors.New("exceeded max depth") | ||||
|  | ||||
| 	errInvalidNamespace = errors.New("object namespace is in an invalid state") | ||||
| ) | ||||
|  | ||||
| // Per RFC 8259, section 9, implementations may enforce a maximum depth. | ||||
| // Such a limit is necessary to prevent stack overflows. | ||||
| const maxNestingDepth = 10000 | ||||
|  | ||||
| type state struct { | ||||
| 	// Tokens validates whether the next token kind is valid. | ||||
| 	Tokens stateMachine | ||||
|  | ||||
| 	// Names is a stack of object names. | ||||
| 	Names objectNameStack | ||||
|  | ||||
| 	// Namespaces is a stack of object namespaces. | ||||
| 	// For performance reasons, Encoder or Decoder may not update this | ||||
| 	// if Marshal or Unmarshal is able to track names in a more efficient way. | ||||
| 	// See makeMapArshaler and makeStructArshaler. | ||||
| 	// Not used if AllowDuplicateNames is true. | ||||
| 	Namespaces objectNamespaceStack | ||||
| } | ||||
|  | ||||
| // needObjectValue reports whether the next token should be an object value. | ||||
| // This method is used by [wrapSyntacticError]. | ||||
| func (s *state) needObjectValue() bool { | ||||
| 	return s.Tokens.Last.needObjectValue() | ||||
| } | ||||
|  | ||||
| func (s *state) reset() { | ||||
| 	s.Tokens.reset() | ||||
| 	s.Names.reset() | ||||
| 	s.Namespaces.reset() | ||||
| } | ||||
|  | ||||
| // Pointer is a JSON Pointer (RFC 6901) that references a particular JSON value | ||||
| // relative to the root of the top-level JSON value. | ||||
| // | ||||
| // A Pointer is a slash-separated list of tokens, where each token is | ||||
| // either a JSON object name or an index to a JSON array element | ||||
| // encoded as a base-10 integer value. | ||||
| // It is impossible to distinguish between an array index and an object name | ||||
| // (that happens to be an base-10 encoded integer) without also knowing | ||||
| // the structure of the top-level JSON value that the pointer refers to. | ||||
| // | ||||
| // There is exactly one representation of a pointer to a particular value, | ||||
| // so comparability of Pointer values is equivalent to checking whether | ||||
| // they both point to the exact same value. | ||||
| type Pointer string | ||||
|  | ||||
| // IsValid reports whether p is a valid JSON Pointer according to RFC 6901. | ||||
| // Note that the concatenation of two valid pointers produces a valid pointer. | ||||
| func (p Pointer) IsValid() bool { | ||||
| 	for i, r := range p { | ||||
| 		switch { | ||||
| 		case r == '~' && (i+1 == len(p) || (p[i+1] != '0' && p[i+1] != '1')): | ||||
| 			return false // invalid escape | ||||
| 		case r == '\ufffd' && !strings.HasPrefix(string(p[i:]), "\ufffd"): | ||||
| 			return false // invalid UTF-8 | ||||
| 		} | ||||
| 	} | ||||
| 	return len(p) == 0 || p[0] == '/' | ||||
| } | ||||
|  | ||||
| // Contains reports whether the JSON value that p points to | ||||
| // is equal to or contains the JSON value that pc points to. | ||||
| func (p Pointer) Contains(pc Pointer) bool { | ||||
| 	// Invariant: len(p) <= len(pc) if p.Contains(pc) | ||||
| 	suffix, ok := strings.CutPrefix(string(pc), string(p)) | ||||
| 	return ok && (suffix == "" || suffix[0] == '/') | ||||
| } | ||||
|  | ||||
| // Parent strips off the last token and returns the remaining pointer. | ||||
| // The parent of an empty p is an empty string. | ||||
| func (p Pointer) Parent() Pointer { | ||||
| 	return p[:max(strings.LastIndexByte(string(p), '/'), 0)] | ||||
| } | ||||
|  | ||||
| // LastToken returns the last token in the pointer. | ||||
| // The last token of an empty p is an empty string. | ||||
| func (p Pointer) LastToken() string { | ||||
| 	last := p[max(strings.LastIndexByte(string(p), '/'), 0):] | ||||
| 	return unescapePointerToken(strings.TrimPrefix(string(last), "/")) | ||||
| } | ||||
|  | ||||
| // AppendToken appends a token to the end of p and returns the full pointer. | ||||
| func (p Pointer) AppendToken(tok string) Pointer { | ||||
| 	return Pointer(appendEscapePointerName([]byte(p+"/"), tok)) | ||||
| } | ||||
|  | ||||
| // TODO: Add Pointer.AppendTokens, | ||||
| // but should this take in a ...string or an iter.Seq[string]? | ||||
|  | ||||
| // Tokens returns an iterator over the reference tokens in the JSON pointer, | ||||
| // starting from the first token until the last token (unless stopped early). | ||||
| func (p Pointer) Tokens() iter.Seq[string] { | ||||
| 	return func(yield func(string) bool) { | ||||
| 		for len(p) > 0 { | ||||
| 			p = Pointer(strings.TrimPrefix(string(p), "/")) | ||||
| 			i := min(uint(strings.IndexByte(string(p), '/')), uint(len(p))) | ||||
| 			if !yield(unescapePointerToken(string(p)[:i])) { | ||||
| 				return | ||||
| 			} | ||||
| 			p = p[i:] | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func unescapePointerToken(token string) string { | ||||
| 	if strings.Contains(token, "~") { | ||||
| 		// Per RFC 6901, section 3, unescape '~' and '/' characters. | ||||
| 		token = strings.ReplaceAll(token, "~1", "/") | ||||
| 		token = strings.ReplaceAll(token, "~0", "~") | ||||
| 	} | ||||
| 	return token | ||||
| } | ||||
|  | ||||
| // appendStackPointer appends a JSON Pointer (RFC 6901) to the current value. | ||||
| // | ||||
| //   - If where is -1, then it points to the previously processed token. | ||||
| // | ||||
| //   - If where is 0, then it points to the parent JSON object or array, | ||||
| //     or an object member if in-between an object member key and value. | ||||
| //     This is useful when the position is ambiguous whether | ||||
| //     we are interested in the previous or next token, or | ||||
| //     when we are uncertain whether the next token | ||||
| //     continues or terminates the current object or array. | ||||
| // | ||||
| //   - If where is +1, then it points to the next expected value, | ||||
| //     assuming that it continues the current JSON object or array. | ||||
| //     As a special case, if the next token is a JSON object name, | ||||
| //     then it points to the parent JSON object. | ||||
| // | ||||
| // Invariant: Must call s.names.copyQuotedBuffer beforehand. | ||||
| func (s state) appendStackPointer(b []byte, where int) []byte { | ||||
| 	var objectDepth int | ||||
| 	for i := 1; i < s.Tokens.Depth(); i++ { | ||||
| 		e := s.Tokens.index(i) | ||||
| 		arrayDelta := -1 // by default point to previous array element | ||||
| 		if isLast := i == s.Tokens.Depth()-1; isLast { | ||||
| 			switch { | ||||
| 			case where < 0 && e.Length() == 0 || where == 0 && !e.needObjectValue() || where > 0 && e.NeedObjectName(): | ||||
| 				return b | ||||
| 			case where > 0 && e.isArray(): | ||||
| 				arrayDelta = 0 // point to next array element | ||||
| 			} | ||||
| 		} | ||||
| 		switch { | ||||
| 		case e.isObject(): | ||||
| 			b = appendEscapePointerName(append(b, '/'), s.Names.getUnquoted(objectDepth)) | ||||
| 			objectDepth++ | ||||
| 		case e.isArray(): | ||||
| 			b = strconv.AppendUint(append(b, '/'), uint64(e.Length()+int64(arrayDelta)), 10) | ||||
| 		} | ||||
| 	} | ||||
| 	return b | ||||
| } | ||||
|  | ||||
| func appendEscapePointerName[Bytes ~[]byte | ~string](b []byte, name Bytes) []byte { | ||||
| 	for _, r := range string(name) { | ||||
| 		// Per RFC 6901, section 3, escape '~' and '/' characters. | ||||
| 		switch r { | ||||
| 		case '~': | ||||
| 			b = append(b, "~0"...) | ||||
| 		case '/': | ||||
| 			b = append(b, "~1"...) | ||||
| 		default: | ||||
| 			b = utf8.AppendRune(b, r) | ||||
| 		} | ||||
| 	} | ||||
| 	return b | ||||
| } | ||||
|  | ||||
| // stateMachine is a push-down automaton that validates whether | ||||
| // a sequence of tokens is valid or not according to the JSON grammar. | ||||
| // It is useful for both encoding and decoding. | ||||
| // | ||||
| // It is a stack where each entry represents a nested JSON object or array. | ||||
| // The stack has a minimum depth of 1 where the first level is a | ||||
| // virtual JSON array to handle a stream of top-level JSON values. | ||||
| // The top-level virtual JSON array is special in that it doesn't require commas | ||||
| // between each JSON value. | ||||
| // | ||||
| // For performance, most methods are carefully written to be inlinable. | ||||
| // The zero value is a valid state machine ready for use. | ||||
| type stateMachine struct { | ||||
| 	Stack []stateEntry | ||||
| 	Last  stateEntry | ||||
| } | ||||
|  | ||||
| // reset resets the state machine. | ||||
| // The machine always starts with a minimum depth of 1. | ||||
| func (m *stateMachine) reset() { | ||||
| 	m.Stack = m.Stack[:0] | ||||
| 	if cap(m.Stack) > 1<<10 { | ||||
| 		m.Stack = nil | ||||
| 	} | ||||
| 	m.Last = stateTypeArray | ||||
| } | ||||
|  | ||||
| // Depth is the current nested depth of JSON objects and arrays. | ||||
| // It is one-indexed (i.e., top-level values have a depth of 1). | ||||
| func (m stateMachine) Depth() int { | ||||
| 	return len(m.Stack) + 1 | ||||
| } | ||||
|  | ||||
| // index returns a reference to the ith entry. | ||||
| // It is only valid until the next push method call. | ||||
| func (m *stateMachine) index(i int) *stateEntry { | ||||
| 	if i == len(m.Stack) { | ||||
| 		return &m.Last | ||||
| 	} | ||||
| 	return &m.Stack[i] | ||||
| } | ||||
|  | ||||
| // DepthLength reports the current nested depth and | ||||
| // the length of the last JSON object or array. | ||||
| func (m stateMachine) DepthLength() (int, int64) { | ||||
| 	return m.Depth(), m.Last.Length() | ||||
| } | ||||
|  | ||||
| // appendLiteral appends a JSON literal as the next token in the sequence. | ||||
| // If an error is returned, the state is not mutated. | ||||
| func (m *stateMachine) appendLiteral() error { | ||||
| 	switch { | ||||
| 	case m.Last.NeedObjectName(): | ||||
| 		return ErrNonStringName | ||||
| 	case !m.Last.isValidNamespace(): | ||||
| 		return errInvalidNamespace | ||||
| 	default: | ||||
| 		m.Last.Increment() | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // appendString appends a JSON string as the next token in the sequence. | ||||
| // If an error is returned, the state is not mutated. | ||||
| func (m *stateMachine) appendString() error { | ||||
| 	switch { | ||||
| 	case !m.Last.isValidNamespace(): | ||||
| 		return errInvalidNamespace | ||||
| 	default: | ||||
| 		m.Last.Increment() | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // appendNumber appends a JSON number as the next token in the sequence. | ||||
| // If an error is returned, the state is not mutated. | ||||
| func (m *stateMachine) appendNumber() error { | ||||
| 	return m.appendLiteral() | ||||
| } | ||||
|  | ||||
| // pushObject appends a JSON start object token as next in the sequence. | ||||
| // If an error is returned, the state is not mutated. | ||||
| func (m *stateMachine) pushObject() error { | ||||
| 	switch { | ||||
| 	case m.Last.NeedObjectName(): | ||||
| 		return ErrNonStringName | ||||
| 	case !m.Last.isValidNamespace(): | ||||
| 		return errInvalidNamespace | ||||
| 	case len(m.Stack) == maxNestingDepth: | ||||
| 		return errMaxDepth | ||||
| 	default: | ||||
| 		m.Last.Increment() | ||||
| 		m.Stack = append(m.Stack, m.Last) | ||||
| 		m.Last = stateTypeObject | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // popObject appends a JSON end object token as next in the sequence. | ||||
| // If an error is returned, the state is not mutated. | ||||
| func (m *stateMachine) popObject() error { | ||||
| 	switch { | ||||
| 	case !m.Last.isObject(): | ||||
| 		return errMismatchDelim | ||||
| 	case m.Last.needObjectValue(): | ||||
| 		return errMissingValue | ||||
| 	case !m.Last.isValidNamespace(): | ||||
| 		return errInvalidNamespace | ||||
| 	default: | ||||
| 		m.Last = m.Stack[len(m.Stack)-1] | ||||
| 		m.Stack = m.Stack[:len(m.Stack)-1] | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // pushArray appends a JSON start array token as next in the sequence. | ||||
| // If an error is returned, the state is not mutated. | ||||
| func (m *stateMachine) pushArray() error { | ||||
| 	switch { | ||||
| 	case m.Last.NeedObjectName(): | ||||
| 		return ErrNonStringName | ||||
| 	case !m.Last.isValidNamespace(): | ||||
| 		return errInvalidNamespace | ||||
| 	case len(m.Stack) == maxNestingDepth: | ||||
| 		return errMaxDepth | ||||
| 	default: | ||||
| 		m.Last.Increment() | ||||
| 		m.Stack = append(m.Stack, m.Last) | ||||
| 		m.Last = stateTypeArray | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // popArray appends a JSON end array token as next in the sequence. | ||||
| // If an error is returned, the state is not mutated. | ||||
| func (m *stateMachine) popArray() error { | ||||
| 	switch { | ||||
| 	case !m.Last.isArray() || len(m.Stack) == 0: // forbid popping top-level virtual JSON array | ||||
| 		return errMismatchDelim | ||||
| 	case !m.Last.isValidNamespace(): | ||||
| 		return errInvalidNamespace | ||||
| 	default: | ||||
| 		m.Last = m.Stack[len(m.Stack)-1] | ||||
| 		m.Stack = m.Stack[:len(m.Stack)-1] | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // NeedIndent reports whether indent whitespace should be injected. | ||||
| // A zero value means that no whitespace should be injected. | ||||
| // A positive value means '\n', indentPrefix, and (n-1) copies of indentBody | ||||
| // should be appended to the output immediately before the next token. | ||||
| func (m stateMachine) NeedIndent(next Kind) (n int) { | ||||
| 	willEnd := next == '}' || next == ']' | ||||
| 	switch { | ||||
| 	case m.Depth() == 1: | ||||
| 		return 0 // top-level values are never indented | ||||
| 	case m.Last.Length() == 0 && willEnd: | ||||
| 		return 0 // an empty object or array is never indented | ||||
| 	case m.Last.Length() == 0 || m.Last.needImplicitComma(next): | ||||
| 		return m.Depth() | ||||
| 	case willEnd: | ||||
| 		return m.Depth() - 1 | ||||
| 	default: | ||||
| 		return 0 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // MayAppendDelim appends a colon or comma that may precede the next token. | ||||
| func (m stateMachine) MayAppendDelim(b []byte, next Kind) []byte { | ||||
| 	switch { | ||||
| 	case m.Last.needImplicitColon(): | ||||
| 		return append(b, ':') | ||||
| 	case m.Last.needImplicitComma(next) && len(m.Stack) != 0: // comma not needed for top-level values | ||||
| 		return append(b, ',') | ||||
| 	default: | ||||
| 		return b | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // needDelim reports whether a colon or comma token should be implicitly emitted | ||||
| // before the next token of the specified kind. | ||||
| // A zero value means no delimiter should be emitted. | ||||
| func (m stateMachine) needDelim(next Kind) (delim byte) { | ||||
| 	switch { | ||||
| 	case m.Last.needImplicitColon(): | ||||
| 		return ':' | ||||
| 	case m.Last.needImplicitComma(next) && len(m.Stack) != 0: // comma not needed for top-level values | ||||
| 		return ',' | ||||
| 	default: | ||||
| 		return 0 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // InvalidateDisabledNamespaces marks all disabled namespaces as invalid. | ||||
| // | ||||
| // For efficiency, Marshal and Unmarshal may disable namespaces since there are | ||||
| // more efficient ways to track duplicate names. However, if an error occurs, | ||||
| // the namespaces in Encoder or Decoder will be left in an inconsistent state. | ||||
| // Mark the namespaces as invalid so that future method calls on | ||||
| // Encoder or Decoder will return an error. | ||||
| func (m *stateMachine) InvalidateDisabledNamespaces() { | ||||
| 	for i := range m.Depth() { | ||||
| 		e := m.index(i) | ||||
| 		if !e.isActiveNamespace() { | ||||
| 			e.invalidateNamespace() | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // stateEntry encodes several artifacts within a single unsigned integer: | ||||
| //   - whether this represents a JSON object or array, | ||||
| //   - whether this object should check for duplicate names, and | ||||
| //   - how many elements are in this JSON object or array. | ||||
| type stateEntry uint64 | ||||
|  | ||||
| const ( | ||||
| 	// The type mask (1 bit) records whether this is a JSON object or array. | ||||
| 	stateTypeMask   stateEntry = 0x8000_0000_0000_0000 | ||||
| 	stateTypeObject stateEntry = 0x8000_0000_0000_0000 | ||||
| 	stateTypeArray  stateEntry = 0x0000_0000_0000_0000 | ||||
|  | ||||
| 	// The name check mask (2 bit) records whether to update | ||||
| 	// the namespaces for the current JSON object and | ||||
| 	// whether the namespace is valid. | ||||
| 	stateNamespaceMask    stateEntry = 0x6000_0000_0000_0000 | ||||
| 	stateDisableNamespace stateEntry = 0x4000_0000_0000_0000 | ||||
| 	stateInvalidNamespace stateEntry = 0x2000_0000_0000_0000 | ||||
|  | ||||
| 	// The count mask (61 bits) records the number of elements. | ||||
| 	stateCountMask    stateEntry = 0x1fff_ffff_ffff_ffff | ||||
| 	stateCountLSBMask stateEntry = 0x0000_0000_0000_0001 | ||||
| 	stateCountOdd     stateEntry = 0x0000_0000_0000_0001 | ||||
| 	stateCountEven    stateEntry = 0x0000_0000_0000_0000 | ||||
| ) | ||||
|  | ||||
| // Length reports the number of elements in the JSON object or array. | ||||
| // Each name and value in an object entry is treated as a separate element. | ||||
| func (e stateEntry) Length() int64 { | ||||
| 	return int64(e & stateCountMask) | ||||
| } | ||||
|  | ||||
| // isObject reports whether this is a JSON object. | ||||
| func (e stateEntry) isObject() bool { | ||||
| 	return e&stateTypeMask == stateTypeObject | ||||
| } | ||||
|  | ||||
| // isArray reports whether this is a JSON array. | ||||
| func (e stateEntry) isArray() bool { | ||||
| 	return e&stateTypeMask == stateTypeArray | ||||
| } | ||||
|  | ||||
| // NeedObjectName reports whether the next token must be a JSON string, | ||||
| // which is necessary for JSON object names. | ||||
| func (e stateEntry) NeedObjectName() bool { | ||||
| 	return e&(stateTypeMask|stateCountLSBMask) == stateTypeObject|stateCountEven | ||||
| } | ||||
|  | ||||
| // needImplicitColon reports whether an colon should occur next, | ||||
| // which always occurs after JSON object names. | ||||
| func (e stateEntry) needImplicitColon() bool { | ||||
| 	return e.needObjectValue() | ||||
| } | ||||
|  | ||||
| // needObjectValue reports whether the next token must be a JSON value, | ||||
| // which is necessary after every JSON object name. | ||||
| func (e stateEntry) needObjectValue() bool { | ||||
| 	return e&(stateTypeMask|stateCountLSBMask) == stateTypeObject|stateCountOdd | ||||
| } | ||||
|  | ||||
| // needImplicitComma reports whether an comma should occur next, | ||||
| // which always occurs after a value in a JSON object or array | ||||
| // before the next value (or name). | ||||
| func (e stateEntry) needImplicitComma(next Kind) bool { | ||||
| 	return !e.needObjectValue() && e.Length() > 0 && next != '}' && next != ']' | ||||
| } | ||||
|  | ||||
| // Increment increments the number of elements for the current object or array. | ||||
| // This assumes that overflow won't practically be an issue since | ||||
| // 1<<bits.OnesCount(stateCountMask) is sufficiently large. | ||||
| func (e *stateEntry) Increment() { | ||||
| 	(*e)++ | ||||
| } | ||||
|  | ||||
| // decrement decrements the number of elements for the current object or array. | ||||
| // It is the callers responsibility to ensure that e.length > 0. | ||||
| func (e *stateEntry) decrement() { | ||||
| 	(*e)-- | ||||
| } | ||||
|  | ||||
| // DisableNamespace disables the JSON object namespace such that the | ||||
| // Encoder or Decoder no longer updates the namespace. | ||||
| func (e *stateEntry) DisableNamespace() { | ||||
| 	*e |= stateDisableNamespace | ||||
| } | ||||
|  | ||||
| // isActiveNamespace reports whether the JSON object namespace is actively | ||||
| // being updated and used for duplicate name checks. | ||||
| func (e stateEntry) isActiveNamespace() bool { | ||||
| 	return e&(stateDisableNamespace) == 0 | ||||
| } | ||||
|  | ||||
| // invalidateNamespace marks the JSON object namespace as being invalid. | ||||
| func (e *stateEntry) invalidateNamespace() { | ||||
| 	*e |= stateInvalidNamespace | ||||
| } | ||||
|  | ||||
| // isValidNamespace reports whether the JSON object namespace is valid. | ||||
| func (e stateEntry) isValidNamespace() bool { | ||||
| 	return e&(stateInvalidNamespace) == 0 | ||||
| } | ||||
|  | ||||
| // objectNameStack is a stack of names when descending into a JSON object. | ||||
| // In contrast to objectNamespaceStack, this only has to remember a single name | ||||
| // per JSON object. | ||||
| // | ||||
| // This data structure may contain offsets to encodeBuffer or decodeBuffer. | ||||
| // It violates clean abstraction of layers, but is significantly more efficient. | ||||
| // This ensures that popping and pushing in the common case is a trivial | ||||
| // push/pop of an offset integer. | ||||
| // | ||||
| // The zero value is an empty names stack ready for use. | ||||
| type objectNameStack struct { | ||||
| 	// offsets is a stack of offsets for each name. | ||||
| 	// A non-negative offset is the ending offset into the local names buffer. | ||||
| 	// A negative offset is the bit-wise inverse of a starting offset into | ||||
| 	// a remote buffer (e.g., encodeBuffer or decodeBuffer). | ||||
| 	// A math.MinInt offset at the end implies that the last object is empty. | ||||
| 	// Invariant: Positive offsets always occur before negative offsets. | ||||
| 	offsets []int | ||||
| 	// unquotedNames is a back-to-back concatenation of names. | ||||
| 	unquotedNames []byte | ||||
| } | ||||
|  | ||||
| func (ns *objectNameStack) reset() { | ||||
| 	ns.offsets = ns.offsets[:0] | ||||
| 	ns.unquotedNames = ns.unquotedNames[:0] | ||||
| 	if cap(ns.offsets) > 1<<6 { | ||||
| 		ns.offsets = nil // avoid pinning arbitrarily large amounts of memory | ||||
| 	} | ||||
| 	if cap(ns.unquotedNames) > 1<<10 { | ||||
| 		ns.unquotedNames = nil // avoid pinning arbitrarily large amounts of memory | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (ns *objectNameStack) length() int { | ||||
| 	return len(ns.offsets) | ||||
| } | ||||
|  | ||||
| // getUnquoted retrieves the ith unquoted name in the stack. | ||||
| // It returns an empty string if the last object is empty. | ||||
| // | ||||
| // Invariant: Must call copyQuotedBuffer beforehand. | ||||
| func (ns *objectNameStack) getUnquoted(i int) []byte { | ||||
| 	ns.ensureCopiedBuffer() | ||||
| 	if i == 0 { | ||||
| 		return ns.unquotedNames[:ns.offsets[0]] | ||||
| 	} else { | ||||
| 		return ns.unquotedNames[ns.offsets[i-1]:ns.offsets[i-0]] | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // invalidOffset indicates that the last JSON object currently has no name. | ||||
| const invalidOffset = math.MinInt | ||||
|  | ||||
| // push descends into a nested JSON object. | ||||
| func (ns *objectNameStack) push() { | ||||
| 	ns.offsets = append(ns.offsets, invalidOffset) | ||||
| } | ||||
|  | ||||
| // ReplaceLastQuotedOffset replaces the last name with the starting offset | ||||
| // to the quoted name in some remote buffer. All offsets provided must be | ||||
| // relative to the same buffer until copyQuotedBuffer is called. | ||||
| func (ns *objectNameStack) ReplaceLastQuotedOffset(i int) { | ||||
| 	// Use bit-wise inversion instead of naive multiplication by -1 to avoid | ||||
| 	// ambiguity regarding zero (which is a valid offset into the names field). | ||||
| 	// Bit-wise inversion is mathematically equivalent to -i-1, | ||||
| 	// such that 0 becomes -1, 1 becomes -2, and so forth. | ||||
| 	// This ensures that remote offsets are always negative. | ||||
| 	ns.offsets[len(ns.offsets)-1] = ^i | ||||
| } | ||||
|  | ||||
| // replaceLastUnquotedName replaces the last name with the provided name. | ||||
| // | ||||
| // Invariant: Must call copyQuotedBuffer beforehand. | ||||
| func (ns *objectNameStack) replaceLastUnquotedName(s string) { | ||||
| 	ns.ensureCopiedBuffer() | ||||
| 	var startOffset int | ||||
| 	if len(ns.offsets) > 1 { | ||||
| 		startOffset = ns.offsets[len(ns.offsets)-2] | ||||
| 	} | ||||
| 	ns.unquotedNames = append(ns.unquotedNames[:startOffset], s...) | ||||
| 	ns.offsets[len(ns.offsets)-1] = len(ns.unquotedNames) | ||||
| } | ||||
|  | ||||
| // clearLast removes any name in the last JSON object. | ||||
| // It is semantically equivalent to ns.push followed by ns.pop. | ||||
| func (ns *objectNameStack) clearLast() { | ||||
| 	ns.offsets[len(ns.offsets)-1] = invalidOffset | ||||
| } | ||||
|  | ||||
| // pop ascends out of a nested JSON object. | ||||
| func (ns *objectNameStack) pop() { | ||||
| 	ns.offsets = ns.offsets[:len(ns.offsets)-1] | ||||
| } | ||||
|  | ||||
| // copyQuotedBuffer copies names from the remote buffer into the local names | ||||
| // buffer so that there are no more offset references into the remote buffer. | ||||
| // This allows the remote buffer to change contents without affecting | ||||
| // the names that this data structure is trying to remember. | ||||
| func (ns *objectNameStack) copyQuotedBuffer(b []byte) { | ||||
| 	// Find the first negative offset. | ||||
| 	var i int | ||||
| 	for i = len(ns.offsets) - 1; i >= 0 && ns.offsets[i] < 0; i-- { | ||||
| 		continue | ||||
| 	} | ||||
|  | ||||
| 	// Copy each name from the remote buffer into the local buffer. | ||||
| 	for i = i + 1; i < len(ns.offsets); i++ { | ||||
| 		if i == len(ns.offsets)-1 && ns.offsets[i] == invalidOffset { | ||||
| 			if i == 0 { | ||||
| 				ns.offsets[i] = 0 | ||||
| 			} else { | ||||
| 				ns.offsets[i] = ns.offsets[i-1] | ||||
| 			} | ||||
| 			break // last JSON object had a push without any names | ||||
| 		} | ||||
|  | ||||
| 		// As a form of Hyrum proofing, we write an invalid character into the | ||||
| 		// buffer to make misuse of Decoder.ReadToken more obvious. | ||||
| 		// We need to undo that mutation here. | ||||
| 		quotedName := b[^ns.offsets[i]:] | ||||
| 		if quotedName[0] == invalidateBufferByte { | ||||
| 			quotedName[0] = '"' | ||||
| 		} | ||||
|  | ||||
| 		// Append the unquoted name to the local buffer. | ||||
| 		var startOffset int | ||||
| 		if i > 0 { | ||||
| 			startOffset = ns.offsets[i-1] | ||||
| 		} | ||||
| 		if n := jsonwire.ConsumeSimpleString(quotedName); n > 0 { | ||||
| 			ns.unquotedNames = append(ns.unquotedNames[:startOffset], quotedName[len(`"`):n-len(`"`)]...) | ||||
| 		} else { | ||||
| 			ns.unquotedNames, _ = jsonwire.AppendUnquote(ns.unquotedNames[:startOffset], quotedName) | ||||
| 		} | ||||
| 		ns.offsets[i] = len(ns.unquotedNames) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (ns *objectNameStack) ensureCopiedBuffer() { | ||||
| 	if len(ns.offsets) > 0 && ns.offsets[len(ns.offsets)-1] < 0 { | ||||
| 		panic("BUG: copyQuotedBuffer not called beforehand") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // objectNamespaceStack is a stack of object namespaces. | ||||
| // This data structure assists in detecting duplicate names. | ||||
| type objectNamespaceStack []objectNamespace | ||||
|  | ||||
| // reset resets the object namespace stack. | ||||
| func (nss *objectNamespaceStack) reset() { | ||||
| 	if cap(*nss) > 1<<10 { | ||||
| 		*nss = nil | ||||
| 	} | ||||
| 	*nss = (*nss)[:0] | ||||
| } | ||||
|  | ||||
| // push starts a new namespace for a nested JSON object. | ||||
| func (nss *objectNamespaceStack) push() { | ||||
| 	if cap(*nss) > len(*nss) { | ||||
| 		*nss = (*nss)[:len(*nss)+1] | ||||
| 		nss.Last().reset() | ||||
| 	} else { | ||||
| 		*nss = append(*nss, objectNamespace{}) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Last returns a pointer to the last JSON object namespace. | ||||
| func (nss objectNamespaceStack) Last() *objectNamespace { | ||||
| 	return &nss[len(nss)-1] | ||||
| } | ||||
|  | ||||
| // pop terminates the namespace for a nested JSON object. | ||||
| func (nss *objectNamespaceStack) pop() { | ||||
| 	*nss = (*nss)[:len(*nss)-1] | ||||
| } | ||||
|  | ||||
| // objectNamespace is the namespace for a JSON object. | ||||
| // In contrast to objectNameStack, this needs to remember a all names | ||||
| // per JSON object. | ||||
| // | ||||
| // The zero value is an empty namespace ready for use. | ||||
| type objectNamespace struct { | ||||
| 	// It relies on a linear search over all the names before switching | ||||
| 	// to use a Go map for direct lookup. | ||||
|  | ||||
| 	// endOffsets is a list of offsets to the end of each name in buffers. | ||||
| 	// The length of offsets is the number of names in the namespace. | ||||
| 	endOffsets []uint | ||||
| 	// allUnquotedNames is a back-to-back concatenation of every name in the namespace. | ||||
| 	allUnquotedNames []byte | ||||
| 	// mapNames is a Go map containing every name in the namespace. | ||||
| 	// Only valid if non-nil. | ||||
| 	mapNames map[string]struct{} | ||||
| } | ||||
|  | ||||
| // reset resets the namespace to be empty. | ||||
| func (ns *objectNamespace) reset() { | ||||
| 	ns.endOffsets = ns.endOffsets[:0] | ||||
| 	ns.allUnquotedNames = ns.allUnquotedNames[:0] | ||||
| 	ns.mapNames = nil | ||||
| 	if cap(ns.endOffsets) > 1<<6 { | ||||
| 		ns.endOffsets = nil // avoid pinning arbitrarily large amounts of memory | ||||
| 	} | ||||
| 	if cap(ns.allUnquotedNames) > 1<<10 { | ||||
| 		ns.allUnquotedNames = nil // avoid pinning arbitrarily large amounts of memory | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // length reports the number of names in the namespace. | ||||
| func (ns *objectNamespace) length() int { | ||||
| 	return len(ns.endOffsets) | ||||
| } | ||||
|  | ||||
| // getUnquoted retrieves the ith unquoted name in the namespace. | ||||
| func (ns *objectNamespace) getUnquoted(i int) []byte { | ||||
| 	if i == 0 { | ||||
| 		return ns.allUnquotedNames[:ns.endOffsets[0]] | ||||
| 	} else { | ||||
| 		return ns.allUnquotedNames[ns.endOffsets[i-1]:ns.endOffsets[i-0]] | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // lastUnquoted retrieves the last name in the namespace. | ||||
| func (ns *objectNamespace) lastUnquoted() []byte { | ||||
| 	return ns.getUnquoted(ns.length() - 1) | ||||
| } | ||||
|  | ||||
| // insertQuoted inserts a name and reports whether it was inserted, | ||||
| // which only occurs if name is not already in the namespace. | ||||
| // The provided name must be a valid JSON string. | ||||
| func (ns *objectNamespace) insertQuoted(name []byte, isVerbatim bool) bool { | ||||
| 	if isVerbatim { | ||||
| 		name = name[len(`"`) : len(name)-len(`"`)] | ||||
| 	} | ||||
| 	return ns.insert(name, !isVerbatim) | ||||
| } | ||||
| func (ns *objectNamespace) InsertUnquoted(name []byte) bool { | ||||
| 	return ns.insert(name, false) | ||||
| } | ||||
| func (ns *objectNamespace) insert(name []byte, quoted bool) bool { | ||||
| 	var allNames []byte | ||||
| 	if quoted { | ||||
| 		allNames, _ = jsonwire.AppendUnquote(ns.allUnquotedNames, name) | ||||
| 	} else { | ||||
| 		allNames = append(ns.allUnquotedNames, name...) | ||||
| 	} | ||||
| 	name = allNames[len(ns.allUnquotedNames):] | ||||
|  | ||||
| 	// Switch to a map if the buffer is too large for linear search. | ||||
| 	// This does not add the current name to the map. | ||||
| 	if ns.mapNames == nil && (ns.length() > 64 || len(ns.allUnquotedNames) > 1024) { | ||||
| 		ns.mapNames = make(map[string]struct{}) | ||||
| 		var startOffset uint | ||||
| 		for _, endOffset := range ns.endOffsets { | ||||
| 			name := ns.allUnquotedNames[startOffset:endOffset] | ||||
| 			ns.mapNames[string(name)] = struct{}{} // allocates a new string | ||||
| 			startOffset = endOffset | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if ns.mapNames == nil { | ||||
| 		// Perform linear search over the buffer to find matching names. | ||||
| 		// It provides O(n) lookup, but does not require any allocations. | ||||
| 		var startOffset uint | ||||
| 		for _, endOffset := range ns.endOffsets { | ||||
| 			if string(ns.allUnquotedNames[startOffset:endOffset]) == string(name) { | ||||
| 				return false | ||||
| 			} | ||||
| 			startOffset = endOffset | ||||
| 		} | ||||
| 	} else { | ||||
| 		// Use the map if it is populated. | ||||
| 		// It provides O(1) lookup, but requires a string allocation per name. | ||||
| 		if _, ok := ns.mapNames[string(name)]; ok { | ||||
| 			return false | ||||
| 		} | ||||
| 		ns.mapNames[string(name)] = struct{}{} // allocates a new string | ||||
| 	} | ||||
|  | ||||
| 	ns.allUnquotedNames = allNames | ||||
| 	ns.endOffsets = append(ns.endOffsets, uint(len(ns.allUnquotedNames))) | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| // removeLast removes the last name in the namespace. | ||||
| func (ns *objectNamespace) removeLast() { | ||||
| 	if ns.mapNames != nil { | ||||
| 		delete(ns.mapNames, string(ns.lastUnquoted())) | ||||
| 	} | ||||
| 	if ns.length()-1 == 0 { | ||||
| 		ns.endOffsets = ns.endOffsets[:0] | ||||
| 		ns.allUnquotedNames = ns.allUnquotedNames[:0] | ||||
| 	} else { | ||||
| 		ns.endOffsets = ns.endOffsets[:ns.length()-1] | ||||
| 		ns.allUnquotedNames = ns.allUnquotedNames[:ns.endOffsets[ns.length()-1]] | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										525
									
								
								vendor/github.com/go-json-experiment/json/jsontext/token.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										525
									
								
								vendor/github.com/go-json-experiment/json/jsontext/token.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,525 @@ | ||||
| // Copyright 2020 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. | ||||
|  | ||||
| package jsontext | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"errors" | ||||
| 	"math" | ||||
| 	"strconv" | ||||
|  | ||||
| 	"github.com/go-json-experiment/json/internal/jsonflags" | ||||
| 	"github.com/go-json-experiment/json/internal/jsonwire" | ||||
| ) | ||||
|  | ||||
| // NOTE: Token is analogous to v1 json.Token. | ||||
|  | ||||
| const ( | ||||
| 	maxInt64  = math.MaxInt64 | ||||
| 	minInt64  = math.MinInt64 | ||||
| 	maxUint64 = math.MaxUint64 | ||||
| 	minUint64 = 0 // for consistency and readability purposes | ||||
|  | ||||
| 	invalidTokenPanic = "invalid jsontext.Token; it has been voided by a subsequent json.Decoder call" | ||||
| ) | ||||
|  | ||||
| var errInvalidToken = errors.New("invalid jsontext.Token") | ||||
|  | ||||
| // Token represents a lexical JSON token, which may be one of the following: | ||||
| //   - a JSON literal (i.e., null, true, or false) | ||||
| //   - a JSON string (e.g., "hello, world!") | ||||
| //   - a JSON number (e.g., 123.456) | ||||
| //   - a start or end delimiter for a JSON object (i.e., { or } ) | ||||
| //   - a start or end delimiter for a JSON array (i.e., [ or ] ) | ||||
| // | ||||
| // A Token cannot represent entire array or object values, while a [Value] can. | ||||
| // There is no Token to represent commas and colons since | ||||
| // these structural tokens can be inferred from the surrounding context. | ||||
| type Token struct { | ||||
| 	nonComparable | ||||
|  | ||||
| 	// Tokens can exist in either a "raw" or an "exact" form. | ||||
| 	// Tokens produced by the Decoder are in the "raw" form. | ||||
| 	// Tokens returned by constructors are usually in the "exact" form. | ||||
| 	// The Encoder accepts Tokens in either the "raw" or "exact" form. | ||||
| 	// | ||||
| 	// The following chart shows the possible values for each Token type: | ||||
| 	//	╔═════════════════╦════════════╤════════════╤════════════╗ | ||||
| 	//	║ Token type      ║ raw field  │ str field  │ num field  ║ | ||||
| 	//	╠═════════════════╬════════════╪════════════╪════════════╣ | ||||
| 	//	║ null   (raw)    ║ "null"     │ ""         │ 0          ║ | ||||
| 	//	║ false  (raw)    ║ "false"    │ ""         │ 0          ║ | ||||
| 	//	║ true   (raw)    ║ "true"     │ ""         │ 0          ║ | ||||
| 	//	║ string (raw)    ║ non-empty  │ ""         │ offset     ║ | ||||
| 	//	║ string (string) ║ nil        │ non-empty  │ 0          ║ | ||||
| 	//	║ number (raw)    ║ non-empty  │ ""         │ offset     ║ | ||||
| 	//	║ number (float)  ║ nil        │ "f"        │ non-zero   ║ | ||||
| 	//	║ number (int64)  ║ nil        │ "i"        │ non-zero   ║ | ||||
| 	//	║ number (uint64) ║ nil        │ "u"        │ non-zero   ║ | ||||
| 	//	║ object (delim)  ║ "{" or "}" │ ""         │ 0          ║ | ||||
| 	//	║ array  (delim)  ║ "[" or "]" │ ""         │ 0          ║ | ||||
| 	//	╚═════════════════╩════════════╧════════════╧════════════╝ | ||||
| 	// | ||||
| 	// Notes: | ||||
| 	//   - For tokens stored in "raw" form, the num field contains the | ||||
| 	//     absolute offset determined by raw.previousOffsetStart(). | ||||
| 	//     The buffer itself is stored in raw.previousBuffer(). | ||||
| 	//   - JSON literals and structural characters are always in the "raw" form. | ||||
| 	//   - JSON strings and numbers can be in either "raw" or "exact" forms. | ||||
| 	//   - The exact zero value of JSON strings and numbers in the "exact" forms | ||||
| 	//     have ambiguous representation. Thus, they are always represented | ||||
| 	//     in the "raw" form. | ||||
|  | ||||
| 	// raw contains a reference to the raw decode buffer. | ||||
| 	// If non-nil, then its value takes precedence over str and num. | ||||
| 	// It is only valid if num == raw.previousOffsetStart(). | ||||
| 	raw *decodeBuffer | ||||
|  | ||||
| 	// str is the unescaped JSON string if num is zero. | ||||
| 	// Otherwise, it is "f", "i", or "u" if num should be interpreted | ||||
| 	// as a float64, int64, or uint64, respectively. | ||||
| 	str string | ||||
|  | ||||
| 	// num is a float64, int64, or uint64 stored as a uint64 value. | ||||
| 	// It is non-zero for any JSON number in the "exact" form. | ||||
| 	num uint64 | ||||
| } | ||||
|  | ||||
| // TODO: Does representing 1-byte delimiters as *decodeBuffer cause performance issues? | ||||
|  | ||||
| var ( | ||||
| 	Null  Token = rawToken("null") | ||||
| 	False Token = rawToken("false") | ||||
| 	True  Token = rawToken("true") | ||||
|  | ||||
| 	BeginObject Token = rawToken("{") | ||||
| 	EndObject   Token = rawToken("}") | ||||
| 	BeginArray  Token = rawToken("[") | ||||
| 	EndArray    Token = rawToken("]") | ||||
|  | ||||
| 	zeroString Token = rawToken(`""`) | ||||
| 	zeroNumber Token = rawToken(`0`) | ||||
|  | ||||
| 	nanString  Token = String("NaN") | ||||
| 	pinfString Token = String("Infinity") | ||||
| 	ninfString Token = String("-Infinity") | ||||
| ) | ||||
|  | ||||
| func rawToken(s string) Token { | ||||
| 	return Token{raw: &decodeBuffer{buf: []byte(s), prevStart: 0, prevEnd: len(s)}} | ||||
| } | ||||
|  | ||||
| // Bool constructs a Token representing a JSON boolean. | ||||
| func Bool(b bool) Token { | ||||
| 	if b { | ||||
| 		return True | ||||
| 	} | ||||
| 	return False | ||||
| } | ||||
|  | ||||
| // String constructs a Token representing a JSON string. | ||||
| // The provided string should contain valid UTF-8, otherwise invalid characters | ||||
| // may be mangled as the Unicode replacement character. | ||||
| func String(s string) Token { | ||||
| 	if len(s) == 0 { | ||||
| 		return zeroString | ||||
| 	} | ||||
| 	return Token{str: s} | ||||
| } | ||||
|  | ||||
| // Float constructs a Token representing a JSON number. | ||||
| // The values NaN, +Inf, and -Inf will be represented | ||||
| // as a JSON string with the values "NaN", "Infinity", and "-Infinity". | ||||
| func Float(n float64) Token { | ||||
| 	switch { | ||||
| 	case math.Float64bits(n) == 0: | ||||
| 		return zeroNumber | ||||
| 	case math.IsNaN(n): | ||||
| 		return nanString | ||||
| 	case math.IsInf(n, +1): | ||||
| 		return pinfString | ||||
| 	case math.IsInf(n, -1): | ||||
| 		return ninfString | ||||
| 	} | ||||
| 	return Token{str: "f", num: math.Float64bits(n)} | ||||
| } | ||||
|  | ||||
| // Int constructs a Token representing a JSON number from an int64. | ||||
| func Int(n int64) Token { | ||||
| 	if n == 0 { | ||||
| 		return zeroNumber | ||||
| 	} | ||||
| 	return Token{str: "i", num: uint64(n)} | ||||
| } | ||||
|  | ||||
| // Uint constructs a Token representing a JSON number from a uint64. | ||||
| func Uint(n uint64) Token { | ||||
| 	if n == 0 { | ||||
| 		return zeroNumber | ||||
| 	} | ||||
| 	return Token{str: "u", num: uint64(n)} | ||||
| } | ||||
|  | ||||
| // Clone makes a copy of the Token such that its value remains valid | ||||
| // even after a subsequent [Decoder.Read] call. | ||||
| func (t Token) Clone() Token { | ||||
| 	// TODO: Allow caller to avoid any allocations? | ||||
| 	if raw := t.raw; raw != nil { | ||||
| 		// Avoid copying globals. | ||||
| 		if t.raw.prevStart == 0 { | ||||
| 			switch t.raw { | ||||
| 			case Null.raw: | ||||
| 				return Null | ||||
| 			case False.raw: | ||||
| 				return False | ||||
| 			case True.raw: | ||||
| 				return True | ||||
| 			case BeginObject.raw: | ||||
| 				return BeginObject | ||||
| 			case EndObject.raw: | ||||
| 				return EndObject | ||||
| 			case BeginArray.raw: | ||||
| 				return BeginArray | ||||
| 			case EndArray.raw: | ||||
| 				return EndArray | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if uint64(raw.previousOffsetStart()) != t.num { | ||||
| 			panic(invalidTokenPanic) | ||||
| 		} | ||||
| 		buf := bytes.Clone(raw.previousBuffer()) | ||||
| 		return Token{raw: &decodeBuffer{buf: buf, prevStart: 0, prevEnd: len(buf)}} | ||||
| 	} | ||||
| 	return t | ||||
| } | ||||
|  | ||||
| // Bool returns the value for a JSON boolean. | ||||
| // It panics if the token kind is not a JSON boolean. | ||||
| func (t Token) Bool() bool { | ||||
| 	switch t.raw { | ||||
| 	case True.raw: | ||||
| 		return true | ||||
| 	case False.raw: | ||||
| 		return false | ||||
| 	default: | ||||
| 		panic("invalid JSON token kind: " + t.Kind().String()) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // appendString appends a JSON string to dst and returns it. | ||||
| // It panics if t is not a JSON string. | ||||
| func (t Token) appendString(dst []byte, flags *jsonflags.Flags) ([]byte, error) { | ||||
| 	if raw := t.raw; raw != nil { | ||||
| 		// Handle raw string value. | ||||
| 		buf := raw.previousBuffer() | ||||
| 		if Kind(buf[0]) == '"' { | ||||
| 			if jsonwire.ConsumeSimpleString(buf) == len(buf) { | ||||
| 				return append(dst, buf...), nil | ||||
| 			} | ||||
| 			dst, _, err := jsonwire.ReformatString(dst, buf, flags) | ||||
| 			return dst, err | ||||
| 		} | ||||
| 	} else if len(t.str) != 0 && t.num == 0 { | ||||
| 		// Handle exact string value. | ||||
| 		return jsonwire.AppendQuote(dst, t.str, flags) | ||||
| 	} | ||||
|  | ||||
| 	panic("invalid JSON token kind: " + t.Kind().String()) | ||||
| } | ||||
|  | ||||
| // String returns the unescaped string value for a JSON string. | ||||
| // For other JSON kinds, this returns the raw JSON representation. | ||||
| func (t Token) String() string { | ||||
| 	// This is inlinable to take advantage of "function outlining". | ||||
| 	// This avoids an allocation for the string(b) conversion | ||||
| 	// if the caller does not use the string in an escaping manner. | ||||
| 	// See https://blog.filippo.io/efficient-go-apis-with-the-inliner/ | ||||
| 	s, b := t.string() | ||||
| 	if len(b) > 0 { | ||||
| 		return string(b) | ||||
| 	} | ||||
| 	return s | ||||
| } | ||||
| func (t Token) string() (string, []byte) { | ||||
| 	if raw := t.raw; raw != nil { | ||||
| 		if uint64(raw.previousOffsetStart()) != t.num { | ||||
| 			panic(invalidTokenPanic) | ||||
| 		} | ||||
| 		buf := raw.previousBuffer() | ||||
| 		if buf[0] == '"' { | ||||
| 			// TODO: Preserve ValueFlags in Token? | ||||
| 			isVerbatim := jsonwire.ConsumeSimpleString(buf) == len(buf) | ||||
| 			return "", jsonwire.UnquoteMayCopy(buf, isVerbatim) | ||||
| 		} | ||||
| 		// Handle tokens that are not JSON strings for fmt.Stringer. | ||||
| 		return "", buf | ||||
| 	} | ||||
| 	if len(t.str) != 0 && t.num == 0 { | ||||
| 		return t.str, nil | ||||
| 	} | ||||
| 	// Handle tokens that are not JSON strings for fmt.Stringer. | ||||
| 	if t.num > 0 { | ||||
| 		switch t.str[0] { | ||||
| 		case 'f': | ||||
| 			return string(jsonwire.AppendFloat(nil, math.Float64frombits(t.num), 64)), nil | ||||
| 		case 'i': | ||||
| 			return strconv.FormatInt(int64(t.num), 10), nil | ||||
| 		case 'u': | ||||
| 			return strconv.FormatUint(uint64(t.num), 10), nil | ||||
| 		} | ||||
| 	} | ||||
| 	return "<invalid jsontext.Token>", nil | ||||
| } | ||||
|  | ||||
| // appendNumber appends a JSON number to dst and returns it. | ||||
| // It panics if t is not a JSON number. | ||||
| func (t Token) appendNumber(dst []byte, flags *jsonflags.Flags) ([]byte, error) { | ||||
| 	if raw := t.raw; raw != nil { | ||||
| 		// Handle raw number value. | ||||
| 		buf := raw.previousBuffer() | ||||
| 		if Kind(buf[0]).normalize() == '0' { | ||||
| 			dst, _, err := jsonwire.ReformatNumber(dst, buf, flags) | ||||
| 			return dst, err | ||||
| 		} | ||||
| 	} else if t.num != 0 { | ||||
| 		// Handle exact number value. | ||||
| 		switch t.str[0] { | ||||
| 		case 'f': | ||||
| 			return jsonwire.AppendFloat(dst, math.Float64frombits(t.num), 64), nil | ||||
| 		case 'i': | ||||
| 			return strconv.AppendInt(dst, int64(t.num), 10), nil | ||||
| 		case 'u': | ||||
| 			return strconv.AppendUint(dst, uint64(t.num), 10), nil | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	panic("invalid JSON token kind: " + t.Kind().String()) | ||||
| } | ||||
|  | ||||
| // Float returns the floating-point value for a JSON number. | ||||
| // It returns a NaN, +Inf, or -Inf value for any JSON string | ||||
| // with the values "NaN", "Infinity", or "-Infinity". | ||||
| // It panics for all other cases. | ||||
| func (t Token) Float() float64 { | ||||
| 	if raw := t.raw; raw != nil { | ||||
| 		// Handle raw number value. | ||||
| 		if uint64(raw.previousOffsetStart()) != t.num { | ||||
| 			panic(invalidTokenPanic) | ||||
| 		} | ||||
| 		buf := raw.previousBuffer() | ||||
| 		if Kind(buf[0]).normalize() == '0' { | ||||
| 			fv, _ := jsonwire.ParseFloat(buf, 64) | ||||
| 			return fv | ||||
| 		} | ||||
| 	} else if t.num != 0 { | ||||
| 		// Handle exact number value. | ||||
| 		switch t.str[0] { | ||||
| 		case 'f': | ||||
| 			return math.Float64frombits(t.num) | ||||
| 		case 'i': | ||||
| 			return float64(int64(t.num)) | ||||
| 		case 'u': | ||||
| 			return float64(uint64(t.num)) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Handle string values with "NaN", "Infinity", or "-Infinity". | ||||
| 	if t.Kind() == '"' { | ||||
| 		switch t.String() { | ||||
| 		case "NaN": | ||||
| 			return math.NaN() | ||||
| 		case "Infinity": | ||||
| 			return math.Inf(+1) | ||||
| 		case "-Infinity": | ||||
| 			return math.Inf(-1) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	panic("invalid JSON token kind: " + t.Kind().String()) | ||||
| } | ||||
|  | ||||
| // Int returns the signed integer value for a JSON number. | ||||
| // The fractional component of any number is ignored (truncation toward zero). | ||||
| // Any number beyond the representation of an int64 will be saturated | ||||
| // to the closest representable value. | ||||
| // It panics if the token kind is not a JSON number. | ||||
| func (t Token) Int() int64 { | ||||
| 	if raw := t.raw; raw != nil { | ||||
| 		// Handle raw integer value. | ||||
| 		if uint64(raw.previousOffsetStart()) != t.num { | ||||
| 			panic(invalidTokenPanic) | ||||
| 		} | ||||
| 		neg := false | ||||
| 		buf := raw.previousBuffer() | ||||
| 		if len(buf) > 0 && buf[0] == '-' { | ||||
| 			neg, buf = true, buf[1:] | ||||
| 		} | ||||
| 		if numAbs, ok := jsonwire.ParseUint(buf); ok { | ||||
| 			if neg { | ||||
| 				if numAbs > -minInt64 { | ||||
| 					return minInt64 | ||||
| 				} | ||||
| 				return -1 * int64(numAbs) | ||||
| 			} else { | ||||
| 				if numAbs > +maxInt64 { | ||||
| 					return maxInt64 | ||||
| 				} | ||||
| 				return +1 * int64(numAbs) | ||||
| 			} | ||||
| 		} | ||||
| 	} else if t.num != 0 { | ||||
| 		// Handle exact integer value. | ||||
| 		switch t.str[0] { | ||||
| 		case 'i': | ||||
| 			return int64(t.num) | ||||
| 		case 'u': | ||||
| 			if t.num > maxInt64 { | ||||
| 				return maxInt64 | ||||
| 			} | ||||
| 			return int64(t.num) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Handle JSON number that is a floating-point value. | ||||
| 	if t.Kind() == '0' { | ||||
| 		switch fv := t.Float(); { | ||||
| 		case fv >= maxInt64: | ||||
| 			return maxInt64 | ||||
| 		case fv <= minInt64: | ||||
| 			return minInt64 | ||||
| 		default: | ||||
| 			return int64(fv) // truncation toward zero | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	panic("invalid JSON token kind: " + t.Kind().String()) | ||||
| } | ||||
|  | ||||
| // Uint returns the unsigned integer value for a JSON number. | ||||
| // The fractional component of any number is ignored (truncation toward zero). | ||||
| // Any number beyond the representation of an uint64 will be saturated | ||||
| // to the closest representable value. | ||||
| // It panics if the token kind is not a JSON number. | ||||
| func (t Token) Uint() uint64 { | ||||
| 	// NOTE: This accessor returns 0 for any negative JSON number, | ||||
| 	// which might be surprising, but is at least consistent with the behavior | ||||
| 	// of saturating out-of-bounds numbers to the closest representable number. | ||||
|  | ||||
| 	if raw := t.raw; raw != nil { | ||||
| 		// Handle raw integer value. | ||||
| 		if uint64(raw.previousOffsetStart()) != t.num { | ||||
| 			panic(invalidTokenPanic) | ||||
| 		} | ||||
| 		neg := false | ||||
| 		buf := raw.previousBuffer() | ||||
| 		if len(buf) > 0 && buf[0] == '-' { | ||||
| 			neg, buf = true, buf[1:] | ||||
| 		} | ||||
| 		if num, ok := jsonwire.ParseUint(buf); ok { | ||||
| 			if neg { | ||||
| 				return minUint64 | ||||
| 			} | ||||
| 			return num | ||||
| 		} | ||||
| 	} else if t.num != 0 { | ||||
| 		// Handle exact integer value. | ||||
| 		switch t.str[0] { | ||||
| 		case 'u': | ||||
| 			return t.num | ||||
| 		case 'i': | ||||
| 			if int64(t.num) < minUint64 { | ||||
| 				return minUint64 | ||||
| 			} | ||||
| 			return uint64(int64(t.num)) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Handle JSON number that is a floating-point value. | ||||
| 	if t.Kind() == '0' { | ||||
| 		switch fv := t.Float(); { | ||||
| 		case fv >= maxUint64: | ||||
| 			return maxUint64 | ||||
| 		case fv <= minUint64: | ||||
| 			return minUint64 | ||||
| 		default: | ||||
| 			return uint64(fv) // truncation toward zero | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	panic("invalid JSON token kind: " + t.Kind().String()) | ||||
| } | ||||
|  | ||||
| // Kind returns the token kind. | ||||
| func (t Token) Kind() Kind { | ||||
| 	switch { | ||||
| 	case t.raw != nil: | ||||
| 		raw := t.raw | ||||
| 		if uint64(raw.previousOffsetStart()) != t.num { | ||||
| 			panic(invalidTokenPanic) | ||||
| 		} | ||||
| 		return Kind(t.raw.buf[raw.prevStart]).normalize() | ||||
| 	case t.num != 0: | ||||
| 		return '0' | ||||
| 	case len(t.str) != 0: | ||||
| 		return '"' | ||||
| 	default: | ||||
| 		return invalidKind | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Kind represents each possible JSON token kind with a single byte, | ||||
| // which is conveniently the first byte of that kind's grammar | ||||
| // with the restriction that numbers always be represented with '0': | ||||
| // | ||||
| //   - 'n': null | ||||
| //   - 'f': false | ||||
| //   - 't': true | ||||
| //   - '"': string | ||||
| //   - '0': number | ||||
| //   - '{': object start | ||||
| //   - '}': object end | ||||
| //   - '[': array start | ||||
| //   - ']': array end | ||||
| // | ||||
| // An invalid kind is usually represented using 0, | ||||
| // but may be non-zero due to invalid JSON data. | ||||
| type Kind byte | ||||
|  | ||||
| const invalidKind Kind = 0 | ||||
|  | ||||
| // String prints the kind in a humanly readable fashion. | ||||
| func (k Kind) String() string { | ||||
| 	switch k { | ||||
| 	case 'n': | ||||
| 		return "null" | ||||
| 	case 'f': | ||||
| 		return "false" | ||||
| 	case 't': | ||||
| 		return "true" | ||||
| 	case '"': | ||||
| 		return "string" | ||||
| 	case '0': | ||||
| 		return "number" | ||||
| 	case '{': | ||||
| 		return "{" | ||||
| 	case '}': | ||||
| 		return "}" | ||||
| 	case '[': | ||||
| 		return "[" | ||||
| 	case ']': | ||||
| 		return "]" | ||||
| 	default: | ||||
| 		return "<invalid jsontext.Kind: " + jsonwire.QuoteRune(string(k)) + ">" | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // normalize coalesces all possible starting characters of a number as just '0'. | ||||
| func (k Kind) normalize() Kind { | ||||
| 	if k == '-' || ('0' <= k && k <= '9') { | ||||
| 		return '0' | ||||
| 	} | ||||
| 	return k | ||||
| } | ||||
							
								
								
									
										393
									
								
								vendor/github.com/go-json-experiment/json/jsontext/value.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										393
									
								
								vendor/github.com/go-json-experiment/json/jsontext/value.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,393 @@ | ||||
| // Copyright 2020 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. | ||||
|  | ||||
| package jsontext | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"errors" | ||||
| 	"io" | ||||
| 	"slices" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/go-json-experiment/json/internal/jsonflags" | ||||
| 	"github.com/go-json-experiment/json/internal/jsonwire" | ||||
| ) | ||||
|  | ||||
| // NOTE: Value is analogous to v1 json.RawMessage. | ||||
|  | ||||
| // AppendFormat formats the JSON value in src and appends it to dst | ||||
| // according to the specified options. | ||||
| // See [Value.Format] for more details about the formatting behavior. | ||||
| // | ||||
| // The dst and src may overlap. | ||||
| // If an error is reported, then the entirety of src is appended to dst. | ||||
| func AppendFormat(dst, src []byte, opts ...Options) ([]byte, error) { | ||||
| 	e := getBufferedEncoder(opts...) | ||||
| 	defer putBufferedEncoder(e) | ||||
| 	e.s.Flags.Set(jsonflags.OmitTopLevelNewline | 1) | ||||
| 	if err := e.s.WriteValue(src); err != nil { | ||||
| 		return append(dst, src...), err | ||||
| 	} | ||||
| 	return append(dst, e.s.Buf...), nil | ||||
| } | ||||
|  | ||||
| // Value represents a single raw JSON value, which may be one of the following: | ||||
| //   - a JSON literal (i.e., null, true, or false) | ||||
| //   - a JSON string (e.g., "hello, world!") | ||||
| //   - a JSON number (e.g., 123.456) | ||||
| //   - an entire JSON object (e.g., {"fizz":"buzz"} ) | ||||
| //   - an entire JSON array (e.g., [1,2,3] ) | ||||
| // | ||||
| // Value can represent entire array or object values, while [Token] cannot. | ||||
| // Value may contain leading and/or trailing whitespace. | ||||
| type Value []byte | ||||
|  | ||||
| // Clone returns a copy of v. | ||||
| func (v Value) Clone() Value { | ||||
| 	return bytes.Clone(v) | ||||
| } | ||||
|  | ||||
| // String returns the string formatting of v. | ||||
| func (v Value) String() string { | ||||
| 	if v == nil { | ||||
| 		return "null" | ||||
| 	} | ||||
| 	return string(v) | ||||
| } | ||||
|  | ||||
| // IsValid reports whether the raw JSON value is syntactically valid | ||||
| // according to the specified options. | ||||
| // | ||||
| // By default (if no options are specified), it validates according to RFC 7493. | ||||
| // It verifies whether the input is properly encoded as UTF-8, | ||||
| // that escape sequences within strings decode to valid Unicode codepoints, and | ||||
| // that all names in each object are unique. | ||||
| // It does not verify whether numbers are representable within the limits | ||||
| // of any common numeric type (e.g., float64, int64, or uint64). | ||||
| // | ||||
| // Relevant options include: | ||||
| //   - [AllowDuplicateNames] | ||||
| //   - [AllowInvalidUTF8] | ||||
| // | ||||
| // All other options are ignored. | ||||
| func (v Value) IsValid(opts ...Options) bool { | ||||
| 	// TODO: Document support for [WithByteLimit] and [WithDepthLimit]. | ||||
| 	d := getBufferedDecoder(v, opts...) | ||||
| 	defer putBufferedDecoder(d) | ||||
| 	_, errVal := d.ReadValue() | ||||
| 	_, errEOF := d.ReadToken() | ||||
| 	return errVal == nil && errEOF == io.EOF | ||||
| } | ||||
|  | ||||
| // Format formats the raw JSON value in place. | ||||
| // | ||||
| // By default (if no options are specified), it validates according to RFC 7493 | ||||
| // and produces the minimal JSON representation, where | ||||
| // all whitespace is elided and JSON strings use the shortest encoding. | ||||
| // | ||||
| // Relevant options include: | ||||
| //   - [AllowDuplicateNames] | ||||
| //   - [AllowInvalidUTF8] | ||||
| //   - [EscapeForHTML] | ||||
| //   - [EscapeForJS] | ||||
| //   - [PreserveRawStrings] | ||||
| //   - [CanonicalizeRawInts] | ||||
| //   - [CanonicalizeRawFloats] | ||||
| //   - [ReorderRawObjects] | ||||
| //   - [SpaceAfterColon] | ||||
| //   - [SpaceAfterComma] | ||||
| //   - [Multiline] | ||||
| //   - [WithIndent] | ||||
| //   - [WithIndentPrefix] | ||||
| // | ||||
| // All other options are ignored. | ||||
| // | ||||
| // It is guaranteed to succeed if the value is valid according to the same options. | ||||
| // If the value is already formatted, then the buffer is not mutated. | ||||
| func (v *Value) Format(opts ...Options) error { | ||||
| 	// TODO: Document support for [WithByteLimit] and [WithDepthLimit]. | ||||
| 	return v.format(opts, nil) | ||||
| } | ||||
|  | ||||
| // format accepts two []Options to avoid the allocation appending them together. | ||||
| // It is equivalent to v.Format(append(opts1, opts2...)...). | ||||
| func (v *Value) format(opts1, opts2 []Options) error { | ||||
| 	e := getBufferedEncoder(opts1...) | ||||
| 	defer putBufferedEncoder(e) | ||||
| 	e.s.Join(opts2...) | ||||
| 	e.s.Flags.Set(jsonflags.OmitTopLevelNewline | 1) | ||||
| 	if err := e.s.WriteValue(*v); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if !bytes.Equal(*v, e.s.Buf) { | ||||
| 		*v = append((*v)[:0], e.s.Buf...) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Compact removes all whitespace from the raw JSON value. | ||||
| // | ||||
| // It does not reformat JSON strings or numbers to use any other representation. | ||||
| // To maximize the set of JSON values that can be formatted, | ||||
| // this permits values with duplicate names and invalid UTF-8. | ||||
| // | ||||
| // Compact is equivalent to calling [Value.Format] with the following options: | ||||
| //   - [AllowDuplicateNames](true) | ||||
| //   - [AllowInvalidUTF8](true) | ||||
| //   - [PreserveRawStrings](true) | ||||
| // | ||||
| // Any options specified by the caller are applied after the initial set | ||||
| // and may deliberately override prior options. | ||||
| func (v *Value) Compact(opts ...Options) error { | ||||
| 	return v.format([]Options{ | ||||
| 		AllowDuplicateNames(true), | ||||
| 		AllowInvalidUTF8(true), | ||||
| 		PreserveRawStrings(true), | ||||
| 	}, opts) | ||||
| } | ||||
|  | ||||
| // Indent reformats the whitespace in the raw JSON value so that each element | ||||
| // in a JSON object or array begins on a indented line according to the nesting. | ||||
| // | ||||
| // It does not reformat JSON strings or numbers to use any other representation. | ||||
| // To maximize the set of JSON values that can be formatted, | ||||
| // this permits values with duplicate names and invalid UTF-8. | ||||
| // | ||||
| // Indent is equivalent to calling [Value.Format] with the following options: | ||||
| //   - [AllowDuplicateNames](true) | ||||
| //   - [AllowInvalidUTF8](true) | ||||
| //   - [PreserveRawStrings](true) | ||||
| //   - [Multiline](true) | ||||
| // | ||||
| // Any options specified by the caller are applied after the initial set | ||||
| // and may deliberately override prior options. | ||||
| func (v *Value) Indent(opts ...Options) error { | ||||
| 	return v.format([]Options{ | ||||
| 		AllowDuplicateNames(true), | ||||
| 		AllowInvalidUTF8(true), | ||||
| 		PreserveRawStrings(true), | ||||
| 		Multiline(true), | ||||
| 	}, opts) | ||||
| } | ||||
|  | ||||
| // Canonicalize canonicalizes the raw JSON value according to the | ||||
| // JSON Canonicalization Scheme (JCS) as defined by RFC 8785 | ||||
| // where it produces a stable representation of a JSON value. | ||||
| // | ||||
| // JSON strings are formatted to use their minimal representation, | ||||
| // JSON numbers are formatted as double precision numbers according | ||||
| // to some stable serialization algorithm. | ||||
| // JSON object members are sorted in ascending order by name. | ||||
| // All whitespace is removed. | ||||
| // | ||||
| // The output stability is dependent on the stability of the application data | ||||
| // (see RFC 8785, Appendix E). It cannot produce stable output from | ||||
| // fundamentally unstable input. For example, if the JSON value | ||||
| // contains ephemeral data (e.g., a frequently changing timestamp), | ||||
| // then the value is still unstable regardless of whether this is called. | ||||
| // | ||||
| // Canonicalize is equivalent to calling [Value.Format] with the following options: | ||||
| //   - [CanonicalizeRawInts](true) | ||||
| //   - [CanonicalizeRawFloats](true) | ||||
| //   - [ReorderRawObjects](true) | ||||
| // | ||||
| // Any options specified by the caller are applied after the initial set | ||||
| // and may deliberately override prior options. | ||||
| // | ||||
| // Note that JCS treats all JSON numbers as IEEE 754 double precision numbers. | ||||
| // Any numbers with precision beyond what is representable by that form | ||||
| // will lose their precision when canonicalized. For example, integer values | ||||
| // beyond ±2⁵³ will lose their precision. To preserve the original representation | ||||
| // of JSON integers, additionally set [CanonicalizeRawInts] to false: | ||||
| // | ||||
| //	v.Canonicalize(jsontext.CanonicalizeRawInts(false)) | ||||
| func (v *Value) Canonicalize(opts ...Options) error { | ||||
| 	return v.format([]Options{ | ||||
| 		CanonicalizeRawInts(true), | ||||
| 		CanonicalizeRawFloats(true), | ||||
| 		ReorderRawObjects(true), | ||||
| 	}, opts) | ||||
| } | ||||
|  | ||||
| // MarshalJSON returns v as the JSON encoding of v. | ||||
| // It returns the stored value as the raw JSON output without any validation. | ||||
| // If v is nil, then this returns a JSON null. | ||||
| func (v Value) MarshalJSON() ([]byte, error) { | ||||
| 	// NOTE: This matches the behavior of v1 json.RawMessage.MarshalJSON. | ||||
| 	if v == nil { | ||||
| 		return []byte("null"), nil | ||||
| 	} | ||||
| 	return v, nil | ||||
| } | ||||
|  | ||||
| // UnmarshalJSON sets v as the JSON encoding of b. | ||||
| // It stores a copy of the provided raw JSON input without any validation. | ||||
| func (v *Value) UnmarshalJSON(b []byte) error { | ||||
| 	// NOTE: This matches the behavior of v1 json.RawMessage.UnmarshalJSON. | ||||
| 	if v == nil { | ||||
| 		return errors.New("jsontext.Value: UnmarshalJSON on nil pointer") | ||||
| 	} | ||||
| 	*v = append((*v)[:0], b...) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Kind returns the starting token kind. | ||||
| // For a valid value, this will never include '}' or ']'. | ||||
| func (v Value) Kind() Kind { | ||||
| 	if v := v[jsonwire.ConsumeWhitespace(v):]; len(v) > 0 { | ||||
| 		return Kind(v[0]).normalize() | ||||
| 	} | ||||
| 	return invalidKind | ||||
| } | ||||
|  | ||||
| const commaAndWhitespace = ", \n\r\t" | ||||
|  | ||||
| type objectMember struct { | ||||
| 	// name is the unquoted name. | ||||
| 	name []byte // e.g., "name" | ||||
| 	// buffer is the entirety of the raw JSON object member | ||||
| 	// starting from right after the previous member (or opening '{') | ||||
| 	// until right after the member value. | ||||
| 	buffer []byte // e.g., `, \n\r\t"name": "value"` | ||||
| } | ||||
|  | ||||
| func (x objectMember) Compare(y objectMember) int { | ||||
| 	if c := jsonwire.CompareUTF16(x.name, y.name); c != 0 { | ||||
| 		return c | ||||
| 	} | ||||
| 	// With [AllowDuplicateNames] or [AllowInvalidUTF8], | ||||
| 	// names could be identical, so also sort using the member value. | ||||
| 	return jsonwire.CompareUTF16( | ||||
| 		bytes.TrimLeft(x.buffer, commaAndWhitespace), | ||||
| 		bytes.TrimLeft(y.buffer, commaAndWhitespace)) | ||||
| } | ||||
|  | ||||
| var objectMemberPool = sync.Pool{New: func() any { return new([]objectMember) }} | ||||
|  | ||||
| func getObjectMembers() *[]objectMember { | ||||
| 	ns := objectMemberPool.Get().(*[]objectMember) | ||||
| 	*ns = (*ns)[:0] | ||||
| 	return ns | ||||
| } | ||||
| func putObjectMembers(ns *[]objectMember) { | ||||
| 	if cap(*ns) < 1<<10 { | ||||
| 		clear(*ns) // avoid pinning name and buffer | ||||
| 		objectMemberPool.Put(ns) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // mustReorderObjects reorders in-place all object members in a JSON value, | ||||
| // which must be valid otherwise it panics. | ||||
| func mustReorderObjects(b []byte) { | ||||
| 	// Obtain a buffered encoder just to use its internal buffer as | ||||
| 	// a scratch buffer for reordering object members. | ||||
| 	e2 := getBufferedEncoder() | ||||
| 	defer putBufferedEncoder(e2) | ||||
|  | ||||
| 	// Disable unnecessary checks to syntactically parse the JSON value. | ||||
| 	d := getBufferedDecoder(b) | ||||
| 	defer putBufferedDecoder(d) | ||||
| 	d.s.Flags.Set(jsonflags.AllowDuplicateNames | jsonflags.AllowInvalidUTF8 | 1) | ||||
| 	mustReorderObjectsFromDecoder(d, &e2.s.Buf) // per RFC 8785, section 3.2.3 | ||||
| } | ||||
|  | ||||
| // mustReorderObjectsFromDecoder recursively reorders all object members in place | ||||
| // according to the ordering specified in RFC 8785, section 3.2.3. | ||||
| // | ||||
| // Pre-conditions: | ||||
| //   - The value is valid (i.e., no decoder errors should ever occur). | ||||
| //   - Initial call is provided a Decoder reading from the start of v. | ||||
| // | ||||
| // Post-conditions: | ||||
| //   - Exactly one JSON value is read from the Decoder. | ||||
| //   - All fully-parsed JSON objects are reordered by directly moving | ||||
| //     the members in the value buffer. | ||||
| // | ||||
| // The runtime is approximately O(n·log(n)) + O(m·log(m)), | ||||
| // where n is len(v) and m is the total number of object members. | ||||
| func mustReorderObjectsFromDecoder(d *Decoder, scratch *[]byte) { | ||||
| 	switch tok, err := d.ReadToken(); tok.Kind() { | ||||
| 	case '{': | ||||
| 		// Iterate and collect the name and offsets for every object member. | ||||
| 		members := getObjectMembers() | ||||
| 		defer putObjectMembers(members) | ||||
| 		var prevMember objectMember | ||||
| 		isSorted := true | ||||
|  | ||||
| 		beforeBody := d.InputOffset() // offset after '{' | ||||
| 		for d.PeekKind() != '}' { | ||||
| 			beforeName := d.InputOffset() | ||||
| 			var flags jsonwire.ValueFlags | ||||
| 			name, _ := d.s.ReadValue(&flags) | ||||
| 			name = jsonwire.UnquoteMayCopy(name, flags.IsVerbatim()) | ||||
| 			mustReorderObjectsFromDecoder(d, scratch) | ||||
| 			afterValue := d.InputOffset() | ||||
|  | ||||
| 			currMember := objectMember{name, d.s.buf[beforeName:afterValue]} | ||||
| 			if isSorted && len(*members) > 0 { | ||||
| 				isSorted = objectMember.Compare(prevMember, currMember) < 0 | ||||
| 			} | ||||
| 			*members = append(*members, currMember) | ||||
| 			prevMember = currMember | ||||
| 		} | ||||
| 		afterBody := d.InputOffset() // offset before '}' | ||||
| 		d.ReadToken() | ||||
|  | ||||
| 		// Sort the members; return early if it's already sorted. | ||||
| 		if isSorted { | ||||
| 			return | ||||
| 		} | ||||
| 		firstBufferBeforeSorting := (*members)[0].buffer | ||||
| 		slices.SortFunc(*members, objectMember.Compare) | ||||
| 		firstBufferAfterSorting := (*members)[0].buffer | ||||
|  | ||||
| 		// Append the reordered members to a new buffer, | ||||
| 		// then copy the reordered members back over the original members. | ||||
| 		// Avoid swapping in place since each member may be a different size | ||||
| 		// where moving a member over a smaller member may corrupt the data | ||||
| 		// for subsequent members before they have been moved. | ||||
| 		// | ||||
| 		// The following invariant must hold: | ||||
| 		//	sum([m.after-m.before for m in members]) == afterBody-beforeBody | ||||
| 		commaAndWhitespacePrefix := func(b []byte) []byte { | ||||
| 			return b[:len(b)-len(bytes.TrimLeft(b, commaAndWhitespace))] | ||||
| 		} | ||||
| 		sorted := (*scratch)[:0] | ||||
| 		for i, member := range *members { | ||||
| 			switch { | ||||
| 			case i == 0 && &member.buffer[0] != &firstBufferBeforeSorting[0]: | ||||
| 				// First member after sorting is not the first member before sorting, | ||||
| 				// so use the prefix of the first member before sorting. | ||||
| 				sorted = append(sorted, commaAndWhitespacePrefix(firstBufferBeforeSorting)...) | ||||
| 				sorted = append(sorted, bytes.TrimLeft(member.buffer, commaAndWhitespace)...) | ||||
| 			case i != 0 && &member.buffer[0] == &firstBufferBeforeSorting[0]: | ||||
| 				// Later member after sorting is the first member before sorting, | ||||
| 				// so use the prefix of the first member after sorting. | ||||
| 				sorted = append(sorted, commaAndWhitespacePrefix(firstBufferAfterSorting)...) | ||||
| 				sorted = append(sorted, bytes.TrimLeft(member.buffer, commaAndWhitespace)...) | ||||
| 			default: | ||||
| 				sorted = append(sorted, member.buffer...) | ||||
| 			} | ||||
| 		} | ||||
| 		if int(afterBody-beforeBody) != len(sorted) { | ||||
| 			panic("BUG: length invariant violated") | ||||
| 		} | ||||
| 		copy(d.s.buf[beforeBody:afterBody], sorted) | ||||
|  | ||||
| 		// Update scratch buffer to the largest amount ever used. | ||||
| 		if len(sorted) > len(*scratch) { | ||||
| 			*scratch = sorted | ||||
| 		} | ||||
| 	case '[': | ||||
| 		for d.PeekKind() != ']' { | ||||
| 			mustReorderObjectsFromDecoder(d, scratch) | ||||
| 		} | ||||
| 		d.ReadToken() | ||||
| 	default: | ||||
| 		if err != nil { | ||||
| 			panic("BUG: " + err.Error()) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										243
									
								
								vendor/github.com/go-json-experiment/json/migrate.sh
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										243
									
								
								vendor/github.com/go-json-experiment/json/migrate.sh
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,243 @@ | ||||
| #!/usr/bin/env bash | ||||
|  | ||||
| GOROOT=${1:-../go} | ||||
| JSONROOT="." | ||||
|  | ||||
| # Check if the Go toolchain has a clean checkout. | ||||
| if [ -n "$(cd $GOROOT; git status --porcelain)" ]; then | ||||
|     (cd $GOROOT; git status --porcelain) | ||||
|     echo "Working directory is not clean." | ||||
|     echo "" | ||||
|     echo "To cleanup, run:" | ||||
|     echo "    (cd $GOROOT && git checkout . && git clean -fd)" | ||||
|     exit 1 | ||||
| fi | ||||
|  | ||||
| /bin/rm -rf $GOROOT/src/encoding/json/* | ||||
| cp $JSONROOT/v1/* $GOROOT/src/encoding/json/ | ||||
| cp -r $JSONROOT/internal/ $GOROOT/src/encoding/json/internal/ | ||||
| mkdir $GOROOT/src/encoding/json/v2/ | ||||
| cp -r $JSONROOT/*.go $GOROOT/src/encoding/json/v2/ | ||||
| mkdir $GOROOT/src/encoding/json/jsontext/ | ||||
| cp -r $JSONROOT/jsontext/*.go $GOROOT/src/encoding/json/jsontext/ | ||||
| find $GOROOT/src/encoding/json -type f -exec sed -i 's|github[.]com/go-json-experiment/json/v1|encoding/json|g' {} + | ||||
| find $GOROOT/src/encoding/json -type f -exec sed -i 's|github[.]com/go-json-experiment/json/|encoding/json/|g' {} + | ||||
| find $GOROOT/src/encoding/json -type f -exec sed -i 's|github[.]com/go-json-experiment/json|encoding/json/v2|g' {} + | ||||
|  | ||||
| # Adjust for changed package path. | ||||
| sed -i 's/json\.struct/v2.struct/g' $GOROOT/src/encoding/json/v2/errors_test.go | ||||
|  | ||||
| # Adjust tests that hardcode formatted error strings. | ||||
| sed -i 's/}`, "Time.UnmarshalJSON: input is not a JSON string/}`, "json: cannot unmarshal JSON object into Go type time.Time/g' $GOROOT/src/time/time_test.go | ||||
| sed -i 's/]`, "Time.UnmarshalJSON: input is not a JSON string/]`, "json: cannot unmarshal JSON array into Go type time.Time/g' $GOROOT/src/time/time_test.go | ||||
|  | ||||
| # Adjust for changed dependency tree. | ||||
| sed -i 's|encoding/json|encoding/json/v2|g' $GOROOT/src/cmd/go/internal/imports/scan_test.go | ||||
| sed -i 's|encoding/binary|internal/reflectlite|g' $GOROOT/src/cmd/go/internal/imports/scan_test.go | ||||
| LINE=$(sed -n '/encoding\/json, encoding\/pem, encoding\/xml, mime;/=' $GOROOT/src/go/build/deps_test.go) | ||||
| sed -i 's|encoding/json, encoding/pem, encoding/xml, mime|encoding/pem, encoding/xml, mime|g' $GOROOT/src/go/build/deps_test.go | ||||
| sed -i "$((LINE+ 1)) i\\\\"                                   $GOROOT/src/go/build/deps_test.go | ||||
| sed -i "$((LINE+ 2)) i\\\tSTR, errors"                        $GOROOT/src/go/build/deps_test.go | ||||
| sed -i "$((LINE+ 3)) i\\\t< encoding/json/internal"           $GOROOT/src/go/build/deps_test.go | ||||
| sed -i "$((LINE+ 4)) i\\\t< encoding/json/internal/jsonflags" $GOROOT/src/go/build/deps_test.go | ||||
| sed -i "$((LINE+ 5)) i\\\t< encoding/json/internal/jsonopts"  $GOROOT/src/go/build/deps_test.go | ||||
| sed -i "$((LINE+ 6)) i\\\t< encoding/json/internal/jsonwire"  $GOROOT/src/go/build/deps_test.go | ||||
| sed -i "$((LINE+ 7)) i\\\t< encoding/json/jsontext;"          $GOROOT/src/go/build/deps_test.go | ||||
| sed -i "$((LINE+ 8)) i\\\\"                                   $GOROOT/src/go/build/deps_test.go | ||||
| sed -i "$((LINE+ 9)) i\\\tFMT,"                               $GOROOT/src/go/build/deps_test.go | ||||
| sed -i "$((LINE+10)) i\\\tencoding/hex,"                      $GOROOT/src/go/build/deps_test.go | ||||
| sed -i "$((LINE+11)) i\\\tencoding/base32,"                   $GOROOT/src/go/build/deps_test.go | ||||
| sed -i "$((LINE+12)) i\\\tencoding/base64,"                   $GOROOT/src/go/build/deps_test.go | ||||
| sed -i "$((LINE+13)) i\\\tencoding/binary,"                   $GOROOT/src/go/build/deps_test.go | ||||
| sed -i "$((LINE+14)) i\\\tencoding/json/jsontext,"            $GOROOT/src/go/build/deps_test.go | ||||
| sed -i "$((LINE+15)) i\\\tencoding/json/internal,"            $GOROOT/src/go/build/deps_test.go | ||||
| sed -i "$((LINE+16)) i\\\tencoding/json/internal/jsonflags,"  $GOROOT/src/go/build/deps_test.go | ||||
| sed -i "$((LINE+17)) i\\\tencoding/json/internal/jsonopts,"   $GOROOT/src/go/build/deps_test.go | ||||
| sed -i "$((LINE+18)) i\\\tencoding/json/internal/jsonwire"    $GOROOT/src/go/build/deps_test.go | ||||
| sed -i "$((LINE+19)) i\\\t< encoding/json/v2"                 $GOROOT/src/go/build/deps_test.go | ||||
| sed -i "$((LINE+20)) i\\\t< encoding/json;"                   $GOROOT/src/go/build/deps_test.go | ||||
| LINE=$(sed -n '/Test-only packages can have anything they want/=' $GOROOT/src/go/build/deps_test.go) | ||||
| sed -i "$((LINE+1)) i\\\tFMT, compress/gzip, embed, encoding/binary < encoding/json/internal/jsontest;" $GOROOT/src/go/build/deps_test.go | ||||
|  | ||||
| # Adjust for newly added API. | ||||
| ISSUE=71497 | ||||
| FILE="next/$ISSUE.txt" | ||||
| NEXT="$GOROOT/doc/next/6-stdlib/99-minor" | ||||
| mkdir -p $NEXT/encoding/json | ||||
| echo "A new [Options] type with associated constructors provide individual options" >> $NEXT/encoding/json/$ISSUE.md | ||||
| echo "to configure \"encoding/json/v2\" to operate with certain historical v1 behavior." >> $NEXT/encoding/json/$ISSUE.md | ||||
| echo "The [DefaultOptionsV2] option represents the set of all options needed" >> $NEXT/encoding/json/$ISSUE.md | ||||
| echo "to configure \"encoding/json/v2\" to entirely operate with historical v1 behavior." >> $NEXT/encoding/json/$ISSUE.md | ||||
| mkdir -p $NEXT/encoding/json/v2 | ||||
| echo "A new major version of \"encoding/json\" for processing JSON at a semantic level which is" >> $NEXT/encoding/json/v2/$ISSUE.md | ||||
| echo "functionality that determines the meaning of JSON values as Go values and vice-versa." >> $NEXT/encoding/json/v2/$ISSUE.md | ||||
| mkdir -p $NEXT/encoding/json/jsontext | ||||
| echo "A new package to process JSON at a syntactic level that" >> $NEXT/encoding/json/jsontext/$ISSUE.md | ||||
| echo "is concerned with processing JSON based on its grammar alone." >> $NEXT/encoding/json/jsontext/$ISSUE.md | ||||
| NEXT="$GOROOT/api/next/$ISSUE.txt" | ||||
| echo "pkg encoding/json, func CallMethodsWithLegacySemantics(bool) jsonopts.Options #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json, func DefaultOptionsV1() jsonopts.Options #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json, func EscapeInvalidUTF8(bool) jsonopts.Options #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json, func FormatBytesWithLegacySemantics(bool) jsonopts.Options #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json, func FormatTimeWithLegacySemantics(bool) jsonopts.Options #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json, func MatchCaseSensitiveDelimiter(bool) jsonopts.Options #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json, func MergeWithLegacySemantics(bool) jsonopts.Options #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json, func OmitEmptyWithLegacyDefinition(bool) jsonopts.Options #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json, func ReportErrorsWithLegacySemantics(bool) jsonopts.Options #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json, func StringifyWithLegacySemantics(bool) jsonopts.Options #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json, func UnmarshalArrayFromAnyLength(bool) jsonopts.Options #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json, method (*Number) UnmarshalJSONFrom(*jsontext.Decoder, jsonopts.Options) error #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json, method (*UnmarshalTypeError) Unwrap() error #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json, method (Number) MarshalJSONTo(*jsontext.Encoder, jsonopts.Options) error #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json, type Marshaler = json.Marshaler #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json, type Options = jsonopts.Options #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json, type RawMessage = jsontext.Value #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json, type UnmarshalTypeError struct, Err error #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json, type Unmarshaler = json.Unmarshaler #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, func AllowDuplicateNames(bool) jsonopts.Options #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, func AllowInvalidUTF8(bool) jsonopts.Options #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, func AppendFormat([]uint8, []uint8, ...jsonopts.Options) ([]uint8, error) #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, func AppendQuote[\$0 interface{ ~[]uint8 | ~string }]([]uint8, \$0) ([]uint8, error) #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, func AppendUnquote[\$0 interface{ ~[]uint8 | ~string }]([]uint8, \$0) ([]uint8, error) #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, func Bool(bool) Token #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, func CanonicalizeRawFloats(bool) jsonopts.Options #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, func CanonicalizeRawInts(bool) jsonopts.Options #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, func EscapeForHTML(bool) jsonopts.Options #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, func EscapeForJS(bool) jsonopts.Options #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, func Float(float64) Token #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, func Int(int64) Token #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, func Multiline(bool) jsonopts.Options #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, func NewDecoder(io.Reader, ...jsonopts.Options) *Decoder #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, func NewEncoder(io.Writer, ...jsonopts.Options) *Encoder #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, func PreserveRawStrings(bool) jsonopts.Options #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, func ReorderRawObjects(bool) jsonopts.Options #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, func SpaceAfterColon(bool) jsonopts.Options #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, func SpaceAfterComma(bool) jsonopts.Options #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, func String(string) Token #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, func Uint(uint64) Token #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, func WithIndent(string) jsonopts.Options #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, func WithIndentPrefix(string) jsonopts.Options #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (*Decoder) InputOffset() int64 #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (*Decoder) PeekKind() Kind #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (*Decoder) ReadToken() (Token, error) #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (*Decoder) ReadValue() (Value, error) #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (*Decoder) Reset(io.Reader, ...jsonopts.Options) #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (*Decoder) SkipValue() error #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (*Decoder) StackDepth() int #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (*Decoder) StackIndex(int) (Kind, int64) #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (*Decoder) StackPointer() Pointer #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (*Decoder) UnreadBuffer() []uint8 #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (*Encoder) OutputOffset() int64 #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (*Encoder) Reset(io.Writer, ...jsonopts.Options) #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (*Encoder) StackDepth() int #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (*Encoder) StackIndex(int) (Kind, int64) #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (*Encoder) StackPointer() Pointer #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (*Encoder) UnusedBuffer() []uint8 #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (*Encoder) WriteToken(Token) error #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (*Encoder) WriteValue(Value) error #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (*SyntacticError) Error() string #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (*SyntacticError) Unwrap() error #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (*Value) Canonicalize(...jsonopts.Options) error #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (*Value) Compact(...jsonopts.Options) error #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (*Value) Format(...jsonopts.Options) error #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (*Value) Indent(...jsonopts.Options) error #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (*Value) UnmarshalJSON([]uint8) error #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (Kind) String() string #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (Pointer) AppendToken(string) Pointer #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (Pointer) Contains(Pointer) bool #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (Pointer) IsValid() bool #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (Pointer) LastToken() string #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (Pointer) Parent() Pointer #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (Pointer) Tokens() iter.Seq[string] #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (Token) Bool() bool #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (Token) Clone() Token #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (Token) Float() float64 #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (Token) Int() int64 #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (Token) Kind() Kind #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (Token) String() string #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (Token) Uint() uint64 #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (Value) Clone() Value #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (Value) IsValid(...jsonopts.Options) bool #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (Value) Kind() Kind #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (Value) MarshalJSON() ([]uint8, error) #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, method (Value) String() string #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, type Decoder struct #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, type Encoder struct #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, type Kind uint8 #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, type Options = jsonopts.Options #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, type Pointer string #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, type SyntacticError struct #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, type SyntacticError struct, ByteOffset int64 #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, type SyntacticError struct, Err error #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, type SyntacticError struct, JSONPointer Pointer #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, type Token struct #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, type Value []uint8 #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, var BeginArray Token #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, var BeginObject Token #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, var EndArray Token #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, var EndObject Token #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, var ErrDuplicateName error #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, var ErrNonStringName error #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, var False Token #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, var Internal exporter #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, var Null Token #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/jsontext, var True Token #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, func DefaultOptionsV2() jsonopts.Options #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, func Deterministic(bool) jsonopts.Options #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, func DiscardUnknownMembers(bool) jsonopts.Options #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, func FormatNilMapAsNull(bool) jsonopts.Options #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, func FormatNilSliceAsNull(bool) jsonopts.Options #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, func GetOption[\$0 interface{}](jsonopts.Options, func(\$0) jsonopts.Options) (\$0, bool) #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, func JoinMarshalers(...*typedArshalers[jsontext.Encoder]) *typedArshalers[jsontext.Encoder] #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, func JoinOptions(...jsonopts.Options) jsonopts.Options #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, func JoinUnmarshalers(...*typedArshalers[jsontext.Decoder]) *typedArshalers[jsontext.Decoder] #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, func Marshal(interface{}, ...jsonopts.Options) ([]uint8, error) #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, func MarshalEncode(*jsontext.Encoder, interface{}, ...jsonopts.Options) error #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, func MarshalFunc[\$0 interface{}](func(\$0) ([]uint8, error)) *typedArshalers[jsontext.Encoder] #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, func MarshalToFunc[\$0 interface{}](func(*jsontext.Encoder, \$0, jsonopts.Options) error) *typedArshalers[jsontext.Encoder] #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, func MarshalWrite(io.Writer, interface{}, ...jsonopts.Options) error #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, func MatchCaseInsensitiveNames(bool) jsonopts.Options #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, func OmitZeroStructFields(bool) jsonopts.Options #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, func RejectUnknownMembers(bool) jsonopts.Options #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, func StringifyNumbers(bool) jsonopts.Options #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, func Unmarshal([]uint8, interface{}, ...jsonopts.Options) error #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, func UnmarshalDecode(*jsontext.Decoder, interface{}, ...jsonopts.Options) error #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, func UnmarshalFromFunc[\$0 interface{}](func(*jsontext.Decoder, \$0, jsonopts.Options) error) *typedArshalers[jsontext.Decoder] #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, func UnmarshalFunc[\$0 interface{}](func([]uint8, \$0) error) *typedArshalers[jsontext.Decoder] #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, func UnmarshalRead(io.Reader, interface{}, ...jsonopts.Options) error #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, func WithMarshalers(*typedArshalers[jsontext.Encoder]) jsonopts.Options #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, func WithUnmarshalers(*typedArshalers[jsontext.Decoder]) jsonopts.Options #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, method (*SemanticError) Error() string #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, method (*SemanticError) Unwrap() error #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, type Marshaler interface { MarshalJSON } #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, type Marshaler interface, MarshalJSON() ([]uint8, error) #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, type MarshalerTo interface { MarshalJSONTo } #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, type MarshalerTo interface, MarshalJSONTo(*jsontext.Encoder, jsonopts.Options) error #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, type Marshalers = typedArshalers[jsontext.Encoder] #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, type Options = jsonopts.Options #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, type SemanticError struct #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, type SemanticError struct, ByteOffset int64 #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, type SemanticError struct, Err error #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, type SemanticError struct, GoType reflect.Type #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, type SemanticError struct, JSONKind jsontext.Kind #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, type SemanticError struct, JSONPointer jsontext.Pointer #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, type SemanticError struct, JSONValue jsontext.Value #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, type Unmarshaler interface { UnmarshalJSON } #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, type Unmarshaler interface, UnmarshalJSON([]uint8) error #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, type UnmarshalerFrom interface { UnmarshalJSONFrom } #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, type UnmarshalerFrom interface, UnmarshalJSONFrom(*jsontext.Decoder, jsonopts.Options) error #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, type Unmarshalers = typedArshalers[jsontext.Decoder] #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, var ErrUnknownName error #$ISSUE" >> $NEXT | ||||
| echo "pkg encoding/json/v2, var SkipFunc error #$ISSUE" >> $NEXT | ||||
| # The following declarations were moved to encoding/json/v2 or encoding/json/jsontext. | ||||
| EXCEPT="$GOROOT/api/except.txt" | ||||
| echo "pkg encoding/json, method (*RawMessage) UnmarshalJSON([]uint8) error" >> $EXCEPT | ||||
| echo "pkg encoding/json, method (RawMessage) MarshalJSON() ([]uint8, error)" >> $EXCEPT | ||||
| echo "pkg encoding/json, type Marshaler interface { MarshalJSON }" >> $EXCEPT | ||||
| echo "pkg encoding/json, type Marshaler interface, MarshalJSON() ([]uint8, error)" >> $EXCEPT | ||||
| echo "pkg encoding/json, type RawMessage []uint8" >> $EXCEPT | ||||
| echo "pkg encoding/json, type Unmarshaler interface { UnmarshalJSON }" >> $EXCEPT | ||||
| echo "pkg encoding/json, type Unmarshaler interface, UnmarshalJSON([]uint8) error" >> $EXCEPT | ||||
|  | ||||
| # Run the tests. | ||||
| (cd $GOROOT/src; ./all.bash) | ||||
							
								
								
									
										286
									
								
								vendor/github.com/go-json-experiment/json/options.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										286
									
								
								vendor/github.com/go-json-experiment/json/options.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,286 @@ | ||||
| // Copyright 2023 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. | ||||
|  | ||||
| package json | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
|  | ||||
| 	"github.com/go-json-experiment/json/internal" | ||||
| 	"github.com/go-json-experiment/json/internal/jsonflags" | ||||
| 	"github.com/go-json-experiment/json/internal/jsonopts" | ||||
| ) | ||||
|  | ||||
| // Options configure [Marshal], [MarshalWrite], [MarshalEncode], | ||||
| // [Unmarshal], [UnmarshalRead], and [UnmarshalDecode] with specific features. | ||||
| // Each function takes in a variadic list of options, where properties | ||||
| // set in later options override the value of previously set properties. | ||||
| // | ||||
| // The Options type is identical to [encoding/json.Options] and | ||||
| // [encoding/json/jsontext.Options]. Options from the other packages can | ||||
| // be used interchangeably with functionality in this package. | ||||
| // | ||||
| // Options represent either a singular option or a set of options. | ||||
| // It can be functionally thought of as a Go map of option properties | ||||
| // (even though the underlying implementation avoids Go maps for performance). | ||||
| // | ||||
| // The constructors (e.g., [Deterministic]) return a singular option value: | ||||
| // | ||||
| //	opt := Deterministic(true) | ||||
| // | ||||
| // which is analogous to creating a single entry map: | ||||
| // | ||||
| //	opt := Options{"Deterministic": true} | ||||
| // | ||||
| // [JoinOptions] composes multiple options values to together: | ||||
| // | ||||
| //	out := JoinOptions(opts...) | ||||
| // | ||||
| // which is analogous to making a new map and copying the options over: | ||||
| // | ||||
| //	out := make(Options) | ||||
| //	for _, m := range opts { | ||||
| //		for k, v := range m { | ||||
| //			out[k] = v | ||||
| //		} | ||||
| //	} | ||||
| // | ||||
| // [GetOption] looks up the value of options parameter: | ||||
| // | ||||
| //	v, ok := GetOption(opts, Deterministic) | ||||
| // | ||||
| // which is analogous to a Go map lookup: | ||||
| // | ||||
| //	v, ok := Options["Deterministic"] | ||||
| // | ||||
| // There is a single Options type, which is used with both marshal and unmarshal. | ||||
| // Some options affect both operations, while others only affect one operation: | ||||
| // | ||||
| //   - [StringifyNumbers] affects marshaling and unmarshaling | ||||
| //   - [Deterministic] affects marshaling only | ||||
| //   - [FormatNilSliceAsNull] affects marshaling only | ||||
| //   - [FormatNilMapAsNull] affects marshaling only | ||||
| //   - [OmitZeroStructFields] affects marshaling only | ||||
| //   - [MatchCaseInsensitiveNames] affects marshaling and unmarshaling | ||||
| //   - [DiscardUnknownMembers] affects marshaling only | ||||
| //   - [RejectUnknownMembers] affects unmarshaling only | ||||
| //   - [WithMarshalers] affects marshaling only | ||||
| //   - [WithUnmarshalers] affects unmarshaling only | ||||
| // | ||||
| // Options that do not affect a particular operation are ignored. | ||||
| type Options = jsonopts.Options | ||||
|  | ||||
| // JoinOptions coalesces the provided list of options into a single Options. | ||||
| // Properties set in later options override the value of previously set properties. | ||||
| func JoinOptions(srcs ...Options) Options { | ||||
| 	var dst jsonopts.Struct | ||||
| 	dst.Join(srcs...) | ||||
| 	return &dst | ||||
| } | ||||
|  | ||||
| // GetOption returns the value stored in opts with the provided setter, | ||||
| // reporting whether the value is present. | ||||
| // | ||||
| // Example usage: | ||||
| // | ||||
| //	v, ok := json.GetOption(opts, json.Deterministic) | ||||
| // | ||||
| // Options are most commonly introspected to alter the JSON representation of | ||||
| // [MarshalerTo.MarshalJSONTo] and [UnmarshalerFrom.UnmarshalJSONFrom] methods, and | ||||
| // [MarshalToFunc] and [UnmarshalFromFunc] functions. | ||||
| // In such cases, the presence bit should generally be ignored. | ||||
| func GetOption[T any](opts Options, setter func(T) Options) (T, bool) { | ||||
| 	return jsonopts.GetOption(opts, setter) | ||||
| } | ||||
|  | ||||
| // DefaultOptionsV2 is the full set of all options that define v2 semantics. | ||||
| // It is equivalent to all options under [Options], [encoding/json.Options], | ||||
| // and [encoding/json/jsontext.Options] being set to false or the zero value, | ||||
| // except for the options related to whitespace formatting. | ||||
| func DefaultOptionsV2() Options { | ||||
| 	return &jsonopts.DefaultOptionsV2 | ||||
| } | ||||
|  | ||||
| // StringifyNumbers specifies that numeric Go types should be marshaled | ||||
| // as a JSON string containing the equivalent JSON number value. | ||||
| // When unmarshaling, numeric Go types are parsed from a JSON string | ||||
| // containing the JSON number without any surrounding whitespace. | ||||
| // | ||||
| // According to RFC 8259, section 6, a JSON implementation may choose to | ||||
| // limit the representation of a JSON number to an IEEE 754 binary64 value. | ||||
| // This may cause decoders to lose precision for int64 and uint64 types. | ||||
| // Quoting JSON numbers as a JSON string preserves the exact precision. | ||||
| // | ||||
| // This affects either marshaling or unmarshaling. | ||||
| func StringifyNumbers(v bool) Options { | ||||
| 	if v { | ||||
| 		return jsonflags.StringifyNumbers | 1 | ||||
| 	} else { | ||||
| 		return jsonflags.StringifyNumbers | 0 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Deterministic specifies that the same input value will be serialized | ||||
| // as the exact same output bytes. Different processes of | ||||
| // the same program will serialize equal values to the same bytes, | ||||
| // but different versions of the same program are not guaranteed | ||||
| // to produce the exact same sequence of bytes. | ||||
| // | ||||
| // This only affects marshaling and is ignored when unmarshaling. | ||||
| func Deterministic(v bool) Options { | ||||
| 	if v { | ||||
| 		return jsonflags.Deterministic | 1 | ||||
| 	} else { | ||||
| 		return jsonflags.Deterministic | 0 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // FormatNilSliceAsNull specifies that a nil Go slice should marshal as a | ||||
| // JSON null instead of the default representation as an empty JSON array | ||||
| // (or an empty JSON string in the case of ~[]byte). | ||||
| // Slice fields explicitly marked with `format:emitempty` still marshal | ||||
| // as an empty JSON array. | ||||
| // | ||||
| // This only affects marshaling and is ignored when unmarshaling. | ||||
| func FormatNilSliceAsNull(v bool) Options { | ||||
| 	if v { | ||||
| 		return jsonflags.FormatNilSliceAsNull | 1 | ||||
| 	} else { | ||||
| 		return jsonflags.FormatNilSliceAsNull | 0 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // FormatNilMapAsNull specifies that a nil Go map should marshal as a | ||||
| // JSON null instead of the default representation as an empty JSON object. | ||||
| // Map fields explicitly marked with `format:emitempty` still marshal | ||||
| // as an empty JSON object. | ||||
| // | ||||
| // This only affects marshaling and is ignored when unmarshaling. | ||||
| func FormatNilMapAsNull(v bool) Options { | ||||
| 	if v { | ||||
| 		return jsonflags.FormatNilMapAsNull | 1 | ||||
| 	} else { | ||||
| 		return jsonflags.FormatNilMapAsNull | 0 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // OmitZeroStructFields specifies that a Go struct should marshal in such a way | ||||
| // that all struct fields that are zero are omitted from the marshaled output | ||||
| // if the value is zero as determined by the "IsZero() bool" method if present, | ||||
| // otherwise based on whether the field is the zero Go value. | ||||
| // This is semantically equivalent to specifying the `omitzero` tag option | ||||
| // on every field in a Go struct. | ||||
| // | ||||
| // This only affects marshaling and is ignored when unmarshaling. | ||||
| func OmitZeroStructFields(v bool) Options { | ||||
| 	if v { | ||||
| 		return jsonflags.OmitZeroStructFields | 1 | ||||
| 	} else { | ||||
| 		return jsonflags.OmitZeroStructFields | 0 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // MatchCaseInsensitiveNames specifies that JSON object members are matched | ||||
| // against Go struct fields using a case-insensitive match of the name. | ||||
| // Go struct fields explicitly marked with `case:strict` or `case:ignore` | ||||
| // always use case-sensitive (or case-insensitive) name matching, | ||||
| // regardless of the value of this option. | ||||
| // | ||||
| // This affects either marshaling or unmarshaling. | ||||
| // For marshaling, this option may alter the detection of duplicate names | ||||
| // (assuming [jsontext.AllowDuplicateNames] is false) from inlined fields | ||||
| // if it matches one of the declared fields in the Go struct. | ||||
| func MatchCaseInsensitiveNames(v bool) Options { | ||||
| 	if v { | ||||
| 		return jsonflags.MatchCaseInsensitiveNames | 1 | ||||
| 	} else { | ||||
| 		return jsonflags.MatchCaseInsensitiveNames | 0 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // DiscardUnknownMembers specifies that marshaling should ignore any | ||||
| // JSON object members stored in Go struct fields dedicated to storing | ||||
| // unknown JSON object members. | ||||
| // | ||||
| // This only affects marshaling and is ignored when unmarshaling. | ||||
| func DiscardUnknownMembers(v bool) Options { | ||||
| 	if v { | ||||
| 		return jsonflags.DiscardUnknownMembers | 1 | ||||
| 	} else { | ||||
| 		return jsonflags.DiscardUnknownMembers | 0 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // RejectUnknownMembers specifies that unknown members should be rejected | ||||
| // when unmarshaling a JSON object, regardless of whether there is a field | ||||
| // to store unknown members. | ||||
| // | ||||
| // This only affects unmarshaling and is ignored when marshaling. | ||||
| func RejectUnknownMembers(v bool) Options { | ||||
| 	if v { | ||||
| 		return jsonflags.RejectUnknownMembers | 1 | ||||
| 	} else { | ||||
| 		return jsonflags.RejectUnknownMembers | 0 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WithMarshalers specifies a list of type-specific marshalers to use, | ||||
| // which can be used to override the default marshal behavior for values | ||||
| // of particular types. | ||||
| // | ||||
| // This only affects marshaling and is ignored when unmarshaling. | ||||
| func WithMarshalers(v *Marshalers) Options { | ||||
| 	return (*marshalersOption)(v) | ||||
| } | ||||
|  | ||||
| // WithUnmarshalers specifies a list of type-specific unmarshalers to use, | ||||
| // which can be used to override the default unmarshal behavior for values | ||||
| // of particular types. | ||||
| // | ||||
| // This only affects unmarshaling and is ignored when marshaling. | ||||
| func WithUnmarshalers(v *Unmarshalers) Options { | ||||
| 	return (*unmarshalersOption)(v) | ||||
| } | ||||
|  | ||||
| // These option types are declared here instead of "jsonopts" | ||||
| // to avoid a dependency on "reflect" from "jsonopts". | ||||
| type ( | ||||
| 	marshalersOption   Marshalers | ||||
| 	unmarshalersOption Unmarshalers | ||||
| ) | ||||
|  | ||||
| func (*marshalersOption) JSONOptions(internal.NotForPublicUse)   {} | ||||
| func (*unmarshalersOption) JSONOptions(internal.NotForPublicUse) {} | ||||
|  | ||||
| // Inject support into "jsonopts" to handle these types. | ||||
| func init() { | ||||
| 	jsonopts.GetUnknownOption = func(src *jsonopts.Struct, zero jsonopts.Options) (any, bool) { | ||||
| 		switch zero.(type) { | ||||
| 		case *marshalersOption: | ||||
| 			if !src.Flags.Has(jsonflags.Marshalers) { | ||||
| 				return (*Marshalers)(nil), false | ||||
| 			} | ||||
| 			return src.Marshalers.(*Marshalers), true | ||||
| 		case *unmarshalersOption: | ||||
| 			if !src.Flags.Has(jsonflags.Unmarshalers) { | ||||
| 				return (*Unmarshalers)(nil), false | ||||
| 			} | ||||
| 			return src.Unmarshalers.(*Unmarshalers), true | ||||
| 		default: | ||||
| 			panic(fmt.Sprintf("unknown option %T", zero)) | ||||
| 		} | ||||
| 	} | ||||
| 	jsonopts.JoinUnknownOption = func(dst *jsonopts.Struct, src jsonopts.Options) { | ||||
| 		switch src := src.(type) { | ||||
| 		case *marshalersOption: | ||||
| 			dst.Flags.Set(jsonflags.Marshalers | 1) | ||||
| 			dst.Marshalers = (*Marshalers)(src) | ||||
| 		case *unmarshalersOption: | ||||
| 			dst.Flags.Set(jsonflags.Unmarshalers | 1) | ||||
| 			dst.Unmarshalers = (*Unmarshalers)(src) | ||||
| 		default: | ||||
| 			panic(fmt.Sprintf("unknown option %T", src)) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
		Reference in New Issue
	
	Block a user