blob: dd85915bd4bfb502184551ec8250a69246c56c50 [file] [log] [blame]
David K. Bainbridgee05cf0c2021-08-19 03:16:50 +00001// Copyright 2018 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// Package protoreflect provides interfaces to dynamically manipulate messages.
6//
7// This package includes type descriptors which describe the structure of types
8// defined in proto source files and value interfaces which provide the
9// ability to examine and manipulate the contents of messages.
10//
11//
12// Protocol Buffer Descriptors
13//
14// Protobuf descriptors (e.g., EnumDescriptor or MessageDescriptor)
15// are immutable objects that represent protobuf type information.
16// They are wrappers around the messages declared in descriptor.proto.
17// Protobuf descriptors alone lack any information regarding Go types.
18//
19// Enums and messages generated by this module implement Enum and ProtoMessage,
20// where the Descriptor and ProtoReflect.Descriptor accessors respectively
21// return the protobuf descriptor for the values.
22//
23// The protobuf descriptor interfaces are not meant to be implemented by
24// user code since they might need to be extended in the future to support
25// additions to the protobuf language.
26// The "google.golang.org/protobuf/reflect/protodesc" package converts between
27// google.protobuf.DescriptorProto messages and protobuf descriptors.
28//
29//
30// Go Type Descriptors
31//
32// A type descriptor (e.g., EnumType or MessageType) is a constructor for
33// a concrete Go type that represents the associated protobuf descriptor.
34// There is commonly a one-to-one relationship between protobuf descriptors and
35// Go type descriptors, but it can potentially be a one-to-many relationship.
36//
37// Enums and messages generated by this module implement Enum and ProtoMessage,
38// where the Type and ProtoReflect.Type accessors respectively
39// return the protobuf descriptor for the values.
40//
41// The "google.golang.org/protobuf/types/dynamicpb" package can be used to
42// create Go type descriptors from protobuf descriptors.
43//
44//
45// Value Interfaces
46//
47// The Enum and Message interfaces provide a reflective view over an
48// enum or message instance. For enums, it provides the ability to retrieve
49// the enum value number for any concrete enum type. For messages, it provides
50// the ability to access or manipulate fields of the message.
51//
52// To convert a proto.Message to a protoreflect.Message, use the
53// former's ProtoReflect method. Since the ProtoReflect method is new to the
54// v2 message interface, it may not be present on older message implementations.
55// The "github.com/golang/protobuf/proto".MessageReflect function can be used
56// to obtain a reflective view on older messages.
57//
58//
59// Relationships
60//
61// The following diagrams demonstrate the relationships between
62// various types declared in this package.
63//
64//
65// ┌───────────────────────────────────┐
66// V │
67// ┌────────────── New(n) ─────────────┐ │
68// │ │ │
69// │ ┌──── Descriptor() ──┐ │ ┌── Number() ──┐ │
70// │ │ V V │ V │
71// ╔════════════╗ ╔════════════════╗ ╔════════╗ ╔════════════╗
72// ║ EnumType ║ ║ EnumDescriptor ║ ║ Enum ║ ║ EnumNumber ║
73// ╚════════════╝ ╚════════════════╝ ╚════════╝ ╚════════════╝
74// Λ Λ │ │
75// │ └─── Descriptor() ──┘ │
76// │ │
77// └────────────────── Type() ───────┘
78//
79// • An EnumType describes a concrete Go enum type.
80// It has an EnumDescriptor and can construct an Enum instance.
81//
82// • An EnumDescriptor describes an abstract protobuf enum type.
83//
84// • An Enum is a concrete enum instance. Generated enums implement Enum.
85//
86//
87// ┌──────────────── New() ─────────────────┐
88// │ │
89// │ ┌─── Descriptor() ─────┐ │ ┌── Interface() ───┐
90// │ │ V V │ V
91// ╔═════════════╗ ╔═══════════════════╗ ╔═════════╗ ╔══════════════╗
92// ║ MessageType ║ ║ MessageDescriptor ║ ║ Message ║ ║ ProtoMessage ║
93// ╚═════════════╝ ╚═══════════════════╝ ╚═════════╝ ╚══════════════╝
94// Λ Λ │ │ Λ │
95// │ └──── Descriptor() ────┘ │ └─ ProtoReflect() ─┘
96// │ │
97// └─────────────────── Type() ─────────┘
98//
99// • A MessageType describes a concrete Go message type.
100// It has a MessageDescriptor and can construct a Message instance.
101//
102// • A MessageDescriptor describes an abstract protobuf message type.
103//
104// • A Message is a concrete message instance. Generated messages implement
105// ProtoMessage, which can convert to/from a Message.
106//
107//
108// ┌── TypeDescriptor() ──┐ ┌───── Descriptor() ─────┐
109// │ V │ V
110// ╔═══════════════╗ ╔═════════════════════════╗ ╔═════════════════════╗
111// ║ ExtensionType ║ ║ ExtensionTypeDescriptor ║ ║ ExtensionDescriptor ║
112// ╚═══════════════╝ ╚═════════════════════════╝ ╚═════════════════════╝
113// Λ │ │ Λ │ Λ
114// └─────── Type() ───────┘ │ └─── may implement ────┘ │
115// │ │
116// └────── implements ────────┘
117//
118// • An ExtensionType describes a concrete Go implementation of an extension.
119// It has an ExtensionTypeDescriptor and can convert to/from
120// abstract Values and Go values.
121//
122// • An ExtensionTypeDescriptor is an ExtensionDescriptor
123// which also has an ExtensionType.
124//
125// • An ExtensionDescriptor describes an abstract protobuf extension field and
126// may not always be an ExtensionTypeDescriptor.
127package protoreflect
128
129import (
130 "fmt"
131 "strings"
132
133 "google.golang.org/protobuf/encoding/protowire"
134 "google.golang.org/protobuf/internal/pragma"
135)
136
137type doNotImplement pragma.DoNotImplement
138
139// ProtoMessage is the top-level interface that all proto messages implement.
140// This is declared in the protoreflect package to avoid a cyclic dependency;
141// use the proto.Message type instead, which aliases this type.
142type ProtoMessage interface{ ProtoReflect() Message }
143
144// Syntax is the language version of the proto file.
145type Syntax syntax
146
147type syntax int8 // keep exact type opaque as the int type may change
148
149const (
150 Proto2 Syntax = 2
151 Proto3 Syntax = 3
152)
153
154// IsValid reports whether the syntax is valid.
155func (s Syntax) IsValid() bool {
156 switch s {
157 case Proto2, Proto3:
158 return true
159 default:
160 return false
161 }
162}
163
164// String returns s as a proto source identifier (e.g., "proto2").
165func (s Syntax) String() string {
166 switch s {
167 case Proto2:
168 return "proto2"
169 case Proto3:
170 return "proto3"
171 default:
172 return fmt.Sprintf("<unknown:%d>", s)
173 }
174}
175
176// GoString returns s as a Go source identifier (e.g., "Proto2").
177func (s Syntax) GoString() string {
178 switch s {
179 case Proto2:
180 return "Proto2"
181 case Proto3:
182 return "Proto3"
183 default:
184 return fmt.Sprintf("Syntax(%d)", s)
185 }
186}
187
188// Cardinality determines whether a field is optional, required, or repeated.
189type Cardinality cardinality
190
191type cardinality int8 // keep exact type opaque as the int type may change
192
193// Constants as defined by the google.protobuf.Cardinality enumeration.
194const (
195 Optional Cardinality = 1 // appears zero or one times
196 Required Cardinality = 2 // appears exactly one time; invalid with Proto3
197 Repeated Cardinality = 3 // appears zero or more times
198)
199
200// IsValid reports whether the cardinality is valid.
201func (c Cardinality) IsValid() bool {
202 switch c {
203 case Optional, Required, Repeated:
204 return true
205 default:
206 return false
207 }
208}
209
210// String returns c as a proto source identifier (e.g., "optional").
211func (c Cardinality) String() string {
212 switch c {
213 case Optional:
214 return "optional"
215 case Required:
216 return "required"
217 case Repeated:
218 return "repeated"
219 default:
220 return fmt.Sprintf("<unknown:%d>", c)
221 }
222}
223
224// GoString returns c as a Go source identifier (e.g., "Optional").
225func (c Cardinality) GoString() string {
226 switch c {
227 case Optional:
228 return "Optional"
229 case Required:
230 return "Required"
231 case Repeated:
232 return "Repeated"
233 default:
234 return fmt.Sprintf("Cardinality(%d)", c)
235 }
236}
237
238// Kind indicates the basic proto kind of a field.
239type Kind kind
240
241type kind int8 // keep exact type opaque as the int type may change
242
243// Constants as defined by the google.protobuf.Field.Kind enumeration.
244const (
245 BoolKind Kind = 8
246 EnumKind Kind = 14
247 Int32Kind Kind = 5
248 Sint32Kind Kind = 17
249 Uint32Kind Kind = 13
250 Int64Kind Kind = 3
251 Sint64Kind Kind = 18
252 Uint64Kind Kind = 4
253 Sfixed32Kind Kind = 15
254 Fixed32Kind Kind = 7
255 FloatKind Kind = 2
256 Sfixed64Kind Kind = 16
257 Fixed64Kind Kind = 6
258 DoubleKind Kind = 1
259 StringKind Kind = 9
260 BytesKind Kind = 12
261 MessageKind Kind = 11
262 GroupKind Kind = 10
263)
264
265// IsValid reports whether the kind is valid.
266func (k Kind) IsValid() bool {
267 switch k {
268 case BoolKind, EnumKind,
269 Int32Kind, Sint32Kind, Uint32Kind,
270 Int64Kind, Sint64Kind, Uint64Kind,
271 Sfixed32Kind, Fixed32Kind, FloatKind,
272 Sfixed64Kind, Fixed64Kind, DoubleKind,
273 StringKind, BytesKind, MessageKind, GroupKind:
274 return true
275 default:
276 return false
277 }
278}
279
280// String returns k as a proto source identifier (e.g., "bool").
281func (k Kind) String() string {
282 switch k {
283 case BoolKind:
284 return "bool"
285 case EnumKind:
286 return "enum"
287 case Int32Kind:
288 return "int32"
289 case Sint32Kind:
290 return "sint32"
291 case Uint32Kind:
292 return "uint32"
293 case Int64Kind:
294 return "int64"
295 case Sint64Kind:
296 return "sint64"
297 case Uint64Kind:
298 return "uint64"
299 case Sfixed32Kind:
300 return "sfixed32"
301 case Fixed32Kind:
302 return "fixed32"
303 case FloatKind:
304 return "float"
305 case Sfixed64Kind:
306 return "sfixed64"
307 case Fixed64Kind:
308 return "fixed64"
309 case DoubleKind:
310 return "double"
311 case StringKind:
312 return "string"
313 case BytesKind:
314 return "bytes"
315 case MessageKind:
316 return "message"
317 case GroupKind:
318 return "group"
319 default:
320 return fmt.Sprintf("<unknown:%d>", k)
321 }
322}
323
324// GoString returns k as a Go source identifier (e.g., "BoolKind").
325func (k Kind) GoString() string {
326 switch k {
327 case BoolKind:
328 return "BoolKind"
329 case EnumKind:
330 return "EnumKind"
331 case Int32Kind:
332 return "Int32Kind"
333 case Sint32Kind:
334 return "Sint32Kind"
335 case Uint32Kind:
336 return "Uint32Kind"
337 case Int64Kind:
338 return "Int64Kind"
339 case Sint64Kind:
340 return "Sint64Kind"
341 case Uint64Kind:
342 return "Uint64Kind"
343 case Sfixed32Kind:
344 return "Sfixed32Kind"
345 case Fixed32Kind:
346 return "Fixed32Kind"
347 case FloatKind:
348 return "FloatKind"
349 case Sfixed64Kind:
350 return "Sfixed64Kind"
351 case Fixed64Kind:
352 return "Fixed64Kind"
353 case DoubleKind:
354 return "DoubleKind"
355 case StringKind:
356 return "StringKind"
357 case BytesKind:
358 return "BytesKind"
359 case MessageKind:
360 return "MessageKind"
361 case GroupKind:
362 return "GroupKind"
363 default:
364 return fmt.Sprintf("Kind(%d)", k)
365 }
366}
367
368// FieldNumber is the field number in a message.
369type FieldNumber = protowire.Number
370
371// FieldNumbers represent a list of field numbers.
372type FieldNumbers interface {
373 // Len reports the number of fields in the list.
374 Len() int
375 // Get returns the ith field number. It panics if out of bounds.
376 Get(i int) FieldNumber
377 // Has reports whether n is within the list of fields.
378 Has(n FieldNumber) bool
379
380 doNotImplement
381}
382
383// FieldRanges represent a list of field number ranges.
384type FieldRanges interface {
385 // Len reports the number of ranges in the list.
386 Len() int
387 // Get returns the ith range. It panics if out of bounds.
388 Get(i int) [2]FieldNumber // start inclusive; end exclusive
389 // Has reports whether n is within any of the ranges.
390 Has(n FieldNumber) bool
391
392 doNotImplement
393}
394
395// EnumNumber is the numeric value for an enum.
396type EnumNumber int32
397
398// EnumRanges represent a list of enum number ranges.
399type EnumRanges interface {
400 // Len reports the number of ranges in the list.
401 Len() int
402 // Get returns the ith range. It panics if out of bounds.
403 Get(i int) [2]EnumNumber // start inclusive; end inclusive
404 // Has reports whether n is within any of the ranges.
405 Has(n EnumNumber) bool
406
407 doNotImplement
408}
409
410// Name is the short name for a proto declaration. This is not the name
411// as used in Go source code, which might not be identical to the proto name.
412type Name string // e.g., "Kind"
413
414// IsValid reports whether s is a syntactically valid name.
415// An empty name is invalid.
416func (s Name) IsValid() bool {
417 return consumeIdent(string(s)) == len(s)
418}
419
420// Names represent a list of names.
421type Names interface {
422 // Len reports the number of names in the list.
423 Len() int
424 // Get returns the ith name. It panics if out of bounds.
425 Get(i int) Name
426 // Has reports whether s matches any names in the list.
427 Has(s Name) bool
428
429 doNotImplement
430}
431
432// FullName is a qualified name that uniquely identifies a proto declaration.
433// A qualified name is the concatenation of the proto package along with the
434// fully-declared name (i.e., name of parent preceding the name of the child),
435// with a '.' delimiter placed between each Name.
436//
437// This should not have any leading or trailing dots.
438type FullName string // e.g., "google.protobuf.Field.Kind"
439
440// IsValid reports whether s is a syntactically valid full name.
441// An empty full name is invalid.
442func (s FullName) IsValid() bool {
443 i := consumeIdent(string(s))
444 if i < 0 {
445 return false
446 }
447 for len(s) > i {
448 if s[i] != '.' {
449 return false
450 }
451 i++
452 n := consumeIdent(string(s[i:]))
453 if n < 0 {
454 return false
455 }
456 i += n
457 }
458 return true
459}
460
461func consumeIdent(s string) (i int) {
462 if len(s) == 0 || !isLetter(s[i]) {
463 return -1
464 }
465 i++
466 for len(s) > i && isLetterDigit(s[i]) {
467 i++
468 }
469 return i
470}
471func isLetter(c byte) bool {
472 return c == '_' || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')
473}
474func isLetterDigit(c byte) bool {
475 return isLetter(c) || ('0' <= c && c <= '9')
476}
477
478// Name returns the short name, which is the last identifier segment.
479// A single segment FullName is the Name itself.
480func (n FullName) Name() Name {
481 if i := strings.LastIndexByte(string(n), '.'); i >= 0 {
482 return Name(n[i+1:])
483 }
484 return Name(n)
485}
486
487// Parent returns the full name with the trailing identifier removed.
488// A single segment FullName has no parent.
489func (n FullName) Parent() FullName {
490 if i := strings.LastIndexByte(string(n), '.'); i >= 0 {
491 return n[:i]
492 }
493 return ""
494}
495
496// Append returns the qualified name appended with the provided short name.
497//
498// Invariant: n == n.Parent().Append(n.Name()) // assuming n is valid
499func (n FullName) Append(s Name) FullName {
500 if n == "" {
501 return FullName(s)
502 }
503 return n + "." + FullName(s)
504}