• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 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 protoregistry.GlobalTypes.FindMessageByName
102// or constructing a dynamic MessageType using dynamicpb.NewMessageType.
103//
104// • A Message is a reflective view over a concrete message instance.
105// Generated messages implement ProtoMessage, which can convert to a Message.
106// Just as how Go's reflect.Value is a reflective view over a Go value,
107// a Message is a reflective view over a concrete protobuf message instance.
108// Using Go reflection as an analogy, the ProtoReflect method is similar to
109// calling reflect.ValueOf, and the Message.Interface method is similar to
110// calling reflect.Value.Interface.
111//
112//	      ┌── TypeDescriptor() ──┐    ┌───── Descriptor() ─────┐
113//	      │                      V    │                        V
114//	╔═══════════════╗  ╔═════════════════════════╗  ╔═════════════════════╗
115//	║ ExtensionType ║  ║ ExtensionTypeDescriptor ║  ║ ExtensionDescriptor ║
116//	╚═══════════════╝  ╚═════════════════════════╝  ╚═════════════════════╝
117//	      Λ                      │   │ Λ                      │ Λ
118//	      └─────── Type() ───────┘   │ └─── may implement ────┘ │
119//	                                 │                          │
120//	                                 └────── implements ────────┘
121//
122// • An ExtensionType describes a concrete Go implementation of an extension.
123// It has an ExtensionTypeDescriptor and can convert to/from
124// abstract Values and Go values.
125//
126// • An ExtensionTypeDescriptor is an ExtensionDescriptor
127// which also has an ExtensionType.
128//
129// • An ExtensionDescriptor describes an abstract protobuf extension field and
130// may not always be an ExtensionTypeDescriptor.
131package protoreflect
132
133import (
134	"fmt"
135	"strings"
136
137	"google.golang.org/protobuf/encoding/protowire"
138	"google.golang.org/protobuf/internal/pragma"
139)
140
141type doNotImplement pragma.DoNotImplement
142
143// ProtoMessage is the top-level interface that all proto messages implement.
144// This is declared in the protoreflect package to avoid a cyclic dependency;
145// use the proto.Message type instead, which aliases this type.
146type ProtoMessage interface{ ProtoReflect() Message }
147
148// Syntax is the language version of the proto file.
149type Syntax syntax
150
151type syntax int8 // keep exact type opaque as the int type may change
152
153const (
154	Proto2 Syntax = 2
155	Proto3 Syntax = 3
156)
157
158// IsValid reports whether the syntax is valid.
159func (s Syntax) IsValid() bool {
160	switch s {
161	case Proto2, Proto3:
162		return true
163	default:
164		return false
165	}
166}
167
168// String returns s as a proto source identifier (e.g., "proto2").
169func (s Syntax) String() string {
170	switch s {
171	case Proto2:
172		return "proto2"
173	case Proto3:
174		return "proto3"
175	default:
176		return fmt.Sprintf("<unknown:%d>", s)
177	}
178}
179
180// GoString returns s as a Go source identifier (e.g., "Proto2").
181func (s Syntax) GoString() string {
182	switch s {
183	case Proto2:
184		return "Proto2"
185	case Proto3:
186		return "Proto3"
187	default:
188		return fmt.Sprintf("Syntax(%d)", s)
189	}
190}
191
192// Cardinality determines whether a field is optional, required, or repeated.
193type Cardinality cardinality
194
195type cardinality int8 // keep exact type opaque as the int type may change
196
197// Constants as defined by the google.protobuf.Cardinality enumeration.
198const (
199	Optional Cardinality = 1 // appears zero or one times
200	Required Cardinality = 2 // appears exactly one time; invalid with Proto3
201	Repeated Cardinality = 3 // appears zero or more times
202)
203
204// IsValid reports whether the cardinality is valid.
205func (c Cardinality) IsValid() bool {
206	switch c {
207	case Optional, Required, Repeated:
208		return true
209	default:
210		return false
211	}
212}
213
214// String returns c as a proto source identifier (e.g., "optional").
215func (c Cardinality) String() string {
216	switch c {
217	case Optional:
218		return "optional"
219	case Required:
220		return "required"
221	case Repeated:
222		return "repeated"
223	default:
224		return fmt.Sprintf("<unknown:%d>", c)
225	}
226}
227
228// GoString returns c as a Go source identifier (e.g., "Optional").
229func (c Cardinality) GoString() string {
230	switch c {
231	case Optional:
232		return "Optional"
233	case Required:
234		return "Required"
235	case Repeated:
236		return "Repeated"
237	default:
238		return fmt.Sprintf("Cardinality(%d)", c)
239	}
240}
241
242// Kind indicates the basic proto kind of a field.
243type Kind kind
244
245type kind int8 // keep exact type opaque as the int type may change
246
247// Constants as defined by the google.protobuf.Field.Kind enumeration.
248const (
249	BoolKind     Kind = 8
250	EnumKind     Kind = 14
251	Int32Kind    Kind = 5
252	Sint32Kind   Kind = 17
253	Uint32Kind   Kind = 13
254	Int64Kind    Kind = 3
255	Sint64Kind   Kind = 18
256	Uint64Kind   Kind = 4
257	Sfixed32Kind Kind = 15
258	Fixed32Kind  Kind = 7
259	FloatKind    Kind = 2
260	Sfixed64Kind Kind = 16
261	Fixed64Kind  Kind = 6
262	DoubleKind   Kind = 1
263	StringKind   Kind = 9
264	BytesKind    Kind = 12
265	MessageKind  Kind = 11
266	GroupKind    Kind = 10
267)
268
269// IsValid reports whether the kind is valid.
270func (k Kind) IsValid() bool {
271	switch k {
272	case BoolKind, EnumKind,
273		Int32Kind, Sint32Kind, Uint32Kind,
274		Int64Kind, Sint64Kind, Uint64Kind,
275		Sfixed32Kind, Fixed32Kind, FloatKind,
276		Sfixed64Kind, Fixed64Kind, DoubleKind,
277		StringKind, BytesKind, MessageKind, GroupKind:
278		return true
279	default:
280		return false
281	}
282}
283
284// String returns k as a proto source identifier (e.g., "bool").
285func (k Kind) String() string {
286	switch k {
287	case BoolKind:
288		return "bool"
289	case EnumKind:
290		return "enum"
291	case Int32Kind:
292		return "int32"
293	case Sint32Kind:
294		return "sint32"
295	case Uint32Kind:
296		return "uint32"
297	case Int64Kind:
298		return "int64"
299	case Sint64Kind:
300		return "sint64"
301	case Uint64Kind:
302		return "uint64"
303	case Sfixed32Kind:
304		return "sfixed32"
305	case Fixed32Kind:
306		return "fixed32"
307	case FloatKind:
308		return "float"
309	case Sfixed64Kind:
310		return "sfixed64"
311	case Fixed64Kind:
312		return "fixed64"
313	case DoubleKind:
314		return "double"
315	case StringKind:
316		return "string"
317	case BytesKind:
318		return "bytes"
319	case MessageKind:
320		return "message"
321	case GroupKind:
322		return "group"
323	default:
324		return fmt.Sprintf("<unknown:%d>", k)
325	}
326}
327
328// GoString returns k as a Go source identifier (e.g., "BoolKind").
329func (k Kind) GoString() string {
330	switch k {
331	case BoolKind:
332		return "BoolKind"
333	case EnumKind:
334		return "EnumKind"
335	case Int32Kind:
336		return "Int32Kind"
337	case Sint32Kind:
338		return "Sint32Kind"
339	case Uint32Kind:
340		return "Uint32Kind"
341	case Int64Kind:
342		return "Int64Kind"
343	case Sint64Kind:
344		return "Sint64Kind"
345	case Uint64Kind:
346		return "Uint64Kind"
347	case Sfixed32Kind:
348		return "Sfixed32Kind"
349	case Fixed32Kind:
350		return "Fixed32Kind"
351	case FloatKind:
352		return "FloatKind"
353	case Sfixed64Kind:
354		return "Sfixed64Kind"
355	case Fixed64Kind:
356		return "Fixed64Kind"
357	case DoubleKind:
358		return "DoubleKind"
359	case StringKind:
360		return "StringKind"
361	case BytesKind:
362		return "BytesKind"
363	case MessageKind:
364		return "MessageKind"
365	case GroupKind:
366		return "GroupKind"
367	default:
368		return fmt.Sprintf("Kind(%d)", k)
369	}
370}
371
372// FieldNumber is the field number in a message.
373type FieldNumber = protowire.Number
374
375// FieldNumbers represent a list of field numbers.
376type FieldNumbers interface {
377	// Len reports the number of fields in the list.
378	Len() int
379	// Get returns the ith field number. It panics if out of bounds.
380	Get(i int) FieldNumber
381	// Has reports whether n is within the list of fields.
382	Has(n FieldNumber) bool
383
384	doNotImplement
385}
386
387// FieldRanges represent a list of field number ranges.
388type FieldRanges interface {
389	// Len reports the number of ranges in the list.
390	Len() int
391	// Get returns the ith range. It panics if out of bounds.
392	Get(i int) [2]FieldNumber // start inclusive; end exclusive
393	// Has reports whether n is within any of the ranges.
394	Has(n FieldNumber) bool
395
396	doNotImplement
397}
398
399// EnumNumber is the numeric value for an enum.
400type EnumNumber int32
401
402// EnumRanges represent a list of enum number ranges.
403type EnumRanges interface {
404	// Len reports the number of ranges in the list.
405	Len() int
406	// Get returns the ith range. It panics if out of bounds.
407	Get(i int) [2]EnumNumber // start inclusive; end inclusive
408	// Has reports whether n is within any of the ranges.
409	Has(n EnumNumber) bool
410
411	doNotImplement
412}
413
414// Name is the short name for a proto declaration. This is not the name
415// as used in Go source code, which might not be identical to the proto name.
416type Name string // e.g., "Kind"
417
418// IsValid reports whether s is a syntactically valid name.
419// An empty name is invalid.
420func (s Name) IsValid() bool {
421	return consumeIdent(string(s)) == len(s)
422}
423
424// Names represent a list of names.
425type Names interface {
426	// Len reports the number of names in the list.
427	Len() int
428	// Get returns the ith name. It panics if out of bounds.
429	Get(i int) Name
430	// Has reports whether s matches any names in the list.
431	Has(s Name) bool
432
433	doNotImplement
434}
435
436// FullName is a qualified name that uniquely identifies a proto declaration.
437// A qualified name is the concatenation of the proto package along with the
438// fully-declared name (i.e., name of parent preceding the name of the child),
439// with a '.' delimiter placed between each Name.
440//
441// This should not have any leading or trailing dots.
442type FullName string // e.g., "google.protobuf.Field.Kind"
443
444// IsValid reports whether s is a syntactically valid full name.
445// An empty full name is invalid.
446func (s FullName) IsValid() bool {
447	i := consumeIdent(string(s))
448	if i < 0 {
449		return false
450	}
451	for len(s) > i {
452		if s[i] != '.' {
453			return false
454		}
455		i++
456		n := consumeIdent(string(s[i:]))
457		if n < 0 {
458			return false
459		}
460		i += n
461	}
462	return true
463}
464
465func consumeIdent(s string) (i int) {
466	if len(s) == 0 || !isLetter(s[i]) {
467		return -1
468	}
469	i++
470	for len(s) > i && isLetterDigit(s[i]) {
471		i++
472	}
473	return i
474}
475func isLetter(c byte) bool {
476	return c == '_' || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')
477}
478func isLetterDigit(c byte) bool {
479	return isLetter(c) || ('0' <= c && c <= '9')
480}
481
482// Name returns the short name, which is the last identifier segment.
483// A single segment FullName is the Name itself.
484func (n FullName) Name() Name {
485	if i := strings.LastIndexByte(string(n), '.'); i >= 0 {
486		return Name(n[i+1:])
487	}
488	return Name(n)
489}
490
491// Parent returns the full name with the trailing identifier removed.
492// A single segment FullName has no parent.
493func (n FullName) Parent() FullName {
494	if i := strings.LastIndexByte(string(n), '.'); i >= 0 {
495		return n[:i]
496	}
497	return ""
498}
499
500// Append returns the qualified name appended with the provided short name.
501//
502// Invariant: n == n.Parent().Append(n.Name()) // assuming n is valid
503func (n FullName) Append(s Name) FullName {
504	if n == "" {
505		return FullName(s)
506	}
507	return n + "." + FullName(s)
508}
509