// Copyright 2019 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.

package impl

import (
	
	

	
	
	
)

type mapInfo struct {
	goType     reflect.Type
	keyWiretag uint64
	valWiretag uint64
	keyFuncs   valueCoderFuncs
	valFuncs   valueCoderFuncs
	keyZero    protoreflect.Value
	keyKind    protoreflect.Kind
	conv       *mapConverter
}

func ( protoreflect.FieldDescriptor,  reflect.Type) ( *MessageInfo,  pointerCoderFuncs) {
	// TODO: Consider generating specialized map coders.
	 := .MapKey()
	 := .MapValue()
	 := protowire.EncodeTag(1, wireTypes[.Kind()])
	 := protowire.EncodeTag(2, wireTypes[.Kind()])
	 := encoderFuncsForValue()
	 := encoderFuncsForValue()
	 := newMapConverter(, )

	 := &mapInfo{
		goType:     ,
		keyWiretag: ,
		valWiretag: ,
		keyFuncs:   ,
		valFuncs:   ,
		keyZero:    .Default(),
		keyKind:    .Kind(),
		conv:       ,
	}
	if .Kind() == protoreflect.MessageKind {
		 = getMessageInfo(.Elem())
	}

	 = pointerCoderFuncs{
		size: func( pointer,  *coderFieldInfo,  marshalOptions) int {
			return sizeMap(.AsValueOf().Elem(), , , )
		},
		marshal: func( []byte,  pointer,  *coderFieldInfo,  marshalOptions) ([]byte, error) {
			return appendMap(, .AsValueOf().Elem(), , , )
		},
		unmarshal: func( []byte,  pointer,  protowire.Type,  *coderFieldInfo,  unmarshalOptions) (unmarshalOutput, error) {
			 := .AsValueOf()
			if .Elem().IsNil() {
				.Elem().Set(reflect.MakeMap(.goType))
			}
			if .mi == nil {
				return consumeMap(, .Elem(), , , , )
			} else {
				return consumeMapOfMessage(, .Elem(), , , , )
			}
		},
	}
	switch .Kind() {
	case protoreflect.MessageKind:
		.merge = mergeMapOfMessage
	case protoreflect.BytesKind:
		.merge = mergeMapOfBytes
	default:
		.merge = mergeMap
	}
	if .isInit != nil {
		.isInit = func( pointer,  *coderFieldInfo) error {
			return isInitMap(.AsValueOf().Elem(), , )
		}
	}
	return , 
}

const (
	mapKeyTagSize = 1 // field 1, tag size 1.
	mapValTagSize = 1 // field 2, tag size 2.
)

func ( reflect.Value,  *mapInfo,  *coderFieldInfo,  marshalOptions) int {
	if .Len() == 0 {
		return 0
	}
	 := 0
	 := mapRange()
	for .Next() {
		 := .conv.keyConv.PBValueOf(.Key()).MapKey()
		 := .keyFuncs.size(.Value(), mapKeyTagSize, )
		var  int
		 := .conv.valConv.PBValueOf(.Value())
		if .mi == nil {
			 = .valFuncs.size(, mapValTagSize, )
		} else {
			 := pointerOfValue(.Value())
			 += mapValTagSize
			 += protowire.SizeBytes(.mi.sizePointer(, ))
		}
		 += .tagsize + protowire.SizeBytes(+)
	}
	return 
}

func ( []byte,  reflect.Value,  protowire.Type,  *mapInfo,  *coderFieldInfo,  unmarshalOptions) ( unmarshalOutput,  error) {
	if  != protowire.BytesType {
		return , errUnknown
	}
	,  := protowire.ConsumeBytes()
	if  < 0 {
		return , errDecode
	}
	var (
		 = .keyZero
		 = .conv.valConv.New()
	)
	for len() > 0 {
		, ,  := protowire.ConsumeTag()
		if  < 0 {
			return , errDecode
		}
		if  > protowire.MaxValidNumber {
			return , errDecode
		}
		 = [:]
		 := errUnknown
		switch  {
		case genid.MapEntry_Key_field_number:
			var  protoreflect.Value
			var  unmarshalOutput
			, ,  = .keyFuncs.unmarshal(, , , , )
			if  != nil {
				break
			}
			 = 
			 = .n
		case genid.MapEntry_Value_field_number:
			var  protoreflect.Value
			var  unmarshalOutput
			, ,  = .valFuncs.unmarshal(, , , , )
			if  != nil {
				break
			}
			 = 
			 = .n
		}
		if  == errUnknown {
			 = protowire.ConsumeFieldValue(, , )
			if  < 0 {
				return , errDecode
			}
		} else if  != nil {
			return , 
		}
		 = [:]
	}
	.SetMapIndex(.conv.keyConv.GoValueOf(), .conv.valConv.GoValueOf())
	.n = 
	return , nil
}

func ( []byte,  reflect.Value,  protowire.Type,  *mapInfo,  *coderFieldInfo,  unmarshalOptions) ( unmarshalOutput,  error) {
	if  != protowire.BytesType {
		return , errUnknown
	}
	,  := protowire.ConsumeBytes()
	if  < 0 {
		return , errDecode
	}
	var (
		 = .keyZero
		 = reflect.New(.mi.GoReflectType.Elem())
	)
	for len() > 0 {
		, ,  := protowire.ConsumeTag()
		if  < 0 {
			return , errDecode
		}
		if  > protowire.MaxValidNumber {
			return , errDecode
		}
		 = [:]
		 := errUnknown
		switch  {
		case 1:
			var  protoreflect.Value
			var  unmarshalOutput
			, ,  = .keyFuncs.unmarshal(, , , , )
			if  != nil {
				break
			}
			 = 
			 = .n
		case 2:
			if  != protowire.BytesType {
				break
			}
			var  []byte
			,  = protowire.ConsumeBytes()
			if  < 0 {
				return , errDecode
			}
			var  unmarshalOutput
			,  = .mi.unmarshalPointer(, pointerOfValue(), 0, )
			if .initialized {
				// Consider this map item initialized so long as we see
				// an initialized value.
				.initialized = true
			}
		}
		if  == errUnknown {
			 = protowire.ConsumeFieldValue(, , )
			if  < 0 {
				return , errDecode
			}
		} else if  != nil {
			return , 
		}
		 = [:]
	}
	.SetMapIndex(.conv.keyConv.GoValueOf(), )
	.n = 
	return , nil
}

func ( []byte, ,  reflect.Value,  *mapInfo,  *coderFieldInfo,  marshalOptions) ([]byte, error) {
	if .mi == nil {
		 := .conv.keyConv.PBValueOf().MapKey()
		 := .conv.valConv.PBValueOf()
		 := 0
		 += .keyFuncs.size(.Value(), mapKeyTagSize, )
		 += .valFuncs.size(, mapValTagSize, )
		 = protowire.AppendVarint(, uint64())
		,  := .keyFuncs.marshal(, .Value(), .keyWiretag, )
		if  != nil {
			return nil, 
		}
		return .valFuncs.marshal(, , .valWiretag, )
	} else {
		 := .conv.keyConv.PBValueOf().MapKey()
		 := pointerOfValue()
		 := .mi.sizePointer(, )
		 := 0
		 += .keyFuncs.size(.Value(), mapKeyTagSize, )
		 += mapValTagSize + protowire.SizeBytes()
		 = protowire.AppendVarint(, uint64())
		,  := .keyFuncs.marshal(, .Value(), .keyWiretag, )
		if  != nil {
			return nil, 
		}
		 = protowire.AppendVarint(, .valWiretag)
		 = protowire.AppendVarint(, uint64())
		return .mi.marshalAppendPointer(, , )
	}
}

func ( []byte,  reflect.Value,  *mapInfo,  *coderFieldInfo,  marshalOptions) ([]byte, error) {
	if .Len() == 0 {
		return , nil
	}
	if .Deterministic() {
		return appendMapDeterministic(, , , , )
	}
	 := mapRange()
	for .Next() {
		var  error
		 = protowire.AppendVarint(, .wiretag)
		,  = appendMapItem(, .Key(), .Value(), , , )
		if  != nil {
			return , 
		}
	}
	return , nil
}

func ( []byte,  reflect.Value,  *mapInfo,  *coderFieldInfo,  marshalOptions) ([]byte, error) {
	 := .MapKeys()
	sort.Slice(, func(,  int) bool {
		switch [].Kind() {
		case reflect.Bool:
			return ![].Bool() && [].Bool()
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			return [].Int() < [].Int()
		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
			return [].Uint() < [].Uint()
		case reflect.Float32, reflect.Float64:
			return [].Float() < [].Float()
		case reflect.String:
			return [].String() < [].String()
		default:
			panic("invalid kind: " + [].Kind().String())
		}
	})
	for ,  := range  {
		var  error
		 = protowire.AppendVarint(, .wiretag)
		,  = appendMapItem(, , .MapIndex(), , , )
		if  != nil {
			return , 
		}
	}
	return , nil
}

func ( reflect.Value,  *mapInfo,  *coderFieldInfo) error {
	if  := .mi;  != nil {
		.init()
		if !.needsInitCheck {
			return nil
		}
		 := mapRange()
		for .Next() {
			 := pointerOfValue(.Value())
			if  := .checkInitializedPointer();  != nil {
				return 
			}
		}
	} else {
		 := mapRange()
		for .Next() {
			 := .conv.valConv.PBValueOf(.Value())
			if  := .valFuncs.isInit();  != nil {
				return 
			}
		}
	}
	return nil
}

func (,  pointer,  *coderFieldInfo,  mergeOptions) {
	 := .AsValueOf(.ft).Elem()
	 := .AsValueOf(.ft).Elem()
	if .Len() == 0 {
		return
	}
	if .IsNil() {
		.Set(reflect.MakeMap(.ft))
	}
	 := mapRange()
	for .Next() {
		.SetMapIndex(.Key(), .Value())
	}
}

func (,  pointer,  *coderFieldInfo,  mergeOptions) {
	 := .AsValueOf(.ft).Elem()
	 := .AsValueOf(.ft).Elem()
	if .Len() == 0 {
		return
	}
	if .IsNil() {
		.Set(reflect.MakeMap(.ft))
	}
	 := mapRange()
	for .Next() {
		.SetMapIndex(.Key(), reflect.ValueOf(append(emptyBuf[:], .Value().Bytes()...)))
	}
}

func (,  pointer,  *coderFieldInfo,  mergeOptions) {
	 := .AsValueOf(.ft).Elem()
	 := .AsValueOf(.ft).Elem()
	if .Len() == 0 {
		return
	}
	if .IsNil() {
		.Set(reflect.MakeMap(.ft))
	}
	 := mapRange()
	for .Next() {
		 := reflect.New(.ft.Elem().Elem())
		if .mi != nil {
			.mi.mergePointer(pointerOfValue(), pointerOfValue(.Value()), )
		} else {
			.Merge(asMessage(), asMessage(.Value()))
		}
		.SetMapIndex(.Key(), )
	}
}