// 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 (
	
	
	

	
	
	
	
	
)

// coderMessageInfo contains per-message information used by the fast-path functions.
// This is a different type from MessageInfo to keep MessageInfo as general-purpose as
// possible.
type coderMessageInfo struct {
	methods protoiface.Methods

	orderedCoderFields []*coderFieldInfo
	denseCoderFields   []*coderFieldInfo
	coderFields        map[protowire.Number]*coderFieldInfo
	sizecacheOffset    offset
	unknownOffset      offset
	unknownPtrKind     bool
	extensionOffset    offset
	needsInitCheck     bool
	isMessageSet       bool
	numRequiredFields  uint8
}

type coderFieldInfo struct {
	funcs      pointerCoderFuncs // fast-path per-field functions
	mi         *MessageInfo      // field's message
	ft         reflect.Type
	validation validationInfo           // information used by message validation
	num        protoreflect.FieldNumber // field number
	offset     offset                   // struct field offset
	wiretag    uint64                   // field tag (number + wire type)
	tagsize    int                      // size of the varint-encoded tag
	isPointer  bool                     // true if IsNil may be called on the struct field
	isRequired bool                     // true if field is required
}

func ( *MessageInfo) ( reflect.Type,  structInfo) {
	.sizecacheOffset = invalidOffset
	.unknownOffset = invalidOffset
	.extensionOffset = invalidOffset

	if .sizecacheOffset.IsValid() && .sizecacheType == sizecacheType {
		.sizecacheOffset = .sizecacheOffset
	}
	if .unknownOffset.IsValid() && (.unknownType == unknownFieldsAType || .unknownType == unknownFieldsBType) {
		.unknownOffset = .unknownOffset
		.unknownPtrKind = .unknownType.Kind() == reflect.Ptr
	}
	if .extensionOffset.IsValid() && .extensionType == extensionFieldsType {
		.extensionOffset = .extensionOffset
	}

	.coderFields = make(map[protowire.Number]*coderFieldInfo)
	 := .Desc.Fields()
	 := make([]coderFieldInfo, .Len())
	for  := 0;  < .Len(); ++ {
		 := .Get()

		 := .fieldsByNumber[.Number()]
		 := .ContainingOneof() != nil && !.ContainingOneof().IsSynthetic()
		if  {
			 = .oneofsByName[.ContainingOneof().Name()]
		}
		 := .Type
		var  uint64
		if !.IsPacked() {
			 = protowire.EncodeTag(.Number(), wireTypes[.Kind()])
		} else {
			 = protowire.EncodeTag(.Number(), protowire.BytesType)
		}
		var  offset
		var  pointerCoderFuncs
		var  *MessageInfo
		switch {
		case  == nil:
			// This never occurs for generated message types.
			// It implies that a hand-crafted type has missing Go fields
			// for specific protobuf message fields.
			 = pointerCoderFuncs{
				size: func( pointer,  *coderFieldInfo,  marshalOptions) int {
					return 0
				},
				marshal: func( []byte,  pointer,  *coderFieldInfo,  marshalOptions) ([]byte, error) {
					return nil, nil
				},
				unmarshal: func( []byte,  pointer,  protowire.Type,  *coderFieldInfo,  unmarshalOptions) (unmarshalOutput, error) {
					panic("missing Go struct field for " + string(.FullName()))
				},
				isInit: func( pointer,  *coderFieldInfo) error {
					panic("missing Go struct field for " + string(.FullName()))
				},
				merge: func(,  pointer,  *coderFieldInfo,  mergeOptions) {
					panic("missing Go struct field for " + string(.FullName()))
				},
			}
		case :
			 = offsetOf(, .Exporter)
		case .IsWeak():
			 = .weakOffset
			 = makeWeakMessageFieldCoder()
		default:
			 = offsetOf(, .Exporter)
			,  = fieldCoder(, )
		}
		 := &[]
		* = coderFieldInfo{
			num:        .Number(),
			offset:     ,
			wiretag:    ,
			ft:         ,
			tagsize:    protowire.SizeVarint(),
			funcs:      ,
			mi:         ,
			validation: newFieldValidationInfo(, , , ),
			isPointer:  .Cardinality() == protoreflect.Repeated || .HasPresence(),
			isRequired: .Cardinality() == protoreflect.Required,
		}
		.orderedCoderFields = append(.orderedCoderFields, )
		.coderFields[.num] = 
	}
	for ,  := 0, .Desc.Oneofs();  < .Len(); ++ {
		if  := .Get(); !.IsSynthetic() {
			.initOneofFieldCoders(, )
		}
	}
	if messageset.IsMessageSet(.Desc) {
		if !.extensionOffset.IsValid() {
			panic(fmt.Sprintf("%v: MessageSet with no extensions field", .Desc.FullName()))
		}
		if !.unknownOffset.IsValid() {
			panic(fmt.Sprintf("%v: MessageSet with no unknown field", .Desc.FullName()))
		}
		.isMessageSet = true
	}
	sort.Slice(.orderedCoderFields, func(,  int) bool {
		return .orderedCoderFields[].num < .orderedCoderFields[].num
	})

	var  protoreflect.FieldNumber
	for ,  := range .orderedCoderFields {
		if .num >= 16 && .num >= 2* {
			break
		}
		 = .num
	}
	.denseCoderFields = make([]*coderFieldInfo, +1)
	for ,  := range .orderedCoderFields {
		if int(.num) >= len(.denseCoderFields) {
			break
		}
		.denseCoderFields[.num] = 
	}

	// To preserve compatibility with historic wire output, marshal oneofs last.
	if .Desc.Oneofs().Len() > 0 {
		sort.Slice(.orderedCoderFields, func(,  int) bool {
			 := .ByNumber(.orderedCoderFields[].num)
			 := .ByNumber(.orderedCoderFields[].num)
			return order.LegacyFieldOrder(, )
		})
	}

	.needsInitCheck = needsInitCheck(.Desc)
	if .methods.Marshal == nil && .methods.Size == nil {
		.methods.Flags |= protoiface.SupportMarshalDeterministic
		.methods.Marshal = .marshal
		.methods.Size = .size
	}
	if .methods.Unmarshal == nil {
		.methods.Flags |= protoiface.SupportUnmarshalDiscardUnknown
		.methods.Unmarshal = .unmarshal
	}
	if .methods.CheckInitialized == nil {
		.methods.CheckInitialized = .checkInitialized
	}
	if .methods.Merge == nil {
		.methods.Merge = .merge
	}
}

// getUnknownBytes returns a *[]byte for the unknown fields.
// It is the caller's responsibility to check whether the pointer is nil.
// This function is specially designed to be inlineable.
func ( *MessageInfo) ( pointer) *[]byte {
	if .unknownPtrKind {
		return *.Apply(.unknownOffset).BytesPtr()
	} else {
		return .Apply(.unknownOffset).Bytes()
	}
}

// mutableUnknownBytes returns a *[]byte for the unknown fields.
// The returned pointer is guaranteed to not be nil.
func ( *MessageInfo) ( pointer) *[]byte {
	if .unknownPtrKind {
		 := .Apply(.unknownOffset).BytesPtr()
		if * == nil {
			* = new([]byte)
		}
		return *
	} else {
		return .Apply(.unknownOffset).Bytes()
	}
}