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

	
)

type opaqueStructInfo struct {
	structInfo
}

// isOpaque determines whether a protobuf message type is on the Opaque API.  It
// checks whether the type is a Go struct that protoc-gen-go would generate.
//
// This function only detects newly generated messages from the v2
// implementation of protoc-gen-go. It is unable to classify generated messages
// that are too old or those that are generated by a different generator
// such as protoc-gen-gogo.
func ( reflect.Type) bool {
	// The current detection mechanism is to simply check the first field
	// for a struct tag with the "protogen" key.
	if .Kind() == reflect.Struct && .NumField() > 0 {
		 := .Field(0).Tag.Get("protogen")
		return strings.HasPrefix(, "opaque.")
	}
	return false
}

func ( *MessageInfo) bool {
	 := .GoReflectType.Elem()
	 := opaqueStructInfo{
		structInfo: .makeStructInfo(),
	}

	if !isOpaque() {
		return false
	}

	defer atomic.StoreUint32(&.initDone, 1)

	.fields = map[protoreflect.FieldNumber]*fieldInfo{}
	 := .Desc.Fields()
	for  := 0;  < .Len(); ++ {
		 := .Get()
		 := .fieldsByNumber[.Number()]
		var  fieldInfo
		,  := usePresenceForField(, )

		switch {
		case .ContainingOneof() != nil && !.ContainingOneof().IsSynthetic():
			// Oneofs are no different for opaque.
			 = fieldInfoForOneof(, .oneofsByName[.ContainingOneof().Name()], .Exporter, .oneofWrappersByNumber[.Number()])
		case .IsMap():
			 = .fieldInfoForMapOpaque(, , )
		case .IsList() && .Message() == nil && :
			 = .fieldInfoForScalarListOpaque(, , )
		case .IsList() && .Message() == nil:
			// Proto3 lists without presence can use same access methods as open
			 = fieldInfoForList(, , .Exporter)
		case .IsList() && :
			 = .fieldInfoForMessageListOpaque(, , )
		case .IsList():
			// Proto3 opaque messages that does not need presence bitmap.
			// Different representation than open struct, but same logic
			 = .fieldInfoForMessageListOpaqueNoPresence(, , )
		case .Message() != nil && :
			 = .fieldInfoForMessageOpaque(, , )
		case .Message() != nil:
			// Proto3 messages without presence can use same access methods as open
			 = fieldInfoForMessage(, , .Exporter)
		default:
			 = .fieldInfoForScalarOpaque(, , )
		}
		.fields[.Number()] = &
	}
	.oneofs = map[protoreflect.Name]*oneofInfo{}
	for  := 0;  < .Desc.Oneofs().Len(); ++ {
		 := .Desc.Oneofs().Get()
		.oneofs[.Name()] = makeOneofInfoOpaque(, , .structInfo, .Exporter)
	}

	.denseFields = make([]*fieldInfo, .Len()*2)
	for  := 0;  < .Len(); ++ {
		if  := .Get(); int(.Number()) < len(.denseFields) {
			.denseFields[.Number()] = .fields[.Number()]
		}
	}

	for  := 0;  < .Len(); {
		 := .Get()
		if  := .ContainingOneof();  != nil && !.ContainingOneof().IsSynthetic() {
			.rangeInfos = append(.rangeInfos, .oneofs[.Name()])
			 += .Fields().Len()
		} else {
			.rangeInfos = append(.rangeInfos, .fields[.Number()])
			++
		}
	}

	.makeExtensionFieldsFunc(, .structInfo)
	.makeUnknownFieldsFunc(, .structInfo)
	.makeOpaqueCoderMethods(, )
	.makeFieldTypes(.structInfo)

	return true
}

func ( *MessageInfo,  protoreflect.OneofDescriptor,  structInfo,  exporter) *oneofInfo {
	 := &oneofInfo{oneofDesc: }
	if .IsSynthetic() {
		 := .Fields().Get(0)
		,  := presenceIndex(.Desc, )
		.which = func( pointer) protoreflect.FieldNumber {
			if .IsNil() {
				return 0
			}
			if !.present(, ) {
				return 0
			}
			return .Fields().Get(0).Number()
		}
		return 
	}
	// Dispatch to non-opaque oneof implementation for non-synthetic oneofs.
	return makeOneofInfo(, , )
}

func ( *MessageInfo) ( opaqueStructInfo,  protoreflect.FieldDescriptor,  reflect.StructField) fieldInfo {
	 := .Type
	if .Kind() != reflect.Map {
		panic(fmt.Sprintf("invalid type: got %v, want map kind", ))
	}
	 := offsetOf()
	 := NewConverter(, )
	return fieldInfo{
		fieldDesc: ,
		has: func( pointer) bool {
			if .IsNil() {
				return false
			}
			// Don't bother checking presence bits, since we need to
			// look at the map length even if the presence bit is set.
			 := .Apply().AsValueOf(.Type).Elem()
			return .Len() > 0
		},
		clear: func( pointer) {
			 := .Apply().AsValueOf(.Type).Elem()
			.Set(reflect.Zero(.Type()))
		},
		get: func( pointer) protoreflect.Value {
			if .IsNil() {
				return .Zero()
			}
			 := .Apply().AsValueOf(.Type).Elem()
			if .Len() == 0 {
				return .Zero()
			}
			return .PBValueOf()
		},
		set: func( pointer,  protoreflect.Value) {
			 := .GoValueOf()
			if .IsNil() {
				panic(fmt.Sprintf("invalid value: setting map field to read-only value"))
			}
			 := .Apply().AsValueOf(.Type).Elem()
			.Set()
		},
		mutable: func( pointer) protoreflect.Value {
			 := .Apply().AsValueOf(.Type).Elem()
			if .IsNil() {
				.Set(reflect.MakeMap(.Type))
			}
			return .PBValueOf()
		},
		newField: func() protoreflect.Value {
			return .New()
		},
	}
}

func ( *MessageInfo) ( opaqueStructInfo,  protoreflect.FieldDescriptor,  reflect.StructField) fieldInfo {
	 := .Type
	if .Kind() != reflect.Slice {
		panic(fmt.Sprintf("invalid type: got %v, want slice kind", ))
	}
	 := NewConverter(reflect.PtrTo(), )
	 := offsetOf()
	,  := presenceIndex(.Desc, )
	return fieldInfo{
		fieldDesc: ,
		has: func( pointer) bool {
			if .IsNil() {
				return false
			}
			 := .Apply().AsValueOf(.Type).Elem()
			return .Len() > 0
		},
		clear: func( pointer) {
			 := .Apply().AsValueOf(.Type).Elem()
			.Set(reflect.Zero(.Type()))
		},
		get: func( pointer) protoreflect.Value {
			if .IsNil() {
				return .Zero()
			}
			 := .Apply().AsValueOf(.Type)
			if .Elem().Len() == 0 {
				return .Zero()
			}
			return .PBValueOf()
		},
		set: func( pointer,  protoreflect.Value) {
			 := .GoValueOf()
			if .IsNil() {
				panic(fmt.Sprintf("invalid value: setting repeated field to read-only value"))
			}
			.setPresent(, )
			 := .Apply().AsValueOf(.Type).Elem()
			.Set(.Elem())
		},
		mutable: func( pointer) protoreflect.Value {
			.setPresent(, )
			return .PBValueOf(.Apply().AsValueOf(.Type))
		},
		newField: func() protoreflect.Value {
			return .New()
		},
	}
}

func ( *MessageInfo) ( opaqueStructInfo,  protoreflect.FieldDescriptor,  reflect.StructField) fieldInfo {
	 := .Type
	if .Kind() != reflect.Ptr || .Elem().Kind() != reflect.Slice {
		panic(fmt.Sprintf("invalid type: got %v, want slice kind", ))
	}
	 := NewConverter(, )
	 := offsetOf()
	,  := presenceIndex(.Desc, )
	 := .Number()
	return fieldInfo{
		fieldDesc: ,
		has: func( pointer) bool {
			if .IsNil() {
				return false
			}
			if !.present(, ) {
				return false
			}
			 := .Apply().AtomicGetPointer()
			if .IsNil() {
				// Lazily unmarshal this field.
				.lazyUnmarshal(, )
				 = .Apply().AtomicGetPointer()
			}
			 := .AsValueOf(.Type.Elem())
			return .Elem().Len() > 0
		},
		clear: func( pointer) {
			 := .Apply()
			 := .AtomicGetPointer()
			if .IsNil() {
				 = .AtomicSetPointerIfNil(pointerOfValue(reflect.New(.Type.Elem())))
				.setPresent(, )
			}
			 := .AsValueOf(.Type.Elem())
			.Elem().Set(reflect.Zero(.Type().Elem()))
		},
		get: func( pointer) protoreflect.Value {
			if .IsNil() {
				return .Zero()
			}
			if !.present(, ) {
				return .Zero()
			}
			 := .Apply().AtomicGetPointer()
			if .IsNil() {
				// Lazily unmarshal this field.
				.lazyUnmarshal(, )
				 = .Apply().AtomicGetPointer()
			}
			 := .AsValueOf(.Type.Elem())
			if .Elem().Len() == 0 {
				return .Zero()
			}
			return .PBValueOf()
		},
		set: func( pointer,  protoreflect.Value) {
			 := .Apply()
			 := .AtomicGetPointer()
			if .IsNil() {
				 = .AtomicSetPointerIfNil(pointerOfValue(reflect.New(.Type.Elem())))
				.setPresent(, )
			}
			 := .AsValueOf(.Type.Elem())
			 := .GoValueOf()
			if .IsNil() {
				panic(fmt.Sprintf("invalid value: setting repeated field to read-only value"))
			} else {
				.Elem().Set(.Elem())
			}
		},
		mutable: func( pointer) protoreflect.Value {
			 := .Apply()
			 := .AtomicGetPointer()
			if .IsNil() {
				if .present(, ) {
					// Lazily unmarshal this field.
					.lazyUnmarshal(, )
					 = .Apply().AtomicGetPointer()
				} else {
					 = .AtomicSetPointerIfNil(pointerOfValue(reflect.New(.Type.Elem())))
					.setPresent(, )
				}
			}
			 := .AsValueOf(.Type.Elem())
			return .PBValueOf()
		},
		newField: func() protoreflect.Value {
			return .New()
		},
	}
}

func ( *MessageInfo) ( opaqueStructInfo,  protoreflect.FieldDescriptor,  reflect.StructField) fieldInfo {
	 := .Type
	if .Kind() != reflect.Ptr || .Elem().Kind() != reflect.Slice {
		panic(fmt.Sprintf("invalid type: got %v, want slice kind", ))
	}
	 := NewConverter(, )
	 := offsetOf()
	return fieldInfo{
		fieldDesc: ,
		has: func( pointer) bool {
			if .IsNil() {
				return false
			}
			 := .Apply().AtomicGetPointer()
			if .IsNil() {
				return false
			}
			 := .AsValueOf(.Type.Elem())
			return .Elem().Len() > 0
		},
		clear: func( pointer) {
			 := .Apply().AtomicGetPointer()
			if !.IsNil() {
				 := .AsValueOf(.Type.Elem())
				.Elem().Set(reflect.Zero(.Type().Elem()))
			}
		},
		get: func( pointer) protoreflect.Value {
			if .IsNil() {
				return .Zero()
			}
			 := .Apply().AtomicGetPointer()
			if .IsNil() {
				return .Zero()
			}
			 := .AsValueOf(.Type.Elem())
			if .Elem().Len() == 0 {
				return .Zero()
			}
			return .PBValueOf()
		},
		set: func( pointer,  protoreflect.Value) {
			 := .Apply().AsValueOf(.Type).Elem()
			if .IsNil() {
				.Set(reflect.New(.Type.Elem()))
			}
			 := .GoValueOf()
			if .IsNil() {
				panic(fmt.Sprintf("invalid value: setting repeated field to read-only value"))
			} else {
				.Elem().Set(.Elem())
			}
		},
		mutable: func( pointer) protoreflect.Value {
			 := .Apply().AsValueOf(.Type).Elem()
			if .IsNil() {
				.Set(reflect.New(.Type.Elem()))
			}
			return .PBValueOf()
		},
		newField: func() protoreflect.Value {
			return .New()
		},
	}
}

func ( *MessageInfo) ( opaqueStructInfo,  protoreflect.FieldDescriptor,  reflect.StructField) fieldInfo {
	 := .Type
	 := .HasPresence()
	if  := .ContainingOneof();  != nil && .IsSynthetic() {
		 = true
	}
	 := false
	if  && .Kind() == reflect.Ptr {
		 = .Elem()
		 = true
	}
	 := NewConverter(, )
	 := offsetOf()
	,  := presenceIndex(.Desc, )
	var  func( pointer) protoreflect.Value
	if ! {
		 = getterForDirectScalar(, , , )
	} else {
		 = getterForOpaqueNullableScalar(, , , , , )
	}
	return fieldInfo{
		fieldDesc: ,
		has: func( pointer) bool {
			if .IsNil() {
				return false
			}
			if  {
				return .present(, )
			}
			 := .Apply().AsValueOf(.Type).Elem()
			switch .Kind() {
			case reflect.Bool:
				return .Bool()
			case reflect.Int32, reflect.Int64:
				return .Int() != 0
			case reflect.Uint32, reflect.Uint64:
				return .Uint() != 0
			case reflect.Float32, reflect.Float64:
				return .Float() != 0 || math.Signbit(.Float())
			case reflect.String, reflect.Slice:
				return .Len() > 0
			default:
				panic(fmt.Sprintf("invalid type: %v", .Type())) // should never happen
			}
		},
		clear: func( pointer) {
			if  {
				.clearPresent(, )
			}
			// This is only valuable for bytes and strings, but we do it unconditionally.
			 := .Apply().AsValueOf(.Type).Elem()
			.Set(reflect.Zero(.Type()))
		},
		get: ,
		// TODO: Implement unsafe fast path for set?
		set: func( pointer,  protoreflect.Value) {
			 := .Apply().AsValueOf(.Type).Elem()
			if  {
				if .IsNil() {
					.Set(reflect.New())
				}
				 = .Elem()
			}

			.Set(.GoValueOf())
			if  && .Kind() == reflect.Slice && .IsNil() {
				.Set(emptyBytes)
			}
			if  {
				.setPresent(, )
			}
		},
		newField: func() protoreflect.Value {
			return .New()
		},
	}
}

func ( *MessageInfo) ( opaqueStructInfo,  protoreflect.FieldDescriptor,  reflect.StructField) fieldInfo {
	 := .Type
	 := NewConverter(, )
	 := offsetOf()
	,  := presenceIndex(.Desc, )
	 := .Number()
	 := .Type.Elem()
	return fieldInfo{
		fieldDesc: ,
		has: func( pointer) bool {
			if .IsNil() {
				return false
			}
			return .present(, )
		},
		clear: func( pointer) {
			.clearPresent(, )
			.Apply().AtomicSetNilPointer()
		},
		get: func( pointer) protoreflect.Value {
			if .IsNil() || !.present(, ) {
				return .Zero()
			}
			 := .Apply()
			 := .AtomicGetPointer()
			if .IsNil() {
				// Lazily unmarshal this field.
				.lazyUnmarshal(, )
				 = .AtomicGetPointer()
			}
			 := .AsValueOf()
			return .PBValueOf()
		},
		set: func( pointer,  protoreflect.Value) {
			 := pointerOfValue(.GoValueOf())
			if .IsNil() {
				panic("invalid nil pointer")
			}
			.Apply().AtomicSetPointer()
			.setPresent(, )
		},
		mutable: func( pointer) protoreflect.Value {
			 := .Apply()
			 := .AtomicGetPointer()
			if .IsNil() {
				if .present(, ) {
					// Lazily unmarshal this field.
					.lazyUnmarshal(, )
					 = .AtomicGetPointer()
				} else {
					 = pointerOfValue(.GoValueOf(.New()))
					.AtomicSetPointer()
					.setPresent(, )
				}
			}
			return .PBValueOf(.AsValueOf(.Type.Elem()))
		},
		newMessage: func() protoreflect.Message {
			return .New().Message()
		},
		newField: func() protoreflect.Value {
			return .New()
		},
	}
}

// A presenceList wraps a List, updating presence bits as necessary when the
// list contents change.
type presenceList struct {
	pvalueList
	setPresence func(bool)
}
type pvalueList interface {
	protoreflect.List
	//Unwrapper
}

func ( presenceList) ( protoreflect.Value) {
	.pvalueList.Append()
	.setPresence(true)
}
func ( presenceList) ( int) {
	.pvalueList.Truncate()
	.setPresence( > 0)
}

// presenceIndex returns the index to pass to presence functions.
//
// TODO: field.Desc.Index() would be simpler, and would give space to record the presence of oneof fields.
func ( protoreflect.MessageDescriptor,  protoreflect.FieldDescriptor) (uint32, presenceSize) {
	 := false
	var ,  uint32
	for  := 0;  < .Fields().Len(); ++ {
		 := .Fields().Get()
		if  ==  {
			 = true
			 = 
		}
		if .ContainingOneof() == nil || isLastOneofField() {
			++
		}
	}
	if ! {
		panic(fmt.Sprintf("BUG: %v not in %v", .Name(), .FullName()))
	}
	return , presenceSize()
}

func ( protoreflect.FieldDescriptor) bool {
	 := .ContainingOneof().Fields()
	return .Get(.Len()-1) == 
}

func ( *MessageInfo) ( pointer,  uint32) {
	.Apply(.presenceOffset).PresenceInfo().SetPresent(, .presenceSize)
}

func ( *MessageInfo) ( pointer,  uint32) {
	.Apply(.presenceOffset).PresenceInfo().ClearPresent()
}

func ( *MessageInfo) ( pointer,  uint32) bool {
	return .Apply(.presenceOffset).PresenceInfo().Present()
}

// usePresenceForField implements the somewhat intricate logic of when
// the presence bitmap is used for a field.  The main logic is that a
// field that is optional or that can be lazy will use the presence
// bit, but for proto2, also maps have a presence bit. It also records
// if the field can ever be lazy, which is true if we have a
// lazyOffset and the field is a message or a slice of messages. A
// field that is lazy will always need a presence bit.  Oneofs are not
// lazy and do not use presence, unless they are a synthetic oneof,
// which is a proto3 optional field. For proto3 optionals, we use the
// presence and they can also be lazy when applicable (a message).
func ( opaqueStructInfo,  protoreflect.FieldDescriptor) (,  bool) {
	 := .(interface{ () bool }).()

	// Non-oneof scalar fields with explicit field presence use the presence array.
	 := .HasPresence() && .Message() == nil && (.ContainingOneof() == nil || .ContainingOneof().IsSynthetic())
	switch {
	case .ContainingOneof() != nil && !.ContainingOneof().IsSynthetic():
		return false, false
	case .IsMap():
		return false, false
	case .Kind() == protoreflect.MessageKind || .Kind() == protoreflect.GroupKind:
		return , 
	default:
		return  || ( && .HasPresence()), false
	}
}