Protocol Buffers - Google's data interchange format (grpc依赖)
https://developers.google.com/protocol-buffers/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
247 lines
7.2 KiB
247 lines
7.2 KiB
# Protobuf Design: Options Attributes |
|
|
|
A proposal to create target and retention attributes to support. |
|
|
|
**Author:** [@kfm](https://github.com/fowles) |
|
|
|
**Approved:** 2022-08-26 |
|
|
|
## Background |
|
|
|
The [Protobuf Editions](what-are-protobuf-editions.md) project plans to use |
|
[custom options](protobuf-editions-design-features.md) to model features and |
|
encourage language bindings to build custom features off options as well. |
|
|
|
This design proposed the specific addition of `target` and `retention` |
|
attributes for options as well as their suggested meaning. |
|
|
|
Both `target` and `retention` attributes are no-ops when applied to fields that |
|
are not options (either from descriptor.proto or custom options). |
|
|
|
## Target Attributes |
|
|
|
Historically, options have only applied to specific entities, but features will |
|
be available on most entities. To allow language specific extensions to restrict |
|
the places where options can bind, we will allow features to explicitly specify |
|
the targets they apply to (similar in concept to the "target" attribute on Java |
|
annotations). `TARGET_TYPE_UNKNOWN` will be treated as absent. |
|
|
|
``` |
|
message FieldOptions { |
|
... |
|
optional OptionTargetType target = 17; |
|
|
|
enum OptionTargetType { |
|
TARGET_TYPE_UNKNOWN = 0; |
|
TARGET_TYPE_FILE = 1; |
|
TARGET_TYPE_EXTENSION_RANGE = 2; |
|
TARGET_TYPE_MESSAGE = 3; |
|
TARGET_TYPE_FIELD = 4; |
|
TARGET_TYPE_ONEOF = 5; |
|
TARGET_TYPE_ENUM = 6; |
|
TARGET_TYPE_ENUM_VALUE = 7; |
|
TARGET_TYPE_SERVICE = 8; |
|
TARGET_TYPE_METHOD = 9; |
|
}; |
|
} |
|
``` |
|
|
|
If no target is provided, `protoc` will permit the target to apply to any |
|
entity. Otherwise, `protoc` will allow an option to be applied at either the |
|
file level or to its target entity (and will produce a compile error for any |
|
other placement). For example |
|
|
|
``` |
|
message Features { |
|
... |
|
|
|
enum EnumType { |
|
OPEN = 0; |
|
CLOSED = 1; |
|
} |
|
optional EnumType enum = 2 [ |
|
target = TARGET_TYPE_ENUM |
|
]; |
|
} |
|
``` |
|
|
|
would allow usage of |
|
|
|
``` |
|
// foo.proto |
|
edition = "tbd" |
|
|
|
option features.enum = OPEN; // allowed at FILE scope |
|
|
|
enum Foo { |
|
option features.enum = CLOSED; // allowed at ENUM scope |
|
A = 2; |
|
B = 4; |
|
} |
|
|
|
message Bar { |
|
option features.enum = CLOSED; // disallowed at Message scope |
|
|
|
enum Baz { |
|
C = 8; |
|
} |
|
} |
|
``` |
|
|
|
## Retention |
|
|
|
To reduce the size of descriptors in protobuf runtimes, features will be |
|
permitted to specify retention rules (again similar in concept to "retention" |
|
attributes on Java annotations). |
|
|
|
``` |
|
enum FeatureRetention { |
|
RETENTION_UNKNOWN = 0; |
|
RETENTION_RUNTIME = 1; |
|
RETENTION_SOURCE = 2; |
|
} |
|
``` |
|
|
|
Options intended to inform code generators or `protoc` itself can be annotated |
|
with `SOURCE` retention. The default retention will be `RUNTIME` as that is the |
|
current behavior for all options. **Code generators that emit generated |
|
descriptors will be required to omit/strip options with `SOURCE` retention from |
|
their generated descriptors.** For example: |
|
|
|
``` |
|
message Cpp { |
|
enum StringType { |
|
STRING = 1; |
|
STRING_VIEW = 0; |
|
CORD = 2; |
|
} |
|
|
|
optional string namespace = 2 [ |
|
retention = RETENTION_SOURCE, |
|
target = TARGET_TYPE_FILE |
|
]; |
|
} |
|
``` |
|
|
|
## Motivation |
|
|
|
While the proximal motivation for these options is for use with "features" in |
|
"editions", I believe they provide sufficient general utility that adding them |
|
directly to `FieldDescriptorOptions` is warranted. For example, significant |
|
savings in binary sizes could be realized if `ExtensionRangeOptions::Metadata` |
|
had only `SOURCE` retention. Previously, we have specifically special-cased this |
|
behavior on a per-field basis, which does work but does not provide good |
|
extensibility. |
|
|
|
## Discussion |
|
|
|
In the initial design `target` was serving the dual purpose of identifying the |
|
semantic entity, and also the granularity of inheritance for features. After |
|
discussion about concerns around over use of inheritance, we decided for a |
|
slightly refined definition that decouples these concerns. `target` **only** |
|
specifies the semantic entity to which an option can apply. Features will be |
|
able to be set on both the `FILE` level and their semantic entity. Everything in |
|
between will be refused in the initial release. This allows us a clean |
|
forward-compatible way to allow arbitrary feature inheritance, but doesn't |
|
commit us to doing that until we need it. |
|
|
|
Similarly, we will start with `optional` target, because we can safely move to |
|
`repeated` later should the need arise. |
|
|
|
The naming for `target` and `retention` are directly modeled after Java |
|
annotations. Other names were considered, but no better name was found and the |
|
similarity to an existing thing won the day. |
|
|
|
## Alternatives |
|
|
|
### Use a repeated `target` proposed |
|
|
|
This is the proposed alternative. |
|
|
|
#### Pros |
|
|
|
* Allows fine-grained control of target applicability. |
|
|
|
#### Cons |
|
|
|
* Harder to generalize for users (every feature's specification is potentially |
|
unique). |
|
|
|
### Allow hierarchy based on `target` semantic location. |
|
|
|
Rather than having a repeated `target` that specifies all locations, we allow |
|
only the level at which it semantically applies to be specified. The protoc |
|
compiler will implicitly allow the field to be used on entities that can |
|
lexically group that type of entry. For this `target` can be either singular or |
|
repeated. |
|
|
|
#### Pros |
|
|
|
* Enables tooling that understands when a feature is used for grouping vs when |
|
it has semantic value (helpful for minimizing churn in large-scale changes). |
|
* Easier to generalize for users (any `FIELD` feature can apply to a message |
|
as opposed to only the `FIELD` features that explicitly specified an |
|
additional `target`). |
|
|
|
#### Cons |
|
|
|
* Forces all `target` applications to be permitted on scoping entities. |
|
|
|
### Use Custom Options (aka "We Must Go Deeper") |
|
|
|
Rather than building `retention` and `target` directly as fields of |
|
`FieldOptions`, we could use custom options to define an equivalent thing. This |
|
option was rejected because it pushes extra syntax onto users for a fundamental |
|
feature. |
|
|
|
#### Pros |
|
|
|
* Doesn't require modifying `descriptor.proto`. |
|
|
|
#### Cons |
|
|
|
* Requires a less-intuitive spelling in user code. |
|
* Requires an additional import for users. |
|
* Language-level features would have to have a magic syntax or a side table |
|
instead of using the same consistent option as user per code gen features. |
|
|
|
### Hard Code Behaviors in `protoc` |
|
|
|
Rather than building a generic mechanism we could simply hard code the behavior |
|
of protoc and document it. |
|
|
|
#### Pros |
|
|
|
* Can't be misused. |
|
|
|
#### Cons |
|
|
|
* Not extensible for users. |
|
* Requires more special cases users need to learn. |
|
|
|
### Original Approved Proposal |
|
|
|
The proposal as originally approved had some slight differences from what was |
|
ultimately implemented: |
|
|
|
* The retention enum did not have an `UNKNOWN` type. |
|
* The enums were defined at the top level instead of nested inside |
|
`FieldOptions`. |
|
* The enum values did not have a scoping prefix. |
|
* The target enum had a `STREAM` entry, but this turned out to be unnecessary |
|
since the syntax that it applied to was removed. |
|
|
|
### Do Nothing |
|
|
|
We could omit this entirely and get ice cream instead. This was rejected because |
|
the proliferation of features on entities they do not apply to is considered too |
|
high a cost. |
|
|
|
#### Pros |
|
|
|
* Ice cream is awesome. |
|
|
|
#### Cons |
|
|
|
* Doesn't address any of the problems that caused this to come up. |
|
* Some people are lactose intolerant.
|
|
|