xref: /aosp_15_r20/external/golang-protobuf/internal/filedesc/build.go (revision 1c12ee1efe575feb122dbf939ff15148a3b3e8f2)
1*1c12ee1eSDan Willemsen// Copyright 2019 The Go Authors. All rights reserved.
2*1c12ee1eSDan Willemsen// Use of this source code is governed by a BSD-style
3*1c12ee1eSDan Willemsen// license that can be found in the LICENSE file.
4*1c12ee1eSDan Willemsen
5*1c12ee1eSDan Willemsen// Package filedesc provides functionality for constructing descriptors.
6*1c12ee1eSDan Willemsen//
7*1c12ee1eSDan Willemsen// The types in this package implement interfaces in the protoreflect package
8*1c12ee1eSDan Willemsen// related to protobuf descripriptors.
9*1c12ee1eSDan Willemsenpackage filedesc
10*1c12ee1eSDan Willemsen
11*1c12ee1eSDan Willemsenimport (
12*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/encoding/protowire"
13*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/internal/genid"
14*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/reflect/protoreflect"
15*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/reflect/protoregistry"
16*1c12ee1eSDan Willemsen)
17*1c12ee1eSDan Willemsen
18*1c12ee1eSDan Willemsen// Builder construct a protoreflect.FileDescriptor from the raw descriptor.
19*1c12ee1eSDan Willemsentype Builder struct {
20*1c12ee1eSDan Willemsen	// GoPackagePath is the Go package path that is invoking this builder.
21*1c12ee1eSDan Willemsen	GoPackagePath string
22*1c12ee1eSDan Willemsen
23*1c12ee1eSDan Willemsen	// RawDescriptor is the wire-encoded bytes of FileDescriptorProto
24*1c12ee1eSDan Willemsen	// and must be populated.
25*1c12ee1eSDan Willemsen	RawDescriptor []byte
26*1c12ee1eSDan Willemsen
27*1c12ee1eSDan Willemsen	// NumEnums is the total number of enums declared in the file.
28*1c12ee1eSDan Willemsen	NumEnums int32
29*1c12ee1eSDan Willemsen	// NumMessages is the total number of messages declared in the file.
30*1c12ee1eSDan Willemsen	// It includes the implicit message declarations for map entries.
31*1c12ee1eSDan Willemsen	NumMessages int32
32*1c12ee1eSDan Willemsen	// NumExtensions is the total number of extensions declared in the file.
33*1c12ee1eSDan Willemsen	NumExtensions int32
34*1c12ee1eSDan Willemsen	// NumServices is the total number of services declared in the file.
35*1c12ee1eSDan Willemsen	NumServices int32
36*1c12ee1eSDan Willemsen
37*1c12ee1eSDan Willemsen	// TypeResolver resolves extension field types for descriptor options.
38*1c12ee1eSDan Willemsen	// If nil, it uses protoregistry.GlobalTypes.
39*1c12ee1eSDan Willemsen	TypeResolver interface {
40*1c12ee1eSDan Willemsen		protoregistry.ExtensionTypeResolver
41*1c12ee1eSDan Willemsen	}
42*1c12ee1eSDan Willemsen
43*1c12ee1eSDan Willemsen	// FileRegistry is use to lookup file, enum, and message dependencies.
44*1c12ee1eSDan Willemsen	// Once constructed, the file descriptor is registered here.
45*1c12ee1eSDan Willemsen	// If nil, it uses protoregistry.GlobalFiles.
46*1c12ee1eSDan Willemsen	FileRegistry interface {
47*1c12ee1eSDan Willemsen		FindFileByPath(string) (protoreflect.FileDescriptor, error)
48*1c12ee1eSDan Willemsen		FindDescriptorByName(protoreflect.FullName) (protoreflect.Descriptor, error)
49*1c12ee1eSDan Willemsen		RegisterFile(protoreflect.FileDescriptor) error
50*1c12ee1eSDan Willemsen	}
51*1c12ee1eSDan Willemsen}
52*1c12ee1eSDan Willemsen
53*1c12ee1eSDan Willemsen// resolverByIndex is an interface Builder.FileRegistry may implement.
54*1c12ee1eSDan Willemsen// If so, it permits looking up an enum or message dependency based on the
55*1c12ee1eSDan Willemsen// sub-list and element index into filetype.Builder.DependencyIndexes.
56*1c12ee1eSDan Willemsentype resolverByIndex interface {
57*1c12ee1eSDan Willemsen	FindEnumByIndex(int32, int32, []Enum, []Message) protoreflect.EnumDescriptor
58*1c12ee1eSDan Willemsen	FindMessageByIndex(int32, int32, []Enum, []Message) protoreflect.MessageDescriptor
59*1c12ee1eSDan Willemsen}
60*1c12ee1eSDan Willemsen
61*1c12ee1eSDan Willemsen// Indexes of each sub-list in filetype.Builder.DependencyIndexes.
62*1c12ee1eSDan Willemsenconst (
63*1c12ee1eSDan Willemsen	listFieldDeps int32 = iota
64*1c12ee1eSDan Willemsen	listExtTargets
65*1c12ee1eSDan Willemsen	listExtDeps
66*1c12ee1eSDan Willemsen	listMethInDeps
67*1c12ee1eSDan Willemsen	listMethOutDeps
68*1c12ee1eSDan Willemsen)
69*1c12ee1eSDan Willemsen
70*1c12ee1eSDan Willemsen// Out is the output of the Builder.
71*1c12ee1eSDan Willemsentype Out struct {
72*1c12ee1eSDan Willemsen	File protoreflect.FileDescriptor
73*1c12ee1eSDan Willemsen
74*1c12ee1eSDan Willemsen	// Enums is all enum descriptors in "flattened ordering".
75*1c12ee1eSDan Willemsen	Enums []Enum
76*1c12ee1eSDan Willemsen	// Messages is all message descriptors in "flattened ordering".
77*1c12ee1eSDan Willemsen	// It includes the implicit message declarations for map entries.
78*1c12ee1eSDan Willemsen	Messages []Message
79*1c12ee1eSDan Willemsen	// Extensions is all extension descriptors in "flattened ordering".
80*1c12ee1eSDan Willemsen	Extensions []Extension
81*1c12ee1eSDan Willemsen	// Service is all service descriptors in "flattened ordering".
82*1c12ee1eSDan Willemsen	Services []Service
83*1c12ee1eSDan Willemsen}
84*1c12ee1eSDan Willemsen
85*1c12ee1eSDan Willemsen// Build constructs a FileDescriptor given the parameters set in Builder.
86*1c12ee1eSDan Willemsen// It assumes that the inputs are well-formed and panics if any inconsistencies
87*1c12ee1eSDan Willemsen// are encountered.
88*1c12ee1eSDan Willemsen//
89*1c12ee1eSDan Willemsen// If NumEnums+NumMessages+NumExtensions+NumServices is zero,
90*1c12ee1eSDan Willemsen// then Build automatically derives them from the raw descriptor.
91*1c12ee1eSDan Willemsenfunc (db Builder) Build() (out Out) {
92*1c12ee1eSDan Willemsen	// Populate the counts if uninitialized.
93*1c12ee1eSDan Willemsen	if db.NumEnums+db.NumMessages+db.NumExtensions+db.NumServices == 0 {
94*1c12ee1eSDan Willemsen		db.unmarshalCounts(db.RawDescriptor, true)
95*1c12ee1eSDan Willemsen	}
96*1c12ee1eSDan Willemsen
97*1c12ee1eSDan Willemsen	// Initialize resolvers and registries if unpopulated.
98*1c12ee1eSDan Willemsen	if db.TypeResolver == nil {
99*1c12ee1eSDan Willemsen		db.TypeResolver = protoregistry.GlobalTypes
100*1c12ee1eSDan Willemsen	}
101*1c12ee1eSDan Willemsen	if db.FileRegistry == nil {
102*1c12ee1eSDan Willemsen		db.FileRegistry = protoregistry.GlobalFiles
103*1c12ee1eSDan Willemsen	}
104*1c12ee1eSDan Willemsen
105*1c12ee1eSDan Willemsen	fd := newRawFile(db)
106*1c12ee1eSDan Willemsen	out.File = fd
107*1c12ee1eSDan Willemsen	out.Enums = fd.allEnums
108*1c12ee1eSDan Willemsen	out.Messages = fd.allMessages
109*1c12ee1eSDan Willemsen	out.Extensions = fd.allExtensions
110*1c12ee1eSDan Willemsen	out.Services = fd.allServices
111*1c12ee1eSDan Willemsen
112*1c12ee1eSDan Willemsen	if err := db.FileRegistry.RegisterFile(fd); err != nil {
113*1c12ee1eSDan Willemsen		panic(err)
114*1c12ee1eSDan Willemsen	}
115*1c12ee1eSDan Willemsen	return out
116*1c12ee1eSDan Willemsen}
117*1c12ee1eSDan Willemsen
118*1c12ee1eSDan Willemsen// unmarshalCounts counts the number of enum, message, extension, and service
119*1c12ee1eSDan Willemsen// declarations in the raw message, which is either a FileDescriptorProto
120*1c12ee1eSDan Willemsen// or a MessageDescriptorProto depending on whether isFile is set.
121*1c12ee1eSDan Willemsenfunc (db *Builder) unmarshalCounts(b []byte, isFile bool) {
122*1c12ee1eSDan Willemsen	for len(b) > 0 {
123*1c12ee1eSDan Willemsen		num, typ, n := protowire.ConsumeTag(b)
124*1c12ee1eSDan Willemsen		b = b[n:]
125*1c12ee1eSDan Willemsen		switch typ {
126*1c12ee1eSDan Willemsen		case protowire.BytesType:
127*1c12ee1eSDan Willemsen			v, m := protowire.ConsumeBytes(b)
128*1c12ee1eSDan Willemsen			b = b[m:]
129*1c12ee1eSDan Willemsen			if isFile {
130*1c12ee1eSDan Willemsen				switch num {
131*1c12ee1eSDan Willemsen				case genid.FileDescriptorProto_EnumType_field_number:
132*1c12ee1eSDan Willemsen					db.NumEnums++
133*1c12ee1eSDan Willemsen				case genid.FileDescriptorProto_MessageType_field_number:
134*1c12ee1eSDan Willemsen					db.unmarshalCounts(v, false)
135*1c12ee1eSDan Willemsen					db.NumMessages++
136*1c12ee1eSDan Willemsen				case genid.FileDescriptorProto_Extension_field_number:
137*1c12ee1eSDan Willemsen					db.NumExtensions++
138*1c12ee1eSDan Willemsen				case genid.FileDescriptorProto_Service_field_number:
139*1c12ee1eSDan Willemsen					db.NumServices++
140*1c12ee1eSDan Willemsen				}
141*1c12ee1eSDan Willemsen			} else {
142*1c12ee1eSDan Willemsen				switch num {
143*1c12ee1eSDan Willemsen				case genid.DescriptorProto_EnumType_field_number:
144*1c12ee1eSDan Willemsen					db.NumEnums++
145*1c12ee1eSDan Willemsen				case genid.DescriptorProto_NestedType_field_number:
146*1c12ee1eSDan Willemsen					db.unmarshalCounts(v, false)
147*1c12ee1eSDan Willemsen					db.NumMessages++
148*1c12ee1eSDan Willemsen				case genid.DescriptorProto_Extension_field_number:
149*1c12ee1eSDan Willemsen					db.NumExtensions++
150*1c12ee1eSDan Willemsen				}
151*1c12ee1eSDan Willemsen			}
152*1c12ee1eSDan Willemsen		default:
153*1c12ee1eSDan Willemsen			m := protowire.ConsumeFieldValue(num, typ, b)
154*1c12ee1eSDan Willemsen			b = b[m:]
155*1c12ee1eSDan Willemsen		}
156*1c12ee1eSDan Willemsen	}
157*1c12ee1eSDan Willemsen}
158