func (fd *FieldDescription) IsOneof() bool {
	return fd.desc.ContainingOneof() != nil
}
IsOneof returns true if the field is declared within a oneof block.
package pb
import (
	"fmt"
	"reflect"
	"google.golang.org/protobuf/proto"
	"google.golang.org/protobuf/reflect/protoreflect"
	exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
	dynamicpb "google.golang.org/protobuf/types/dynamicpb"
	anypb "google.golang.org/protobuf/types/known/anypb"
	dpb "google.golang.org/protobuf/types/known/durationpb"
	structpb "google.golang.org/protobuf/types/known/structpb"
	tpb "google.golang.org/protobuf/types/known/timestamppb"
	wrapperspb "google.golang.org/protobuf/types/known/wrapperspb"
)
type description interface {
	Zero() proto.Message
}
func NewTypeDescription(typeName string, desc protoreflect.MessageDescriptor) *TypeDescription {
	msgType := dynamicpb.NewMessageType(desc)
	msgZero := dynamicpb.NewMessage(desc)
	fieldMap := map[string]*FieldDescription{}
	fields := desc.Fields()
	for i := 0; i < fields.Len(); i++ {
		f := fields.Get(i)
		fieldMap[string(f.Name())] = NewFieldDescription(f)
	}
	return &TypeDescription{
		typeName:    typeName,
		desc:        desc,
		msgType:     msgType,
		fieldMap:    fieldMap,
		reflectType: reflectTypeOf(msgZero),
		zeroMsg:     zeroValueOf(msgZero),
	}
}
type TypeDescription struct {
	typeName    string
	desc        protoreflect.MessageDescriptor
	msgType     protoreflect.MessageType
	fieldMap    map[string]*FieldDescription
	reflectType reflect.Type
	zeroMsg     proto.Message
}
func (td *TypeDescription) FieldMap() map[string]*FieldDescription {
	return td.fieldMap
}
func (td *TypeDescription) FieldByName(name string) (*FieldDescription, bool) {
	fd, found := td.fieldMap[name]
	if !found {
		return nil, false
	}
	return fd, true
}
func (td *TypeDescription) MaybeUnwrap(msg proto.Message) (interface{}, bool) {
	return unwrap(td, msg)
}
func (td *TypeDescription) Name() string {
	return string(td.desc.FullName())
}
func (td *TypeDescription) New() protoreflect.Message {
	return td.msgType.New()
}
func (td *TypeDescription) ReflectType() reflect.Type {
	return td.reflectType
}
func (td *TypeDescription) Zero() proto.Message {
	return td.zeroMsg
}
func NewFieldDescription(fieldDesc protoreflect.FieldDescriptor) *FieldDescription {
	var reflectType reflect.Type
	var zeroMsg proto.Message
	switch fieldDesc.Kind() {
	case protoreflect.EnumKind:
		reflectType = reflectTypeOf(protoreflect.EnumNumber(0))
	case protoreflect.MessageKind:
		zeroMsg = dynamicpb.NewMessage(fieldDesc.Message())
		reflectType = reflectTypeOf(zeroMsg)
	default:
		reflectType = reflectTypeOf(fieldDesc.Default().Interface())
		if fieldDesc.IsList() {
			parentMsg := dynamicpb.NewMessage(fieldDesc.ContainingMessage())
			listField := parentMsg.NewField(fieldDesc).List()
			elem := listField.NewElement().Interface()
			switch elemType := elem.(type) {
			case protoreflect.Message:
				elem = elemType.Interface()
			}
			reflectType = reflectTypeOf(elem)
		}
	}
	if fieldDesc.IsList() {
		reflectType = reflect.SliceOf(reflectType)
	}
	var keyType, valType *FieldDescription
	if fieldDesc.IsMap() {
		keyType = NewFieldDescription(fieldDesc.MapKey())
		valType = NewFieldDescription(fieldDesc.MapValue())
	}
	return &FieldDescription{
		desc:        fieldDesc,
		KeyType:     keyType,
		ValueType:   valType,
		reflectType: reflectType,
		zeroMsg:     zeroValueOf(zeroMsg),
	}
}
type FieldDescription struct {
	KeyType *FieldDescription
	ValueType *FieldDescription
	desc        protoreflect.FieldDescriptor
	reflectType reflect.Type
	zeroMsg     proto.Message
}
func (fd *FieldDescription) CheckedType() *exprpb.Type {
	if fd.desc.IsMap() {
		return &exprpb.Type{
			TypeKind: &exprpb.Type_MapType_{
				MapType: &exprpb.Type_MapType{
					KeyType:   fd.KeyType.typeDefToType(),
					ValueType: fd.ValueType.typeDefToType(),
				},
			},
		}
	}
	if fd.desc.IsList() {
		return &exprpb.Type{
			TypeKind: &exprpb.Type_ListType_{
				ListType: &exprpb.Type_ListType{
					ElemType: fd.typeDefToType()}}}
	}
	return fd.typeDefToType()
}
func (fd *FieldDescription) Descriptor() protoreflect.FieldDescriptor {
	return fd.desc
}
func (fd *FieldDescription) IsSet(target interface{}) bool {
	switch v := target.(type) {
	case proto.Message:
		pbRef := v.ProtoReflect()
		pbDesc := pbRef.Descriptor()
		if pbDesc == fd.desc.ContainingMessage() {
			return pbRef.Has(fd.desc)
		}
		return pbRef.Has(pbDesc.Fields().ByName(protoreflect.Name(fd.Name())))
	default:
		return false
	}
}
func (fd *FieldDescription) GetFrom(target interface{}) (interface{}, error) {
	v, ok := target.(proto.Message)
	if !ok {
		return nil, fmt.Errorf("unsupported field selection target: (%T)%v", target, target)
	}
	pbRef := v.ProtoReflect()
	pbDesc := pbRef.Descriptor()
	var fieldVal interface{}
	if pbDesc == fd.desc.ContainingMessage() {
		fieldVal = pbRef.Get(fd.desc).Interface()
	} else {
		fieldVal = pbRef.Get(pbDesc.Fields().ByName(protoreflect.Name(fd.Name()))).Interface()
	}
	switch fv := fieldVal.(type) {
	case bool, []byte, float32, float64, int32, int64, string, uint32, uint64, protoreflect.List:
		return fv, nil
	case protoreflect.EnumNumber:
		return int64(fv), nil
	case protoreflect.Map:
		return &Map{Map: fv, KeyType: fd.KeyType, ValueType: fd.ValueType}, nil
	case protoreflect.Message:
		unwrapped, _ := fd.MaybeUnwrapDynamic(fv)
		return unwrapped, nil
	default:
		return fv, nil
	}
}
func (fd *FieldDescription) IsEnum() bool {
	return fd.desc.Kind() == protoreflect.EnumKind
}
func (fd *FieldDescription) IsMap() bool {
	return fd.desc.IsMap()
}
func (fd *FieldDescription) IsMessage() bool {
	return fd.desc.Kind() == protoreflect.MessageKind
}