Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

minimal support v2 messages in *dynamic.Message #533

Merged
merged 3 commits into from Sep 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
100 changes: 47 additions & 53 deletions desc/builder/doc.go
Expand Up @@ -3,8 +3,7 @@
// new descriptors as are there methods for converting existing descriptors into
// builders, for modification.
//
//
// Factory Functions
// # Factory Functions
//
// Builders are created using the numerous factory functions. Each type of
// descriptor has two kinds of factory functions for the corresponding type of
Expand All @@ -26,8 +25,7 @@
// nil values for required fields (such as field types, RPC method types, and
// extendee type for extensions).
//
//
// Auto-Assigning Tag Numbers and File Names
// # Auto-Assigning Tag Numbers and File Names
//
// The factory function for fields does not accept a tag number. This is because
// tags, for fields where none is set or is explicitly set to zero, are
Expand All @@ -48,8 +46,7 @@
// can have their tags auto-assigned. If an extension is constructed with a zero
// tag (which is not valid), the factory function will panic.
//
//
// Descriptor Hierarchy
// # Descriptor Hierarchy
//
// The hierarchy for builders is mutable. A descriptor builder, such as a field,
// can be moved from one message to another. When this is done, the field is
Expand All @@ -59,10 +56,10 @@
// can simply be copied. This allows for copying a descriptor from one parent to
// another, like so:
//
// msg := builder.FromMessage(someMsgDesc)
// field1 := msg.GetField("foo")
// field2 := *field1 // field2 is now a copy
// otherMsg.AddField(&field2)
// msg := builder.FromMessage(someMsgDesc)
// field1 := msg.GetField("foo")
// field2 := *field1 // field2 is now a copy
// otherMsg.AddField(&field2)
//
// All descriptors have a link up the hierarchy to the file in which they were
// declared. However, it is *not* necessary to construct this full hierarchy
Expand All @@ -80,22 +77,21 @@
// unnamed) package. In order to put descriptors into a proper package
// namespace, they must be added to a file that has the right package name.
//
//
// Builder Pattern and Method Chaining
// # Builder Pattern and Method Chaining
//
// Each descriptor has some special fields that can only be updated via a Set*
// method. They also all have some exported fields that can be updated by just
// assigning to the field. But even exported fields have accompanying Set*
// methods in order to support a typical method-chaining flow when building
// objects:
//
// msg, err := builder.NewMessage("MyMessage").
// AddField(NewField("foo", FieldTypeScalar(descriptor.FieldDescriptorProto_TYPE_STRING)).
// SetDefaultValue("bar")).
// AddField(NewField("baz", FieldTypeScalar(descriptor.FieldDescriptorProto_TYPE_INT64)).
// SetLabel(descriptor.FieldDescriptorProto_LABEL_REPEATED).
// SetOptions(&descriptor.FieldOptions{Packed: proto.Bool(true)})).
// Build()
// msg, err := builder.NewMessage("MyMessage").
// AddField(NewField("foo", FieldTypeScalar(descriptor.FieldDescriptorProto_TYPE_STRING)).
// SetDefaultValue("bar")).
// AddField(NewField("baz", FieldTypeScalar(descriptor.FieldDescriptorProto_TYPE_INT64)).
// SetLabel(descriptor.FieldDescriptorProto_LABEL_REPEATED).
// SetOptions(&descriptor.FieldOptions{Packed: proto.Bool(true)})).
// Build()
//
// So the various Set* methods all return the builder itself so that multiple
// fields may be set in a single invocation chain.
Expand All @@ -104,8 +100,7 @@
// can return an error if validation fails. If the method-chaining Set* form is
// used with inputs that fail validation, the Set* method will panic.
//
//
// Type References and Imported Types
// # Type References and Imported Types
//
// When defining fields whose type is a message or enum and when defining
// methods (whose request and response type are a message), the type can be set
Expand All @@ -128,8 +123,7 @@
// imports the other). And the same would be true if one or both files were
// explicitly assigned to a file, but not both to the same file.
//
//
// Validations and Caveats
// # Validations and Caveats
//
// Descriptors that are attained from a builder do not necessarily represent a
// valid construct in the proto source language. There are some validations
Expand All @@ -153,40 +147,40 @@
// in errors (or panics for factory functions and methods that do not return
// errors). These are the rules that are currently enforced:
//
// 1. Import cycles are not allowed. (See above for more details.)
// 2. Within a single file, symbols are not allowed to have naming conflicts.
// This means that is not legal to create a message and an extension with
// the same name in the same file.
// 3. Messages are not allowed to have multiple fields with the same tag. Note
// that only non-extension fields are checked when using builders. So
// builders will allow tag collisions for extensions. (Use caution.)
// 4. Map keys can only be integer types, booleans, and strings.
// 5. Fields cannot have tags in the special reserved range 19000-19999. Also
// the maximum allowed tag value is 536870911 (2^29 - 1). Finally, fields
// cannot have negative values.
// 6. Element names should include only underscore, letters, and numbers, and
// must begin with an underscore or letter.
// 1. Import cycles are not allowed. (See above for more details.)
// 2. Within a single file, symbols are not allowed to have naming conflicts.
// This means that is not legal to create a message and an extension with
// the same name in the same file.
// 3. Messages are not allowed to have multiple fields with the same tag. Note
// that only non-extension fields are checked when using builders. So
// builders will allow tag collisions for extensions. (Use caution.)
// 4. Map keys can only be integer types, booleans, and strings.
// 5. Fields cannot have tags in the special reserved range 19000-19999. Also
// the maximum allowed tag value is 536870911 (2^29 - 1). Finally, fields
// cannot have negative values.
// 6. Element names should include only underscore, letters, and numbers, and
// must begin with an underscore or letter.
//
// Validation rules that are *not* enforced by builders, and thus would be
// allowed and result in illegal constructs, include the following:
//
// 1. Files with a syntax of proto3 are not allowed to have required fields.
// 2. Files with a syntax of proto3 are not allowed to have messages that
// define extension ranges.
// 3. Files with a syntax of proto3 are not allowed to use groups.
// 4. Files with a syntax of proto3 are not allowed to declare default values
// for fields.
// 5. Names are supposed to be globally unique, even across multiple files
// if multiple files are defined in the same package.
// 6. Extension fields must use tag numbers that are in an extension range
// defined on the extended message.
// 7. Multiple extensions for the same message cannot re-use tag numbers, even
// across multiple files.
// 8. Non-extension fields are not allowed to use tags that lie in a message's
// extension ranges or reserved ranges.
// 9. Non-extension fields are not allowed to use names that the message has
// marked as reserved.
// 10. Extension ranges and reserved ranges must not overlap.
// 1. Files with a syntax of proto3 are not allowed to have required fields.
// 2. Files with a syntax of proto3 are not allowed to have messages that
// define extension ranges.
// 3. Files with a syntax of proto3 are not allowed to use groups.
// 4. Files with a syntax of proto3 are not allowed to declare default values
// for fields.
// 5. Names are supposed to be globally unique, even across multiple files
// if multiple files are defined in the same package.
// 6. Extension fields must use tag numbers that are in an extension range
// defined on the extended message.
// 7. Multiple extensions for the same message cannot re-use tag numbers, even
// across multiple files.
// 8. Non-extension fields are not allowed to use tags that lie in a message's
// extension ranges or reserved ranges.
// 9. Non-extension fields are not allowed to use names that the message has
// marked as reserved.
// 10. Extension ranges and reserved ranges must not overlap.
//
// This list may change in the future, as more validation rules may be
// implemented in the builders.
Expand Down
27 changes: 15 additions & 12 deletions desc/builder/field.go
Expand Up @@ -538,19 +538,22 @@ func (flb *FieldBuilder) buildProto(path []int32, sourceInfo *dpb.SourceCodeInfo
return nil, fmt.Errorf("tag for field %s cannot be above max %d", GetFullyQualifiedName(flb), maxTag)
}

fd := &dpb.FieldDescriptorProto{
Name: proto.String(flb.name),
Number: proto.Int32(flb.number),
Options: flb.Options,
Label: lbl,
Type: flb.fieldType.fieldType.Enum(),
TypeName: typeName,
JsonName: proto.String(jsName),
DefaultValue: def,
Extendee: extendee,
}
var proto3Optional *bool
if flb.Proto3Optional {
internal.SetProto3Optional(fd)
proto3Optional = proto.Bool(true)
}

fd := &dpb.FieldDescriptorProto{
Name: proto.String(flb.name),
Number: proto.Int32(flb.number),
Options: flb.Options,
Label: lbl,
Type: flb.fieldType.fieldType.Enum(),
TypeName: typeName,
JsonName: proto.String(jsName),
DefaultValue: def,
Extendee: extendee,
Proto3Optional: proto3Optional,
}
return fd, nil
}
Expand Down
6 changes: 4 additions & 2 deletions desc/convert.go
Expand Up @@ -160,7 +160,8 @@ func addAllFiles(src []*FileDescriptor, results *[]*dpb.FileDescriptorProto, see
// set's *last* file will be the returned descriptor. The set's remaining files must comprise
// the full set of transitive dependencies of that last file. This is the same format and
// order used by protoc when emitting a FileDescriptorSet file with an invocation like so:
// protoc --descriptor_set_out=./test.protoset --include_imports -I. test.proto
//
// protoc --descriptor_set_out=./test.protoset --include_imports -I. test.proto
func CreateFileDescriptorFromSet(fds *dpb.FileDescriptorSet) (*FileDescriptor, error) {
return createFileDescriptorFromSet(fds, nil)
}
Expand All @@ -180,7 +181,8 @@ func createFileDescriptorFromSet(fds *dpb.FileDescriptorSet, r *ImportResolver)
// full set of transitive dependencies for all files therein or else a link error will occur
// and be returned instead of the slice of descriptors. This is the same format used by
// protoc when a FileDescriptorSet file with an invocation like so:
// protoc --descriptor_set_out=./test.protoset --include_imports -I. test.proto
//
// protoc --descriptor_set_out=./test.protoset --include_imports -I. test.proto
func CreateFileDescriptorsFromSet(fds *dpb.FileDescriptorSet) (map[string]*FileDescriptor, error) {
return createFileDescriptorsFromSet(fds, nil)
}
Expand Down
29 changes: 15 additions & 14 deletions desc/descriptor.go
Expand Up @@ -1040,7 +1040,7 @@ func (fd *FieldDescriptor) IsRepeated() bool {
// extensions), will be nested in synthetic oneofs that contain only the single
// field.
func (fd *FieldDescriptor) IsProto3Optional() bool {
return internal.GetProto3Optional(fd.proto)
return fd.proto.GetProto3Optional()
}

// HasPresence returns true if this field can distinguish when a value is
Expand Down Expand Up @@ -1101,19 +1101,20 @@ func (fd *FieldDescriptor) GetEnumType() *EnumDescriptor {
// Otherwise, it returns the declared default value for the field or a zero value, if no
// default is declared or if the file is proto3. The type of said return value corresponds
// to the type of the field:
// +-------------------------+-----------+
// | Declared Type | Go Type |
// +-------------------------+-----------+
// | int32, sint32, sfixed32 | int32 |
// | int64, sint64, sfixed64 | int64 |
// | uint32, fixed32 | uint32 |
// | uint64, fixed64 | uint64 |
// | float | float32 |
// | double | double32 |
// | bool | bool |
// | string | string |
// | bytes | []byte |
// +-------------------------+-----------+
//
// +-------------------------+-----------+
// | Declared Type | Go Type |
// +-------------------------+-----------+
// | int32, sint32, sfixed32 | int32 |
// | int64, sint64, sfixed64 | int64 |
// | uint32, fixed32 | uint32 |
// | uint64, fixed64 | uint64 |
// | float | float32 |
// | double | double32 |
// | bool | bool |
// | string | string |
// | bytes | []byte |
// +-------------------------+-----------+
func (fd *FieldDescriptor) GetDefaultValue() interface{} {
return fd.getDefaultValue()
}
Expand Down
7 changes: 2 additions & 5 deletions desc/doc.go
Expand Up @@ -27,8 +27,7 @@
// Also see the grpcreflect, dynamic, and grpcdynamic packages in this same
// repo to see just how useful rich descriptors really are.
//
//
// Loading Descriptors
// # Loading Descriptors
//
// Rich descriptors can be accessed in similar ways as their "poor" cousins
// (descriptor protos). Instead of using proto.FileDescriptor, use
Expand All @@ -40,8 +39,7 @@
// the descriptors returned from these Load* functions will include source code
// information, and thus include comments for elements.
//
//
// Creating Descriptors
// # Creating Descriptors
//
// It is also possible create rich descriptors for proto messages that a given
// Go program doesn't even know about. For example, they could be loaded from a
Expand All @@ -61,5 +59,4 @@
//
// Also see the desc/builder sub-package, for another API that makes it easier
// to synthesize descriptors programmatically.
//
package desc
26 changes: 16 additions & 10 deletions desc/imports.go
Expand Up @@ -76,25 +76,31 @@ func ResolveImport(importPath string) string {
//
// For example, let's say we have two proto source files: "foo/bar.proto" and
// "fubar/baz.proto". The latter imports the former using a line like so:
// import "foo/bar.proto";
//
// import "foo/bar.proto";
//
// However, when protoc is invoked, the command-line args looks like so:
// protoc -Ifoo/ --go_out=foo/ bar.proto
// protoc -I./ -Ifubar/ --go_out=fubar/ baz.proto
//
// protoc -Ifoo/ --go_out=foo/ bar.proto
// protoc -I./ -Ifubar/ --go_out=fubar/ baz.proto
//
// Because the path given to protoc is just "bar.proto" and "baz.proto", this is
// how they are registered in the Go protobuf runtime. So, when loading the
// descriptor for "fubar/baz.proto", we'll see an import path of "foo/bar.proto"
// but will find no file registered with that path:
// fd, err := desc.LoadFileDescriptor("baz.proto")
// // err will be non-nil, complaining that there is no such file
// // found named "foo/bar.proto"
//
// fd, err := desc.LoadFileDescriptor("baz.proto")
// // err will be non-nil, complaining that there is no such file
// // found named "foo/bar.proto"
//
// This can be remedied by registering alternate import paths using an
// ImportResolver. Continuing with the example above, the code below would fix
// any link issue:
// var r desc.ImportResolver
// r.RegisterImportPath("bar.proto", "foo/bar.proto")
// fd, err := r.LoadFileDescriptor("baz.proto")
// // err will be nil; descriptor successfully loaded!
//
// var r desc.ImportResolver
// r.RegisterImportPath("bar.proto", "foo/bar.proto")
// fd, err := r.LoadFileDescriptor("baz.proto")
// // err will be nil; descriptor successfully loaded!
//
// If there are files that are *always* imported using a different relative
// path then how they are registered, consider using the global
Expand Down