// 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 extensionFieldInfo struct {
	wiretag             uint64
	tagsize             int
	unmarshalNeedsValue bool
	funcs               valueCoderFuncs
	validation          validationInfo
}

var legacyExtensionFieldInfoCache sync.Map // map[protoreflect.ExtensionType]*extensionFieldInfo

func ( protoreflect.ExtensionType) *extensionFieldInfo {
	if ,  := .(*ExtensionInfo);  {
		.lazyInit()
		return .info
	}
	return legacyLoadExtensionFieldInfo()
}

// legacyLoadExtensionFieldInfo dynamically loads a *ExtensionInfo for xt.
func ( protoreflect.ExtensionType) *extensionFieldInfo {
	if ,  := legacyExtensionFieldInfoCache.Load();  {
		return .(*extensionFieldInfo)
	}
	 := makeExtensionFieldInfo(.TypeDescriptor())
	if ,  := legacyMessageTypeCache.LoadOrStore(, );  {
		return .(*extensionFieldInfo)
	}
	return 
}

func ( protoreflect.ExtensionDescriptor) *extensionFieldInfo {
	var  uint64
	if !.IsPacked() {
		 = protowire.EncodeTag(.Number(), wireTypes[.Kind()])
	} else {
		 = protowire.EncodeTag(.Number(), protowire.BytesType)
	}
	 := &extensionFieldInfo{
		wiretag: ,
		tagsize: protowire.SizeVarint(),
		funcs:   encoderFuncsForValue(),
	}
	// Does the unmarshal function need a value passed to it?
	// This is true for composite types, where we pass in a message, list, or map to fill in,
	// and for enums, where we pass in a prototype value to specify the concrete enum type.
	switch .Kind() {
	case protoreflect.MessageKind, protoreflect.GroupKind, protoreflect.EnumKind:
		.unmarshalNeedsValue = true
	default:
		if .Cardinality() == protoreflect.Repeated {
			.unmarshalNeedsValue = true
		}
	}
	return 
}

type lazyExtensionValue struct {
	atomicOnce uint32 // atomically set if value is valid
	mu         sync.Mutex
	xi         *extensionFieldInfo
	value      protoreflect.Value
	b          []byte
	fn         func() protoreflect.Value
}

type ExtensionField struct {
	typ protoreflect.ExtensionType

	// value is either the value of GetValue,
	// or a *lazyExtensionValue that then returns the value of GetValue.
	value protoreflect.Value
	lazy  *lazyExtensionValue
}

func ( *ExtensionField) ( protoreflect.ExtensionType,  *extensionFieldInfo,  protowire.Number,  protowire.Type,  []byte) {
	if .lazy == nil {
		.lazy = &lazyExtensionValue{xi: }
	}
	.typ = 
	.lazy.xi = 
	.lazy.b = protowire.AppendTag(.lazy.b, , )
	.lazy.b = append(.lazy.b, ...)
}

func ( *ExtensionField) ( protoreflect.ExtensionType) bool {
	if .typ == nil {
		return true
	}
	if .typ ==  && .lazy != nil && atomic.LoadUint32(&.lazy.atomicOnce) == 0 {
		return true
	}
	return false
}

func ( *ExtensionField) () {
	.lazy.mu.Lock()
	defer .lazy.mu.Unlock()
	if atomic.LoadUint32(&.lazy.atomicOnce) == 1 {
		return
	}
	if .lazy.xi != nil {
		 := .lazy.b
		 := .typ.New()
		for len() > 0 {
			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 {
					panic(errors.New("bad tag in lazy extension decoding"))
				}
				 = [:]
			}
			 := protowire.Number( >> 3)
			 := protowire.Type( & 7)
			var  unmarshalOutput
			var  error
			, ,  = .lazy.xi.funcs.unmarshal(, , , , lazyUnmarshalOptions)
			if  != nil {
				panic(errors.New("decode failure in lazy extension decoding: %v", ))
			}
			 = [.n:]
		}
		.lazy.value = 
	} else {
		.lazy.value = .lazy.fn()
	}
	.lazy.xi = nil
	.lazy.fn = nil
	.lazy.b = nil
	atomic.StoreUint32(&.lazy.atomicOnce, 1)
}

// Set sets the type and value of the extension field.
// This must not be called concurrently.
func ( *ExtensionField) ( protoreflect.ExtensionType,  protoreflect.Value) {
	.typ = 
	.value = 
	.lazy = nil
}

// SetLazy sets the type and a value that is to be lazily evaluated upon first use.
// This must not be called concurrently.
func ( *ExtensionField) ( protoreflect.ExtensionType,  func() protoreflect.Value) {
	.typ = 
	.lazy = &lazyExtensionValue{fn: }
}

// Value returns the value of the extension field.
// This may be called concurrently.
func ( *ExtensionField) () protoreflect.Value {
	if .lazy != nil {
		if atomic.LoadUint32(&.lazy.atomicOnce) == 0 {
			.lazyInit()
		}
		return .lazy.value
	}
	return .value
}

// Type returns the type of the extension field.
// This may be called concurrently.
func ( ExtensionField) () protoreflect.ExtensionType {
	return .typ
}

// IsSet returns whether the extension field is set.
// This may be called concurrently.
func ( ExtensionField) () bool {
	return .typ != nil
}

// IsLazy reports whether a field is lazily encoded.
// It is exported for testing.
func ( protoreflect.Message,  protoreflect.FieldDescriptor) bool {
	var  *MessageInfo
	var  pointer
	switch m := .(type) {
	case *messageState:
		 = .messageInfo()
		 = .pointer()
	case *messageReflectWrapper:
		 = .messageInfo()
		 = .pointer()
	default:
		return false
	}
	,  := .(protoreflect.ExtensionTypeDescriptor)
	if ! {
		return false
	}
	 := .Type()
	 := .extensionMap()
	if  == nil {
		return false
	}
	,  := (*)[int32(.Number())]
	if ! {
		return false
	}
	return .typ ==  && .lazy != nil && atomic.LoadUint32(&.lazy.atomicOnce) == 0
}