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

	
	
	
	
	preg 
	piface 
)

var enableLazy int32 = func() int32 {
	if os.Getenv("GOPROTODEBUG") == "nolazy" {
		return 0
	}
	return 1
}()

// EnableLazyUnmarshal enables lazy unmarshaling.
func ( bool) {
	if  {
		atomic.StoreInt32(&enableLazy, 1)
		return
	}
	atomic.StoreInt32(&enableLazy, 0)
}

// LazyEnabled reports whether lazy unmarshalling is currently enabled.
func () bool {
	return atomic.LoadInt32(&enableLazy) != 0
}

// UnmarshalField unmarshals a field in a message.
func ( interface{},  protowire.Number) {
	switch m := .(type) {
	case *messageState:
		.messageInfo().lazyUnmarshal(.pointer(), )
	case *messageReflectWrapper:
		.messageInfo().lazyUnmarshal(.pointer(), )
	default:
		panic(fmt.Sprintf("unsupported wrapper type %T", ))
	}
}

func ( *MessageInfo) ( pointer,  protoreflect.FieldNumber) {
	var  *coderFieldInfo
	if int() < len(.denseCoderFields) {
		 = .denseCoderFields[]
	} else {
		 = .coderFields[]
	}
	if  == nil {
		panic(fmt.Sprintf("lazyUnmarshal: field info for %v.%v", .Desc.FullName(), ))
	}
	 := *.Apply(.lazyOffset).LazyInfoPtr()
	, , , ,  := .FindFieldInProto(uint32())
	if ! &&  == nil {
		panic(fmt.Sprintf("lazyUnmarshal: can't find field data for %v.%v", .Desc.FullName(), ))
	}
	// The actual pointer in the message can not be set until the whole struct is filled in, otherwise we will have races.
	// Create another pointer and set it atomically, if we won the race and the pointer in the original message is still nil.
	 := pointerOfValue(reflect.New(.ft))
	if  != nil {
		for ,  := range  {
			.unmarshalField(.Buffer()[.Start:.End], , , , .UnmarshalFlags())
		}
	} else {
		.unmarshalField(.Buffer()[:], , , , .UnmarshalFlags())
	}
	.Apply(.offset).AtomicSetPointerIfNil(.Elem())
}

func ( *MessageInfo) ( []byte,  pointer,  *coderFieldInfo,  *protolazy.XXX_lazyUnmarshalInfo,  piface.UnmarshalInputFlags) error {
	 := lazyUnmarshalOptions
	.flags |= 
	for len() > 0 {
		// Parse the tag (field number and wire type).
		var  uint64
		if [0] < 0x80 {
			 = uint64([0])
			 = [1:]
		} else if len() >= 2 && [1] < 128 {
			 = uint64([0]&0x7f) + uint64([1])<<7
			 = [2:]
		} else {
			var  int
			,  = protowire.ConsumeVarint()
			if  < 0 {
				return errors.New("invalid wire data")
			}
			 = [:]
		}
		var  protowire.Number
		if  :=  >> 3;  < uint64(protowire.MinValidNumber) ||  > uint64(protowire.MaxValidNumber) {
			return errors.New("invalid wire data")
		} else {
			 = protowire.Number()
		}
		 := protowire.Type( & 7)
		if  == .num {
			,  := .funcs.unmarshal(, , , , )
			if  == nil {
				 = [.n:]
				continue
			}
			if  != errUnknown {
				return 
			}
		}
		 := protowire.ConsumeFieldValue(, , )
		if  < 0 {
			return errors.New("invalid wire data")
		}
		 = [:]
	}
	return nil
}

func ( *MessageInfo) ( []byte,  *coderFieldInfo,  protowire.Type,  unmarshalOptions) ( unmarshalOutput,  ValidationStatus) {
	 := .validation.mi
	if  == nil {
		 := .Desc.Fields().ByNumber(.num)
		if  == nil {
			return , ValidationUnknown
		}
		 := .Message().FullName()
		,  := preg.GlobalTypes.FindMessageByName()
		if  != nil {
			return , ValidationUnknown
		}
		var  bool
		,  = .(*MessageInfo)
		if ! {
			return , ValidationUnknown
		}
	}
	.init()
	switch .validation.typ {
	case validationTypeMessage:
		if  != protowire.BytesType {
			return , ValidationWrongWireType
		}
		,  := protowire.ConsumeBytes()
		if  < 0 {
			return , ValidationInvalid
		}
		,  := .validate(, 0, )
		.n = 
		return , 
	case validationTypeGroup:
		if  != protowire.StartGroupType {
			return , ValidationWrongWireType
		}
		,  := .validate(, .num, )
		return , 
	default:
		return , ValidationUnknown
	}
}

// unmarshalPointerLazy is similar to unmarshalPointerEager, but it
// specifically handles lazy unmarshalling.  it expects lazyOffset and
// presenceOffset to both be valid.
func ( *MessageInfo) ( []byte,  pointer,  protowire.Number,  unmarshalOptions) ( unmarshalOutput,  error) {
	 := true
	var  uint64
	var  **protolazy.XXX_lazyUnmarshalInfo
	var  presence
	var  []protolazy.IndexEntry
	var  protowire.Number
	 := false
	 := false
	 = .Apply(.presenceOffset).PresenceInfo()
	 = .Apply(.lazyOffset).LazyInfoPtr()
	if !.AnyPresent(.presenceSize) {
		if .CanBeLazy() {
			// If the message contains existing data, we need to merge into it.
			// Lazy unmarshaling doesn't merge, so only enable it when the
			// message is empty (has no presence bitmap).
			 = true
			if * == nil {
				* = &protolazy.XXX_lazyUnmarshalInfo{}
			}
			(*).SetUnmarshalFlags(.flags)
			if !.AliasBuffer() {
				// Make a copy of the buffer for lazy unmarshaling.
				// Set the AliasBuffer flag so recursive unmarshal
				// operations reuse the copy.
				 = append([]byte{}, ...)
				.flags |= piface.UnmarshalAliasBuffer
			}
			(*).SetBuffer()
		}
	}
	// Track special handling of lazy fields.
	//
	// In the common case, all fields are lazyValidateOnly (and lazyFields remains nil).
	// In the event that validation for a field fails, this map tracks handling of the field.
	type  uint8
	const (
		    = iota // validate the field only
		                     // eagerly unmarshal the field
		                   // unmarshal the field after the message is fully processed
	)
	var  map[*coderFieldInfo]
	var  *map[int32]ExtensionField
	 := len()
	 := 0
	for len() > 0 {
		// Parse the tag (field number and wire type).
		var  uint64
		if [0] < 0x80 {
			 = uint64([0])
			 = [1:]
		} else if len() >= 2 && [1] < 128 {
			 = uint64([0]&0x7f) + uint64([1])<<7
			 = [2:]
		} else {
			var  int
			,  = protowire.ConsumeVarint()
			if  < 0 {
				return , errDecode
			}
			 = [:]
		}
		var  protowire.Number
		if  :=  >> 3;  < uint64(protowire.MinValidNumber) ||  > uint64(protowire.MaxValidNumber) {
			return , errors.New("invalid field number")
		} else {
			 = protowire.Number()
		}
		 := protowire.Type( & 7)

		if  == protowire.EndGroupType {
			if  !=  {
				return , errors.New("mismatching end group marker")
			}
			 = 0
			break
		}

		var  *coderFieldInfo
		if int() < len(.denseCoderFields) {
			 = .denseCoderFields[]
		} else {
			 = .coderFields[]
		}
		var  int
		 := errUnknown
		 := false
	:
		switch {
		case  != nil:
			if .funcs.unmarshal == nil {
				break
			}
			if .isLazy &&  {
				switch {
				case  == nil || [] == :
					// Attempt to validate this field and leave it for later lazy unmarshaling.
					,  := .skipField(, , , )
					switch  {
					case ValidationValid:
						// Skip over the valid field and continue.
						 = nil
						.SetPresentUnatomic(.presenceIndex, .presenceSize)
						 |= .validation.requiredBit
						if !.initialized {
							 = false
						}
						 = .n
						break 
					case ValidationInvalid:
						return , errors.New("invalid proto wire format")
					case ValidationWrongWireType:
						break 
					case ValidationUnknown:
						if  == nil {
							 = make(map[*coderFieldInfo])
						}
						if .Present(.presenceIndex) {
							// We were unable to determine if the field is valid or not,
							// and we've already skipped over at least one instance of this
							// field. Clear the presence bit (so if we stop decoding early,
							// we don't leave a partially-initialized field around) and flag
							// the field for unmarshaling before we return.
							.ClearPresent(.presenceIndex)
							[] = 
							 = true
							break 
						} else {
							// We were unable to determine if the field is valid or not,
							// but this is the first time we've seen it. Flag it as needing
							// eager unmarshaling and fall through to the eager unmarshal case below.
							[] = 
						}
					}
				case [] == :
					// This field will be unmarshaled in a separate pass below.
					// Skip over it here.
					 = true
					break 
				default:
					// Eagerly unmarshal the field.
				}
			}
			if .isLazy && ! && .Present(.presenceIndex) {
				if .Apply(.offset).AtomicGetPointer().IsNil() {
					.lazyUnmarshal(, .num)
				}
			}
			var  unmarshalOutput
			,  = .funcs.unmarshal(, .Apply(.offset), , , )
			 = .n
			if  != nil {
				break
			}
			 |= .validation.requiredBit
			if .funcs.isInit != nil && !.initialized {
				 = false
			}
			if .presenceIndex != noPresence {
				.SetPresentUnatomic(.presenceIndex, .presenceSize)
			}
		default:
			// Possible extension.
			if  == nil && .extensionOffset.IsValid() {
				 = .Apply(.extensionOffset).Extensions()
				if * == nil {
					* = make(map[int32]ExtensionField)
				}
			}
			if  == nil {
				break
			}
			var  unmarshalOutput
			,  = .unmarshalExtension(, , , *, )
			if  != nil {
				break
			}
			 = .n
			if !.initialized {
				 = false
			}
		}
		if  != nil {
			if  != errUnknown {
				return , 
			}
			 = protowire.ConsumeFieldValue(, , )
			if  < 0 {
				return , errDecode
			}
			if ! && !.DiscardUnknown() && .unknownOffset.IsValid() {
				 := .mutableUnknownBytes()
				* = protowire.AppendTag(*, , )
				* = append(*, [:]...)
			}
		}
		 = [:]
		 :=  - len()
		if  &&  != nil && .isLazy {
			if  !=  {
				 = append(, protolazy.IndexEntry{
					FieldNum: uint32(),
					Start:    uint32(),
					End:      uint32(),
				})
			} else {
				 := len() - 1
				[].End = uint32()
				[].MultipleContiguous = true
			}
		}
		if  <  {
			 = true
		}
		 = 
		 = 
	}
	if  != 0 {
		return , errors.New("missing end group marker")
	}
	if  != nil {
		// Some fields failed validation, and now need to be unmarshaled.
		for ,  := range  {
			if  !=  {
				continue
			}
			 = false
			if * == nil {
				* = &protolazy.XXX_lazyUnmarshalInfo{}
			}
			if  := .unmarshalField((*).Buffer(), .Apply(.offset), , *, .flags);  != nil {
				return , 
			}
			.SetPresentUnatomic(.presenceIndex, .presenceSize)
		}
	}
	if  {
		if  {
			sort.Slice(, func(,  int) bool {
				return [].FieldNum < [].FieldNum ||
					([].FieldNum == [].FieldNum &&
						[].Start < [].Start)
			})
		}
		if * == nil {
			* = &protolazy.XXX_lazyUnmarshalInfo{}
		}

		(*).SetIndex()
	}
	if .numRequiredFields > 0 && bits.OnesCount64() != int(.numRequiredFields) {
		 = false
	}
	if  {
		.initialized = true
	}
	.n =  - len()
	return , nil
}