123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513 |
- // Copyright 2018 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 protoreflect provides interfaces to dynamically manipulate messages.
- //
- // This package includes type descriptors which describe the structure of types
- // defined in proto source files and value interfaces which provide the
- // ability to examine and manipulate the contents of messages.
- //
- // # Protocol Buffer Descriptors
- //
- // Protobuf descriptors (e.g., [EnumDescriptor] or [MessageDescriptor])
- // are immutable objects that represent protobuf type information.
- // They are wrappers around the messages declared in descriptor.proto.
- // Protobuf descriptors alone lack any information regarding Go types.
- //
- // Enums and messages generated by this module implement [Enum] and [ProtoMessage],
- // where the Descriptor and ProtoReflect.Descriptor accessors respectively
- // return the protobuf descriptor for the values.
- //
- // The protobuf descriptor interfaces are not meant to be implemented by
- // user code since they might need to be extended in the future to support
- // additions to the protobuf language.
- // The [google.golang.org/protobuf/reflect/protodesc] package converts between
- // google.protobuf.DescriptorProto messages and protobuf descriptors.
- //
- // # Go Type Descriptors
- //
- // A type descriptor (e.g., [EnumType] or [MessageType]) is a constructor for
- // a concrete Go type that represents the associated protobuf descriptor.
- // There is commonly a one-to-one relationship between protobuf descriptors and
- // Go type descriptors, but it can potentially be a one-to-many relationship.
- //
- // Enums and messages generated by this module implement [Enum] and [ProtoMessage],
- // where the Type and ProtoReflect.Type accessors respectively
- // return the protobuf descriptor for the values.
- //
- // The [google.golang.org/protobuf/types/dynamicpb] package can be used to
- // create Go type descriptors from protobuf descriptors.
- //
- // # Value Interfaces
- //
- // The [Enum] and [Message] interfaces provide a reflective view over an
- // enum or message instance. For enums, it provides the ability to retrieve
- // the enum value number for any concrete enum type. For messages, it provides
- // the ability to access or manipulate fields of the message.
- //
- // To convert a [google.golang.org/protobuf/proto.Message] to a [protoreflect.Message], use the
- // former's ProtoReflect method. Since the ProtoReflect method is new to the
- // v2 message interface, it may not be present on older message implementations.
- // The [github.com/golang/protobuf/proto.MessageReflect] function can be used
- // to obtain a reflective view on older messages.
- //
- // # Relationships
- //
- // The following diagrams demonstrate the relationships between
- // various types declared in this package.
- //
- // ┌───────────────────────────────────┐
- // V │
- // ┌────────────── New(n) ─────────────┐ │
- // │ │ │
- // │ ┌──── Descriptor() ──┐ │ ┌── Number() ──┐ │
- // │ │ V V │ V │
- // ╔════════════╗ ╔════════════════╗ ╔════════╗ ╔════════════╗
- // ║ EnumType ║ ║ EnumDescriptor ║ ║ Enum ║ ║ EnumNumber ║
- // ╚════════════╝ ╚════════════════╝ ╚════════╝ ╚════════════╝
- // Λ Λ │ │
- // │ └─── Descriptor() ──┘ │
- // │ │
- // └────────────────── Type() ───────┘
- //
- // • An [EnumType] describes a concrete Go enum type.
- // It has an EnumDescriptor and can construct an Enum instance.
- //
- // • An [EnumDescriptor] describes an abstract protobuf enum type.
- //
- // • An [Enum] is a concrete enum instance. Generated enums implement Enum.
- //
- // ┌──────────────── New() ─────────────────┐
- // │ │
- // │ ┌─── Descriptor() ─────┐ │ ┌── Interface() ───┐
- // │ │ V V │ V
- // ╔═════════════╗ ╔═══════════════════╗ ╔═════════╗ ╔══════════════╗
- // ║ MessageType ║ ║ MessageDescriptor ║ ║ Message ║ ║ ProtoMessage ║
- // ╚═════════════╝ ╚═══════════════════╝ ╚═════════╝ ╚══════════════╝
- // Λ Λ │ │ Λ │
- // │ └──── Descriptor() ────┘ │ └─ ProtoReflect() ─┘
- // │ │
- // └─────────────────── Type() ─────────┘
- //
- // • A [MessageType] describes a concrete Go message type.
- // It has a [MessageDescriptor] and can construct a [Message] instance.
- // Just as how Go's [reflect.Type] is a reflective description of a Go type,
- // a [MessageType] is a reflective description of a Go type for a protobuf message.
- //
- // • A [MessageDescriptor] describes an abstract protobuf message type.
- // It has no understanding of Go types. In order to construct a [MessageType]
- // from just a [MessageDescriptor], you can consider looking up the message type
- // in the global registry using the FindMessageByName method on
- // [google.golang.org/protobuf/reflect/protoregistry.GlobalTypes]
- // or constructing a dynamic [MessageType] using
- // [google.golang.org/protobuf/types/dynamicpb.NewMessageType].
- //
- // • A [Message] is a reflective view over a concrete message instance.
- // Generated messages implement [ProtoMessage], which can convert to a [Message].
- // Just as how Go's [reflect.Value] is a reflective view over a Go value,
- // a [Message] is a reflective view over a concrete protobuf message instance.
- // Using Go reflection as an analogy, the [ProtoMessage.ProtoReflect] method is similar to
- // calling [reflect.ValueOf], and the [Message.Interface] method is similar to
- // calling [reflect.Value.Interface].
- //
- // ┌── TypeDescriptor() ──┐ ┌───── Descriptor() ─────┐
- // │ V │ V
- // ╔═══════════════╗ ╔═════════════════════════╗ ╔═════════════════════╗
- // ║ ExtensionType ║ ║ ExtensionTypeDescriptor ║ ║ ExtensionDescriptor ║
- // ╚═══════════════╝ ╚═════════════════════════╝ ╚═════════════════════╝
- // Λ │ │ Λ │ Λ
- // └─────── Type() ───────┘ │ └─── may implement ────┘ │
- // │ │
- // └────── implements ────────┘
- //
- // • An [ExtensionType] describes a concrete Go implementation of an extension.
- // It has an [ExtensionTypeDescriptor] and can convert to/from
- // an abstract [Value] and a Go value.
- //
- // • An [ExtensionTypeDescriptor] is an [ExtensionDescriptor]
- // which also has an [ExtensionType].
- //
- // • An [ExtensionDescriptor] describes an abstract protobuf extension field and
- // may not always be an [ExtensionTypeDescriptor].
- package protoreflect
- import (
- "fmt"
- "strings"
- "google.golang.org/protobuf/encoding/protowire"
- "google.golang.org/protobuf/internal/pragma"
- )
- type doNotImplement pragma.DoNotImplement
- // ProtoMessage is the top-level interface that all proto messages implement.
- // This is declared in the protoreflect package to avoid a cyclic dependency;
- // use the [google.golang.org/protobuf/proto.Message] type instead, which aliases this type.
- type ProtoMessage interface{ ProtoReflect() Message }
- // Syntax is the language version of the proto file.
- type Syntax syntax
- type syntax int8 // keep exact type opaque as the int type may change
- const (
- Proto2 Syntax = 2
- Proto3 Syntax = 3
- Editions Syntax = 4
- )
- // IsValid reports whether the syntax is valid.
- func (s Syntax) IsValid() bool {
- switch s {
- case Proto2, Proto3:
- return true
- default:
- return false
- }
- }
- // String returns s as a proto source identifier (e.g., "proto2").
- func (s Syntax) String() string {
- switch s {
- case Proto2:
- return "proto2"
- case Proto3:
- return "proto3"
- case Editions:
- return "editions"
- default:
- return fmt.Sprintf("<unknown:%d>", s)
- }
- }
- // GoString returns s as a Go source identifier (e.g., "Proto2").
- func (s Syntax) GoString() string {
- switch s {
- case Proto2:
- return "Proto2"
- case Proto3:
- return "Proto3"
- default:
- return fmt.Sprintf("Syntax(%d)", s)
- }
- }
- // Cardinality determines whether a field is optional, required, or repeated.
- type Cardinality cardinality
- type cardinality int8 // keep exact type opaque as the int type may change
- // Constants as defined by the google.protobuf.Cardinality enumeration.
- const (
- Optional Cardinality = 1 // appears zero or one times
- Required Cardinality = 2 // appears exactly one time; invalid with Proto3
- Repeated Cardinality = 3 // appears zero or more times
- )
- // IsValid reports whether the cardinality is valid.
- func (c Cardinality) IsValid() bool {
- switch c {
- case Optional, Required, Repeated:
- return true
- default:
- return false
- }
- }
- // String returns c as a proto source identifier (e.g., "optional").
- func (c Cardinality) String() string {
- switch c {
- case Optional:
- return "optional"
- case Required:
- return "required"
- case Repeated:
- return "repeated"
- default:
- return fmt.Sprintf("<unknown:%d>", c)
- }
- }
- // GoString returns c as a Go source identifier (e.g., "Optional").
- func (c Cardinality) GoString() string {
- switch c {
- case Optional:
- return "Optional"
- case Required:
- return "Required"
- case Repeated:
- return "Repeated"
- default:
- return fmt.Sprintf("Cardinality(%d)", c)
- }
- }
- // Kind indicates the basic proto kind of a field.
- type Kind kind
- type kind int8 // keep exact type opaque as the int type may change
- // Constants as defined by the google.protobuf.Field.Kind enumeration.
- const (
- BoolKind Kind = 8
- EnumKind Kind = 14
- Int32Kind Kind = 5
- Sint32Kind Kind = 17
- Uint32Kind Kind = 13
- Int64Kind Kind = 3
- Sint64Kind Kind = 18
- Uint64Kind Kind = 4
- Sfixed32Kind Kind = 15
- Fixed32Kind Kind = 7
- FloatKind Kind = 2
- Sfixed64Kind Kind = 16
- Fixed64Kind Kind = 6
- DoubleKind Kind = 1
- StringKind Kind = 9
- BytesKind Kind = 12
- MessageKind Kind = 11
- GroupKind Kind = 10
- )
- // IsValid reports whether the kind is valid.
- func (k Kind) IsValid() bool {
- switch k {
- case BoolKind, EnumKind,
- Int32Kind, Sint32Kind, Uint32Kind,
- Int64Kind, Sint64Kind, Uint64Kind,
- Sfixed32Kind, Fixed32Kind, FloatKind,
- Sfixed64Kind, Fixed64Kind, DoubleKind,
- StringKind, BytesKind, MessageKind, GroupKind:
- return true
- default:
- return false
- }
- }
- // String returns k as a proto source identifier (e.g., "bool").
- func (k Kind) String() string {
- switch k {
- case BoolKind:
- return "bool"
- case EnumKind:
- return "enum"
- case Int32Kind:
- return "int32"
- case Sint32Kind:
- return "sint32"
- case Uint32Kind:
- return "uint32"
- case Int64Kind:
- return "int64"
- case Sint64Kind:
- return "sint64"
- case Uint64Kind:
- return "uint64"
- case Sfixed32Kind:
- return "sfixed32"
- case Fixed32Kind:
- return "fixed32"
- case FloatKind:
- return "float"
- case Sfixed64Kind:
- return "sfixed64"
- case Fixed64Kind:
- return "fixed64"
- case DoubleKind:
- return "double"
- case StringKind:
- return "string"
- case BytesKind:
- return "bytes"
- case MessageKind:
- return "message"
- case GroupKind:
- return "group"
- default:
- return fmt.Sprintf("<unknown:%d>", k)
- }
- }
- // GoString returns k as a Go source identifier (e.g., "BoolKind").
- func (k Kind) GoString() string {
- switch k {
- case BoolKind:
- return "BoolKind"
- case EnumKind:
- return "EnumKind"
- case Int32Kind:
- return "Int32Kind"
- case Sint32Kind:
- return "Sint32Kind"
- case Uint32Kind:
- return "Uint32Kind"
- case Int64Kind:
- return "Int64Kind"
- case Sint64Kind:
- return "Sint64Kind"
- case Uint64Kind:
- return "Uint64Kind"
- case Sfixed32Kind:
- return "Sfixed32Kind"
- case Fixed32Kind:
- return "Fixed32Kind"
- case FloatKind:
- return "FloatKind"
- case Sfixed64Kind:
- return "Sfixed64Kind"
- case Fixed64Kind:
- return "Fixed64Kind"
- case DoubleKind:
- return "DoubleKind"
- case StringKind:
- return "StringKind"
- case BytesKind:
- return "BytesKind"
- case MessageKind:
- return "MessageKind"
- case GroupKind:
- return "GroupKind"
- default:
- return fmt.Sprintf("Kind(%d)", k)
- }
- }
- // FieldNumber is the field number in a message.
- type FieldNumber = protowire.Number
- // FieldNumbers represent a list of field numbers.
- type FieldNumbers interface {
- // Len reports the number of fields in the list.
- Len() int
- // Get returns the ith field number. It panics if out of bounds.
- Get(i int) FieldNumber
- // Has reports whether n is within the list of fields.
- Has(n FieldNumber) bool
- doNotImplement
- }
- // FieldRanges represent a list of field number ranges.
- type FieldRanges interface {
- // Len reports the number of ranges in the list.
- Len() int
- // Get returns the ith range. It panics if out of bounds.
- Get(i int) [2]FieldNumber // start inclusive; end exclusive
- // Has reports whether n is within any of the ranges.
- Has(n FieldNumber) bool
- doNotImplement
- }
- // EnumNumber is the numeric value for an enum.
- type EnumNumber int32
- // EnumRanges represent a list of enum number ranges.
- type EnumRanges interface {
- // Len reports the number of ranges in the list.
- Len() int
- // Get returns the ith range. It panics if out of bounds.
- Get(i int) [2]EnumNumber // start inclusive; end inclusive
- // Has reports whether n is within any of the ranges.
- Has(n EnumNumber) bool
- doNotImplement
- }
- // Name is the short name for a proto declaration. This is not the name
- // as used in Go source code, which might not be identical to the proto name.
- type Name string // e.g., "Kind"
- // IsValid reports whether s is a syntactically valid name.
- // An empty name is invalid.
- func (s Name) IsValid() bool {
- return consumeIdent(string(s)) == len(s)
- }
- // Names represent a list of names.
- type Names interface {
- // Len reports the number of names in the list.
- Len() int
- // Get returns the ith name. It panics if out of bounds.
- Get(i int) Name
- // Has reports whether s matches any names in the list.
- Has(s Name) bool
- doNotImplement
- }
- // FullName is a qualified name that uniquely identifies a proto declaration.
- // A qualified name is the concatenation of the proto package along with the
- // fully-declared name (i.e., name of parent preceding the name of the child),
- // with a '.' delimiter placed between each [Name].
- //
- // This should not have any leading or trailing dots.
- type FullName string // e.g., "google.protobuf.Field.Kind"
- // IsValid reports whether s is a syntactically valid full name.
- // An empty full name is invalid.
- func (s FullName) IsValid() bool {
- i := consumeIdent(string(s))
- if i < 0 {
- return false
- }
- for len(s) > i {
- if s[i] != '.' {
- return false
- }
- i++
- n := consumeIdent(string(s[i:]))
- if n < 0 {
- return false
- }
- i += n
- }
- return true
- }
- func consumeIdent(s string) (i int) {
- if len(s) == 0 || !isLetter(s[i]) {
- return -1
- }
- i++
- for len(s) > i && isLetterDigit(s[i]) {
- i++
- }
- return i
- }
- func isLetter(c byte) bool {
- return c == '_' || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')
- }
- func isLetterDigit(c byte) bool {
- return isLetter(c) || ('0' <= c && c <= '9')
- }
- // Name returns the short name, which is the last identifier segment.
- // A single segment FullName is the [Name] itself.
- func (n FullName) Name() Name {
- if i := strings.LastIndexByte(string(n), '.'); i >= 0 {
- return Name(n[i+1:])
- }
- return Name(n)
- }
- // Parent returns the full name with the trailing identifier removed.
- // A single segment FullName has no parent.
- func (n FullName) Parent() FullName {
- if i := strings.LastIndexByte(string(n), '.'); i >= 0 {
- return n[:i]
- }
- return ""
- }
- // Append returns the qualified name appended with the provided short name.
- //
- // Invariant: n == n.Parent().Append(n.Name()) // assuming n is valid
- func (n FullName) Append(s Name) FullName {
- if n == "" {
- return FullName(s)
- }
- return n + "." + FullName(s)
- }
|