// Copyright 2018 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 fieldInfo struct {
	fieldDesc protoreflect.FieldDescriptor

	// These fields are used for protobuf reflection support.
	has        func(pointer) bool
	clear      func(pointer)
	get        func(pointer) protoreflect.Value
	set        func(pointer, protoreflect.Value)
	mutable    func(pointer) protoreflect.Value
	newMessage func() protoreflect.Message
	newField   func() protoreflect.Value
}

func ( protoreflect.FieldDescriptor) fieldInfo {
	// This never occurs for generated message types.
	// It implies that a hand-crafted type has missing Go fields
	// for specific protobuf message fields.
	return fieldInfo{
		fieldDesc: ,
		has: func( pointer) bool {
			return false
		},
		clear: func( pointer) {
			panic("missing Go struct field for " + string(.FullName()))
		},
		get: func( pointer) protoreflect.Value {
			return .Default()
		},
		set: func( pointer,  protoreflect.Value) {
			panic("missing Go struct field for " + string(.FullName()))
		},
		mutable: func( pointer) protoreflect.Value {
			panic("missing Go struct field for " + string(.FullName()))
		},
		newMessage: func() protoreflect.Message {
			panic("missing Go struct field for " + string(.FullName()))
		},
		newField: func() protoreflect.Value {
			if  := .Default(); .IsValid() {
				return 
			}
			panic("missing Go struct field for " + string(.FullName()))
		},
	}
}

func ( protoreflect.FieldDescriptor,  reflect.StructField,  exporter,  reflect.Type) fieldInfo {
	 := .Type
	if .Kind() != reflect.Interface {
		panic(fmt.Sprintf("field %v has invalid type: got %v, want interface kind", .FullName(), ))
	}
	if .Kind() != reflect.Struct {
		panic(fmt.Sprintf("field %v has invalid type: got %v, want struct kind", .FullName(), ))
	}
	if !reflect.PtrTo().Implements() {
		panic(fmt.Sprintf("field %v has invalid type: %v does not implement %v", .FullName(), , ))
	}
	 := NewConverter(.Field(0).Type, )
	 := .Message() != nil

	// TODO: Implement unsafe fast path?
	 := offsetOf(, )
	return fieldInfo{
		// NOTE: The logic below intentionally assumes that oneof fields are
		// well-formatted. That is, the oneof interface never contains a
		// typed nil pointer to one of the wrapper structs.

		fieldDesc: ,
		has: func( pointer) bool {
			if .IsNil() {
				return false
			}
			 := .Apply().AsValueOf(.Type).Elem()
			if .IsNil() || .Elem().Type().Elem() !=  || .Elem().IsNil() {
				return false
			}
			return true
		},
		clear: func( pointer) {
			 := .Apply().AsValueOf(.Type).Elem()
			if .IsNil() || .Elem().Type().Elem() !=  {
				// NOTE: We intentionally don't check for rv.Elem().IsNil()
				// so that (*OneofWrapperType)(nil) gets cleared to nil.
				return
			}
			.Set(reflect.Zero(.Type()))
		},
		get: func( pointer) protoreflect.Value {
			if .IsNil() {
				return .Zero()
			}
			 := .Apply().AsValueOf(.Type).Elem()
			if .IsNil() || .Elem().Type().Elem() !=  || .Elem().IsNil() {
				return .Zero()
			}
			 = .Elem().Elem().Field(0)
			return .PBValueOf()
		},
		set: func( pointer,  protoreflect.Value) {
			 := .Apply().AsValueOf(.Type).Elem()
			if .IsNil() || .Elem().Type().Elem() !=  || .Elem().IsNil() {
				.Set(reflect.New())
			}
			 = .Elem().Elem().Field(0)
			.Set(.GoValueOf())
		},
		mutable: func( pointer) protoreflect.Value {
			if ! {
				panic(fmt.Sprintf("field %v with invalid Mutable call on field with non-composite type", .FullName()))
			}
			 := .Apply().AsValueOf(.Type).Elem()
			if .IsNil() || .Elem().Type().Elem() !=  || .Elem().IsNil() {
				.Set(reflect.New())
			}
			 = .Elem().Elem().Field(0)
			if .Kind() == reflect.Ptr && .IsNil() {
				.Set(.GoValueOf(protoreflect.ValueOfMessage(.New().Message())))
			}
			return .PBValueOf()
		},
		newMessage: func() protoreflect.Message {
			return .New().Message()
		},
		newField: func() protoreflect.Value {
			return .New()
		},
	}
}

func ( protoreflect.FieldDescriptor,  reflect.StructField,  exporter) fieldInfo {
	 := .Type
	if .Kind() != reflect.Map {
		panic(fmt.Sprintf("field %v has invalid type: got %v, want map kind", .FullName(), ))
	}
	 := NewConverter(, )

	// TODO: Implement unsafe fast path?
	 := offsetOf(, )
	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).Elem()
			if .Len() == 0 {
				return .Zero()
			}
			return .PBValueOf()
		},
		set: func( pointer,  protoreflect.Value) {
			 := .Apply().AsValueOf(.Type).Elem()
			 := .GoValueOf()
			if .IsNil() {
				panic(fmt.Sprintf("map field %v cannot be set with read-only value", .FullName()))
			}
			.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 ( protoreflect.FieldDescriptor,  reflect.StructField,  exporter) fieldInfo {
	 := .Type
	if .Kind() != reflect.Slice {
		panic(fmt.Sprintf("field %v has invalid type: got %v, want slice kind", .FullName(), ))
	}
	 := NewConverter(reflect.PtrTo(), )

	// TODO: Implement unsafe fast path?
	 := offsetOf(, )
	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) {
			 := .Apply().AsValueOf(.Type).Elem()
			 := .GoValueOf()
			if .IsNil() {
				panic(fmt.Sprintf("list field %v cannot be set with read-only value", .FullName()))
			}
			.Set(.Elem())
		},
		mutable: func( pointer) protoreflect.Value {
			 := .Apply().AsValueOf(.Type)
			return .PBValueOf()
		},
		newField: func() protoreflect.Value {
			return .New()
		},
	}
}

var (
	nilBytes   = reflect.ValueOf([]byte(nil))
	emptyBytes = reflect.ValueOf([]byte{})
)

func ( protoreflect.FieldDescriptor,  reflect.StructField,  exporter) fieldInfo {
	 := .Type
	 := .HasPresence()
	 := .Kind() == reflect.Slice && .Elem().Kind() == reflect.Uint8
	if  {
		if .Kind() != reflect.Ptr && .Kind() != reflect.Slice {
			// This never occurs for generated message types.
			// Despite the protobuf type system specifying presence,
			// the Go field type cannot represent it.
			 = false
		}
		if .Kind() == reflect.Ptr {
			 = .Elem()
		}
	}
	 := NewConverter(, )

	// TODO: Implement unsafe fast path?
	 := offsetOf(, )
	return fieldInfo{
		fieldDesc: ,
		has: func( pointer) bool {
			if .IsNil() {
				return false
			}
			 := .Apply().AsValueOf(.Type).Elem()
			if  {
				return !.IsNil()
			}
			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("field %v has invalid type: %v", .FullName(), .Type())) // should never happen
			}
		},
		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  {
				if .IsNil() {
					return .Zero()
				}
				if .Kind() == reflect.Ptr {
					 = .Elem()
				}
			}
			return .PBValueOf()
		},
		set: func( pointer,  protoreflect.Value) {
			 := .Apply().AsValueOf(.Type).Elem()
			if  && .Kind() == reflect.Ptr {
				if .IsNil() {
					.Set(reflect.New())
				}
				 = .Elem()
			}
			.Set(.GoValueOf())
			if  && .Len() == 0 {
				if  {
					.Set(emptyBytes) // preserve presence
				} else {
					.Set(nilBytes) // do not preserve presence
				}
			}
		},
		newField: func() protoreflect.Value {
			return .New()
		},
	}
}

func ( protoreflect.FieldDescriptor,  offset) fieldInfo {
	if !flags.ProtoLegacy {
		panic("no support for proto1 weak fields")
	}

	var  sync.Once
	var  protoreflect.MessageType
	 := func() {
		.Do(func() {
			 := .Message().FullName()
			, _ = protoregistry.GlobalTypes.FindMessageByName()
			if  == nil {
				panic(fmt.Sprintf("weak message %v for field %v is not linked in", , .FullName()))
			}
		})
	}

	 := .Number()
	return fieldInfo{
		fieldDesc: ,
		has: func( pointer) bool {
			if .IsNil() {
				return false
			}
			,  := .Apply().WeakFields().get()
			return 
		},
		clear: func( pointer) {
			.Apply().WeakFields().clear()
		},
		get: func( pointer) protoreflect.Value {
			()
			if .IsNil() {
				return protoreflect.ValueOfMessage(.Zero())
			}
			,  := .Apply().WeakFields().get()
			if ! {
				return protoreflect.ValueOfMessage(.Zero())
			}
			return protoreflect.ValueOfMessage(.ProtoReflect())
		},
		set: func( pointer,  protoreflect.Value) {
			()
			 := .Message()
			if .Descriptor() != .Descriptor() {
				if ,  := .Descriptor().FullName(), .Descriptor().FullName();  !=  {
					panic(fmt.Sprintf("field %v has mismatching message descriptor: got %v, want %v", .FullName(), , ))
				}
				panic(fmt.Sprintf("field %v has mismatching message descriptor: %v", .FullName(), .Descriptor().FullName()))
			}
			.Apply().WeakFields().set(, .Interface())
		},
		mutable: func( pointer) protoreflect.Value {
			()
			 := .Apply().WeakFields()
			,  := .get()
			if ! {
				 = .New().Interface()
				.set(, )
			}
			return protoreflect.ValueOfMessage(.ProtoReflect())
		},
		newMessage: func() protoreflect.Message {
			()
			return .New()
		},
		newField: func() protoreflect.Value {
			()
			return protoreflect.ValueOfMessage(.New())
		},
	}
}

func ( protoreflect.FieldDescriptor,  reflect.StructField,  exporter) fieldInfo {
	 := .Type
	 := NewConverter(, )

	// TODO: Implement unsafe fast path?
	 := offsetOf(, )
	return fieldInfo{
		fieldDesc: ,
		has: func( pointer) bool {
			if .IsNil() {
				return false
			}
			 := .Apply().AsValueOf(.Type).Elem()
			if .Type.Kind() != reflect.Ptr {
				return !isZero()
			}
			return !.IsNil()
		},
		clear: func( pointer) {
			 := .Apply().AsValueOf(.Type).Elem()
			.Set(reflect.Zero(.Type()))
		},
		get: func( pointer) protoreflect.Value {
			if .IsNil() {
				return .Zero()
			}
			 := .Apply().AsValueOf(.Type).Elem()
			return .PBValueOf()
		},
		set: func( pointer,  protoreflect.Value) {
			 := .Apply().AsValueOf(.Type).Elem()
			.Set(.GoValueOf())
			if .Type.Kind() == reflect.Ptr && .IsNil() {
				panic(fmt.Sprintf("field %v has invalid nil pointer", .FullName()))
			}
		},
		mutable: func( pointer) protoreflect.Value {
			 := .Apply().AsValueOf(.Type).Elem()
			if .Type.Kind() == reflect.Ptr && .IsNil() {
				.Set(.GoValueOf(.New()))
			}
			return .PBValueOf()
		},
		newMessage: func() protoreflect.Message {
			return .New().Message()
		},
		newField: func() protoreflect.Value {
			return .New()
		},
	}
}

type oneofInfo struct {
	oneofDesc protoreflect.OneofDescriptor
	which     func(pointer) protoreflect.FieldNumber
}

func ( protoreflect.OneofDescriptor,  structInfo,  exporter) *oneofInfo {
	 := &oneofInfo{oneofDesc: }
	if .IsSynthetic() {
		 := .fieldsByNumber[.Fields().Get(0).Number()]
		 := offsetOf(, )
		.which = func( pointer) protoreflect.FieldNumber {
			if .IsNil() {
				return 0
			}
			 := .Apply().AsValueOf(.Type).Elem()
			if .IsNil() { // valid on either *T or []byte
				return 0
			}
			return .Fields().Get(0).Number()
		}
	} else {
		 := .oneofsByName[.Name()]
		 := offsetOf(, )
		.which = func( pointer) protoreflect.FieldNumber {
			if .IsNil() {
				return 0
			}
			 := .Apply().AsValueOf(.Type).Elem()
			if .IsNil() {
				return 0
			}
			 = .Elem()
			if .IsNil() {
				return 0
			}
			return .oneofWrappersByType[.Type().Elem()]
		}
	}
	return 
}

// isZero is identical to reflect.Value.IsZero.
// TODO: Remove this when Go1.13 is the minimally supported Go version.
func ( reflect.Value) bool {
	switch .Kind() {
	case reflect.Bool:
		return !.Bool()
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return .Int() == 0
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		return .Uint() == 0
	case reflect.Float32, reflect.Float64:
		return math.Float64bits(.Float()) == 0
	case reflect.Complex64, reflect.Complex128:
		 := .Complex()
		return math.Float64bits(real()) == 0 && math.Float64bits(imag()) == 0
	case reflect.Array:
		for  := 0;  < .Len(); ++ {
			if !(.Index()) {
				return false
			}
		}
		return true
	case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer:
		return .IsNil()
	case reflect.String:
		return .Len() == 0
	case reflect.Struct:
		for  := 0;  < .NumField(); ++ {
			if !(.Field()) {
				return false
			}
		}
		return true
	default:
		panic(&reflect.ValueError{"reflect.Value.IsZero", .Kind()})
	}
}