[ObjC] Add the concept of a closed enum.

- FieldDescriptor:
  - Add a new flag to mark when the enum on the field is closed (vs open).
  - Support computing the state for when generated sources predate the support.
- EnumDescriptor:
  - Support passing flags to the descriptor creation, currently closed is the
    only new flag.
  - Add an isClosed property to expose the state of the enum.

This does NOT update generation yet, allows things to be tested before the
generation support is added.

PiperOrigin-RevId: 488671606
pull/10991/head
Protobuf Team Bot 2 years ago committed by Copybara-Service
parent 3a74266787
commit 7bb699be43
  1. 12
      objectivec/GPBDescriptor.h
  2. 83
      objectivec/GPBDescriptor.m
  3. 48
      objectivec/GPBDescriptor_PackagePrivate.h
  4. 3
      objectivec/GPBDictionary.m
  5. 26
      objectivec/GPBMessage.m
  6. 3
      objectivec/GPBUtilities.m

@ -235,6 +235,18 @@ typedef NS_ENUM(uint8_t, GPBFieldType) {
@property(nonatomic, readonly, copy) NSString *name; @property(nonatomic, readonly, copy) NSString *name;
/** Function that validates that raw values are valid enum values. */ /** Function that validates that raw values are valid enum values. */
@property(nonatomic, readonly) GPBEnumValidationFunc enumVerifier; @property(nonatomic, readonly) GPBEnumValidationFunc enumVerifier;
/**
* Is this a closed enum, meaning that it:
* - Has a fixed set of named values.
* - Encountering values not in this set causes them to be treated as unknown
* fields.
* - The first value (i.e., the default) may be nonzero.
*
* NOTE: This is only accurate if the generate sources for a proto file were
* generated with a protobuf release after the v21.9 version, as the ObjC
* generator wasn't capturing this information.
*/
@property(nonatomic, readonly) BOOL isClosed;
/** /**
* Returns the enum value name for the given raw enum. * Returns the enum value name for the given raw enum.

@ -51,7 +51,8 @@
file:(GPBFileDescriptor *)file file:(GPBFileDescriptor *)file
includesDefault:(BOOL)includesDefault includesDefault:(BOOL)includesDefault
usesClassRefs:(BOOL)usesClassRefs usesClassRefs:(BOOL)usesClassRefs
proto3OptionalKnown:(BOOL)proto3OptionalKnown; proto3OptionalKnown:(BOOL)proto3OptionalKnown
closedEnumSupportKnown:(BOOL)closedEnumSupportKnown;
@end @end
@ -60,7 +61,8 @@
valueNames:(const char *)valueNames valueNames:(const char *)valueNames
values:(const int32_t *)values values:(const int32_t *)values
count:(uint32_t)valueCount count:(uint32_t)valueCount
enumVerifier:(GPBEnumValidationFunc)enumVerifier; enumVerifier:(GPBEnumValidationFunc)enumVerifier
flags:(GPBEnumDescriptorInitializationFlags)flags;
@end @end
// Direct access is use for speed, to avoid even internally declaring things // Direct access is use for speed, to avoid even internally declaring things
@ -150,6 +152,8 @@ static NSArray *NewFieldsArrayForHasIndex(int hasIndex, NSArray *allMessageField
BOOL fieldsIncludeDefault = (flags & GPBDescriptorInitializationFlag_FieldsWithDefault) != 0; BOOL fieldsIncludeDefault = (flags & GPBDescriptorInitializationFlag_FieldsWithDefault) != 0;
BOOL usesClassRefs = (flags & GPBDescriptorInitializationFlag_UsesClassRefs) != 0; BOOL usesClassRefs = (flags & GPBDescriptorInitializationFlag_UsesClassRefs) != 0;
BOOL proto3OptionalKnown = (flags & GPBDescriptorInitializationFlag_Proto3OptionalKnown) != 0; BOOL proto3OptionalKnown = (flags & GPBDescriptorInitializationFlag_Proto3OptionalKnown) != 0;
BOOL closedEnumSupportKnown =
(flags & GPBDescriptorInitializationFlag_ClosedEnumSupportKnown) != 0;
void *desc; void *desc;
for (uint32_t i = 0; i < fieldCount; ++i) { for (uint32_t i = 0; i < fieldCount; ++i) {
@ -164,7 +168,8 @@ static NSArray *NewFieldsArrayForHasIndex(int hasIndex, NSArray *allMessageField
file:file file:file
includesDefault:fieldsIncludeDefault includesDefault:fieldsIncludeDefault
usesClassRefs:usesClassRefs usesClassRefs:usesClassRefs
proto3OptionalKnown:proto3OptionalKnown]; proto3OptionalKnown:proto3OptionalKnown
closedEnumSupportKnown:closedEnumSupportKnown];
[fields addObject:fieldDescriptor]; [fields addObject:fieldDescriptor];
[fieldDescriptor release]; [fieldDescriptor release];
} }
@ -475,7 +480,8 @@ uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) {
file:(GPBFileDescriptor *)file file:(GPBFileDescriptor *)file
includesDefault:(BOOL)includesDefault includesDefault:(BOOL)includesDefault
usesClassRefs:(BOOL)usesClassRefs usesClassRefs:(BOOL)usesClassRefs
proto3OptionalKnown:(BOOL)proto3OptionalKnown { proto3OptionalKnown:(BOOL)proto3OptionalKnown
closedEnumSupportKnown:(BOOL)closedEnumSupportKnown {
if ((self = [super init])) { if ((self = [super init])) {
GPBMessageFieldDescription *coreDesc; GPBMessageFieldDescription *coreDesc;
if (includesDefault) { if (includesDefault) {
@ -506,6 +512,21 @@ uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) {
} }
} }
// If the ClosedEnum flag wasn't known (i.e. generated code from an older
// version), compute the flag for the rest of the runtime.
if (!closedEnumSupportKnown) {
// NOTE: This isn't correct, it is using the syntax of the file that
// declared the field, not the syntax of the file that declared the
// enum; but for older generated code, that's all we have and that happens
// to be what the runtime was doing (even though it was wrong). This is
// only wrong in the rare cases an enum is declared in a proto3 syntax
// file but used for a field in the proto2 syntax file.
BOOL isClosedEnum = (dataType == GPBDataTypeEnum && file.syntax != GPBFileSyntaxProto3);
if (isClosedEnum) {
coreDesc->flags |= GPBFieldClosedEnum;
}
}
if (isMapOrArray) { if (isMapOrArray) {
// map<>/repeated fields get a *Count property (inplace of a has*) to // map<>/repeated fields get a *Count property (inplace of a has*) to
// support checking if there are any entries without triggering // support checking if there are any entries without triggering
@ -535,9 +556,14 @@ uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) {
NSAssert(msgClass_, @"Class %s not defined", className); NSAssert(msgClass_, @"Class %s not defined", className);
} }
} else if (dataType == GPBDataTypeEnum) { } else if (dataType == GPBDataTypeEnum) {
enumDescriptor_ = coreDesc->dataTypeSpecific.enumDescFunc();
#if defined(DEBUG) && DEBUG
NSAssert((coreDesc->flags & GPBFieldHasEnumDescriptor) != 0, NSAssert((coreDesc->flags & GPBFieldHasEnumDescriptor) != 0,
@"Field must have GPBFieldHasEnumDescriptor set"); @"Field must have GPBFieldHasEnumDescriptor set");
enumDescriptor_ = coreDesc->dataTypeSpecific.enumDescFunc(); NSAssert(!closedEnumSupportKnown ||
(((coreDesc->flags & GPBFieldClosedEnum) != 0) == enumDescriptor_.isClosed),
@"Internal error, ClosedEnum flag doesn't agree with EnumDescriptor");
#endif // DEBUG
} }
// Non map<>/repeated fields can have defaults in proto2 syntax. // Non map<>/repeated fields can have defaults in proto2 syntax.
@ -740,6 +766,7 @@ uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) {
const uint8_t *extraTextFormatInfo_; const uint8_t *extraTextFormatInfo_;
uint32_t *nameOffsets_; uint32_t *nameOffsets_;
uint32_t valueCount_; uint32_t valueCount_;
uint32_t flags_;
} }
@synthesize name = name_; @synthesize name = name_;
@ -749,12 +776,14 @@ uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) {
valueNames:(const char *)valueNames valueNames:(const char *)valueNames
values:(const int32_t *)values values:(const int32_t *)values
count:(uint32_t)valueCount count:(uint32_t)valueCount
enumVerifier:(GPBEnumValidationFunc)enumVerifier { enumVerifier:(GPBEnumValidationFunc)enumVerifier
flags:(GPBEnumDescriptorInitializationFlags)flags {
GPBEnumDescriptor *descriptor = [[self alloc] initWithName:name GPBEnumDescriptor *descriptor = [[self alloc] initWithName:name
valueNames:valueNames valueNames:valueNames
values:values values:values
count:valueCount count:valueCount
enumVerifier:enumVerifier]; enumVerifier:enumVerifier
flags:flags];
return descriptor; return descriptor;
} }
@ -763,29 +792,61 @@ uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) {
values:(const int32_t *)values values:(const int32_t *)values
count:(uint32_t)valueCount count:(uint32_t)valueCount
enumVerifier:(GPBEnumValidationFunc)enumVerifier enumVerifier:(GPBEnumValidationFunc)enumVerifier
flags:(GPBEnumDescriptorInitializationFlags)flags
extraTextFormatInfo:(const char *)extraTextFormatInfo { extraTextFormatInfo:(const char *)extraTextFormatInfo {
// Call the common case. // Call the common case.
GPBEnumDescriptor *descriptor = [self allocDescriptorForName:name GPBEnumDescriptor *descriptor = [self allocDescriptorForName:name
valueNames:valueNames valueNames:valueNames
values:values values:values
count:valueCount count:valueCount
enumVerifier:enumVerifier]; enumVerifier:enumVerifier
flags:flags];
// Set the extra info. // Set the extra info.
descriptor->extraTextFormatInfo_ = (const uint8_t *)extraTextFormatInfo; descriptor->extraTextFormatInfo_ = (const uint8_t *)extraTextFormatInfo;
return descriptor; return descriptor;
} }
+ (instancetype)allocDescriptorForName:(NSString *)name
valueNames:(const char *)valueNames
values:(const int32_t *)values
count:(uint32_t)valueCount
enumVerifier:(GPBEnumValidationFunc)enumVerifier {
return [self allocDescriptorForName:name
valueNames:valueNames
values:values
count:valueCount
enumVerifier:enumVerifier
flags:GPBEnumDescriptorInitializationFlag_None];
}
+ (instancetype)allocDescriptorForName:(NSString *)name
valueNames:(const char *)valueNames
values:(const int32_t *)values
count:(uint32_t)valueCount
enumVerifier:(GPBEnumValidationFunc)enumVerifier
extraTextFormatInfo:(const char *)extraTextFormatInfo {
return [self allocDescriptorForName:name
valueNames:valueNames
values:values
count:valueCount
enumVerifier:enumVerifier
flags:GPBEnumDescriptorInitializationFlag_None
extraTextFormatInfo:extraTextFormatInfo];
}
- (instancetype)initWithName:(NSString *)name - (instancetype)initWithName:(NSString *)name
valueNames:(const char *)valueNames valueNames:(const char *)valueNames
values:(const int32_t *)values values:(const int32_t *)values
count:(uint32_t)valueCount count:(uint32_t)valueCount
enumVerifier:(GPBEnumValidationFunc)enumVerifier { enumVerifier:(GPBEnumValidationFunc)enumVerifier
flags:(GPBEnumDescriptorInitializationFlags)flags {
if ((self = [super init])) { if ((self = [super init])) {
name_ = [name copy]; name_ = [name copy];
valueNames_ = valueNames; valueNames_ = valueNames;
values_ = values; values_ = values;
valueCount_ = valueCount; valueCount_ = valueCount;
enumVerifier_ = enumVerifier; enumVerifier_ = enumVerifier;
flags_ = flags;
} }
return self; return self;
} }
@ -796,6 +857,10 @@ uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) {
[super dealloc]; [super dealloc];
} }
- (BOOL)isClosed {
return (flags_ & GPBEnumDescriptorInitializationFlag_IsClosed) != 0;
}
- (void)calcValueNameOffsets { - (void)calcValueNameOffsets {
@synchronized(self) { @synchronized(self) {
if (nameOffsets_ != NULL) { if (nameOffsets_ != NULL) {

@ -73,6 +73,18 @@ typedef NS_OPTIONS(uint16_t, GPBFieldFlags) {
GPBFieldMapKeySFixed64 = 10 << 8, GPBFieldMapKeySFixed64 = 10 << 8,
GPBFieldMapKeyBool = 11 << 8, GPBFieldMapKeyBool = 11 << 8,
GPBFieldMapKeyString = 12 << 8, GPBFieldMapKeyString = 12 << 8,
// If the enum for this field is "closed", meaning that it:
// - Has a fixed set of named values.
// - Encountering values not in this set causes them to be treated as unknown
// fields.
// - The first value (i.e., the default) may be nonzero.
// NOTE: This could be tracked just on the GPBEnumDescriptor, but to support
// previously generated code, there would be not data to get the behavior
// correct, so instead it is tracked on the field. If old source compatibility
// is removed, this could be removed and the GPBEnumDescription fetched from
// the GPBFieldDescriptor instead.
GPBFieldClosedEnum = 1 << 12,
}; };
// NOTE: The structures defined here have their members ordered to minimize // NOTE: The structures defined here have their members ordered to minimize
@ -173,6 +185,12 @@ typedef NS_OPTIONS(uint32_t, GPBDescriptorInitializationFlags) {
// at startup. This allows older generated code to still work with the // at startup. This allows older generated code to still work with the
// current runtime library. // current runtime library.
GPBDescriptorInitializationFlag_Proto3OptionalKnown = 1 << 3, GPBDescriptorInitializationFlag_Proto3OptionalKnown = 1 << 3,
// This flag is used to indicate that the generated sources already contain
// the `GPBFieldCloseEnum` flag and it doesn't have to be computed at startup.
// This allows the older generated code to still work with the current runtime
// library.
GPBDescriptorInitializationFlag_ClosedEnumSupportKnown = 1 << 4,
}; };
@interface GPBDescriptor () { @interface GPBDescriptor () {
@ -236,14 +254,36 @@ typedef NS_OPTIONS(uint32_t, GPBDescriptorInitializationFlags) {
} }
@end @end
typedef NS_OPTIONS(uint32_t, GPBEnumDescriptorInitializationFlags) {
GPBEnumDescriptorInitializationFlag_None = 0,
// Marks this enum as a closed enum.
GPBEnumDescriptorInitializationFlag_IsClosed = 1 << 1,
};
@interface GPBEnumDescriptor () @interface GPBEnumDescriptor ()
// valueNames, values and extraTextFormatInfo have to be long lived, they are // valueNames, values and extraTextFormatInfo have to be long lived, they are
// held as raw pointers. // held as raw pointers.
+ (instancetype)allocDescriptorForName:(NSString *)name
valueNames:(const char *)valueNames
values:(const int32_t *)values
count:(uint32_t)valueCount
enumVerifier:(GPBEnumValidationFunc)enumVerifier
flags:(GPBEnumDescriptorInitializationFlags)flags;
+ (instancetype)allocDescriptorForName:(NSString *)name
valueNames:(const char *)valueNames
values:(const int32_t *)values
count:(uint32_t)valueCount
enumVerifier:(GPBEnumValidationFunc)enumVerifier
flags:(GPBEnumDescriptorInitializationFlags)flags
extraTextFormatInfo:(const char *)extraTextFormatInfo;
// Deprecated. Calls above with `flags = 0`
+ (instancetype)allocDescriptorForName:(NSString *)name + (instancetype)allocDescriptorForName:(NSString *)name
valueNames:(const char *)valueNames valueNames:(const char *)valueNames
values:(const int32_t *)values values:(const int32_t *)values
count:(uint32_t)valueCount count:(uint32_t)valueCount
enumVerifier:(GPBEnumValidationFunc)enumVerifier; enumVerifier:(GPBEnumValidationFunc)enumVerifier;
// Deprecated. Calls above with `flags = 0`
+ (instancetype)allocDescriptorForName:(NSString *)name + (instancetype)allocDescriptorForName:(NSString *)name
valueNames:(const char *)valueNames valueNames:(const char *)valueNames
values:(const int32_t *)values values:(const int32_t *)values
@ -297,6 +337,10 @@ GPB_INLINE uint32_t GPBFieldNumber(GPBFieldDescriptor *field) {
return field->description_->number; return field->description_->number;
} }
GPB_INLINE BOOL GPBFieldIsClosedEnum(GPBFieldDescriptor *field) {
return (field->description_->flags & GPBFieldClosedEnum) != 0;
}
#pragma clang diagnostic pop #pragma clang diagnostic pop
uint32_t GPBFieldTag(GPBFieldDescriptor *self); uint32_t GPBFieldTag(GPBFieldDescriptor *self);
@ -307,10 +351,6 @@ uint32_t GPBFieldTag(GPBFieldDescriptor *self);
// would be the wire type for packed. // would be the wire type for packed.
uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self); uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self);
GPB_INLINE BOOL GPBHasPreservingUnknownEnumSemantics(GPBFileSyntax syntax) {
return syntax == GPBFileSyntaxProto3;
}
GPB_INLINE BOOL GPBExtensionIsRepeated(GPBExtensionDescription *description) { GPB_INLINE BOOL GPBExtensionIsRepeated(GPBExtensionDescription *description) {
return (description->options & GPBExtensionRepeated) != 0; return (description->options & GPBExtensionRepeated) != 0;
} }

@ -501,8 +501,7 @@ void GPBDictionaryReadEntry(id mapDictionary, GPBCodedInputStream *stream,
[(NSMutableDictionary *)mapDictionary setObject:value.valueString forKey:key.valueString]; [(NSMutableDictionary *)mapDictionary setObject:value.valueString forKey:key.valueString];
} else { } else {
if (valueDataType == GPBDataTypeEnum) { if (valueDataType == GPBDataTypeEnum) {
if (GPBHasPreservingUnknownEnumSemantics([parentMessage descriptor].file.syntax) || if (!GPBFieldIsClosedEnum(field) || [field isValidEnumValue:value.valueEnum]) {
[field isValidEnumValue:value.valueEnum]) {
[mapDictionary setGPBGenericValue:&value forGPBGenericValueKey:&key]; [mapDictionary setGPBGenericValue:&value forGPBGenericValueKey:&key];
} else { } else {
NSData *data = [mapDictionary serializedDataForUnknownValue:value.valueEnum NSData *data = [mapDictionary serializedDataForUnknownValue:value.valueEnum

@ -2058,7 +2058,7 @@ static GPBUnknownFieldSet *GetOrMakeUnknownFields(GPBMessage *self) {
#pragma mark - MergeFromCodedInputStream Support #pragma mark - MergeFromCodedInputStream Support
static void MergeSingleFieldFromCodedInputStream( static void MergeSingleFieldFromCodedInputStream(
GPBMessage *self, GPBFieldDescriptor *field, GPBFileSyntax syntax, GPBMessage *self, GPBFieldDescriptor *field,
GPBCodedInputStream *input, id<GPBExtensionRegistry>extensionRegistry) { GPBCodedInputStream *input, id<GPBExtensionRegistry>extensionRegistry) {
GPBDataType fieldDataType = GPBGetFieldDataType(field); GPBDataType fieldDataType = GPBGetFieldDataType(field);
switch (fieldDataType) { switch (fieldDataType) {
@ -2128,8 +2128,7 @@ static void MergeSingleFieldFromCodedInputStream(
case GPBDataTypeEnum: { case GPBDataTypeEnum: {
int32_t val = GPBCodedInputStreamReadEnum(&input->state_); int32_t val = GPBCodedInputStreamReadEnum(&input->state_);
if (GPBHasPreservingUnknownEnumSemantics(syntax) || if (!GPBFieldIsClosedEnum(field) || [field isValidEnumValue:val]) {
[field isValidEnumValue:val]) {
GPBSetInt32IvarWithFieldPrivate(self, field, val); GPBSetInt32IvarWithFieldPrivate(self, field, val);
} else { } else {
GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self); GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self);
@ -2140,7 +2139,7 @@ static void MergeSingleFieldFromCodedInputStream(
} }
static void MergeRepeatedPackedFieldFromCodedInputStream( static void MergeRepeatedPackedFieldFromCodedInputStream(
GPBMessage *self, GPBFieldDescriptor *field, GPBFileSyntax syntax, GPBMessage *self, GPBFieldDescriptor *field,
GPBCodedInputStream *input) { GPBCodedInputStream *input) {
GPBDataType fieldDataType = GPBGetFieldDataType(field); GPBDataType fieldDataType = GPBGetFieldDataType(field);
GPBCodedInputStreamState *state = &input->state_; GPBCodedInputStreamState *state = &input->state_;
@ -2179,8 +2178,7 @@ static void MergeRepeatedPackedFieldFromCodedInputStream(
case GPBDataTypeEnum: { case GPBDataTypeEnum: {
int32_t val = GPBCodedInputStreamReadEnum(state); int32_t val = GPBCodedInputStreamReadEnum(state);
if (GPBHasPreservingUnknownEnumSemantics(syntax) || if (!GPBFieldIsClosedEnum(field) || [field isValidEnumValue:val]) {
[field isValidEnumValue:val]) {
[(GPBEnumArray*)genericArray addRawValue:val]; [(GPBEnumArray*)genericArray addRawValue:val];
} else { } else {
GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self); GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self);
@ -2194,7 +2192,7 @@ static void MergeRepeatedPackedFieldFromCodedInputStream(
} }
static void MergeRepeatedNotPackedFieldFromCodedInputStream( static void MergeRepeatedNotPackedFieldFromCodedInputStream(
GPBMessage *self, GPBFieldDescriptor *field, GPBFileSyntax syntax, GPBMessage *self, GPBFieldDescriptor *field,
GPBCodedInputStream *input, id<GPBExtensionRegistry>extensionRegistry) { GPBCodedInputStream *input, id<GPBExtensionRegistry>extensionRegistry) {
GPBCodedInputStreamState *state = &input->state_; GPBCodedInputStreamState *state = &input->state_;
id genericArray = GetOrCreateArrayIvarWithField(self, field); id genericArray = GetOrCreateArrayIvarWithField(self, field);
@ -2247,8 +2245,7 @@ static void MergeRepeatedNotPackedFieldFromCodedInputStream(
} }
case GPBDataTypeEnum: { case GPBDataTypeEnum: {
int32_t val = GPBCodedInputStreamReadEnum(state); int32_t val = GPBCodedInputStreamReadEnum(state);
if (GPBHasPreservingUnknownEnumSemantics(syntax) || if (!GPBFieldIsClosedEnum(field) || [field isValidEnumValue:val]) {
[field isValidEnumValue:val]) {
[(GPBEnumArray*)genericArray addRawValue:val]; [(GPBEnumArray*)genericArray addRawValue:val];
} else { } else {
GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self); GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self);
@ -2262,7 +2259,6 @@ static void MergeRepeatedNotPackedFieldFromCodedInputStream(
- (void)mergeFromCodedInputStream:(GPBCodedInputStream *)input - (void)mergeFromCodedInputStream:(GPBCodedInputStream *)input
extensionRegistry:(id<GPBExtensionRegistry>)extensionRegistry { extensionRegistry:(id<GPBExtensionRegistry>)extensionRegistry {
GPBDescriptor *descriptor = [self descriptor]; GPBDescriptor *descriptor = [self descriptor];
GPBFileSyntax syntax = descriptor.file.syntax;
GPBCodedInputStreamState *state = &input->state_; GPBCodedInputStreamState *state = &input->state_;
uint32_t tag = 0; uint32_t tag = 0;
NSUInteger startingIndex = 0; NSUInteger startingIndex = 0;
@ -2280,7 +2276,7 @@ static void MergeRepeatedNotPackedFieldFromCodedInputStream(
if (GPBFieldTag(fieldDescriptor) == tag) { if (GPBFieldTag(fieldDescriptor) == tag) {
GPBFieldType fieldType = fieldDescriptor.fieldType; GPBFieldType fieldType = fieldDescriptor.fieldType;
if (fieldType == GPBFieldTypeSingle) { if (fieldType == GPBFieldTypeSingle) {
MergeSingleFieldFromCodedInputStream(self, fieldDescriptor, syntax, MergeSingleFieldFromCodedInputStream(self, fieldDescriptor,
input, extensionRegistry); input, extensionRegistry);
// Well formed protos will only have a single field once, advance // Well formed protos will only have a single field once, advance
// the starting index to the next field. // the starting index to the next field.
@ -2288,13 +2284,13 @@ static void MergeRepeatedNotPackedFieldFromCodedInputStream(
} else if (fieldType == GPBFieldTypeRepeated) { } else if (fieldType == GPBFieldTypeRepeated) {
if (fieldDescriptor.isPackable) { if (fieldDescriptor.isPackable) {
MergeRepeatedPackedFieldFromCodedInputStream( MergeRepeatedPackedFieldFromCodedInputStream(
self, fieldDescriptor, syntax, input); self, fieldDescriptor, input);
// Well formed protos will only have a repeated field that is // Well formed protos will only have a repeated field that is
// packed once, advance the starting index to the next field. // packed once, advance the starting index to the next field.
startingIndex += 1; startingIndex += 1;
} else { } else {
MergeRepeatedNotPackedFieldFromCodedInputStream( MergeRepeatedNotPackedFieldFromCodedInputStream(
self, fieldDescriptor, syntax, input, extensionRegistry); self, fieldDescriptor, input, extensionRegistry);
} }
} else { // fieldType == GPBFieldTypeMap } else { // fieldType == GPBFieldTypeMap
// GPB*Dictionary or NSDictionary, exact type doesn't matter at this // GPB*Dictionary or NSDictionary, exact type doesn't matter at this
@ -2325,13 +2321,13 @@ static void MergeRepeatedNotPackedFieldFromCodedInputStream(
BOOL alternateIsPacked = !fieldDescriptor.isPackable; BOOL alternateIsPacked = !fieldDescriptor.isPackable;
if (alternateIsPacked) { if (alternateIsPacked) {
MergeRepeatedPackedFieldFromCodedInputStream( MergeRepeatedPackedFieldFromCodedInputStream(
self, fieldDescriptor, syntax, input); self, fieldDescriptor, input);
// Well formed protos will only have a repeated field that is // Well formed protos will only have a repeated field that is
// packed once, advance the starting index to the next field. // packed once, advance the starting index to the next field.
startingIndex += 1; startingIndex += 1;
} else { } else {
MergeRepeatedNotPackedFieldFromCodedInputStream( MergeRepeatedNotPackedFieldFromCodedInputStream(
self, fieldDescriptor, syntax, input, extensionRegistry); self, fieldDescriptor, input, extensionRegistry);
} }
merged = YES; merged = YES;
break; break;

@ -669,8 +669,7 @@ int32_t GPBGetMessageEnumField(GPBMessage *self, GPBFieldDescriptor *field) {
// If this is presevering unknown enums, make sure the value is valid before // If this is presevering unknown enums, make sure the value is valid before
// returning it. // returning it.
GPBFileSyntax syntax = [self descriptor].file.syntax; if (!GPBFieldIsClosedEnum(field) && ![field isValidEnumValue:result]) {
if (GPBHasPreservingUnknownEnumSemantics(syntax) && ![field isValidEnumValue:result]) {
result = kGPBUnrecognizedEnumeratorValue; result = kGPBUnrecognizedEnumeratorValue;
} }
return result; return result;

Loading…
Cancel
Save