package msgpack

import (
	
	
	
)

var valueEncoders []encoderFunc

//nolint:gochecknoinits
func () {
	valueEncoders = []encoderFunc{
		reflect.Bool:          encodeBoolValue,
		reflect.Int:           encodeIntValue,
		reflect.Int8:          encodeInt8CondValue,
		reflect.Int16:         encodeInt16CondValue,
		reflect.Int32:         encodeInt32CondValue,
		reflect.Int64:         encodeInt64CondValue,
		reflect.Uint:          encodeUintValue,
		reflect.Uint8:         encodeUint8CondValue,
		reflect.Uint16:        encodeUint16CondValue,
		reflect.Uint32:        encodeUint32CondValue,
		reflect.Uint64:        encodeUint64CondValue,
		reflect.Float32:       encodeFloat32Value,
		reflect.Float64:       encodeFloat64Value,
		reflect.Complex64:     encodeUnsupportedValue,
		reflect.Complex128:    encodeUnsupportedValue,
		reflect.Array:         encodeArrayValue,
		reflect.Chan:          encodeUnsupportedValue,
		reflect.Func:          encodeUnsupportedValue,
		reflect.Interface:     encodeInterfaceValue,
		reflect.Map:           encodeMapValue,
		reflect.Ptr:           encodeUnsupportedValue,
		reflect.Slice:         encodeSliceValue,
		reflect.String:        encodeStringValue,
		reflect.Struct:        encodeStructValue,
		reflect.UnsafePointer: encodeUnsupportedValue,
	}
}

func ( reflect.Type) encoderFunc {
	if ,  := typeEncMap.Load();  {
		return .(encoderFunc)
	}
	 := _getEncoder()
	typeEncMap.Store(, )
	return 
}

func ( reflect.Type) encoderFunc {
	 := .Kind()

	if  == reflect.Ptr {
		if ,  := typeEncMap.Load(.Elem());  {
			return ptrEncoderFunc()
		}
	}

	if .Implements(customEncoderType) {
		return encodeCustomValue
	}
	if .Implements(marshalerType) {
		return marshalValue
	}
	if .Implements(binaryMarshalerType) {
		return marshalBinaryValue
	}
	if .Implements(textMarshalerType) {
		return marshalTextValue
	}

	// Addressable struct field value.
	if  != reflect.Ptr {
		 := reflect.PtrTo()
		if .Implements(customEncoderType) {
			return encodeCustomValuePtr
		}
		if .Implements(marshalerType) {
			return marshalValuePtr
		}
		if .Implements(binaryMarshalerType) {
			return marshalBinaryValueAddr
		}
		if .Implements(textMarshalerType) {
			return marshalTextValueAddr
		}
	}

	if  == errorType {
		return encodeErrorValue
	}

	switch  {
	case reflect.Ptr:
		return ptrEncoderFunc()
	case reflect.Slice:
		 := .Elem()
		if .Kind() == reflect.Uint8 {
			return encodeByteSliceValue
		}
		if  == stringType {
			return encodeStringSliceValue
		}
	case reflect.Array:
		if .Elem().Kind() == reflect.Uint8 {
			return encodeByteArrayValue
		}
	case reflect.Map:
		if .Key() == stringType {
			switch .Elem() {
			case stringType:
				return encodeMapStringStringValue
			case interfaceType:
				return encodeMapStringInterfaceValue
			}
		}
	}

	return valueEncoders[]
}

func ( reflect.Type) encoderFunc {
	 := getEncoder(.Elem())
	return func( *Encoder,  reflect.Value) error {
		if .IsNil() {
			return .EncodeNil()
		}
		return (, .Elem())
	}
}

func ( *Encoder,  reflect.Value) error {
	if !.CanAddr() {
		return fmt.Errorf("msgpack: Encode(non-addressable %T)", .Interface())
	}
	 := .Addr().Interface().(CustomEncoder)
	return .EncodeMsgpack()
}

func ( *Encoder,  reflect.Value) error {
	if nilable(.Kind()) && .IsNil() {
		return .EncodeNil()
	}

	 := .Interface().(CustomEncoder)
	return .EncodeMsgpack()
}

func ( *Encoder,  reflect.Value) error {
	if !.CanAddr() {
		return fmt.Errorf("msgpack: Encode(non-addressable %T)", .Interface())
	}
	return marshalValue(, .Addr())
}

func ( *Encoder,  reflect.Value) error {
	if nilable(.Kind()) && .IsNil() {
		return .EncodeNil()
	}

	 := .Interface().(Marshaler)
	,  := .MarshalMsgpack()
	if  != nil {
		return 
	}
	_,  = .w.Write()
	return 
}

func ( *Encoder,  reflect.Value) error {
	return .EncodeBool(.Bool())
}

func ( *Encoder,  reflect.Value) error {
	if .IsNil() {
		return .EncodeNil()
	}
	return .EncodeValue(.Elem())
}

func ( *Encoder,  reflect.Value) error {
	if .IsNil() {
		return .EncodeNil()
	}
	return .EncodeString(.Interface().(error).Error())
}

func ( *Encoder,  reflect.Value) error {
	return fmt.Errorf("msgpack: Encode(unsupported %s)", .Type())
}

func ( reflect.Kind) bool {
	switch  {
	case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
		return true
	}
	return false
}

//------------------------------------------------------------------------------

func ( *Encoder,  reflect.Value) error {
	if !.CanAddr() {
		return fmt.Errorf("msgpack: Encode(non-addressable %T)", .Interface())
	}
	return marshalBinaryValue(, .Addr())
}

func ( *Encoder,  reflect.Value) error {
	if nilable(.Kind()) && .IsNil() {
		return .EncodeNil()
	}

	 := .Interface().(encoding.BinaryMarshaler)
	,  := .MarshalBinary()
	if  != nil {
		return 
	}

	return .EncodeBytes()
}

//------------------------------------------------------------------------------

func ( *Encoder,  reflect.Value) error {
	if !.CanAddr() {
		return fmt.Errorf("msgpack: Encode(non-addressable %T)", .Interface())
	}
	return marshalTextValue(, .Addr())
}

func ( *Encoder,  reflect.Value) error {
	if nilable(.Kind()) && .IsNil() {
		return .EncodeNil()
	}

	 := .Interface().(encoding.TextMarshaler)
	,  := .MarshalText()
	if  != nil {
		return 
	}

	return .EncodeBytes()
}