Skip to content

Commit 0e17905

Browse files
neildgopherbot
authored andcommitted
encoding/json: add json/v2 with GOEXPERIMENT=jsonv2 guard
This imports the proposed new v2 JSON API implemented in github.com/go-json-experiment/json as of commit d3c622f1b874954c355e60c8e6b6baa5f60d2fed. When GOEXPERIMENT=jsonv2 is set, the encoding/json/v2 and encoding/jsontext packages are visible, the encoding/json package is implemented in terms of encoding/json/v2, and the encoding/json package include various additional APIs. (See #71497 for details.) When GOEXPERIMENT=jsonv2 is not set, the new API is not present and the encoding/json package is unchanged. The experimental API is not bound by the Go compatibility promise and is expected to evolve as updates are made to the json/v2 proposal. The contents of encoding/json/internal/jsontest/testdata are compressed with zstd v1.5.7 with the -19 option. Fixes #71845 For #71497 Change-Id: Ib8c94e5f0586b6aaa22833190b41cf6ef59f4f01 Reviewed-on: https://go-review.googlesource.com/c/go/+/665796 Auto-Submit: Damien Neil <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Michael Pratt <[email protected]> Reviewed-by: Joseph Tsai <[email protected]> Reviewed-by: Dmitri Shuralyov <[email protected]>
1 parent c889004 commit 0e17905

File tree

107 files changed

+39814
-3
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

107 files changed

+39814
-3
lines changed

src/encoding/json/bench_test.go

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
// We benchmark converting between the JSON form
99
// and in-memory data structures.
1010

11+
//go:build !goexperiment.jsonv2
12+
1113
package json
1214

1315
import (

src/encoding/json/decode.go

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
// Represents JSON data structure using native Go types: booleans, floats,
66
// strings, arrays, and maps.
77

8+
//go:build !goexperiment.jsonv2
9+
810
package json
911

1012
import (

src/encoding/json/decode_test.go

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5+
//go:build !goexperiment.jsonv2
6+
57
package json
68

79
import (

src/encoding/json/encode.go

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5+
//go:build !goexperiment.jsonv2
6+
57
// Package json implements encoding and decoding of JSON as defined in
68
// RFC 7159. The mapping between JSON and Go values is described
79
// in the documentation for the Marshal and Unmarshal functions.

src/encoding/json/encode_test.go

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5+
//go:build !goexperiment.jsonv2
6+
57
package json
68

79
import (

src/encoding/json/example_marshaling_test.go

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5+
//go:build !goexperiment.jsonv2
6+
57
package json_test
68

79
import (

src/encoding/json/example_test.go

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5+
//go:build !goexperiment.jsonv2
6+
57
package json_test
68

79
import (

src/encoding/json/example_text_marshaling_test.go

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5+
//go:build !goexperiment.jsonv2
6+
57
package json_test
68

79
import (

src/encoding/json/fold.go

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5+
//go:build !goexperiment.jsonv2
6+
57
package json
68

79
import (

src/encoding/json/fold_test.go

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5+
//go:build !goexperiment.jsonv2
6+
57
package json
68

79
import (

src/encoding/json/fuzz_test.go

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5+
//go:build !goexperiment.jsonv2
6+
57
package json
68

79
import (

src/encoding/json/indent.go

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5+
//go:build !goexperiment.jsonv2
6+
57
package json
68

79
import "bytes"
+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright 2023 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
//go:build goexperiment.jsonv2
6+
7+
package internal
8+
9+
import "errors"
10+
11+
// NotForPublicUse is a marker type that an API is for internal use only.
12+
// It does not perfectly prevent usage of that API, but helps to restrict usage.
13+
// Anything with this marker is not covered by the Go compatibility agreement.
14+
type NotForPublicUse struct{}
15+
16+
// AllowInternalUse is passed from "json" to "jsontext" to authenticate
17+
// that the caller can have access to internal functionality.
18+
var AllowInternalUse NotForPublicUse
19+
20+
// Sentinel error values internally shared between jsonv1 and jsonv2.
21+
var (
22+
ErrCycle = errors.New("encountered a cycle")
23+
ErrNonNilReference = errors.New("value must be passed as a non-nil pointer reference")
24+
)
25+
26+
var (
27+
// TransformMarshalError converts a v2 error into a v1 error.
28+
// It is called only at the top-level of a Marshal function.
29+
TransformMarshalError func(any, error) error
30+
// NewMarshalerError constructs a jsonv1.MarshalerError.
31+
// It is called after a user-defined Marshal method/function fails.
32+
NewMarshalerError func(any, error, string) error
33+
// TransformUnmarshalError converts a v2 error into a v1 error.
34+
// It is called only at the top-level of a Unmarshal function.
35+
TransformUnmarshalError func(any, error) error
36+
37+
// NewRawNumber returns new(jsonv1.Number).
38+
NewRawNumber func() any
39+
// RawNumberOf returns jsonv1.Number(b).
40+
RawNumberOf func(b []byte) any
41+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
// Copyright 2023 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
//go:build goexperiment.jsonv2
6+
7+
// jsonflags implements all the optional boolean flags.
8+
// These flags are shared across both "json", "jsontext", and "jsonopts".
9+
package jsonflags
10+
11+
import "encoding/json/internal"
12+
13+
// Bools represents zero or more boolean flags, all set to true or false.
14+
// The least-significant bit is the boolean value of all flags in the set.
15+
// The remaining bits identify which particular flags.
16+
//
17+
// In common usage, this is OR'd with 0 or 1. For example:
18+
// - (AllowInvalidUTF8 | 0) means "AllowInvalidUTF8 is false"
19+
// - (Multiline | Indent | 1) means "Multiline and Indent are true"
20+
type Bools uint64
21+
22+
func (Bools) JSONOptions(internal.NotForPublicUse) {}
23+
24+
const (
25+
// AllFlags is the set of all flags.
26+
AllFlags = AllCoderFlags | AllArshalV2Flags | AllArshalV1Flags
27+
28+
// AllCoderFlags is the set of all encoder/decoder flags.
29+
AllCoderFlags = (maxCoderFlag - 1) - initFlag
30+
31+
// AllArshalV2Flags is the set of all v2 marshal/unmarshal flags.
32+
AllArshalV2Flags = (maxArshalV2Flag - 1) - (maxCoderFlag - 1)
33+
34+
// AllArshalV1Flags is the set of all v1 marshal/unmarshal flags.
35+
AllArshalV1Flags = (maxArshalV1Flag - 1) - (maxArshalV2Flag - 1)
36+
37+
// NonBooleanFlags is the set of non-boolean flags,
38+
// where the value is some other concrete Go type.
39+
// The value of the flag is stored within jsonopts.Struct.
40+
NonBooleanFlags = 0 |
41+
Indent |
42+
IndentPrefix |
43+
ByteLimit |
44+
DepthLimit |
45+
Marshalers |
46+
Unmarshalers
47+
48+
// DefaultV1Flags is the set of booleans flags that default to true under
49+
// v1 semantics. None of the non-boolean flags differ between v1 and v2.
50+
DefaultV1Flags = 0 |
51+
AllowDuplicateNames |
52+
AllowInvalidUTF8 |
53+
EscapeForHTML |
54+
EscapeForJS |
55+
EscapeInvalidUTF8 |
56+
PreserveRawStrings |
57+
Deterministic |
58+
FormatNilMapAsNull |
59+
FormatNilSliceAsNull |
60+
MatchCaseInsensitiveNames |
61+
CallMethodsWithLegacySemantics |
62+
FormatBytesWithLegacySemantics |
63+
FormatTimeWithLegacySemantics |
64+
MatchCaseSensitiveDelimiter |
65+
MergeWithLegacySemantics |
66+
OmitEmptyWithLegacyDefinition |
67+
ReportErrorsWithLegacySemantics |
68+
StringifyWithLegacySemantics |
69+
UnmarshalArrayFromAnyLength
70+
71+
// AnyWhitespace reports whether the encoded output might have any whitespace.
72+
AnyWhitespace = Multiline | SpaceAfterColon | SpaceAfterComma
73+
74+
// WhitespaceFlags is the set of flags related to whitespace formatting.
75+
// In contrast to AnyWhitespace, this includes Indent and IndentPrefix
76+
// as those settings take no effect if Multiline is false.
77+
WhitespaceFlags = AnyWhitespace | Indent | IndentPrefix
78+
79+
// AnyEscape is the set of flags related to escaping in a JSON string.
80+
AnyEscape = EscapeForHTML | EscapeForJS | EscapeInvalidUTF8
81+
82+
// CanonicalizeNumbers is the set of flags related to raw number canonicalization.
83+
CanonicalizeNumbers = CanonicalizeRawInts | CanonicalizeRawFloats
84+
)
85+
86+
// Encoder and decoder flags.
87+
const (
88+
initFlag Bools = 1 << iota // reserved for the boolean value itself
89+
90+
AllowDuplicateNames // encode or decode
91+
AllowInvalidUTF8 // encode or decode
92+
WithinArshalCall // encode or decode; for internal use by json.Marshal and json.Unmarshal
93+
OmitTopLevelNewline // encode only; for internal use by json.Marshal and json.MarshalWrite
94+
PreserveRawStrings // encode only
95+
CanonicalizeRawInts // encode only
96+
CanonicalizeRawFloats // encode only
97+
ReorderRawObjects // encode only
98+
EscapeForHTML // encode only
99+
EscapeForJS // encode only
100+
EscapeInvalidUTF8 // encode only; only exposed in v1
101+
Multiline // encode only
102+
SpaceAfterColon // encode only
103+
SpaceAfterComma // encode only
104+
Indent // encode only; non-boolean flag
105+
IndentPrefix // encode only; non-boolean flag
106+
ByteLimit // encode or decode; non-boolean flag
107+
DepthLimit // encode or decode; non-boolean flag
108+
109+
maxCoderFlag
110+
)
111+
112+
// Marshal and Unmarshal flags (for v2).
113+
const (
114+
_ Bools = (maxCoderFlag >> 1) << iota
115+
116+
StringifyNumbers // marshal or unmarshal
117+
Deterministic // marshal only
118+
FormatNilMapAsNull // marshal only
119+
FormatNilSliceAsNull // marshal only
120+
OmitZeroStructFields // marshal only
121+
MatchCaseInsensitiveNames // marshal or unmarshal
122+
DiscardUnknownMembers // marshal only
123+
RejectUnknownMembers // unmarshal only
124+
Marshalers // marshal only; non-boolean flag
125+
Unmarshalers // unmarshal only; non-boolean flag
126+
127+
maxArshalV2Flag
128+
)
129+
130+
// Marshal and Unmarshal flags (for v1).
131+
const (
132+
_ Bools = (maxArshalV2Flag >> 1) << iota
133+
134+
CallMethodsWithLegacySemantics // marshal or unmarshal
135+
FormatBytesWithLegacySemantics // marshal or unmarshal
136+
FormatTimeWithLegacySemantics // marshal or unmarshal
137+
MatchCaseSensitiveDelimiter // marshal or unmarshal
138+
MergeWithLegacySemantics // unmarshal
139+
OmitEmptyWithLegacyDefinition // marshal
140+
ReportErrorsWithLegacySemantics // marshal or unmarshal
141+
StringifyWithLegacySemantics // marshal or unmarshal
142+
StringifyBoolsAndStrings // marshal or unmarshal; for internal use by jsonv2.makeStructArshaler
143+
UnmarshalAnyWithRawNumber // unmarshal; for internal use by jsonv1.Decoder.UseNumber
144+
UnmarshalArrayFromAnyLength // unmarshal
145+
146+
maxArshalV1Flag
147+
)
148+
149+
// Flags is a set of boolean flags.
150+
// If the presence bit is zero, then the value bit must also be zero.
151+
// The least-significant bit of both fields is always zero.
152+
//
153+
// Unlike Bools, which can represent a set of bools that are all true or false,
154+
// Flags represents a set of bools, each individually may be true or false.
155+
type Flags struct{ Presence, Values uint64 }
156+
157+
// Join joins two sets of flags such that the latter takes precedence.
158+
func (dst *Flags) Join(src Flags) {
159+
// Copy over all source presence bits over to the destination (using OR),
160+
// then invert the source presence bits to clear out source value (using AND-NOT),
161+
// then copy over source value bits over to the destination (using OR).
162+
// e.g., dst := Flags{Presence: 0b_1100_0011, Value: 0b_1000_0011}
163+
// e.g., src := Flags{Presence: 0b_0101_1010, Value: 0b_1001_0010}
164+
dst.Presence |= src.Presence // e.g., 0b_1100_0011 | 0b_0101_1010 -> 0b_110_11011
165+
dst.Values &= ^src.Presence // e.g., 0b_1000_0011 & 0b_1010_0101 -> 0b_100_00001
166+
dst.Values |= src.Values // e.g., 0b_1000_0001 | 0b_1001_0010 -> 0b_100_10011
167+
}
168+
169+
// Set sets both the presence and value for the provided bool (or set of bools).
170+
func (fs *Flags) Set(f Bools) {
171+
// Select out the bits for the flag identifiers (everything except LSB),
172+
// then set the presence for all the identifier bits (using OR),
173+
// then invert the identifier bits to clear out the values (using AND-NOT),
174+
// then copy over all the identifier bits to the value if LSB is 1.
175+
// e.g., fs := Flags{Presence: 0b_0101_0010, Value: 0b_0001_0010}
176+
// e.g., f := 0b_1001_0001
177+
id := uint64(f) &^ uint64(1) // e.g., 0b_1001_0001 & 0b_1111_1110 -> 0b_1001_0000
178+
fs.Presence |= id // e.g., 0b_0101_0010 | 0b_1001_0000 -> 0b_1101_0011
179+
fs.Values &= ^id // e.g., 0b_0001_0010 & 0b_0110_1111 -> 0b_0000_0010
180+
fs.Values |= uint64(f&1) * id // e.g., 0b_0000_0010 | 0b_1001_0000 -> 0b_1001_0010
181+
}
182+
183+
// Get reports whether the bool (or any of the bools) is true.
184+
// This is generally only used with a singular bool.
185+
// The value bit of f (i.e., the LSB) is ignored.
186+
func (fs Flags) Get(f Bools) bool {
187+
return fs.Values&uint64(f) > 0
188+
}
189+
190+
// Has reports whether the bool (or any of the bools) is set.
191+
// The value bit of f (i.e., the LSB) is ignored.
192+
func (fs Flags) Has(f Bools) bool {
193+
return fs.Presence&uint64(f) > 0
194+
}
195+
196+
// Clear clears both the presence and value for the provided bool or bools.
197+
// The value bit of f (i.e., the LSB) is ignored.
198+
func (fs *Flags) Clear(f Bools) {
199+
// Invert f to produce a mask to clear all bits in f (using AND).
200+
// e.g., fs := Flags{Presence: 0b_0101_0010, Value: 0b_0001_0010}
201+
// e.g., f := 0b_0001_1000
202+
mask := uint64(^f) // e.g., 0b_0001_1000 -> 0b_1110_0111
203+
fs.Presence &= mask // e.g., 0b_0101_0010 & 0b_1110_0111 -> 0b_0100_0010
204+
fs.Values &= mask // e.g., 0b_0001_0010 & 0b_1110_0111 -> 0b_0000_0010
205+
}

0 commit comments

Comments
 (0)