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 (
	
	
	
	

	
	
	
	pref 
)
legacyEnumName returns the name of enums used in legacy code. It is neither the protobuf full name nor the qualified Go name, but rather an odd hybrid of both.
func ( pref.EnumDescriptor) string {
	var  string
	 := string(.FullName())
	if  := .ParentFile();  != nil {
		 = string(.Package())
		 = strings.TrimPrefix(, +".")
	}
	if  == "" {
		return strs.GoCamelCase()
	}
	return  + "." + strs.GoCamelCase()
}
legacyWrapEnum wraps v as a protoreflect.Enum, where v must be a int32 kind and not implement the v2 API already.
func ( reflect.Value) pref.Enum {
	 := legacyLoadEnumType(.Type())
	return .New(pref.EnumNumber(.Int()))
}

var legacyEnumTypeCache sync.Map // map[reflect.Type]protoreflect.EnumType
legacyLoadEnumType dynamically loads a protoreflect.EnumType for t, where t must be an int32 kind and not implement the v2 API already.
Fast-path: check if a EnumType is cached for this concrete type.
	if ,  := legacyEnumTypeCache.Load();  {
		return .(pref.EnumType)
	}
Slow-path: derive enum descriptor and initialize EnumType.
	var  pref.EnumType
	 := LegacyLoadEnumDesc()
	 = &legacyEnumType{
		desc:   ,
		goType: ,
	}
	if ,  := legacyEnumTypeCache.LoadOrStore(, );  {
		return .(pref.EnumType)
	}
	return 
}

type legacyEnumType struct {
	desc   pref.EnumDescriptor
	goType reflect.Type
	m      sync.Map // map[protoreflect.EnumNumber]proto.Enum
}

func ( *legacyEnumType) ( pref.EnumNumber) pref.Enum {
	if ,  := .m.Load();  {
		return .(pref.Enum)
	}
	 := &legacyEnumWrapper{num: , pbTyp: , goTyp: .goType}
	.m.Store(, )
	return 
}
func ( *legacyEnumType) () pref.EnumDescriptor {
	return .desc
}

type legacyEnumWrapper struct {
	num   pref.EnumNumber
	pbTyp pref.EnumType
	goTyp reflect.Type
}

func ( *legacyEnumWrapper) () pref.EnumDescriptor {
	return .pbTyp.Descriptor()
}
func ( *legacyEnumWrapper) () pref.EnumType {
	return .pbTyp
}
func ( *legacyEnumWrapper) () pref.EnumNumber {
	return .num
}
func ( *legacyEnumWrapper) () pref.Enum {
	return 
}
func ( *legacyEnumWrapper) () interface{} {
	 := reflect.New(.goTyp).Elem()
	.SetInt(int64(.num))
	return .Interface()
}

var (
	_ pref.Enum = (*legacyEnumWrapper)(nil)
	_ unwrapper = (*legacyEnumWrapper)(nil)
)

var legacyEnumDescCache sync.Map // map[reflect.Type]protoreflect.EnumDescriptor
LegacyLoadEnumDesc returns an EnumDescriptor derived from the Go type, which must be an int32 kind and not implement the v2 API already. This is exported for testing purposes.
Fast-path: check if an EnumDescriptor is cached for this concrete type.
	if ,  := legacyEnumDescCache.Load();  {
		return .(pref.EnumDescriptor)
	}
Slow-path: initialize EnumDescriptor from the raw descriptor.
	 := reflect.Zero().Interface()
	if ,  := .(pref.Enum);  {
		panic(fmt.Sprintf("%v already implements proto.Enum", ))
	}
	,  := .(enumV1)
	if ! {
		return aberrantLoadEnumDesc()
	}
	,  := .EnumDescriptor()

	var  pref.EnumDescriptor
	if len() == 1 {
		 = legacyLoadFileDesc().Enums().Get([0])
	} else {
		 := legacyLoadFileDesc().Messages().Get([0])
		for ,  := range [1 : len()-1] {
			 = .Messages().Get()
		}
		 = .Enums().Get([len()-1])
	}
	if ,  := legacyEnumDescCache.LoadOrStore(, );  {
		return .(protoreflect.EnumDescriptor)
	}
	return 
}

var aberrantEnumDescCache sync.Map // map[reflect.Type]protoreflect.EnumDescriptor
aberrantLoadEnumDesc returns an EnumDescriptor derived from the Go type, which must not implement protoreflect.Enum or enumV1. If the type does not implement enumV1, then there is no reliable way to derive the original protobuf type information. We are unable to use the global enum registry since it is unfortunately keyed by the protobuf full name, which we also do not know. Thus, this produces some bogus enum descriptor based on the Go type name.
Fast-path: check if an EnumDescriptor is cached for this concrete type.
	if ,  := aberrantEnumDescCache.Load();  {
		return .(pref.EnumDescriptor)
	}
Slow-path: construct a bogus, but unique EnumDescriptor.
TODO: Use the presence of a UnmarshalJSON method to determine proto2?

	 := &.L2.Values.List[0]
	.L0.FullName = .L0.FullName + "_UNKNOWN" // e.g., github_com.user.repo.MyEnum_UNKNOWN
	.L0.ParentFile = .L0.ParentFile
	.L0.Parent = 
TODO: We could use the String method to obtain some enum value names by starting at 0 and print the enum until it produces invalid identifiers. An exhaustive query is clearly impractical, but can be best-effort.

	if ,  := aberrantEnumDescCache.LoadOrStore(, );  {
		return .(pref.EnumDescriptor)
	}
	return 
}
AberrantDeriveFullName derives a fully qualified protobuf name for the given Go type The provided name is not guaranteed to be stable nor universally unique. It should be sufficiently unique within a program. This is exported for testing purposes.
func ( reflect.Type) pref.FullName {
	 := func( rune) rune {
		switch {
		case  == '/':
			return '.'
		case 'a' <=  &&  <= 'z', 'A' <=  &&  <= 'Z', '0' <=  &&  <= '9':
			return 
		default:
			return '_'
		}
	}
	 := strings.Map(, .PkgPath())
	 := strings.Map(, .Name())
	if  == "" {
		 = fmt.Sprintf("UnknownX%X", reflect.ValueOf().Pointer())
	}

	 := append(strings.Split(, "."), )
	for ,  := range  {
		if  == "" || ('0' <= [0] && [0] <= '9') {
			[] = "x" + 
		}
	}
	return pref.FullName(strings.Join(, "."))