package mapstructure

import (
	
	
	
	
	
	
	
	
	
	
)

// typedDecodeHook takes a raw DecodeHookFunc (an any) and turns
// it into the proper DecodeHookFunc type, such as DecodeHookFuncType.
func typedDecodeHook( DecodeHookFunc) DecodeHookFunc {
	// Create variables here so we can reference them with the reflect pkg
	var  DecodeHookFuncType
	var  DecodeHookFuncKind
	var  DecodeHookFuncValue

	// Fill in the variables into this interface and the rest is done
	// automatically using the reflect package.
	 := []any{, , }

	 := reflect.ValueOf()
	 := .Type()
	for ,  := range  {
		 := reflect.ValueOf().Type()
		if .ConvertibleTo() {
			return .Convert().Interface()
		}
	}

	return nil
}

// cachedDecodeHook takes a raw DecodeHookFunc (an any) and turns
// it into a closure to be used directly
// if the type fails to convert we return a closure always erroring to keep the previous behaviour
func cachedDecodeHook( DecodeHookFunc) func( reflect.Value,  reflect.Value) (any, error) {
	switch f := typedDecodeHook().(type) {
	case DecodeHookFuncType:
		return func( reflect.Value,  reflect.Value) (any, error) {
			return (.Type(), .Type(), .Interface())
		}
	case DecodeHookFuncKind:
		return func( reflect.Value,  reflect.Value) (any, error) {
			return (.Kind(), .Kind(), .Interface())
		}
	case DecodeHookFuncValue:
		return func( reflect.Value,  reflect.Value) (any, error) {
			return (, )
		}
	default:
		return func( reflect.Value,  reflect.Value) (any, error) {
			return nil, errors.New("invalid decode hook signature")
		}
	}
}

// DecodeHookExec executes the given decode hook. This should be used
// since it'll naturally degrade to the older backwards compatible DecodeHookFunc
// that took reflect.Kind instead of reflect.Type.
func (
	 DecodeHookFunc,
	 reflect.Value,  reflect.Value,
) (any, error) {
	switch f := typedDecodeHook().(type) {
	case DecodeHookFuncType:
		return (.Type(), .Type(), .Interface())
	case DecodeHookFuncKind:
		return (.Kind(), .Kind(), .Interface())
	case DecodeHookFuncValue:
		return (, )
	default:
		return nil, errors.New("invalid decode hook signature")
	}
}

// ComposeDecodeHookFunc creates a single DecodeHookFunc that
// automatically composes multiple DecodeHookFuncs.
//
// The composed funcs are called in order, with the result of the
// previous transformation.
func ( ...DecodeHookFunc) DecodeHookFunc {
	 := make([]func( reflect.Value,  reflect.Value) (any, error), 0, len())
	for ,  := range  {
		 = append(, cachedDecodeHook())
	}
	return func( reflect.Value,  reflect.Value) (any, error) {
		var  error
		 := .Interface()

		 := 
		for ,  := range  {
			,  = (, )
			if  != nil {
				return nil, 
			}
			if ,  := .(reflect.Value);  {
				 = 
			} else {
				 = reflect.ValueOf()
			}
		}

		return , nil
	}
}

// OrComposeDecodeHookFunc executes all input hook functions until one of them returns no error. In that case its value is returned.
// If all hooks return an error, OrComposeDecodeHookFunc returns an error concatenating all error messages.
func ( ...DecodeHookFunc) DecodeHookFunc {
	 := make([]func( reflect.Value,  reflect.Value) (any, error), 0, len())
	for ,  := range  {
		 = append(, cachedDecodeHook())
	}
	return func(,  reflect.Value) (any, error) {
		var  string
		var  any
		var  error

		for ,  := range  {
			,  = (, )
			if  != nil {
				 += .Error() + "\n"
				continue
			}

			return , nil
		}

		return nil, errors.New()
	}
}

// StringToSliceHookFunc returns a DecodeHookFunc that converts
// string to []string by splitting on the given sep.
func ( string) DecodeHookFunc {
	return func(
		 reflect.Type,
		 reflect.Type,
		 any,
	) (any, error) {
		if .Kind() != reflect.String {
			return , nil
		}
		if  != reflect.SliceOf() {
			return , nil
		}

		 := .(string)
		if  == "" {
			return []string{}, nil
		}

		return strings.Split(, ), nil
	}
}

// StringToWeakSliceHookFunc brings back the old (pre-v2) behavior of [StringToSliceHookFunc].
//
// As of mapstructure v2.0.0 [StringToSliceHookFunc] checks if the return type is a string slice.
// This function removes that check.
func ( string) DecodeHookFunc {
	return func(
		 reflect.Type,
		 reflect.Type,
		 any,
	) (any, error) {
		if .Kind() != reflect.String || .Kind() != reflect.Slice {
			return , nil
		}

		 := .(string)
		if  == "" {
			return []string{}, nil
		}

		return strings.Split(, ), nil
	}
}

// StringToTimeDurationHookFunc returns a DecodeHookFunc that converts
// strings to time.Duration.
func () DecodeHookFunc {
	return func(
		 reflect.Type,
		 reflect.Type,
		 any,
	) (any, error) {
		if .Kind() != reflect.String {
			return , nil
		}
		if  != reflect.TypeOf(time.Duration(5)) {
			return , nil
		}

		// Convert it by parsing
		,  := time.ParseDuration(.(string))

		return , wrapTimeParseDurationError()
	}
}

// StringToTimeLocationHookFunc returns a DecodeHookFunc that converts
// strings to *time.Location.
func () DecodeHookFunc {
	return func(
		 reflect.Type,
		 reflect.Type,
		 any,
	) (any, error) {
		if .Kind() != reflect.String {
			return , nil
		}
		if  != reflect.TypeOf(time.Local) {
			return , nil
		}
		,  := time.LoadLocation(.(string))

		return , wrapTimeParseLocationError()
	}
}

// StringToURLHookFunc returns a DecodeHookFunc that converts
// strings to *url.URL.
func () DecodeHookFunc {
	return func(
		 reflect.Type,
		 reflect.Type,
		 any,
	) (any, error) {
		if .Kind() != reflect.String {
			return , nil
		}
		if  != reflect.TypeOf(&url.URL{}) {
			return , nil
		}

		// Convert it by parsing
		,  := url.Parse(.(string))

		return , wrapUrlError()
	}
}

// StringToIPHookFunc returns a DecodeHookFunc that converts
// strings to net.IP
func () DecodeHookFunc {
	return func(
		 reflect.Type,
		 reflect.Type,
		 any,
	) (any, error) {
		if .Kind() != reflect.String {
			return , nil
		}
		if  != reflect.TypeOf(net.IP{}) {
			return , nil
		}

		// Convert it by parsing
		 := net.ParseIP(.(string))
		if  == nil {
			return net.IP{}, fmt.Errorf("failed parsing ip")
		}

		return , nil
	}
}

// StringToIPNetHookFunc returns a DecodeHookFunc that converts
// strings to net.IPNet
func () DecodeHookFunc {
	return func(
		 reflect.Type,
		 reflect.Type,
		 any,
	) (any, error) {
		if .Kind() != reflect.String {
			return , nil
		}
		if  != reflect.TypeOf(net.IPNet{}) {
			return , nil
		}

		// Convert it by parsing
		, ,  := net.ParseCIDR(.(string))
		return , wrapNetParseError()
	}
}

// StringToTimeHookFunc returns a DecodeHookFunc that converts
// strings to time.Time.
func ( string) DecodeHookFunc {
	return func(
		 reflect.Type,
		 reflect.Type,
		 any,
	) (any, error) {
		if .Kind() != reflect.String {
			return , nil
		}
		if  != reflect.TypeOf(time.Time{}) {
			return , nil
		}

		// Convert it by parsing
		,  := time.Parse(, .(string))

		return , wrapTimeParseError()
	}
}

// WeaklyTypedHook is a DecodeHookFunc which adds support for weak typing to
// the decoder.
//
// Note that this is significantly different from the WeaklyTypedInput option
// of the DecoderConfig.
func (
	 reflect.Kind,
	 reflect.Kind,
	 any,
) (any, error) {
	 := reflect.ValueOf()
	switch  {
	case reflect.String:
		switch  {
		case reflect.Bool:
			if .Bool() {
				return "1", nil
			}
			return "0", nil
		case reflect.Float32:
			return strconv.FormatFloat(.Float(), 'f', -1, 64), nil
		case reflect.Int:
			return strconv.FormatInt(.Int(), 10), nil
		case reflect.Slice:
			 := .Type()
			 := .Elem().Kind()
			if  == reflect.Uint8 {
				return string(.Interface().([]uint8)), nil
			}
		case reflect.Uint:
			return strconv.FormatUint(.Uint(), 10), nil
		}
	}

	return , nil
}

func () DecodeHookFunc {
	return func( reflect.Value,  reflect.Value) (any, error) {
		if .Kind() != reflect.Struct {
			return .Interface(), nil
		}

		var  any = struct{}{}
		if .Type() != reflect.TypeOf(&).Elem() {
			return .Interface(), nil
		}

		 := make(map[string]any)
		.Set(reflect.ValueOf())

		return .Interface(), nil
	}
}

// TextUnmarshallerHookFunc returns a DecodeHookFunc that applies
// strings to the UnmarshalText function, when the target type
// implements the encoding.TextUnmarshaler interface
func () DecodeHookFuncType {
	return func(
		 reflect.Type,
		 reflect.Type,
		 any,
	) (any, error) {
		if .Kind() != reflect.String {
			return , nil
		}
		 := reflect.New().Interface()
		,  := .(encoding.TextUnmarshaler)
		if ! {
			return , nil
		}
		,  := .(string)
		if ! {
			 = reflect.Indirect(reflect.ValueOf(&)).Elem().String()
		}
		if  := .UnmarshalText([]byte());  != nil {
			return nil, 
		}
		return , nil
	}
}

// StringToNetIPAddrHookFunc returns a DecodeHookFunc that converts
// strings to netip.Addr.
func () DecodeHookFunc {
	return func(
		 reflect.Type,
		 reflect.Type,
		 any,
	) (any, error) {
		if .Kind() != reflect.String {
			return , nil
		}
		if  != reflect.TypeOf(netip.Addr{}) {
			return , nil
		}

		// Convert it by parsing
		,  := netip.ParseAddr(.(string))

		return , wrapNetIPParseAddrError()
	}
}

// StringToNetIPAddrPortHookFunc returns a DecodeHookFunc that converts
// strings to netip.AddrPort.
func () DecodeHookFunc {
	return func(
		 reflect.Type,
		 reflect.Type,
		 any,
	) (any, error) {
		if .Kind() != reflect.String {
			return , nil
		}
		if  != reflect.TypeOf(netip.AddrPort{}) {
			return , nil
		}

		// Convert it by parsing
		,  := netip.ParseAddrPort(.(string))

		return , wrapNetIPParseAddrPortError()
	}
}

// StringToNetIPPrefixHookFunc returns a DecodeHookFunc that converts
// strings to netip.Prefix.
func () DecodeHookFunc {
	return func(
		 reflect.Type,
		 reflect.Type,
		 any,
	) (any, error) {
		if .Kind() != reflect.String {
			return , nil
		}
		if  != reflect.TypeOf(netip.Prefix{}) {
			return , nil
		}

		// Convert it by parsing
		,  := netip.ParsePrefix(.(string))

		return , wrapNetIPParsePrefixError()
	}
}

// StringToBasicTypeHookFunc returns a DecodeHookFunc that converts
// strings to basic types.
// int8, uint8, int16, uint16, int32, uint32, int64, uint64, int, uint, float32, float64, bool, byte, rune, complex64, complex128
func () DecodeHookFunc {
	return ComposeDecodeHookFunc(
		StringToInt8HookFunc(),
		StringToUint8HookFunc(),
		StringToInt16HookFunc(),
		StringToUint16HookFunc(),
		StringToInt32HookFunc(),
		StringToUint32HookFunc(),
		StringToInt64HookFunc(),
		StringToUint64HookFunc(),
		StringToIntHookFunc(),
		StringToUintHookFunc(),
		StringToFloat32HookFunc(),
		StringToFloat64HookFunc(),
		StringToBoolHookFunc(),
		// byte and rune are aliases for uint8 and int32 respectively
		// StringToByteHookFunc(),
		// StringToRuneHookFunc(),
		StringToComplex64HookFunc(),
		StringToComplex128HookFunc(),
	)
}

// StringToInt8HookFunc returns a DecodeHookFunc that converts
// strings to int8.
func () DecodeHookFunc {
	return func( reflect.Type,  reflect.Type,  any) (any, error) {
		if .Kind() != reflect.String || .Kind() != reflect.Int8 {
			return , nil
		}

		// Convert it by parsing
		,  := strconv.ParseInt(.(string), 0, 8)
		return int8(), wrapStrconvNumError()
	}
}

// StringToUint8HookFunc returns a DecodeHookFunc that converts
// strings to uint8.
func () DecodeHookFunc {
	return func( reflect.Type,  reflect.Type,  any) (any, error) {
		if .Kind() != reflect.String || .Kind() != reflect.Uint8 {
			return , nil
		}

		// Convert it by parsing
		,  := strconv.ParseUint(.(string), 0, 8)
		return uint8(), wrapStrconvNumError()
	}
}

// StringToInt16HookFunc returns a DecodeHookFunc that converts
// strings to int16.
func () DecodeHookFunc {
	return func( reflect.Type,  reflect.Type,  any) (any, error) {
		if .Kind() != reflect.String || .Kind() != reflect.Int16 {
			return , nil
		}

		// Convert it by parsing
		,  := strconv.ParseInt(.(string), 0, 16)
		return int16(), wrapStrconvNumError()
	}
}

// StringToUint16HookFunc returns a DecodeHookFunc that converts
// strings to uint16.
func () DecodeHookFunc {
	return func( reflect.Type,  reflect.Type,  any) (any, error) {
		if .Kind() != reflect.String || .Kind() != reflect.Uint16 {
			return , nil
		}

		// Convert it by parsing
		,  := strconv.ParseUint(.(string), 0, 16)
		return uint16(), wrapStrconvNumError()
	}
}

// StringToInt32HookFunc returns a DecodeHookFunc that converts
// strings to int32.
func () DecodeHookFunc {
	return func( reflect.Type,  reflect.Type,  any) (any, error) {
		if .Kind() != reflect.String || .Kind() != reflect.Int32 {
			return , nil
		}

		// Convert it by parsing
		,  := strconv.ParseInt(.(string), 0, 32)
		return int32(), wrapStrconvNumError()
	}
}

// StringToUint32HookFunc returns a DecodeHookFunc that converts
// strings to uint32.
func () DecodeHookFunc {
	return func( reflect.Type,  reflect.Type,  any) (any, error) {
		if .Kind() != reflect.String || .Kind() != reflect.Uint32 {
			return , nil
		}

		// Convert it by parsing
		,  := strconv.ParseUint(.(string), 0, 32)
		return uint32(), wrapStrconvNumError()
	}
}

// StringToInt64HookFunc returns a DecodeHookFunc that converts
// strings to int64.
func () DecodeHookFunc {
	return func( reflect.Type,  reflect.Type,  any) (any, error) {
		if .Kind() != reflect.String || .Kind() != reflect.Int64 {
			return , nil
		}

		// Convert it by parsing
		,  := strconv.ParseInt(.(string), 0, 64)
		return int64(), wrapStrconvNumError()
	}
}

// StringToUint64HookFunc returns a DecodeHookFunc that converts
// strings to uint64.
func () DecodeHookFunc {
	return func( reflect.Type,  reflect.Type,  any) (any, error) {
		if .Kind() != reflect.String || .Kind() != reflect.Uint64 {
			return , nil
		}

		// Convert it by parsing
		,  := strconv.ParseUint(.(string), 0, 64)
		return uint64(), wrapStrconvNumError()
	}
}

// StringToIntHookFunc returns a DecodeHookFunc that converts
// strings to int.
func () DecodeHookFunc {
	return func( reflect.Type,  reflect.Type,  any) (any, error) {
		if .Kind() != reflect.String || .Kind() != reflect.Int {
			return , nil
		}

		// Convert it by parsing
		,  := strconv.ParseInt(.(string), 0, 0)
		return int(), wrapStrconvNumError()
	}
}

// StringToUintHookFunc returns a DecodeHookFunc that converts
// strings to uint.
func () DecodeHookFunc {
	return func( reflect.Type,  reflect.Type,  any) (any, error) {
		if .Kind() != reflect.String || .Kind() != reflect.Uint {
			return , nil
		}

		// Convert it by parsing
		,  := strconv.ParseUint(.(string), 0, 0)
		return uint(), wrapStrconvNumError()
	}
}

// StringToFloat32HookFunc returns a DecodeHookFunc that converts
// strings to float32.
func () DecodeHookFunc {
	return func( reflect.Type,  reflect.Type,  any) (any, error) {
		if .Kind() != reflect.String || .Kind() != reflect.Float32 {
			return , nil
		}

		// Convert it by parsing
		,  := strconv.ParseFloat(.(string), 32)
		return float32(), wrapStrconvNumError()
	}
}

// StringToFloat64HookFunc returns a DecodeHookFunc that converts
// strings to float64.
func () DecodeHookFunc {
	return func( reflect.Type,  reflect.Type,  any) (any, error) {
		if .Kind() != reflect.String || .Kind() != reflect.Float64 {
			return , nil
		}

		// Convert it by parsing
		,  := strconv.ParseFloat(.(string), 64)
		return , wrapStrconvNumError()
	}
}

// StringToBoolHookFunc returns a DecodeHookFunc that converts
// strings to bool.
func () DecodeHookFunc {
	return func( reflect.Type,  reflect.Type,  any) (any, error) {
		if .Kind() != reflect.String || .Kind() != reflect.Bool {
			return , nil
		}

		// Convert it by parsing
		,  := strconv.ParseBool(.(string))
		return , wrapStrconvNumError()
	}
}

// StringToByteHookFunc returns a DecodeHookFunc that converts
// strings to byte.
func () DecodeHookFunc {
	return StringToUint8HookFunc()
}

// StringToRuneHookFunc returns a DecodeHookFunc that converts
// strings to rune.
func () DecodeHookFunc {
	return StringToInt32HookFunc()
}

// StringToComplex64HookFunc returns a DecodeHookFunc that converts
// strings to complex64.
func () DecodeHookFunc {
	return func( reflect.Type,  reflect.Type,  any) (any, error) {
		if .Kind() != reflect.String || .Kind() != reflect.Complex64 {
			return , nil
		}

		// Convert it by parsing
		,  := strconv.ParseComplex(.(string), 64)
		return complex64(), wrapStrconvNumError()
	}
}

// StringToComplex128HookFunc returns a DecodeHookFunc that converts
// strings to complex128.
func () DecodeHookFunc {
	return func( reflect.Type,  reflect.Type,  any) (any, error) {
		if .Kind() != reflect.String || .Kind() != reflect.Complex128 {
			return , nil
		}

		// Convert it by parsing
		,  := strconv.ParseComplex(.(string), 128)
		return , wrapStrconvNumError()
	}
}