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

ObjC Proto3 optional support #7421

Merged
merged 8 commits into from Apr 24, 2020
Merged
1 change: 1 addition & 0 deletions objectivec/DevTools/compile_testing_protos.sh
Expand Up @@ -158,6 +158,7 @@ compile_protos() {
--objc_out="${OUTPUT_DIR}/google/protobuf" \
--proto_path=src/google/protobuf/ \
--proto_path=src \
--experimental_allow_proto3_optional \
"$@"
}

Expand Down
4 changes: 2 additions & 2 deletions objectivec/GPBAny.pbobjc.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions objectivec/GPBAny.pbobjc.m

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions objectivec/GPBApi.pbobjc.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

36 changes: 18 additions & 18 deletions objectivec/GPBApi.pbobjc.m

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion objectivec/GPBBootstrap.h
Expand Up @@ -132,7 +132,7 @@
// Current library runtime version.
// - Gets bumped when the runtime makes changes to the interfaces between the
// generated code and runtime (things added/removed, etc).
#define GOOGLE_PROTOBUF_OBJC_VERSION 30003
#define GOOGLE_PROTOBUF_OBJC_VERSION 30004

// Minimum runtime version supported for compiling/running against.
// - Gets changed when support for the older generated code is dropped.
Expand Down
41 changes: 25 additions & 16 deletions objectivec/GPBDescriptor.m
Expand Up @@ -128,6 +128,8 @@ @implementation GPBDescriptor {
(flags & GPBDescriptorInitializationFlag_FieldsWithDefault) != 0;
BOOL usesClassRefs =
(flags & GPBDescriptorInitializationFlag_UsesClassRefs) != 0;
BOOL proto3OptionalKnown =
(flags & GPBDescriptorInitializationFlag_Proto3OptionalKnown) != 0;

void *desc;
for (uint32_t i = 0; i < fieldCount; ++i) {
Expand All @@ -146,6 +148,7 @@ @implementation GPBDescriptor {
[[GPBFieldDescriptor alloc] initWithFieldDescription:desc
includesDefault:fieldsIncludeDefault
usesClassRefs:usesClassRefs
proto3OptionalKnown:proto3OptionalKnown
syntax:syntax];
[fields addObject:fieldDescriptor];
[fieldDescriptor release];
Expand Down Expand Up @@ -488,6 +491,7 @@ - (instancetype)init {
- (instancetype)initWithFieldDescription:(void *)description
includesDefault:(BOOL)includesDefault
usesClassRefs:(BOOL)usesClassRefs
proto3OptionalKnown:(BOOL)proto3OptionalKnown
syntax:(GPBFileSyntax)syntax {
if ((self = [super init])) {
GPBMessageFieldDescription *coreDesc;
Expand All @@ -504,20 +508,34 @@ - (instancetype)initWithFieldDescription:(void *)description
BOOL isMessage = GPBDataTypeIsMessage(dataType);
BOOL isMapOrArray = GPBFieldIsMapOrArray(self);

// If proto3 optionals weren't known (i.e. generated code from an
// older version), compute the flag for the rest of the runtime.
if (!proto3OptionalKnown) {
// If it was...
// - proto3 syntax
// - not repeated/map
// - not in a oneof (negative has index)
// - not a message (the flag doesn't make sense for messages)
BOOL clearOnZero = ((syntax == GPBFileSyntaxProto3) &&
!isMapOrArray &&
(coreDesc->hasIndex >= 0) &&
!isMessage);
if (clearOnZero) {
coreDesc->flags |= GPBFieldClearHasIvarOnZero;
}
}

if (isMapOrArray) {
// map<>/repeated fields get a *Count property (inplace of a has*) to
// support checking if there are any entries without triggering
// autocreation.
hasOrCountSel_ = SelFromStrings(NULL, coreDesc->name, "_Count", NO);
} else {
// If there is a positive hasIndex, then:
// - All fields types for proto2 messages get has* selectors.
// - Only message fields for proto3 messages get has* selectors.
// Note: the positive check is to handle oneOfs, we can't check
// containingOneof_ because it isn't set until after initialization.
// It is a single field; it gets has/setHas selectors if...
// - not in a oneof (negative has index)
// - not clearing on zero
if ((coreDesc->hasIndex >= 0) &&
(coreDesc->hasIndex != GPBNoHasBit) &&
((syntax != GPBFileSyntaxProto3) || isMessage)) {
((coreDesc->flags & GPBFieldClearHasIvarOnZero) == 0)) {
hasOrCountSel_ = SelFromStrings("has", coreDesc->name, NULL, NO);
setHasSel_ = SelFromStrings("setHas", coreDesc->name, NULL, YES);
}
Expand Down Expand Up @@ -567,15 +585,6 @@ - (instancetype)initWithFieldDescription:(void *)description
return self;
}

- (instancetype)initWithFieldDescription:(void *)description
includesDefault:(BOOL)includesDefault
syntax:(GPBFileSyntax)syntax {
return [self initWithFieldDescription:description
includesDefault:includesDefault
usesClassRefs:NO
syntax:syntax];
}

- (void)dealloc {
if (description_->dataType == GPBDataTypeBytes &&
!(description_->flags & GPBFieldRepeated)) {
Expand Down
19 changes: 12 additions & 7 deletions objectivec/GPBDescriptor_PackagePrivate.h
Expand Up @@ -45,6 +45,10 @@ typedef NS_OPTIONS(uint16_t, GPBFieldFlags) {
GPBFieldOptional = 1 << 3,
GPBFieldHasDefaultValue = 1 << 4,

// Indicate that the field should "clear" when set to zero value. This is the
// proto3 non optional behavior for singular data (ints, data, string, enum)
// fields.
GPBFieldClearHasIvarOnZero = 1 << 5,
// Indicates the field needs custom handling for the TextFormat name, if not
// set, the name can be derived from the ObjC name.
GPBFieldTextFormatNameCustom = 1 << 6,
Expand Down Expand Up @@ -149,7 +153,13 @@ typedef NS_OPTIONS(uint32_t, GPBDescriptorInitializationFlags) {
// This is used as a stopgap as we move from using class names to class
// references. The runtime needs to support both until we allow a
// breaking change in the runtime.
GPBDescriptorInitializationFlag_UsesClassRefs = 1 << 2,
GPBDescriptorInitializationFlag_UsesClassRefs = 1 << 2,

// This flag is used to indicate that the generated sources already contain
// the `GPBFieldClearHasIvarOnZero` flag and it doesn't have to be computed
// at startup. This allows older generated code to still work with the
// current runtime library.
GPBDescriptorInitializationFlag_Proto3OptionalKnown = 1 << 3,
};

@interface GPBDescriptor () {
Expand Down Expand Up @@ -225,14 +235,9 @@ typedef NS_OPTIONS(uint32_t, GPBDescriptorInitializationFlags) {
- (instancetype)initWithFieldDescription:(void *)description
includesDefault:(BOOL)includesDefault
usesClassRefs:(BOOL)usesClassRefs
proto3OptionalKnown:(BOOL)proto3OptionalKnown
syntax:(GPBFileSyntax)syntax;

// Deprecated. Equivalent to calling above with `usesClassRefs = NO`.
- (instancetype)initWithFieldDescription:(void *)description
includesDefault:(BOOL)includesDefault
syntax:(GPBFileSyntax)syntax;


@end

@interface GPBEnumDescriptor ()
Expand Down
4 changes: 2 additions & 2 deletions objectivec/GPBDuration.pbobjc.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions objectivec/GPBDuration.pbobjc.m

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.