// 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
	var  func( pointer) protoreflect.Value
	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(, )
	 := offsetOf()

	// Generate specialized getter functions to avoid going through reflect.Value
	if  {
		 = getterForNullableScalar(, , , )
	} else {
		 = getterForDirectScalar(, , , )
	}

	return fieldInfo{
		fieldDesc: ,
		has: func( pointer) bool {
			if .IsNil() {
				return false
			}
			if  {
				return !.Apply().Elem().IsNil()
			}
			 := .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("field %v has invalid type: %v", .FullName(), .Type())) // should never happen
			}
		},
		clear: func( pointer) {
			 := .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  && .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,  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 
}