package json
import (
)
var errUnsupportedMutation = errors.New("unsupported calls must not read or write any tokens")
var errNonSingularValue = errors.New("must read or write exactly one value")
type Marshalers = typedMarshalers
func ( ...*Marshalers) *Marshalers {
return newMarshalers(...)
}
type Unmarshalers = typedUnmarshalers
func ( ...*Unmarshalers) *Unmarshalers {
return newUnmarshalers(...)
}
type typedMarshalers = typedArshalers[jsontext.Encoder]
type typedUnmarshalers = typedArshalers[jsontext.Decoder]
type typedArshalers[ any] struct {
nonComparable
fncVals []typedArshaler[]
fncCache sync.Map
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 ( ...*Marshalers) *Marshalers { return newTypedArshalers(...) }
func ( ...*Unmarshalers) *Unmarshalers { return newTypedArshalers(...) }
func [ any]( ...*typedArshalers[]) *typedArshalers[] {
var typedArshalers[]
for , := range {
if != nil {
.fncVals = append(.fncVals, .fncVals...)
.fromAny = .fromAny || .fromAny
}
}
if len(.fncVals) == 0 {
return nil
}
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
}
var []func(*, addressableValue, *jsonopts.Struct) error
for , := range .fncVals {
if !castableTo(, .typ) {
continue
}
= append(, .fnc)
if !.maySkip {
break
}
}
if len() == 0 {
.fncCache.Store(, nil)
return , false
}
:=
= func( *, addressableValue, *jsonopts.Struct) error {
for , := range {
if := (, , ); !errors.Is(, errors.ErrUnsupported) {
return
}
}
return (, , )
}
, := .fncCache.LoadOrStore(, )
return .(func(*, addressableValue, *jsonopts.Struct) error), true
}
func [ any]( func() ([]byte, error)) *Marshalers {
:= reflect.TypeFor[]()
assertCastableTo(, true)
:= typedMarshaler{
typ: ,
fnc: func( *jsontext.Encoder, addressableValue, *jsonopts.Struct) error {
, := reflect.TypeAssert[](.castTo())
, := ()
if != nil {
= wrapErrUnsupported(, "marshal function of type func(T) ([]byte, error)")
if .Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return internal.NewMarshalerError(.Addr().Interface(), , "MarshalFunc")
}
= newMarshalErrorBefore(, , )
return collapseSemanticErrors()
}
if := .WriteValue(); != nil {
if .Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return internal.NewMarshalerError(.Addr().Interface(), , "MarshalFunc")
}
if isSyntacticError() {
= newMarshalErrorBefore(, , )
}
return
}
return nil
},
}
return &Marshalers{fncVals: []typedMarshaler{}, fromAny: castableToFromAny()}
}
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)
, := reflect.TypeAssert[](.castTo())
:= (, )
.Flags.Set(jsonflags.WithinArshalCall | 0)
, := .Tokens.DepthLength()
if == nil && ( != || +1 != ) {
= errNonSingularValue
}
if != nil {
if errors.Is(, errors.ErrUnsupported) {
if == && == {
return
}
= errUnsupportedMutation
}
if .Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return internal.NewMarshalerError(.Addr().Interface(), , "MarshalToFunc")
}
if !export.IsIOError() {
= newSemanticErrorWithPosition(, , , , )
}
return
}
return nil
},
maySkip: true,
}
return &Marshalers{fncVals: []typedMarshaler{}, fromAny: castableToFromAny()}
}
func [ any]( func([]byte, ) error) *Unmarshalers {
:= reflect.TypeFor[]()
assertCastableTo(, false)
:= typedUnmarshaler{
typ: ,
fnc: func( *jsontext.Decoder, addressableValue, *jsonopts.Struct) error {
, := .ReadValue()
if != nil {
return
}
, := reflect.TypeAssert[](.castTo())
= (, )
if != nil {
= wrapErrUnsupported(, "unmarshal function of type func([]byte, T) error")
if .Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return
}
= newUnmarshalErrorAfter(, , )
return collapseSemanticErrors()
}
return nil
},
}
return &Unmarshalers{fncVals: []typedUnmarshaler{}, fromAny: castableToFromAny()}
}
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()
if == 1 && .AtEOF() {
return io.EOF
}
.Flags.Set(jsonflags.WithinArshalCall | 1)
, := reflect.TypeAssert[](.castTo())
:= (, )
.Flags.Set(jsonflags.WithinArshalCall | 0)
, := .Tokens.DepthLength()
if == nil && ( != || +1 != ) {
= errNonSingularValue
}
if != nil {
if errors.Is(, errors.ErrUnsupported) {
if == && == {
return
}
= errUnsupportedMutation
}
if .Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
if := .SkipUntil(, +1); != nil {
return
}
return
}
if !isSyntacticError() && !export.IsIOError() {
= newSemanticErrorWithPosition(, , , , )
}
return
}
return nil
},
maySkip: true,
}
return &Unmarshalers{fncVals: []typedUnmarshaler{}, fromAny: castableToFromAny()}
}
func ( reflect.Type, bool) {
switch .Kind() {
case reflect.Interface:
return
case reflect.Pointer:
if .Name() == "" {
return
}
default:
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", ))
}
}
func (, reflect.Type) bool {
switch .Kind() {
case reflect.Interface:
return reflect.PointerTo().Implements()
case reflect.Pointer:
return reflect.PointerTo() ==
default:
return ==
}
}
func ( addressableValue) ( reflect.Type) reflect.Value {
switch .Kind() {
case reflect.Interface:
return .Addr().Convert()
case reflect.Pointer:
return .Addr()
default:
return .Value
}
}
func ( reflect.Type) bool {
for , := range []reflect.Type{anyType, boolType, stringType, float64Type, mapStringAnyType, sliceAnyType} {
if castableTo(, ) {
return true
}
}
return false
}