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// 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} 505