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