func (r *MessageRegistry) ServiceAsApi(sd *desc.ServiceDescriptor) *api.Api {
	ms := sd.GetMethods()
	methods := make([]*api.Method, len(ms))
	for i, m := range ms {
		methods[i] = r.methodAsApi(m)
	}
	return &api.Api{
		Name:          sd.GetFullyQualifiedName(),
		Methods:       methods,
		Options:       r.options(sd.GetOptions()),
		Syntax:        syntax(sd.GetFile()),
		SourceContext: &source_context.SourceContext{FileName: sd.GetFile().GetName()},
	}
}
ServiceAsApi converts the given service descriptor into a ptype API description.
package msgregistry
import (
	"fmt"
	"reflect"
	"strings"
	"sync"
	"github.com/golang/protobuf/jsonpb"
	"github.com/golang/protobuf/proto"
	"github.com/golang/protobuf/protoc-gen-go/descriptor"
	"github.com/golang/protobuf/ptypes"
	"github.com/golang/protobuf/ptypes/any"
	"github.com/golang/protobuf/ptypes/wrappers"
	"google.golang.org/genproto/protobuf/api"
	"google.golang.org/genproto/protobuf/ptype"
	"google.golang.org/genproto/protobuf/source_context"
	"github.com/jhump/protoreflect/desc"
	"github.com/jhump/protoreflect/dynamic"
)
const googleApisDomain = "type.googleapis.com"
type ErrUnexpectedType struct {
	URL          string
	ShouldBeEnum bool
}
func (e *ErrUnexpectedType) Error() string {
	msg := "wanted message, got enum"
	if e.ShouldBeEnum {
		msg = "wanted enum, got message"
	}
	return fmt.Sprintf("type for URL %q is the wrong type: %s", e.URL, msg)
}
type MessageRegistry struct {
	resolver       typeResolver
	mf             *dynamic.MessageFactory
	er             *dynamic.ExtensionRegistry
	mu             sync.RWMutex
	types          map[string]desc.Descriptor
	baseUrls       map[string]string
	defaultBaseUrl string
}
func NewMessageRegistryWithDefaults() *MessageRegistry {
	mf := dynamic.NewMessageFactoryWithDefaults()
	return &MessageRegistry{
		mf: mf,
		er: mf.GetExtensionRegistry(),
	}
}
func (r *MessageRegistry) WithFetcher(fetcher TypeFetcher) *MessageRegistry {
	r.resolver = typeResolver{fetcher: fetcher, mr: r}
	return r
}
func (r *MessageRegistry) WithMessageFactory(mf *dynamic.MessageFactory) *MessageRegistry {
	r.mf = mf
	if mf == nil {
		r.er = nil
	} else {
		r.er = mf.GetExtensionRegistry()
	}
	return r
}
func (r *MessageRegistry) WithDefaultBaseUrl(baseUrl string) *MessageRegistry {
	baseUrl = stripTrailingSlash(baseUrl)
	r.defaultBaseUrl = baseUrl
	return r
}
func stripTrailingSlash(url string) string {
	if url[len(url)-1] == '/' {
		return url[:len(url)-1]
	}
	return url
}
func (r *MessageRegistry) AddMessage(url string, md *desc.MessageDescriptor) error {
	url = ensureScheme(url)
	baseUrl := strings.TrimSuffix(url, "/"+md.GetFullyQualifiedName())
	if url == baseUrl {
		return fmt.Errorf("URL %s is invalid: it should end with path element %s", url, md.GetFullyQualifiedName())
	}
	r.mu.Lock()
	defer r.mu.Unlock()
	if r.types == nil {
		r.types = map[string]desc.Descriptor{}
	}
	r.types[url] = md
	if r.baseUrls == nil {
		r.baseUrls = map[string]string{}
	}
	r.baseUrls[md.GetFullyQualifiedName()] = baseUrl
	return nil
}
func (r *MessageRegistry) AddEnum(url string, ed *desc.EnumDescriptor) error {
	url = ensureScheme(url)
	baseUrl := strings.TrimSuffix(url, "/"+ed.GetFullyQualifiedName())
	if url == baseUrl {
		return fmt.Errorf("URL %s is invalid: it should end with path element %s", url, ed.GetFullyQualifiedName())
	}
	r.mu.Lock()
	defer r.mu.Unlock()
	if r.types == nil {
		r.types = map[string]desc.Descriptor{}
	}
	r.types[url] = ed
	if r.baseUrls == nil {
		r.baseUrls = map[string]string{}
	}
	r.baseUrls[ed.GetFullyQualifiedName()] = baseUrl
	return nil
}
func (r *MessageRegistry) AddFile(baseUrl string, fd *desc.FileDescriptor) {
	baseUrl = stripTrailingSlash(ensureScheme(baseUrl))
	r.mu.Lock()
	defer r.mu.Unlock()
	if r.types == nil {
		r.types = map[string]desc.Descriptor{}
	}
	if r.baseUrls == nil {
		r.baseUrls = map[string]string{}
	}
	r.addEnumTypesLocked(baseUrl, fd.GetEnumTypes())
	r.addMessageTypesLocked(baseUrl, fd.GetMessageTypes())
}
func (r *MessageRegistry) addEnumTypesLocked(baseUrl string, enums []*desc.EnumDescriptor) {
	for _, ed := range enums {
		url := fmt.Sprintf("%s/%s", baseUrl, ed.GetFullyQualifiedName())
		r.types[url] = ed
		r.baseUrls[ed.GetFullyQualifiedName()] = baseUrl
	}
}
func (r *MessageRegistry) addMessageTypesLocked(baseUrl string, msgs []*desc.MessageDescriptor) {
	for _, md := range msgs {
		url := fmt.Sprintf("%s/%s", baseUrl, md.GetFullyQualifiedName())
		r.types[url] = md
		r.baseUrls[md.GetFullyQualifiedName()] = baseUrl
		r.addEnumTypesLocked(baseUrl, md.GetNestedEnumTypes())
		r.addMessageTypesLocked(baseUrl, md.GetNestedMessageTypes())
	}
}
func (r *MessageRegistry) FindMessageTypeByUrl(url string) (*desc.MessageDescriptor, error) {
	md, err := r.getRegisteredMessageTypeByUrl(url)
	if err != nil {
		return nil, err
	} else if md != nil {
		return md, err
	}
	if r.resolver.fetcher == nil {
		return nil, nil
	}
	return r.resolver.resolveUrlToMessageDescriptor(url)
}
func (r *MessageRegistry) getRegisteredMessageTypeByUrl(url string) (*desc.MessageDescriptor, error) {
	if r != nil {
		r.mu.RLock()
		m := r.types[ensureScheme(url)]
		r.mu.RUnlock()
		if m != nil {
			if md, ok := m.(*desc.MessageDescriptor); ok {
				return md, nil
			}
			return nil, &ErrUnexpectedType{
				URL: url,
			}
		}
	}
	var ktr *dynamic.KnownTypeRegistry
	if r != nil {
		ktr = r.mf.GetKnownTypeRegistry()
	}
	msgType := ktr.GetKnownType(typeName(url))
	if msgType == nil {
		return nil, nil
	}
	return desc.LoadMessageDescriptorForType(msgType)
}
func (r *MessageRegistry) FindEnumTypeByUrl(url string) (*desc.EnumDescriptor, error) {
	ed, err := r.getRegisteredEnumTypeByUrl(url)
	if err != nil {
		return nil, err
	} else if ed != nil {
		return ed, err
	}
	if r.resolver.fetcher == nil {
		return nil, nil
	}
	if ed, err := r.resolver.resolveUrlToEnumDescriptor(url); err != nil {
		return nil, err
	} else {
		return ed, nil
	}
}
func (r *MessageRegistry) getRegisteredEnumTypeByUrl(url string) (*desc.EnumDescriptor, error) {
	if r == nil {
		return nil, nil
	}
	r.mu.RLock()
	m := r.types[ensureScheme(url)]
	r.mu.RUnlock()
	if m != nil {
		if ed, ok := m.(*desc.EnumDescriptor); ok {
			return ed, nil
		}
		return nil, &ErrUnexpectedType{
			URL: url,
		}
	}
	return nil, nil
}
func (r *MessageRegistry) ResolveApiIntoServiceDescriptor(a *api.Api) (*desc.ServiceDescriptor, error) {
	if r == nil {
		return nil, nil
	}
	msgs := map[string]*desc.MessageDescriptor{}
	unresolved := map[string]struct{}{}
	for _, m := range a.Methods {
		md, err := r.getRegisteredMessageTypeByUrl(m.RequestTypeUrl)
		if err != nil {
			return nil, err
		} else if md == nil {
			if r.resolver.fetcher == nil {
				return nil, nil
			}
			unresolved[m.RequestTypeUrl] = struct{}{}
		} else {
			msgs[m.RequestTypeUrl] = md
		}
		md, err = r.getRegisteredMessageTypeByUrl(m.ResponseTypeUrl)
		if err != nil {
			return nil, err
		} else if md == nil {
			if r.resolver.fetcher == nil {
				return nil, nil
			}
			unresolved[m.ResponseTypeUrl] = struct{}{}
		} else {
			msgs[m.ResponseTypeUrl] = md
		}
	}
	if len(unresolved) > 0 {
		unresolvedSlice := make([]string, 0, len(unresolved))
		for k := range unresolved {
			unresolvedSlice = append(unresolvedSlice, k)
		}
		mp, err := r.resolver.resolveUrlsToMessageDescriptors(unresolvedSlice...)
		if err != nil {
			return nil, err
		}
		for u, md := range mp {
			msgs[u] = md
		}
	}
	var fileName string
	if a.SourceContext != nil && a.SourceContext.FileName != "" {
		fileName = a.SourceContext.FileName
	} else {
		fileName = "--unknown--.proto"
	}
	files := map[string]*fileEntry{}
	fe := &fileEntry{}
	fe.proto3 = a.Syntax == ptype.Syntax_SYNTAX_PROTO3
	files[fileName] = fe
	fe.types.addType(a.Name, createServiceDescriptor(a, r))
	added := newNameTracker()
	for _, md := range msgs {
		addDescriptors(fileName, files, md, msgs, added)
	}
	fileDescriptors, err := toFileDescriptors(files, (*typeTrie).rewriteDescriptor)
	if err != nil {
		return nil, err
	}
	return fileDescriptors[fileName].FindService(a.Name), nil
}
func (r *MessageRegistry) UnmarshalAny(any *any.Any) (proto.Message, error) {
	return r.unmarshalAny(any, r.FindMessageTypeByUrl)
}
func (r *MessageRegistry) unmarshalAny(any *any.Any, fetch func(string) (*desc.MessageDescriptor, error)) (proto.Message, error) {
	name, err := ptypes.AnyMessageName(any)
	if err != nil {
		return nil, err
	}
	var msg proto.Message
	var mf *dynamic.MessageFactory
	var ktr *dynamic.KnownTypeRegistry
	if r != nil {
		mf = r.mf
		ktr = r.mf.GetKnownTypeRegistry()
	}
	if msg = ktr.CreateIfKnown(name); msg == nil {
		if md, err := fetch(any.TypeUrl); err != nil {
			return nil, err
		} else if md == nil {
			return nil, fmt.Errorf("unknown message type: %s", any.TypeUrl)
		} else {
			msg = mf.NewDynamicMessage(md)
		}
	}
	err = proto.Unmarshal(any.Value, msg)
	if err != nil {
		return nil, err
	} else {
		return msg, nil
	}
}
func (r *MessageRegistry) AddBaseUrlForElement(baseUrl, packageOrTypeName string) {
	if baseUrl[len(baseUrl)-1] == '/' {
		baseUrl = baseUrl[:len(baseUrl)-1]
	}
	r.mu.Lock()
	defer r.mu.Unlock()
	if r.baseUrls == nil {
		r.baseUrls = map[string]string{}
	}
	r.baseUrls[packageOrTypeName] = baseUrl
}
func (r *MessageRegistry) MarshalAny(m proto.Message) (*any.Any, error) {
	var md *desc.MessageDescriptor
	if dm, ok := m.(*dynamic.Message); ok {
		md = dm.GetMessageDescriptor()
	} else {
		var err error
		md, err = desc.LoadMessageDescriptorForMessage(m)
		if err != nil {
			return nil, err
		}
	}
	if b, err := proto.Marshal(m); err != nil {
		return nil, err
	} else {
		return &any.Any{TypeUrl: r.ComputeUrl(md), Value: b}, nil
	}
}
func (r *MessageRegistry) MessageAsPType(md *desc.MessageDescriptor) *ptype.Type {
	fs := md.GetFields()
	fields := make([]*ptype.Field, len(fs))
	for i, f := range fs {
		fields[i] = r.fieldAsPType(f)
	}
	oos := md.GetOneOfs()
	oneOfs := make([]string, len(oos))
	for i, oo := range oos {
		oneOfs[i] = oo.GetName()
	}
	return &ptype.Type{
		Name:          md.GetFullyQualifiedName(),
		Fields:        fields,
		Oneofs:        oneOfs,
		Options:       r.options(md.GetOptions()),
		Syntax:        syntax(md.GetFile()),
		SourceContext: &source_context.SourceContext{FileName: md.GetFile().GetName()},
	}
}
func (r *MessageRegistry) fieldAsPType(fd *desc.FieldDescriptor) *ptype.Field {
	opts := r.options(fd.GetOptions())
	for i, o := range opts {
		if o.Name == "packed" {
			opts = append(opts[:i], opts[i+1:]...)
			break
		}
	}
	var oneOf int32
	if fd.AsFieldDescriptorProto().OneofIndex != nil {
		oneOf = fd.AsFieldDescriptorProto().GetOneofIndex() + 1
	}
	var card ptype.Field_Cardinality
	switch fd.GetLabel() {
	case descriptor.FieldDescriptorProto_LABEL_OPTIONAL:
		card = ptype.Field_CARDINALITY_OPTIONAL
	case descriptor.FieldDescriptorProto_LABEL_REPEATED:
		card = ptype.Field_CARDINALITY_REPEATED
	case descriptor.FieldDescriptorProto_LABEL_REQUIRED:
		card = ptype.Field_CARDINALITY_REQUIRED
	}
	var url string
	var kind ptype.Field_Kind
	switch fd.GetType() {
	case descriptor.FieldDescriptorProto_TYPE_ENUM:
		kind = ptype.Field_TYPE_ENUM
		url = r.ComputeUrl(fd.GetEnumType())
	case descriptor.FieldDescriptorProto_TYPE_GROUP:
		kind = ptype.Field_TYPE_GROUP
		url = r.ComputeUrl(fd.GetMessageType())
	case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
		kind = ptype.Field_TYPE_MESSAGE
		url = r.ComputeUrl(fd.GetMessageType())
	case descriptor.FieldDescriptorProto_TYPE_BYTES:
		kind = ptype.Field_TYPE_BYTES
	case descriptor.FieldDescriptorProto_TYPE_STRING:
		kind = ptype.Field_TYPE_STRING
	case descriptor.FieldDescriptorProto_TYPE_BOOL:
		kind = ptype.Field_TYPE_BOOL
	case descriptor.FieldDescriptorProto_TYPE_DOUBLE:
		kind = ptype.Field_TYPE_DOUBLE
	case descriptor.FieldDescriptorProto_TYPE_FLOAT:
		kind = ptype.Field_TYPE_FLOAT
	case descriptor.FieldDescriptorProto_TYPE_FIXED32:
		kind = ptype.Field_TYPE_FIXED32
	case descriptor.FieldDescriptorProto_TYPE_FIXED64:
		kind = ptype.Field_TYPE_FIXED64
	case descriptor.FieldDescriptorProto_TYPE_INT32:
		kind = ptype.Field_TYPE_INT32
	case descriptor.FieldDescriptorProto_TYPE_INT64:
		kind = ptype.Field_TYPE_INT64
	case descriptor.FieldDescriptorProto_TYPE_SFIXED32:
		kind = ptype.Field_TYPE_SFIXED32
	case descriptor.FieldDescriptorProto_TYPE_SFIXED64:
		kind = ptype.Field_TYPE_SFIXED64
	case descriptor.FieldDescriptorProto_TYPE_SINT32:
		kind = ptype.Field_TYPE_SINT32
	case descriptor.FieldDescriptorProto_TYPE_SINT64:
		kind = ptype.Field_TYPE_SINT64
	case descriptor.FieldDescriptorProto_TYPE_UINT32:
		kind = ptype.Field_TYPE_UINT32
	case descriptor.FieldDescriptorProto_TYPE_UINT64:
		kind = ptype.Field_TYPE_UINT64
	}
	return &ptype.Field{
		Name:         fd.GetName(),
		Number:       fd.GetNumber(),
		JsonName:     fd.AsFieldDescriptorProto().GetJsonName(),
		OneofIndex:   oneOf,
		DefaultValue: fd.AsFieldDescriptorProto().GetDefaultValue(),
		Options:      opts,
		Packed:       fd.GetFieldOptions().GetPacked(),
		TypeUrl:      url,
		Cardinality:  card,
		Kind:         kind,
	}
}
func (r *MessageRegistry) EnumAsPType(ed *desc.EnumDescriptor) *ptype.Enum {
	vs := ed.GetValues()
	vals := make([]*ptype.EnumValue, len(vs))
	for i, v := range vs {
		vals[i] = r.enumValueAsPType(v)
	}
	return &ptype.Enum{
		Name:          ed.GetFullyQualifiedName(),
		Enumvalue:     vals,
		Options:       r.options(ed.GetOptions()),
		Syntax:        syntax(ed.GetFile()),
		SourceContext: &source_context.SourceContext{FileName: ed.GetFile().GetName()},
	}
}
func (r *MessageRegistry) enumValueAsPType(vd *desc.EnumValueDescriptor) *ptype.EnumValue {
	return &ptype.EnumValue{
		Name:    vd.GetName(),
		Number:  vd.GetNumber(),
		Options: r.options(vd.GetOptions()),
	}
}