package msgpack

import (
	
	
	
	
	

	
)

var errorType = reflect.TypeOf((*error)(nil)).Elem()

var (
	customEncoderType = reflect.TypeOf((*CustomEncoder)(nil)).Elem()
	customDecoderType = reflect.TypeOf((*CustomDecoder)(nil)).Elem()
)

var (
	marshalerType   = reflect.TypeOf((*Marshaler)(nil)).Elem()
	unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
)

var (
	binaryMarshalerType   = reflect.TypeOf((*encoding.BinaryMarshaler)(nil)).Elem()
	binaryUnmarshalerType = reflect.TypeOf((*encoding.BinaryUnmarshaler)(nil)).Elem()
)

var (
	textMarshalerType   = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
	textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
)

type (
	encoderFunc func(*Encoder, reflect.Value) error
	decoderFunc func(*Decoder, reflect.Value) error
)

var (
	typeEncMap sync.Map
	typeDecMap sync.Map
)

// Register registers encoder and decoder functions for a value.
// This is low level API and in most cases you should prefer implementing
// CustomEncoder/CustomDecoder or Marshaler/Unmarshaler interfaces.
func ( interface{},  encoderFunc,  decoderFunc) {
	 := reflect.TypeOf()
	if  != nil {
		typeEncMap.Store(, )
	}
	if  != nil {
		typeDecMap.Store(, )
	}
}

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

const defaultStructTag = "msgpack"

var structs = newStructCache()

type structCache struct {
	m sync.Map
}

type structCacheKey struct {
	tag string
	typ reflect.Type
}

func () *structCache {
	return new(structCache)
}

func ( *structCache) ( reflect.Type,  string) *fields {
	 := structCacheKey{tag: , typ: }

	if ,  := .m.Load();  {
		return .(*fields)
	}

	 := getFields(, )
	.m.Store(, )

	return 
}

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

type field struct {
	name      string
	index     []int
	omitEmpty bool
	encoder   encoderFunc
	decoder   decoderFunc
}

func ( *field) ( reflect.Value,  bool) bool {
	,  := fieldByIndex(, .index)
	if ! {
		return true
	}
	return (.omitEmpty || ) && isEmptyValue()
}

func ( *field) ( *Encoder,  reflect.Value) error {
	,  := fieldByIndex(, .index)
	if ! {
		return .EncodeNil()
	}
	return .encoder(, )
}

func ( *field) ( *Decoder,  reflect.Value) error {
	 := fieldByIndexAlloc(, .index)
	return .decoder(, )
}

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

type fields struct {
	Type    reflect.Type
	Map     map[string]*field
	List    []*field
	AsArray bool

	hasOmitEmpty bool
}

func ( reflect.Type) *fields {
	return &fields{
		Type: ,
		Map:  make(map[string]*field, .NumField()),
		List: make([]*field, 0, .NumField()),
	}
}

func ( *fields) ( *field) {
	.warnIfFieldExists(.name)
	.Map[.name] = 
	.List = append(.List, )
	if .omitEmpty {
		.hasOmitEmpty = true
	}
}

func ( *fields) ( string) {
	if ,  := .Map[];  {
		log.Printf("msgpack: %s already has field=%s", .Type, )
	}
}

func ( *fields) ( reflect.Value,  bool) []*field {
	if !.hasOmitEmpty && ! {
		return .List
	}

	 := make([]*field, 0, len(.List))

	for ,  := range .List {
		if !.Omit(, ) {
			 = append(, )
		}
	}

	return 
}

func ( reflect.Type,  string) *fields {
	 := newFields()

	var  bool
	for  := 0;  < .NumField(); ++ {
		 := .Field()

		 := .Tag.Get(defaultStructTag)
		if  == "" &&  != "" {
			 = .Tag.Get()
		}

		 := tagparser.Parse()
		if .Name == "-" {
			continue
		}

		if .Name == "_msgpack" {
			.AsArray = .HasOption("as_array") || .HasOption("asArray")
			if .HasOption("omitempty") {
				 = true
			}
		}

		if .PkgPath != "" && !.Anonymous {
			continue
		}

		 := &field{
			name:      .Name,
			index:     .Index,
			omitEmpty:  || .HasOption("omitempty"),
		}

		if .HasOption("intern") {
			switch .Type.Kind() {
			case reflect.Interface:
				.encoder = encodeInternedInterfaceValue
				.decoder = decodeInternedInterfaceValue
			case reflect.String:
				.encoder = encodeInternedStringValue
				.decoder = decodeInternedStringValue
			default:
				 := fmt.Errorf("msgpack: intern strings are not supported on %s", .Type)
				panic()
			}
		} else {
			.encoder = getEncoder(.Type)
			.decoder = getDecoder(.Type)
		}

		if .name == "" {
			.name = .Name
		}

		if .Anonymous && !.HasOption("noinline") {
			 := .HasOption("inline")
			if  {
				inlineFields(, .Type, , )
			} else {
				 = shouldInline(, .Type, , )
			}

			if  {
				if ,  := .Map[.name];  {
					log.Printf("msgpack: %s already has field=%s", .Type, .name)
				}
				.Map[.name] = 
				continue
			}
		}

		.Add()

		if ,  := .Options["alias"];  {
			.warnIfFieldExists()
			.Map[] = 
		}
	}
	return 
}

var (
	encodeStructValuePtr uintptr
	decodeStructValuePtr uintptr
)

//nolint:gochecknoinits
func () {
	encodeStructValuePtr = reflect.ValueOf(encodeStructValue).Pointer()
	decodeStructValuePtr = reflect.ValueOf(decodeStructValue).Pointer()
}

func ( *fields,  reflect.Type,  *field,  string) {
	 := getFields(, ).List
	for ,  := range  {
		if ,  := .Map[.name];  {
			// Don't inline shadowed fields.
			continue
		}
		.index = append(.index, .index...)
		.Add()
	}
}

func ( *fields,  reflect.Type,  *field,  string) bool {
	var  encoderFunc
	var  decoderFunc

	if .Kind() == reflect.Struct {
		 = .encoder
		 = .decoder
	} else {
		for .Kind() == reflect.Ptr {
			 = .Elem()
			 = getEncoder()
			 = getDecoder()
		}
		if .Kind() != reflect.Struct {
			return false
		}
	}

	if reflect.ValueOf().Pointer() != encodeStructValuePtr {
		return false
	}
	if reflect.ValueOf().Pointer() != decodeStructValuePtr {
		return false
	}

	 := getFields(, ).List
	for ,  := range  {
		if ,  := .Map[.name];  {
			// Don't auto inline if there are shadowed fields.
			return false
		}
	}

	for ,  := range  {
		.index = append(.index, .index...)
		.Add()
	}
	return true
}

type isZeroer interface {
	IsZero() bool
}

func ( reflect.Value) bool {
	 := .Kind()

	for  == reflect.Interface {
		if .IsNil() {
			return true
		}
		 = .Elem()
		 = .Kind()
	}

	if ,  := .Interface().(isZeroer);  {
		return nilable() && .IsNil() || .IsZero()
	}

	switch  {
	case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
		return .Len() == 0
	case reflect.Bool:
		return !.Bool()
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return .Int() == 0
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		return .Uint() == 0
	case reflect.Float32, reflect.Float64:
		return .Float() == 0
	case reflect.Ptr:
		return .IsNil()
	default:
		return false
	}
}

func ( reflect.Value,  []int) ( reflect.Value,  bool) {
	if len() == 1 {
		return .Field([0]), true
	}

	for ,  := range  {
		if  > 0 {
			if .Kind() == reflect.Ptr {
				if .IsNil() {
					return , false
				}
				 = .Elem()
			}
		}
		 = .Field()
	}

	return , true
}

func ( reflect.Value,  []int) reflect.Value {
	if len() == 1 {
		return .Field([0])
	}

	for ,  := range  {
		if  > 0 {
			var  bool
			,  = indirectNil()
			if ! {
				return 
			}
		}
		 = .Field()
	}

	return 
}

func ( reflect.Value) (reflect.Value, bool) {
	if .Kind() == reflect.Ptr {
		if .IsNil() {
			if !.CanSet() {
				return , false
			}
			 := .Type().Elem()
			if .Kind() != reflect.Struct {
				return , false
			}
			.Set(reflect.New())
		}
		 = .Elem()
	}
	return , true
}