-
Notifications
You must be signed in to change notification settings - Fork 18.8k
Description
The current JSONv2 design contains three packages (encoding/json, encoding/jsontext, and encoding/json/v2), all of which define an Options type for customizing marshal and unmarshal behavior. These three Options types are each an alias to the same type, encoding/json/internal/jsonopts.Options. For example:
https://pkg.go.dev/encoding/json/v2#Options
An Options is either a single option, such as "enable deterministic marshalling" or an aggregate of multiple options created by json.JoinOptions. Options are passed as variadic parameters, and options defined in one package may be used in another.
I do not propose substantial changes to any of the above.
The json.GetOption function allows retrieving the value of an option from an Options. This function takes two parameters: An Options and a setter function. It returns the value of the option that is set by the setter. For example:
opts := json.JoinOptions(
json.Deterministic(true),
json.StringifyNumbers(true),
)
// Note that json.Deterministic is a function!
deterministic := json.GetOption(opts, json.Deterministic) // trueI believe that json.GetOption is very clever, but also confusing and unidiomatic. Its implementation is subtle. It is not a conventional design.
JSONv2 includes an internal type which represents a collection of options: encoding/json/internal/jsonopts.Struct. This type can represent all options defined by packages under encoding/json/…, offers efficient read and write access, and is used by most of the JSON internals to pass options around the call stack.
The fact that jsonopts.Struct exists is an indication that there is a need for a simple, compact, mutable, mostly-allocation-free representation of a collection of options. This is the type that the JSON internals use by preference.
I propose replacing json.GetOption with an exported version of jsonopts.Struct.
Specifically:
We rename Options to Option in all JSONv2 packages. A json.Option is now a single option.
We add an encoding/json/jsonopts package with a jsonopts.Options type representing a collection of options:
package jsonopts
// Option is identical in use to the current Options,
// although the definition may be different.
type Option interface {
JSONOptions(internal.NotForPublicUse)
}
// Options is a collection of options.
//
// Options implements the Option interface,
// and may be passed to functions that take ...Option parameters.
//
// Unlike the current internal/jsonopts.Struct,
// Options is an opaque type with accessors for each option.
type Options struct{}
// Join returns an Options describing the provided options.
func Join(options ...Option) Options
// Join updates opts with the provided options.
func (opts *Options) Join(options ...Option)
// Options has accessor methods for all options.
func (opts Options) AllowDuplicateNames() bool
func (opts Options) SetAllowDuplicateNames(v bool)
func (opts Options) AllowInvalidUTF8() bool
func (opts Options) SetAllowInvalidUTF8(v bool)
// etc., for all options.That's the proposal. We retain all the convenience of the existing variadic options, but offer a conventional options value type as well.
Converting the above GetOption example to the new API:
var opts jsonopts.Options
opts.SetDeterministic(true)
opts.SetStringifyNumbers(true)
deterministic := opts.Deterministic() // trueOr:
opts := jsonopts.Join(
json.Deterministic(true),
json.StringifyNumbers(true),
)
deterministic := opts.Deterministic() // trueMetadata
Metadata
Assignees
Labels
Type
Projects
Status