// 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.

//go:build goexperiment.jsonv2

// jsonflags implements all the optional boolean flags. // These flags are shared across both "json", "jsontext", and "jsonopts".
package jsonflags import // 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) (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 ( *Flags) ( 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} .Presence |= .Presence // e.g., 0b_1100_0011 | 0b_0101_1010 -> 0b_110_11011 .Values &= ^.Presence // e.g., 0b_1000_0011 & 0b_1010_0101 -> 0b_100_00001 .Values |= .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 ( *Flags) ( 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 := uint64() &^ uint64(1) // e.g., 0b_1001_0001 & 0b_1111_1110 -> 0b_1001_0000 .Presence |= // e.g., 0b_0101_0010 | 0b_1001_0000 -> 0b_1101_0011 .Values &= ^ // e.g., 0b_0001_0010 & 0b_0110_1111 -> 0b_0000_0010 .Values |= uint64(&1) * // 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 ( Flags) ( Bools) bool { return .Values&uint64() > 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 ( Flags) ( Bools) bool { return .Presence&uint64() > 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 ( *Flags) ( 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 := uint64(^) // e.g., 0b_0001_1000 -> 0b_1110_0111 .Presence &= // e.g., 0b_0101_0010 & 0b_1110_0111 -> 0b_0100_0010 .Values &= // e.g., 0b_0001_0010 & 0b_1110_0111 -> 0b_0000_0010 }