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

package json

import (
	
	
	
	

	
	
	
	
)

// 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.
var SkipFunc = 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.
type Marshalers = 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 m2
func ( ...*Marshalers) *Marshalers {
	return newMarshalers(...)
}

// 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.
type Unmarshalers = 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 u2
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 // 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       { return newTypedArshalers(...) }
func newUnmarshalers( ...*Unmarshalers) *Unmarshalers { return newTypedArshalers(...) }
func newTypedArshalers[ 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
	}

	// 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) error
	for ,  := range .fncVals {
		if !castableTo(, .typ) {
			continue
		}
		 = append(, .fnc)
		if !.maySkip {
			break // subsequent arshalers will never be called
		}
	}

	if len() == 0 {
		.fncCache.Store(, nil) // nil to indicate that no funcs found
		return , 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) {
					return internal.NewMarshalerError(.Addr().Interface(), , "MarshalFunc") // unlike unmarshal, always wrapped
				}
				 = newMarshalErrorBefore(, , )
				return collapseSemanticErrors()
			}
			if  := .WriteValue();  != nil {
				if .Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
					return internal.NewMarshalerError(.Addr().Interface(), , "MarshalFunc") // unlike unmarshal, always wrapped
				}
				if isSyntacticError() {
					 = newMarshalErrorBefore(, , )
				}
				return 
			}
			return nil
		},
	}
	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  ==  &&  ==  {
						return SkipFunc
					}
					 = errSkipMutation
				}
				if .Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
					return internal.NewMarshalerError(.Addr().Interface(), , "MarshalToFunc") // unlike unmarshal, always wrapped
				}
				if !export.IsIOError() {
					 = newSemanticErrorWithPosition(, , , , )
				}
				return 
			}
			return nil
		},
		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(, , )
				return collapseSemanticErrors()
			}
			return nil
		},
	}
	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  ==  &&  ==  {
						return SkipFunc
					}
					 = errSkipMutation
				}
				if .Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
					if  := .SkipUntil(, +1);  != nil {
						return 
					}
					return  // unlike marshal, never wrapped
				}
				if !isSyntacticError() && !export.IsIOError() {
					 = newSemanticErrorWithPosition(, , , , )
				}
				return 
			}
			return nil
		},
		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() {
	case reflect.Interface:
		return
	case reflect.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() {
	case reflect.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.
		return reflect.PointerTo().Implements()
	case reflect.Pointer:
		// Common case for unmarshaling.
		// From must be a concrete or interface type.
		return reflect.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() {
	case reflect.Interface:
		return .Addr().Convert()
	case reflect.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} {
		if castableTo(, ) {
			return true
		}
	}
	return false
}

func wrapSkipFunc( error,  string) error {
	if  == SkipFunc {
		return errors.New( + " cannot be skipped")
	}
	return 
}