// 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.//go:build goexperiment.jsonv2package jsonimport ()// 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.varSkipFunc = 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.typeMarshalers = 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 m2func ( ...*Marshalers) *Marshalers {returnnewMarshalers(...)}// 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.typeUnmarshalers = 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 u2func ( ...*Unmarshalers) *Unmarshalers {returnnewUnmarshalers(...)}type typedMarshalers = typedArshalers[jsontext.Encoder]type typedUnmarshalers = typedArshalers[jsontext.Decoder]type typedArshalers[ any] struct {nonComparable fncVals []typedArshaler[] 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[ any] struct { typ reflect.Type fnc func(*, addressableValue, *jsonopts.Struct) error maySkip bool}func newMarshalers( ...*Marshalers) *Marshalers { returnnewTypedArshalers(...) }func newUnmarshalers( ...*Unmarshalers) *Unmarshalers { returnnewTypedArshalers(...) }func newTypedArshalers[ any]( ...*typedArshalers[]) *typedArshalers[] {vartypedArshalers[]for , := range {if != nil { .fncVals = append(.fncVals, .fncVals...) .fromAny = .fromAny || .fromAny } }iflen(.fncVals) == 0 {returnnil }return &}func ( *typedArshalers[]) ( func(*, addressableValue, *jsonopts.Struct) error, reflect.Type) (func(*, addressableValue, *jsonopts.Struct) error, bool) {if == nil {return , false }if , := .fncCache.Load(); {if == nil {return , false }return .(func(*, 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 []func(*, addressableValue, *jsonopts.Struct) errorfor , := range .fncVals {if !castableTo(, .typ) {continue } = append(, .fnc)if !.maySkip {break// subsequent arshalers will never be called } }iflen() == 0 { .fncCache.Store(, nil) // nil to indicate that no funcs foundreturn , false }// Construct an arshaler that may call every applicable arshaler. := = func( *, addressableValue, *jsonopts.Struct) error {for , := range {if := (, , ); != SkipFunc {return// may be nil or non-nil } }return (, , ) }// Use the first stored so duplicate work can be garbage collected. , := .fncCache.LoadOrStore(, )return .(func(*, 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 [ any]( func() ([]byte, error)) *Marshalers { := reflect.TypeFor[]()assertCastableTo(, true) := typedMarshaler{typ: ,fnc: func( *jsontext.Encoder, addressableValue, *jsonopts.Struct) error { , := (.castTo().Interface().())if != nil { = wrapSkipFunc(, "marshal function of type func(T) ([]byte, error)")if .Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {returninternal.NewMarshalerError(.Addr().Interface(), , "MarshalFunc") // unlike unmarshal, always wrapped } = newMarshalErrorBefore(, , )returncollapseSemanticErrors() }if := .WriteValue(); != nil {if .Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {returninternal.NewMarshalerError(.Addr().Interface(), , "MarshalFunc") // unlike unmarshal, always wrapped }ifisSyntacticError() { = newMarshalErrorBefore(, , ) }return }returnnil }, }return &Marshalers{fncVals: []typedMarshaler{}, fromAny: castableToFromAny()}}// 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 [ any]( func(*jsontext.Encoder, ) error) *Marshalers { := reflect.TypeFor[]()assertCastableTo(, true) := typedMarshaler{typ: ,fnc: func( *jsontext.Encoder, addressableValue, *jsonopts.Struct) error { := export.Encoder() , := .Tokens.DepthLength() .Flags.Set(jsonflags.WithinArshalCall | 1) := (, .castTo().Interface().()) .Flags.Set(jsonflags.WithinArshalCall | 0) , := .Tokens.DepthLength()if == nil && ( != || +1 != ) { = errNonSingularValue }if != nil {if == SkipFunc {if == && == {returnSkipFunc } = errSkipMutation }if .Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {returninternal.NewMarshalerError(.Addr().Interface(), , "MarshalToFunc") // unlike unmarshal, always wrapped }if !export.IsIOError() { = newSemanticErrorWithPosition(, , , , ) }return }returnnil },maySkip: true, }return &Marshalers{fncVals: []typedMarshaler{}, fromAny: castableToFromAny()}}// 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 [ any]( func([]byte, ) error) *Unmarshalers { := reflect.TypeFor[]()assertCastableTo(, false) := typedUnmarshaler{typ: ,fnc: func( *jsontext.Decoder, addressableValue, *jsonopts.Struct) error { , := .ReadValue()if != nil {return// must be a syntactic or I/O error } = (, .castTo().Interface().())if != nil { = wrapSkipFunc(, "unmarshal function of type func([]byte, T) error")if .Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {return// unlike marshal, never wrapped } = newUnmarshalErrorAfter(, , )returncollapseSemanticErrors() }returnnil }, }return &Unmarshalers{fncVals: []typedUnmarshaler{}, fromAny: castableToFromAny()}}// 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 [ any]( func(*jsontext.Decoder, ) error) *Unmarshalers { := reflect.TypeFor[]()assertCastableTo(, false) := typedUnmarshaler{typ: ,fnc: func( *jsontext.Decoder, addressableValue, *jsonopts.Struct) error { := export.Decoder() , := .Tokens.DepthLength() .Flags.Set(jsonflags.WithinArshalCall | 1) := (, .castTo().Interface().()) .Flags.Set(jsonflags.WithinArshalCall | 0) , := .Tokens.DepthLength()if == nil && ( != || +1 != ) { = errNonSingularValue }if != nil {if == SkipFunc {if == && == {returnSkipFunc } = errSkipMutation }if .Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {if := .SkipUntil(, +1); != nil {return }return// unlike marshal, never wrapped }if !isSyntacticError() && !export.IsIOError() { = newSemanticErrorWithPosition(, , , , ) }return }returnnil },maySkip: true, }return &Unmarshalers{fncVals: []typedUnmarshaler{}, fromAny: castableToFromAny()}}// 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( reflect.Type, bool) {switch .Kind() {casereflect.Interface:returncasereflect.Pointer:// Only allow unnamed pointers to be consistent with the fact that // taking the address of a value produces an unnamed pointer type.if .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 {return } }if {panic(fmt.Sprintf("input type %v must be an interface type, an unnamed pointer type, or a non-pointer type", )) } else {panic(fmt.Sprintf("input type %v must be an interface type or an unnamed pointer type", )) }}// 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(, reflect.Type) bool {switch .Kind() {casereflect.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.returnreflect.PointerTo().Implements()casereflect.Pointer:// Common case for unmarshaling. // From must be a concrete or interface type.returnreflect.PointerTo() == default:// Common case for marshaling. // From must be a concrete type.return == }}// 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 ( addressableValue) ( reflect.Type) reflect.Value {switch .Kind() {casereflect.Interface:return .Addr().Convert()casereflect.Pointer:return .Addr()default:return .Value }}// castableToFromAny reports whether "to" can be casted to from any// of the dynamic types used to represent arbitrary JSON.func castableToFromAny( reflect.Type) bool {for , := range []reflect.Type{anyType, boolType, stringType, float64Type, mapStringAnyType, sliceAnyType} {ifcastableTo(, ) {returntrue } }returnfalse}func wrapSkipFunc( error, string) error {if == SkipFunc {returnerrors.New( + " cannot be skipped") }return}
The pages are generated with Goldsv0.7.7-preview. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.