审查视图

vendor/google.golang.org/protobuf/internal/filedesc/build.go 4.9 KB
tangxvhui authored
1 2 3 4 5 6 7 8 9
// Copyright 2019 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 filedesc provides functionality for constructing descriptors.
package filedesc

import (
	"google.golang.org/protobuf/encoding/protowire"
唐旭辉 authored
10
	"google.golang.org/protobuf/internal/genid"
tangxvhui authored
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
	"google.golang.org/protobuf/reflect/protoreflect"
	pref "google.golang.org/protobuf/reflect/protoreflect"
	preg "google.golang.org/protobuf/reflect/protoregistry"
)

// Builder construct a protoreflect.FileDescriptor from the raw descriptor.
type Builder struct {
	// GoPackagePath is the Go package path that is invoking this builder.
	GoPackagePath string

	// RawDescriptor is the wire-encoded bytes of FileDescriptorProto
	// and must be populated.
	RawDescriptor []byte

	// NumEnums is the total number of enums declared in the file.
	NumEnums int32
	// NumMessages is the total number of messages declared in the file.
	// It includes the implicit message declarations for map entries.
	NumMessages int32
	// NumExtensions is the total number of extensions declared in the file.
	NumExtensions int32
	// NumServices is the total number of services declared in the file.
	NumServices int32

	// TypeResolver resolves extension field types for descriptor options.
	// If nil, it uses protoregistry.GlobalTypes.
	TypeResolver interface {
		preg.ExtensionTypeResolver
	}

	// FileRegistry is use to lookup file, enum, and message dependencies.
	// Once constructed, the file descriptor is registered here.
	// If nil, it uses protoregistry.GlobalFiles.
	FileRegistry interface {
		FindFileByPath(string) (protoreflect.FileDescriptor, error)
		FindDescriptorByName(pref.FullName) (pref.Descriptor, error)
		RegisterFile(pref.FileDescriptor) error
	}
}

// resolverByIndex is an interface Builder.FileRegistry may implement.
// If so, it permits looking up an enum or message dependency based on the
// sub-list and element index into filetype.Builder.DependencyIndexes.
type resolverByIndex interface {
	FindEnumByIndex(int32, int32, []Enum, []Message) pref.EnumDescriptor
	FindMessageByIndex(int32, int32, []Enum, []Message) pref.MessageDescriptor
}

// Indexes of each sub-list in filetype.Builder.DependencyIndexes.
const (
	listFieldDeps int32 = iota
	listExtTargets
	listExtDeps
	listMethInDeps
	listMethOutDeps
)

// Out is the output of the Builder.
type Out struct {
	File pref.FileDescriptor

	// Enums is all enum descriptors in "flattened ordering".
	Enums []Enum
	// Messages is all message descriptors in "flattened ordering".
	// It includes the implicit message declarations for map entries.
	Messages []Message
	// Extensions is all extension descriptors in "flattened ordering".
	Extensions []Extension
	// Service is all service descriptors in "flattened ordering".
	Services []Service
}

// Build constructs a FileDescriptor given the parameters set in Builder.
// It assumes that the inputs are well-formed and panics if any inconsistencies
// are encountered.
//
// If NumEnums+NumMessages+NumExtensions+NumServices is zero,
// then Build automatically derives them from the raw descriptor.
func (db Builder) Build() (out Out) {
	// Populate the counts if uninitialized.
	if db.NumEnums+db.NumMessages+db.NumExtensions+db.NumServices == 0 {
		db.unmarshalCounts(db.RawDescriptor, true)
	}

	// Initialize resolvers and registries if unpopulated.
	if db.TypeResolver == nil {
		db.TypeResolver = preg.GlobalTypes
	}
	if db.FileRegistry == nil {
		db.FileRegistry = preg.GlobalFiles
	}

	fd := newRawFile(db)
	out.File = fd
	out.Enums = fd.allEnums
	out.Messages = fd.allMessages
	out.Extensions = fd.allExtensions
	out.Services = fd.allServices

	if err := db.FileRegistry.RegisterFile(fd); err != nil {
		panic(err)
	}
	return out
}

// unmarshalCounts counts the number of enum, message, extension, and service
// declarations in the raw message, which is either a FileDescriptorProto
// or a MessageDescriptorProto depending on whether isFile is set.
func (db *Builder) unmarshalCounts(b []byte, isFile bool) {
	for len(b) > 0 {
		num, typ, n := protowire.ConsumeTag(b)
		b = b[n:]
		switch typ {
		case protowire.BytesType:
			v, m := protowire.ConsumeBytes(b)
			b = b[m:]
			if isFile {
				switch num {
唐旭辉 authored
129
				case genid.FileDescriptorProto_EnumType_field_number:
tangxvhui authored
130
					db.NumEnums++
唐旭辉 authored
131
				case genid.FileDescriptorProto_MessageType_field_number:
tangxvhui authored
132 133
					db.unmarshalCounts(v, false)
					db.NumMessages++
唐旭辉 authored
134
				case genid.FileDescriptorProto_Extension_field_number:
tangxvhui authored
135
					db.NumExtensions++
唐旭辉 authored
136
				case genid.FileDescriptorProto_Service_field_number:
tangxvhui authored
137 138 139 140
					db.NumServices++
				}
			} else {
				switch num {
唐旭辉 authored
141
				case genid.DescriptorProto_EnumType_field_number:
tangxvhui authored
142
					db.NumEnums++
唐旭辉 authored
143
				case genid.DescriptorProto_NestedType_field_number:
tangxvhui authored
144 145
					db.unmarshalCounts(v, false)
					db.NumMessages++
唐旭辉 authored
146
				case genid.DescriptorProto_Extension_field_number:
tangxvhui authored
147 148 149 150 151 152 153 154 155
					db.NumExtensions++
				}
			}
		default:
			m := protowire.ConsumeFieldValue(num, typ, b)
			b = b[m:]
		}
	}
}