aboutsummaryrefslogtreecommitdiffhomepage
path: root/objectivec/GPBUtilities.m
diff options
context:
space:
mode:
Diffstat (limited to 'objectivec/GPBUtilities.m')
-rw-r--r--objectivec/GPBUtilities.m724
1 files changed, 590 insertions, 134 deletions
diff --git a/objectivec/GPBUtilities.m b/objectivec/GPBUtilities.m
index d4d6471f..e2a12ca4 100644
--- a/objectivec/GPBUtilities.m
+++ b/objectivec/GPBUtilities.m
@@ -39,10 +39,29 @@
#import "GPBUnknownField.h"
#import "GPBUnknownFieldSet.h"
+// Direct access is use for speed, to avoid even internally declaring things
+// read/write, etc. The warning is enabled in the project to ensure code calling
+// protos can turn on -Wdirect-ivar-access without issues.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdirect-ivar-access"
+
static void AppendTextFormatForMessage(GPBMessage *message,
NSMutableString *toStr,
NSString *lineIndent);
+// Are two datatypes the same basic type representation (ex Int32 and SInt32).
+// Marked unused because currently only called from asserts/debug.
+static BOOL DataTypesEquivalent(GPBDataType type1,
+ GPBDataType type2) __attribute__ ((unused));
+
+// Basic type representation for a type (ex: for SInt32 it is Int32).
+// Marked unused because currently only called from asserts/debug.
+static GPBDataType BaseDataType(GPBDataType type) __attribute__ ((unused));
+
+// String name for a data type.
+// Marked unused because currently only called from asserts/debug.
+static NSString *TypeToString(GPBDataType dataType) __attribute__ ((unused));
+
NSData *GPBEmptyNSData(void) {
static dispatch_once_t onceToken;
static NSData *defaultNSData = nil;
@@ -52,8 +71,169 @@ NSData *GPBEmptyNSData(void) {
return defaultNSData;
}
+void GPBMessageDropUnknownFieldsRecursively(GPBMessage *initialMessage) {
+ if (!initialMessage) {
+ return;
+ }
+
+ // Use an array as a list to process to avoid recursion.
+ NSMutableArray *todo = [NSMutableArray arrayWithObject:initialMessage];
+
+ while (todo.count) {
+ GPBMessage *msg = todo.lastObject;
+ [todo removeLastObject];
+
+ // Clear unknowns.
+ msg.unknownFields = nil;
+
+ // Handle the message fields.
+ GPBDescriptor *descriptor = [[msg class] descriptor];
+ for (GPBFieldDescriptor *field in descriptor->fields_) {
+ if (!GPBFieldDataTypeIsMessage(field)) {
+ continue;
+ }
+ switch (field.fieldType) {
+ case GPBFieldTypeSingle:
+ if (GPBGetHasIvarField(msg, field)) {
+ GPBMessage *fieldMessage = GPBGetObjectIvarWithFieldNoAutocreate(msg, field);
+ [todo addObject:fieldMessage];
+ }
+ break;
+
+ case GPBFieldTypeRepeated: {
+ NSArray *fieldMessages = GPBGetObjectIvarWithFieldNoAutocreate(msg, field);
+ if (fieldMessages.count) {
+ [todo addObjectsFromArray:fieldMessages];
+ }
+ break;
+ }
+
+ case GPBFieldTypeMap: {
+ id rawFieldMap = GPBGetObjectIvarWithFieldNoAutocreate(msg, field);
+ switch (field.mapKeyDataType) {
+ case GPBDataTypeBool:
+ [(GPBBoolObjectDictionary*)rawFieldMap enumerateKeysAndObjectsUsingBlock:^(
+ BOOL key, id _Nonnull object, BOOL * _Nonnull stop) {
+ #pragma unused(key, stop)
+ [todo addObject:object];
+ }];
+ break;
+ case GPBDataTypeFixed32:
+ case GPBDataTypeUInt32:
+ [(GPBUInt32ObjectDictionary*)rawFieldMap enumerateKeysAndObjectsUsingBlock:^(
+ uint32_t key, id _Nonnull object, BOOL * _Nonnull stop) {
+ #pragma unused(key, stop)
+ [todo addObject:object];
+ }];
+ break;
+ case GPBDataTypeInt32:
+ case GPBDataTypeSFixed32:
+ case GPBDataTypeSInt32:
+ [(GPBInt32ObjectDictionary*)rawFieldMap enumerateKeysAndObjectsUsingBlock:^(
+ int32_t key, id _Nonnull object, BOOL * _Nonnull stop) {
+ #pragma unused(key, stop)
+ [todo addObject:object];
+ }];
+ break;
+ case GPBDataTypeFixed64:
+ case GPBDataTypeUInt64:
+ [(GPBUInt64ObjectDictionary*)rawFieldMap enumerateKeysAndObjectsUsingBlock:^(
+ uint64_t key, id _Nonnull object, BOOL * _Nonnull stop) {
+ #pragma unused(key, stop)
+ [todo addObject:object];
+ }];
+ break;
+ case GPBDataTypeInt64:
+ case GPBDataTypeSFixed64:
+ case GPBDataTypeSInt64:
+ [(GPBInt64ObjectDictionary*)rawFieldMap enumerateKeysAndObjectsUsingBlock:^(
+ int64_t key, id _Nonnull object, BOOL * _Nonnull stop) {
+ #pragma unused(key, stop)
+ [todo addObject:object];
+ }];
+ break;
+ case GPBDataTypeString:
+ [(NSDictionary*)rawFieldMap enumerateKeysAndObjectsUsingBlock:^(
+ NSString * _Nonnull key, GPBMessage * _Nonnull obj, BOOL * _Nonnull stop) {
+ #pragma unused(key, stop)
+ [todo addObject:obj];
+ }];
+ break;
+ case GPBDataTypeFloat:
+ case GPBDataTypeDouble:
+ case GPBDataTypeEnum:
+ case GPBDataTypeBytes:
+ case GPBDataTypeGroup:
+ case GPBDataTypeMessage:
+ NSCAssert(NO, @"Aren't valid key types.");
+ }
+ break;
+ } // switch(field.mapKeyDataType)
+ } // switch(field.fieldType)
+ } // for(fields)
+
+ // Handle any extensions holding messages.
+ for (GPBExtensionDescriptor *extension in [msg extensionsCurrentlySet]) {
+ if (!GPBDataTypeIsMessage(extension.dataType)) {
+ continue;
+ }
+ if (extension.isRepeated) {
+ NSArray *extMessages = [msg getExtension:extension];
+ [todo addObjectsFromArray:extMessages];
+ } else {
+ GPBMessage *extMessage = [msg getExtension:extension];
+ [todo addObject:extMessage];
+ }
+ } // for(extensionsCurrentlySet)
+
+ } // while(todo.count)
+}
+
+
+// -- About Version Checks --
+// There's actually 3 places these checks all come into play:
+// 1. When the generated source is compile into .o files, the header check
+// happens. This is checking the protoc used matches the library being used
+// when making the .o.
+// 2. Every place a generated proto header is included in a developer's code,
+// the header check comes into play again. But this time it is checking that
+// the current library headers being used still support/match the ones for
+// the generated code.
+// 3. At runtime the final check here (GPBCheckRuntimeVersionsInternal), is
+// called from the generated code passing in values captured when the
+// generated code's .o was made. This checks that at runtime the generated
+// code and runtime library match.
+
+void GPBCheckRuntimeVersionSupport(int32_t objcRuntimeVersion) {
+ // NOTE: This is passing the value captured in the compiled code to check
+ // against the values captured when the runtime support was compiled. This
+ // ensures the library code isn't in a different framework/library that
+ // was generated with a non matching version.
+ if (GOOGLE_PROTOBUF_OBJC_VERSION < objcRuntimeVersion) {
+ // Library is too old for headers.
+ [NSException raise:NSInternalInconsistencyException
+ format:@"Linked to ProtocolBuffer runtime version %d,"
+ @" but code compiled needing atleast %d!",
+ GOOGLE_PROTOBUF_OBJC_VERSION, objcRuntimeVersion];
+ }
+ if (objcRuntimeVersion < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION) {
+ // Headers are too old for library.
+ [NSException raise:NSInternalInconsistencyException
+ format:@"Proto generation source compiled against runtime"
+ @" version %d, but this version of the runtime only"
+ @" supports back to %d!",
+ objcRuntimeVersion,
+ GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION];
+ }
+}
+
+// This api is no longer used for version checks. 30001 is the last version
+// using this old versioning model. When that support is removed, this function
+// can be removed (along with the declaration in GPBUtilities_PackagePrivate.h).
void GPBCheckRuntimeVersionInternal(int32_t version) {
- if (version != GOOGLE_PROTOBUF_OBJC_GEN_VERSION) {
+ GPBInternalCompileAssert(GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION == 30001,
+ time_to_remove_this_old_version_shim);
+ if (version != GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION) {
[NSException raise:NSInternalInconsistencyException
format:@"Linked to ProtocolBuffer runtime version %d,"
@" but code compiled with version %d!",
@@ -111,7 +291,7 @@ BOOL GPBGetHasIvar(GPBMessage *self, int32_t idx, uint32_t fieldNumber) {
} else {
NSCAssert(idx != GPBNoHasBit, @"Invalid has bit.");
uint32_t byteIndex = idx / 32;
- uint32_t bitMask = (1 << (idx % 32));
+ uint32_t bitMask = (1U << (idx % 32));
BOOL hasIvar =
(self->messageStorage_->_has_storage_[byteIndex] & bitMask) ? YES : NO;
return hasIvar;
@@ -135,7 +315,7 @@ void GPBSetHasIvar(GPBMessage *self, int32_t idx, uint32_t fieldNumber,
NSCAssert(idx != GPBNoHasBit, @"Invalid has bit.");
uint32_t *has_storage = self->messageStorage_->_has_storage_;
uint32_t byte = idx / 32;
- uint32_t bitMask = (1 << (idx % 32));
+ uint32_t bitMask = (1U << (idx % 32));
if (value) {
has_storage[byte] |= bitMask;
} else {
@@ -145,9 +325,8 @@ void GPBSetHasIvar(GPBMessage *self, int32_t idx, uint32_t fieldNumber,
}
void GPBMaybeClearOneof(GPBMessage *self, GPBOneofDescriptor *oneof,
- uint32_t fieldNumberNotToClear) {
- int32_t hasIndex = oneof->oneofDescription_->index;
- uint32_t fieldNumberSet = GPBGetHasOneof(self, hasIndex);
+ int32_t oneofHasIndex, uint32_t fieldNumberNotToClear) {
+ uint32_t fieldNumberSet = GPBGetHasOneof(self, oneofHasIndex);
if ((fieldNumberSet == fieldNumberNotToClear) || (fieldNumberSet == 0)) {
// Do nothing/nothing set in the oneof.
return;
@@ -168,7 +347,7 @@ void GPBMaybeClearOneof(GPBMessage *self, GPBOneofDescriptor *oneof,
// Set to nothing stored in the oneof.
// (field number doesn't matter since setting to nothing).
- GPBSetHasIvar(self, hasIndex, 1, NO);
+ GPBSetHasIvar(self, oneofHasIndex, 1, NO);
}
#pragma mark - IVar accessors
@@ -176,6 +355,14 @@ void GPBMaybeClearOneof(GPBMessage *self, GPBOneofDescriptor *oneof,
//%PDDM-DEFINE IVAR_POD_ACCESSORS_DEFN(NAME, TYPE)
//%TYPE GPBGetMessage##NAME##Field(GPBMessage *self,
//% TYPE$S NAME$S GPBFieldDescriptor *field) {
+//%#if defined(DEBUG) && DEBUG
+//% NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+//% GPBDataType##NAME),
+//% @"Attempting to get value of TYPE from field %@ "
+//% @"of %@ which is of type %@.",
+//% [self class], field.name,
+//% TypeToString(GPBGetFieldDataType(field)));
+//%#endif
//% if (GPBGetHasIvarField(self, field)) {
//% uint8_t *storage = (uint8_t *)self->messageStorage_;
//% TYPE *typePtr = (TYPE *)&storage[field->description_->offset];
@@ -198,13 +385,24 @@ void GPBMaybeClearOneof(GPBMessage *self, GPBOneofDescriptor *oneof,
//% NAME$S GPBFieldDescriptor *field,
//% NAME$S TYPE value,
//% NAME$S GPBFileSyntax syntax) {
+//%#if defined(DEBUG) && DEBUG
+//% NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+//% GPBDataType##NAME),
+//% @"Attempting to set field %@ of %@ which is of type %@ with "
+//% @"value of type TYPE.",
+//% [self class], field.name,
+//% TypeToString(GPBGetFieldDataType(field)));
+//%#endif
//% GPBOneofDescriptor *oneof = field->containingOneof_;
//% if (oneof) {
-//% GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field));
+//% GPBMessageFieldDescription *fieldDesc = field->description_;
+//% GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
//% }
+//%#if defined(DEBUG) && DEBUG
//% NSCAssert(self->messageStorage_ != NULL,
//% @"%@: All messages should have storage (from init)",
//% [self class]);
+//%#endif
//%#if defined(__clang_analyzer__)
//% if (self->messageStorage_ == NULL) return;
//%#endif
@@ -212,9 +410,10 @@ void GPBMaybeClearOneof(GPBMessage *self, GPBOneofDescriptor *oneof,
//% TYPE *typePtr = (TYPE *)&storage[field->description_->offset];
//% *typePtr = value;
//% // proto2: any value counts as having been set; proto3, it
-//% // has to be a non zero value.
-//% BOOL hasValue =
-//% (syntax == GPBFileSyntaxProto2) || (value != (TYPE)0);
+//% // has to be a non zero value or be in a oneof.
+//% BOOL hasValue = ((syntax == GPBFileSyntaxProto2)
+//% || (value != (TYPE)0)
+//% || (field->containingOneof_ != NULL));
//% GPBSetHasIvarField(self, field, hasValue);
//% GPBBecomeVisibleToAutocreator(self);
//%}
@@ -223,6 +422,14 @@ void GPBMaybeClearOneof(GPBMessage *self, GPBOneofDescriptor *oneof,
//%// Only exists for public api, no core code should use this.
//%TYPE *GPBGetMessage##NAME##Field(GPBMessage *self,
//% TYPE$S NAME$S GPBFieldDescriptor *field) {
+//%#if defined(DEBUG) && DEBUG
+//% NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+//% GPBDataType##NAME),
+//% @"Attempting to get value of TYPE from field %@ "
+//% @"of %@ which is of type %@.",
+//% [self class], field.name,
+//% TypeToString(GPBGetFieldDataType(field)));
+//%#endif
//% return (TYPE *)GPBGetObjectIvarWithField(self, field);
//%}
//%
@@ -230,6 +437,14 @@ void GPBMaybeClearOneof(GPBMessage *self, GPBOneofDescriptor *oneof,
//%void GPBSetMessage##NAME##Field(GPBMessage *self,
//% NAME$S GPBFieldDescriptor *field,
//% NAME$S TYPE *value) {
+//%#if defined(DEBUG) && DEBUG
+//% NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+//% GPBDataType##NAME),
+//% @"Attempting to set field %@ of %@ which is of type %@ with "
+//% @"value of type TYPE.",
+//% [self class], field.name,
+//% TypeToString(GPBGetFieldDataType(field)));
+//%#endif
//% GPBSetObjectIvarWithField(self, field, (id)value);
//%}
//%
@@ -287,7 +502,7 @@ void GPBSetRetainedObjectIvarWithFieldInternal(GPBMessage *self,
GPBDataType fieldType = GPBGetFieldDataType(field);
BOOL isMapOrArray = GPBFieldIsMapOrArray(field);
BOOL fieldIsMessage = GPBDataTypeIsMessage(fieldType);
-#ifdef DEBUG
+#if defined(DEBUG) && DEBUG
if (value == nil && !isMapOrArray && !fieldIsMessage &&
field.hasDefaultValue) {
// Setting a message to nil is an obvious way to "clear" the value
@@ -321,7 +536,8 @@ void GPBSetRetainedObjectIvarWithFieldInternal(GPBMessage *self,
// oneof.
GPBOneofDescriptor *oneof = field->containingOneof_;
if (oneof) {
- GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field));
+ GPBMessageFieldDescription *fieldDesc = field->description_;
+ GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
}
// Clear "has" if they are being set to nil.
BOOL setHasValue = (value != nil);
@@ -330,8 +546,19 @@ void GPBSetRetainedObjectIvarWithFieldInternal(GPBMessage *self,
// zero, they are being cleared.
if ((syntax == GPBFileSyntaxProto3) && !fieldIsMessage &&
([value length] == 0)) {
- setHasValue = NO;
- value = nil;
+ // Except, if the field was in a oneof, then it still gets recorded as
+ // having been set so the state of the oneof can be serialized back out.
+ if (!oneof) {
+ setHasValue = NO;
+ }
+ if (setHasValue) {
+ NSCAssert(value != nil, @"Should never be setting has for nil");
+ } else {
+ // The value passed in was retained, it must be released since we
+ // aren't saving anything in the field.
+ [value release];
+ value = nil;
+ }
}
GPBSetHasIvarField(self, field, setHasValue);
}
@@ -347,9 +574,11 @@ void GPBSetRetainedObjectIvarWithFieldInternal(GPBMessage *self,
if (field.fieldType == GPBFieldTypeRepeated) {
// If the old array was autocreated by us, then clear it.
if (GPBDataTypeIsObject(fieldType)) {
- GPBAutocreatedArray *autoArray = oldValue;
- if (autoArray->_autocreator == self) {
- autoArray->_autocreator = nil;
+ if ([oldValue isKindOfClass:[GPBAutocreatedArray class]]) {
+ GPBAutocreatedArray *autoArray = oldValue;
+ if (autoArray->_autocreator == self) {
+ autoArray->_autocreator = nil;
+ }
}
} else {
// Type doesn't matter, it is a GPB*Array.
@@ -362,9 +591,11 @@ void GPBSetRetainedObjectIvarWithFieldInternal(GPBMessage *self,
// If the old map was autocreated by us, then clear it.
if ((field.mapKeyDataType == GPBDataTypeString) &&
GPBDataTypeIsObject(fieldType)) {
- GPBAutocreatedDictionary *autoDict = oldValue;
- if (autoDict->_autocreator == self) {
- autoDict->_autocreator = nil;
+ if ([oldValue isKindOfClass:[GPBAutocreatedDictionary class]]) {
+ GPBAutocreatedDictionary *autoDict = oldValue;
+ if (autoDict->_autocreator == self) {
+ autoDict->_autocreator = nil;
+ }
}
} else {
// Type doesn't matter, it is a GPB*Dictionary.
@@ -397,33 +628,6 @@ id GPBGetObjectIvarWithFieldNoAutocreate(GPBMessage *self,
return *typePtr;
}
-id GPBGetObjectIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) {
- NSCAssert(!GPBFieldIsMapOrArray(field), @"Shouldn't get here");
- if (GPBGetHasIvarField(self, field)) {
- uint8_t *storage = (uint8_t *)self->messageStorage_;
- id *typePtr = (id *)&storage[field->description_->offset];
- return *typePtr;
- }
- // Not set...
-
- // Non messages (string/data), get their default.
- if (!GPBFieldDataTypeIsMessage(field)) {
- return field.defaultValue.valueMessage;
- }
-
- dispatch_semaphore_wait(self->readOnlySemaphore_, DISPATCH_TIME_FOREVER);
- GPBMessage *result = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
- if (!result) {
- // For non repeated messages, create the object, set it and return it.
- // This object will not initially be visible via GPBGetHasIvar, so
- // we save its creator so it can become visible if it's mutated later.
- result = GPBCreateMessageWithAutocreator(field.msgClass, self, field);
- GPBSetAutocreatedRetainedObjectIvarWithField(self, field, result);
- }
- dispatch_semaphore_signal(self->readOnlySemaphore_);
- return result;
-}
-
// Only exists for public api, no core code should use this.
int32_t GPBGetMessageEnumField(GPBMessage *self, GPBFieldDescriptor *field) {
GPBFileSyntax syntax = [self descriptor].file.syntax;
@@ -433,6 +637,13 @@ int32_t GPBGetMessageEnumField(GPBMessage *self, GPBFieldDescriptor *field) {
int32_t GPBGetEnumIvarWithFieldInternal(GPBMessage *self,
GPBFieldDescriptor *field,
GPBFileSyntax syntax) {
+#if defined(DEBUG) && DEBUG
+ NSCAssert(GPBGetFieldDataType(field) == GPBDataTypeEnum,
+ @"Attempting to get value of type Enum from field %@ "
+ @"of %@ which is of type %@.",
+ [self class], field.name,
+ TypeToString(GPBGetFieldDataType(field)));
+#endif
int32_t result = GPBGetMessageInt32Field(self, field);
// If this is presevering unknown enums, make sure the value is valid before
// returning it.
@@ -453,6 +664,13 @@ void GPBSetMessageEnumField(GPBMessage *self, GPBFieldDescriptor *field,
void GPBSetEnumIvarWithFieldInternal(GPBMessage *self,
GPBFieldDescriptor *field, int32_t value,
GPBFileSyntax syntax) {
+#if defined(DEBUG) && DEBUG
+ NSCAssert(GPBGetFieldDataType(field) == GPBDataTypeEnum,
+ @"Attempting to set field %@ of %@ which is of type %@ with "
+ @"value of type Enum.",
+ [self class], field.name,
+ TypeToString(GPBGetFieldDataType(field)));
+#endif
// Don't allow in unknown values. Proto3 can use the Raw method.
if (![field isValidEnumValue:value]) {
[NSException raise:NSInvalidArgumentException
@@ -476,15 +694,22 @@ void GPBSetMessageRawEnumField(GPBMessage *self, GPBFieldDescriptor *field,
GPBSetInt32IvarWithFieldInternal(self, field, value, syntax);
}
-//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(Bool, BOOL)
-// This block of code is generated, do not edit it directly.
-
BOOL GPBGetMessageBoolField(GPBMessage *self,
GPBFieldDescriptor *field) {
+#if defined(DEBUG) && DEBUG
+ NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field), GPBDataTypeBool),
+ @"Attempting to get value of type bool from field %@ "
+ @"of %@ which is of type %@.",
+ [self class], field.name,
+ TypeToString(GPBGetFieldDataType(field)));
+#endif
if (GPBGetHasIvarField(self, field)) {
- uint8_t *storage = (uint8_t *)self->messageStorage_;
- BOOL *typePtr = (BOOL *)&storage[field->description_->offset];
- return *typePtr;
+ // Bools are stored in the has bits to avoid needing explicit space in the
+ // storage structure.
+ // (the field number passed to the HasIvar helper doesn't really matter
+ // since the offset is never negative)
+ GPBMessageFieldDescription *fieldDesc = field->description_;
+ return GPBGetHasIvar(self, (int32_t)(fieldDesc->offset), fieldDesc->number);
} else {
return field.defaultValue.valueBool;
}
@@ -503,23 +728,30 @@ void GPBSetBoolIvarWithFieldInternal(GPBMessage *self,
GPBFieldDescriptor *field,
BOOL value,
GPBFileSyntax syntax) {
+#if defined(DEBUG) && DEBUG
+ NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field), GPBDataTypeBool),
+ @"Attempting to set field %@ of %@ which is of type %@ with "
+ @"value of type bool.",
+ [self class], field.name,
+ TypeToString(GPBGetFieldDataType(field)));
+#endif
+ GPBMessageFieldDescription *fieldDesc = field->description_;
GPBOneofDescriptor *oneof = field->containingOneof_;
if (oneof) {
- GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field));
+ GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
}
- NSCAssert(self->messageStorage_ != NULL,
- @"%@: All messages should have storage (from init)",
- [self class]);
-#if defined(__clang_analyzer__)
- if (self->messageStorage_ == NULL) return;
-#endif
- uint8_t *storage = (uint8_t *)self->messageStorage_;
- BOOL *typePtr = (BOOL *)&storage[field->description_->offset];
- *typePtr = value;
+
+ // Bools are stored in the has bits to avoid needing explicit space in the
+ // storage structure.
+ // (the field number passed to the HasIvar helper doesn't really matter since
+ // the offset is never negative)
+ GPBSetHasIvar(self, (int32_t)(fieldDesc->offset), fieldDesc->number, value);
+
// proto2: any value counts as having been set; proto3, it
- // has to be a non zero value.
- BOOL hasValue =
- (syntax == GPBFileSyntaxProto2) || (value != (BOOL)0);
+ // has to be a non zero value or be in a oneof.
+ BOOL hasValue = ((syntax == GPBFileSyntaxProto2)
+ || (value != (BOOL)0)
+ || (field->containingOneof_ != NULL));
GPBSetHasIvarField(self, field, hasValue);
GPBBecomeVisibleToAutocreator(self);
}
@@ -529,6 +761,14 @@ void GPBSetBoolIvarWithFieldInternal(GPBMessage *self,
int32_t GPBGetMessageInt32Field(GPBMessage *self,
GPBFieldDescriptor *field) {
+#if defined(DEBUG) && DEBUG
+ NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+ GPBDataTypeInt32),
+ @"Attempting to get value of int32_t from field %@ "
+ @"of %@ which is of type %@.",
+ [self class], field.name,
+ TypeToString(GPBGetFieldDataType(field)));
+#endif
if (GPBGetHasIvarField(self, field)) {
uint8_t *storage = (uint8_t *)self->messageStorage_;
int32_t *typePtr = (int32_t *)&storage[field->description_->offset];
@@ -551,13 +791,24 @@ void GPBSetInt32IvarWithFieldInternal(GPBMessage *self,
GPBFieldDescriptor *field,
int32_t value,
GPBFileSyntax syntax) {
+#if defined(DEBUG) && DEBUG
+ NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+ GPBDataTypeInt32),
+ @"Attempting to set field %@ of %@ which is of type %@ with "
+ @"value of type int32_t.",
+ [self class], field.name,
+ TypeToString(GPBGetFieldDataType(field)));
+#endif
GPBOneofDescriptor *oneof = field->containingOneof_;
if (oneof) {
- GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field));
+ GPBMessageFieldDescription *fieldDesc = field->description_;
+ GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
}
+#if defined(DEBUG) && DEBUG
NSCAssert(self->messageStorage_ != NULL,
@"%@: All messages should have storage (from init)",
[self class]);
+#endif
#if defined(__clang_analyzer__)
if (self->messageStorage_ == NULL) return;
#endif
@@ -565,9 +816,10 @@ void GPBSetInt32IvarWithFieldInternal(GPBMessage *self,
int32_t *typePtr = (int32_t *)&storage[field->description_->offset];
*typePtr = value;
// proto2: any value counts as having been set; proto3, it
- // has to be a non zero value.
- BOOL hasValue =
- (syntax == GPBFileSyntaxProto2) || (value != (int32_t)0);
+ // has to be a non zero value or be in a oneof.
+ BOOL hasValue = ((syntax == GPBFileSyntaxProto2)
+ || (value != (int32_t)0)
+ || (field->containingOneof_ != NULL));
GPBSetHasIvarField(self, field, hasValue);
GPBBecomeVisibleToAutocreator(self);
}
@@ -577,6 +829,14 @@ void GPBSetInt32IvarWithFieldInternal(GPBMessage *self,
uint32_t GPBGetMessageUInt32Field(GPBMessage *self,
GPBFieldDescriptor *field) {
+#if defined(DEBUG) && DEBUG
+ NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+ GPBDataTypeUInt32),
+ @"Attempting to get value of uint32_t from field %@ "
+ @"of %@ which is of type %@.",
+ [self class], field.name,
+ TypeToString(GPBGetFieldDataType(field)));
+#endif
if (GPBGetHasIvarField(self, field)) {
uint8_t *storage = (uint8_t *)self->messageStorage_;
uint32_t *typePtr = (uint32_t *)&storage[field->description_->offset];
@@ -599,13 +859,24 @@ void GPBSetUInt32IvarWithFieldInternal(GPBMessage *self,
GPBFieldDescriptor *field,
uint32_t value,
GPBFileSyntax syntax) {
+#if defined(DEBUG) && DEBUG
+ NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+ GPBDataTypeUInt32),
+ @"Attempting to set field %@ of %@ which is of type %@ with "
+ @"value of type uint32_t.",
+ [self class], field.name,
+ TypeToString(GPBGetFieldDataType(field)));
+#endif
GPBOneofDescriptor *oneof = field->containingOneof_;
if (oneof) {
- GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field));
+ GPBMessageFieldDescription *fieldDesc = field->description_;
+ GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
}
+#if defined(DEBUG) && DEBUG
NSCAssert(self->messageStorage_ != NULL,
@"%@: All messages should have storage (from init)",
[self class]);
+#endif
#if defined(__clang_analyzer__)
if (self->messageStorage_ == NULL) return;
#endif
@@ -613,9 +884,10 @@ void GPBSetUInt32IvarWithFieldInternal(GPBMessage *self,
uint32_t *typePtr = (uint32_t *)&storage[field->description_->offset];
*typePtr = value;
// proto2: any value counts as having been set; proto3, it
- // has to be a non zero value.
- BOOL hasValue =
- (syntax == GPBFileSyntaxProto2) || (value != (uint32_t)0);
+ // has to be a non zero value or be in a oneof.
+ BOOL hasValue = ((syntax == GPBFileSyntaxProto2)
+ || (value != (uint32_t)0)
+ || (field->containingOneof_ != NULL));
GPBSetHasIvarField(self, field, hasValue);
GPBBecomeVisibleToAutocreator(self);
}
@@ -625,6 +897,14 @@ void GPBSetUInt32IvarWithFieldInternal(GPBMessage *self,
int64_t GPBGetMessageInt64Field(GPBMessage *self,
GPBFieldDescriptor *field) {
+#if defined(DEBUG) && DEBUG
+ NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+ GPBDataTypeInt64),
+ @"Attempting to get value of int64_t from field %@ "
+ @"of %@ which is of type %@.",
+ [self class], field.name,
+ TypeToString(GPBGetFieldDataType(field)));
+#endif
if (GPBGetHasIvarField(self, field)) {
uint8_t *storage = (uint8_t *)self->messageStorage_;
int64_t *typePtr = (int64_t *)&storage[field->description_->offset];
@@ -647,13 +927,24 @@ void GPBSetInt64IvarWithFieldInternal(GPBMessage *self,
GPBFieldDescriptor *field,
int64_t value,
GPBFileSyntax syntax) {
+#if defined(DEBUG) && DEBUG
+ NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+ GPBDataTypeInt64),
+ @"Attempting to set field %@ of %@ which is of type %@ with "
+ @"value of type int64_t.",
+ [self class], field.name,
+ TypeToString(GPBGetFieldDataType(field)));
+#endif
GPBOneofDescriptor *oneof = field->containingOneof_;
if (oneof) {
- GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field));
+ GPBMessageFieldDescription *fieldDesc = field->description_;
+ GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
}
+#if defined(DEBUG) && DEBUG
NSCAssert(self->messageStorage_ != NULL,
@"%@: All messages should have storage (from init)",
[self class]);
+#endif
#if defined(__clang_analyzer__)
if (self->messageStorage_ == NULL) return;
#endif
@@ -661,9 +952,10 @@ void GPBSetInt64IvarWithFieldInternal(GPBMessage *self,
int64_t *typePtr = (int64_t *)&storage[field->description_->offset];
*typePtr = value;
// proto2: any value counts as having been set; proto3, it
- // has to be a non zero value.
- BOOL hasValue =
- (syntax == GPBFileSyntaxProto2) || (value != (int64_t)0);
+ // has to be a non zero value or be in a oneof.
+ BOOL hasValue = ((syntax == GPBFileSyntaxProto2)
+ || (value != (int64_t)0)
+ || (field->containingOneof_ != NULL));
GPBSetHasIvarField(self, field, hasValue);
GPBBecomeVisibleToAutocreator(self);
}
@@ -673,6 +965,14 @@ void GPBSetInt64IvarWithFieldInternal(GPBMessage *self,
uint64_t GPBGetMessageUInt64Field(GPBMessage *self,
GPBFieldDescriptor *field) {
+#if defined(DEBUG) && DEBUG
+ NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+ GPBDataTypeUInt64),
+ @"Attempting to get value of uint64_t from field %@ "
+ @"of %@ which is of type %@.",
+ [self class], field.name,
+ TypeToString(GPBGetFieldDataType(field)));
+#endif
if (GPBGetHasIvarField(self, field)) {
uint8_t *storage = (uint8_t *)self->messageStorage_;
uint64_t *typePtr = (uint64_t *)&storage[field->description_->offset];
@@ -695,13 +995,24 @@ void GPBSetUInt64IvarWithFieldInternal(GPBMessage *self,
GPBFieldDescriptor *field,
uint64_t value,
GPBFileSyntax syntax) {
+#if defined(DEBUG) && DEBUG
+ NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+ GPBDataTypeUInt64),
+ @"Attempting to set field %@ of %@ which is of type %@ with "
+ @"value of type uint64_t.",
+ [self class], field.name,
+ TypeToString(GPBGetFieldDataType(field)));
+#endif
GPBOneofDescriptor *oneof = field->containingOneof_;
if (oneof) {
- GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field));
+ GPBMessageFieldDescription *fieldDesc = field->description_;
+ GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
}
+#if defined(DEBUG) && DEBUG
NSCAssert(self->messageStorage_ != NULL,
@"%@: All messages should have storage (from init)",
[self class]);
+#endif
#if defined(__clang_analyzer__)
if (self->messageStorage_ == NULL) return;
#endif
@@ -709,9 +1020,10 @@ void GPBSetUInt64IvarWithFieldInternal(GPBMessage *self,
uint64_t *typePtr = (uint64_t *)&storage[field->description_->offset];
*typePtr = value;
// proto2: any value counts as having been set; proto3, it
- // has to be a non zero value.
- BOOL hasValue =
- (syntax == GPBFileSyntaxProto2) || (value != (uint64_t)0);
+ // has to be a non zero value or be in a oneof.
+ BOOL hasValue = ((syntax == GPBFileSyntaxProto2)
+ || (value != (uint64_t)0)
+ || (field->containingOneof_ != NULL));
GPBSetHasIvarField(self, field, hasValue);
GPBBecomeVisibleToAutocreator(self);
}
@@ -721,6 +1033,14 @@ void GPBSetUInt64IvarWithFieldInternal(GPBMessage *self,
float GPBGetMessageFloatField(GPBMessage *self,
GPBFieldDescriptor *field) {
+#if defined(DEBUG) && DEBUG
+ NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+ GPBDataTypeFloat),
+ @"Attempting to get value of float from field %@ "
+ @"of %@ which is of type %@.",
+ [self class], field.name,
+ TypeToString(GPBGetFieldDataType(field)));
+#endif
if (GPBGetHasIvarField(self, field)) {
uint8_t *storage = (uint8_t *)self->messageStorage_;
float *typePtr = (float *)&storage[field->description_->offset];
@@ -743,13 +1063,24 @@ void GPBSetFloatIvarWithFieldInternal(GPBMessage *self,
GPBFieldDescriptor *field,
float value,
GPBFileSyntax syntax) {
+#if defined(DEBUG) && DEBUG
+ NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+ GPBDataTypeFloat),
+ @"Attempting to set field %@ of %@ which is of type %@ with "
+ @"value of type float.",
+ [self class], field.name,
+ TypeToString(GPBGetFieldDataType(field)));
+#endif
GPBOneofDescriptor *oneof = field->containingOneof_;
if (oneof) {
- GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field));
+ GPBMessageFieldDescription *fieldDesc = field->description_;
+ GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
}
+#if defined(DEBUG) && DEBUG
NSCAssert(self->messageStorage_ != NULL,
@"%@: All messages should have storage (from init)",
[self class]);
+#endif
#if defined(__clang_analyzer__)
if (self->messageStorage_ == NULL) return;
#endif
@@ -757,9 +1088,10 @@ void GPBSetFloatIvarWithFieldInternal(GPBMessage *self,
float *typePtr = (float *)&storage[field->description_->offset];
*typePtr = value;
// proto2: any value counts as having been set; proto3, it
- // has to be a non zero value.
- BOOL hasValue =
- (syntax == GPBFileSyntaxProto2) || (value != (float)0);
+ // has to be a non zero value or be in a oneof.
+ BOOL hasValue = ((syntax == GPBFileSyntaxProto2)
+ || (value != (float)0)
+ || (field->containingOneof_ != NULL));
GPBSetHasIvarField(self, field, hasValue);
GPBBecomeVisibleToAutocreator(self);
}
@@ -769,6 +1101,14 @@ void GPBSetFloatIvarWithFieldInternal(GPBMessage *self,
double GPBGetMessageDoubleField(GPBMessage *self,
GPBFieldDescriptor *field) {
+#if defined(DEBUG) && DEBUG
+ NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+ GPBDataTypeDouble),
+ @"Attempting to get value of double from field %@ "
+ @"of %@ which is of type %@.",
+ [self class], field.name,
+ TypeToString(GPBGetFieldDataType(field)));
+#endif
if (GPBGetHasIvarField(self, field)) {
uint8_t *storage = (uint8_t *)self->messageStorage_;
double *typePtr = (double *)&storage[field->description_->offset];
@@ -791,13 +1131,24 @@ void GPBSetDoubleIvarWithFieldInternal(GPBMessage *self,
GPBFieldDescriptor *field,
double value,
GPBFileSyntax syntax) {
+#if defined(DEBUG) && DEBUG
+ NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+ GPBDataTypeDouble),
+ @"Attempting to set field %@ of %@ which is of type %@ with "
+ @"value of type double.",
+ [self class], field.name,
+ TypeToString(GPBGetFieldDataType(field)));
+#endif
GPBOneofDescriptor *oneof = field->containingOneof_;
if (oneof) {
- GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field));
+ GPBMessageFieldDescription *fieldDesc = field->description_;
+ GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
}
+#if defined(DEBUG) && DEBUG
NSCAssert(self->messageStorage_ != NULL,
@"%@: All messages should have storage (from init)",
[self class]);
+#endif
#if defined(__clang_analyzer__)
if (self->messageStorage_ == NULL) return;
#endif
@@ -805,14 +1156,15 @@ void GPBSetDoubleIvarWithFieldInternal(GPBMessage *self,
double *typePtr = (double *)&storage[field->description_->offset];
*typePtr = value;
// proto2: any value counts as having been set; proto3, it
- // has to be a non zero value.
- BOOL hasValue =
- (syntax == GPBFileSyntaxProto2) || (value != (double)0);
+ // has to be a non zero value or be in a oneof.
+ BOOL hasValue = ((syntax == GPBFileSyntaxProto2)
+ || (value != (double)0)
+ || (field->containingOneof_ != NULL));
GPBSetHasIvarField(self, field, hasValue);
GPBBecomeVisibleToAutocreator(self);
}
-//%PDDM-EXPAND-END (7 expansions)
+//%PDDM-EXPAND-END (6 expansions)
// Aliases are function calls that are virtually the same.
@@ -822,6 +1174,14 @@ void GPBSetDoubleIvarWithFieldInternal(GPBMessage *self,
// Only exists for public api, no core code should use this.
NSString *GPBGetMessageStringField(GPBMessage *self,
GPBFieldDescriptor *field) {
+#if defined(DEBUG) && DEBUG
+ NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+ GPBDataTypeString),
+ @"Attempting to get value of NSString from field %@ "
+ @"of %@ which is of type %@.",
+ [self class], field.name,
+ TypeToString(GPBGetFieldDataType(field)));
+#endif
return (NSString *)GPBGetObjectIvarWithField(self, field);
}
@@ -829,6 +1189,14 @@ NSString *GPBGetMessageStringField(GPBMessage *self,
void GPBSetMessageStringField(GPBMessage *self,
GPBFieldDescriptor *field,
NSString *value) {
+#if defined(DEBUG) && DEBUG
+ NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+ GPBDataTypeString),
+ @"Attempting to set field %@ of %@ which is of type %@ with "
+ @"value of type NSString.",
+ [self class], field.name,
+ TypeToString(GPBGetFieldDataType(field)));
+#endif
GPBSetObjectIvarWithField(self, field, (id)value);
}
@@ -838,6 +1206,14 @@ void GPBSetMessageStringField(GPBMessage *self,
// Only exists for public api, no core code should use this.
NSData *GPBGetMessageBytesField(GPBMessage *self,
GPBFieldDescriptor *field) {
+#if defined(DEBUG) && DEBUG
+ NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+ GPBDataTypeBytes),
+ @"Attempting to get value of NSData from field %@ "
+ @"of %@ which is of type %@.",
+ [self class], field.name,
+ TypeToString(GPBGetFieldDataType(field)));
+#endif
return (NSData *)GPBGetObjectIvarWithField(self, field);
}
@@ -845,6 +1221,14 @@ NSData *GPBGetMessageBytesField(GPBMessage *self,
void GPBSetMessageBytesField(GPBMessage *self,
GPBFieldDescriptor *field,
NSData *value) {
+#if defined(DEBUG) && DEBUG
+ NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+ GPBDataTypeBytes),
+ @"Attempting to set field %@ of %@ which is of type %@ with "
+ @"value of type NSData.",
+ [self class], field.name,
+ TypeToString(GPBGetFieldDataType(field)));
+#endif
GPBSetObjectIvarWithField(self, field, (id)value);
}
@@ -854,6 +1238,14 @@ void GPBSetMessageBytesField(GPBMessage *self,
// Only exists for public api, no core code should use this.
GPBMessage *GPBGetMessageMessageField(GPBMessage *self,
GPBFieldDescriptor *field) {
+#if defined(DEBUG) && DEBUG
+ NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+ GPBDataTypeMessage),
+ @"Attempting to get value of GPBMessage from field %@ "
+ @"of %@ which is of type %@.",
+ [self class], field.name,
+ TypeToString(GPBGetFieldDataType(field)));
+#endif
return (GPBMessage *)GPBGetObjectIvarWithField(self, field);
}
@@ -861,6 +1253,14 @@ GPBMessage *GPBGetMessageMessageField(GPBMessage *self,
void GPBSetMessageMessageField(GPBMessage *self,
GPBFieldDescriptor *field,
GPBMessage *value) {
+#if defined(DEBUG) && DEBUG
+ NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+ GPBDataTypeMessage),
+ @"Attempting to set field %@ of %@ which is of type %@ with "
+ @"value of type GPBMessage.",
+ [self class], field.name,
+ TypeToString(GPBGetFieldDataType(field)));
+#endif
GPBSetObjectIvarWithField(self, field, (id)value);
}
@@ -870,6 +1270,14 @@ void GPBSetMessageMessageField(GPBMessage *self,
// Only exists for public api, no core code should use this.
GPBMessage *GPBGetMessageGroupField(GPBMessage *self,
GPBFieldDescriptor *field) {
+#if defined(DEBUG) && DEBUG
+ NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+ GPBDataTypeGroup),
+ @"Attempting to get value of GPBMessage from field %@ "
+ @"of %@ which is of type %@.",
+ [self class], field.name,
+ TypeToString(GPBGetFieldDataType(field)));
+#endif
return (GPBMessage *)GPBGetObjectIvarWithField(self, field);
}
@@ -877,26 +1285,24 @@ GPBMessage *GPBGetMessageGroupField(GPBMessage *self,
void GPBSetMessageGroupField(GPBMessage *self,
GPBFieldDescriptor *field,
GPBMessage *value) {
+#if defined(DEBUG) && DEBUG
+ NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
+ GPBDataTypeGroup),
+ @"Attempting to set field %@ of %@ which is of type %@ with "
+ @"value of type GPBMessage.",
+ [self class], field.name,
+ TypeToString(GPBGetFieldDataType(field)));
+#endif
GPBSetObjectIvarWithField(self, field, (id)value);
}
//%PDDM-EXPAND-END (4 expansions)
-// Only exists for public api, no core code should use this.
-id GPBGetMessageRepeatedField(GPBMessage *self, GPBFieldDescriptor *field) {
-#if DEBUG
- if (field.fieldType != GPBFieldTypeRepeated) {
- [NSException raise:NSInvalidArgumentException
- format:@"%@.%@ is not a repeated field.",
- [self class], field.name];
- }
-#endif
- return GPBGetObjectIvarWithField(self, field);
-}
+// GPBGetMessageRepeatedField is defined in GPBMessage.m
// Only exists for public api, no core code should use this.
void GPBSetMessageRepeatedField(GPBMessage *self, GPBFieldDescriptor *field, id array) {
-#if DEBUG
+#if defined(DEBUG) && DEBUG
if (field.fieldType != GPBFieldTypeRepeated) {
[NSException raise:NSInvalidArgumentException
format:@"%@.%@ is not a repeated field.",
@@ -935,10 +1341,10 @@ void GPBSetMessageRepeatedField(GPBMessage *self, GPBFieldDescriptor *field, id
case GPBDataTypeString:
case GPBDataTypeMessage:
case GPBDataTypeGroup:
- expectedClass = [NSMutableDictionary class];
+ expectedClass = [NSMutableArray class];
break;
case GPBDataTypeEnum:
- expectedClass = [GPBBoolArray class];
+ expectedClass = [GPBEnumArray class];
break;
}
if (array && ![array isKindOfClass:expectedClass]) {
@@ -950,8 +1356,40 @@ void GPBSetMessageRepeatedField(GPBMessage *self, GPBFieldDescriptor *field, id
GPBSetObjectIvarWithField(self, field, array);
}
-#if DEBUG
-static NSString *TypeToStr(GPBDataType dataType) {
+static GPBDataType BaseDataType(GPBDataType type) {
+ switch (type) {
+ case GPBDataTypeSFixed32:
+ case GPBDataTypeInt32:
+ case GPBDataTypeSInt32:
+ case GPBDataTypeEnum:
+ return GPBDataTypeInt32;
+ case GPBDataTypeFixed32:
+ case GPBDataTypeUInt32:
+ return GPBDataTypeUInt32;
+ case GPBDataTypeSFixed64:
+ case GPBDataTypeInt64:
+ case GPBDataTypeSInt64:
+ return GPBDataTypeInt64;
+ case GPBDataTypeFixed64:
+ case GPBDataTypeUInt64:
+ return GPBDataTypeUInt64;
+ case GPBDataTypeMessage:
+ case GPBDataTypeGroup:
+ return GPBDataTypeMessage;
+ case GPBDataTypeBool:
+ case GPBDataTypeFloat:
+ case GPBDataTypeDouble:
+ case GPBDataTypeBytes:
+ case GPBDataTypeString:
+ return type;
+ }
+}
+
+static BOOL DataTypesEquivalent(GPBDataType type1, GPBDataType type2) {
+ return BaseDataType(type1) == BaseDataType(type2);
+}
+
+static NSString *TypeToString(GPBDataType dataType) {
switch (dataType) {
case GPBDataTypeBool:
return @"Bool";
@@ -979,27 +1417,16 @@ static NSString *TypeToStr(GPBDataType dataType) {
case GPBDataTypeGroup:
return @"Object";
case GPBDataTypeEnum:
- return @"Bool";
+ return @"Enum";
}
}
-#endif
-// Only exists for public api, no core code should use this.
-id GPBGetMessageMapField(GPBMessage *self, GPBFieldDescriptor *field) {
-#if DEBUG
- if (field.fieldType != GPBFieldTypeMap) {
- [NSException raise:NSInvalidArgumentException
- format:@"%@.%@ is not a map<> field.",
- [self class], field.name];
- }
-#endif
- return GPBGetObjectIvarWithField(self, field);
-}
+// GPBGetMessageMapField is defined in GPBMessage.m
// Only exists for public api, no core code should use this.
void GPBSetMessageMapField(GPBMessage *self, GPBFieldDescriptor *field,
id dictionary) {
-#if DEBUG
+#if defined(DEBUG) && DEBUG
if (field.fieldType != GPBFieldTypeMap) {
[NSException raise:NSInvalidArgumentException
format:@"%@.%@ is not a map<> field.",
@@ -1008,8 +1435,8 @@ void GPBSetMessageMapField(GPBMessage *self, GPBFieldDescriptor *field,
if (dictionary) {
GPBDataType keyDataType = field.mapKeyDataType;
GPBDataType valueDataType = GPBGetFieldDataType(field);
- NSString *keyStr = TypeToStr(keyDataType);
- NSString *valueStr = TypeToStr(valueDataType);
+ NSString *keyStr = TypeToString(keyDataType);
+ NSString *valueStr = TypeToString(valueDataType);
if (keyDataType == GPBDataTypeString) {
keyStr = @"String";
}
@@ -1039,8 +1466,11 @@ void GPBSetMessageMapField(GPBMessage *self, GPBFieldDescriptor *field,
const char *GPBMessageEncodingForSelector(SEL selector, BOOL instanceSel) {
Protocol *protocol =
objc_getProtocol(GPBStringifySymbol(GPBMessageSignatureProtocol));
+ NSCAssert(protocol, @"Missing GPBMessageSignatureProtocol");
struct objc_method_description description =
protocol_getMethodDescription(protocol, selector, NO, instanceSel);
+ NSCAssert(description.name != Nil && description.types != nil,
+ @"Missing method for selector %@", NSStringFromSelector(selector));
return description.types;
}
@@ -1059,7 +1489,15 @@ static void AppendStringEscaped(NSString *toPrint, NSMutableString *destStr) {
case '\'': [destStr appendString:@"\\\'"]; break;
case '\\': [destStr appendString:@"\\\\"]; break;
default:
- [destStr appendFormat:@"%C", aChar];
+ // This differs slightly from the C++ code in that the C++ doesn't
+ // generate UTF8; it looks at the string in UTF8, but escapes every
+ // byte > 0x7E.
+ if (aChar < 0x20) {
+ [destStr appendFormat:@"\\%d%d%d",
+ (aChar / 64), ((aChar % 64) / 8), (aChar % 8)];
+ } else {
+ [destStr appendFormat:@"%C", aChar];
+ }
break;
}
}
@@ -1126,6 +1564,8 @@ static void AppendTextFormatForMapMessageField(
[toStr appendString:@"\n"];
[toStr appendString:valueLine];
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wswitch-enum"
switch (valueDataType) {
case GPBDataTypeString:
AppendStringEscaped(value, toStr);
@@ -1146,6 +1586,7 @@ static void AppendTextFormatForMapMessageField(
NSCAssert(NO, @"Can't happen");
break;
}
+#pragma clang diagnostic pop
[toStr appendString:@"\n"];
[toStr appendString:msgEnd];
@@ -1167,6 +1608,8 @@ static void AppendTextFormatForMapMessageField(
}
[toStr appendString:valueLine];
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wswitch-enum"
switch (valueDataType) {
case GPBDataTypeString:
AppendStringEscaped(valueObj, toStr);
@@ -1204,6 +1647,7 @@ static void AppendTextFormatForMapMessageField(
[toStr appendString:valueObj];
break;
}
+#pragma clang diagnostic pop
[toStr appendString:@"\n"];
[toStr appendString:msgEnd];
@@ -1473,7 +1917,8 @@ static void AppendTextFormatForMessage(GPBMessage *message,
NSUInteger fieldCount = fieldsArray.count;
const GPBExtensionRange *extensionRanges = descriptor.extensionRanges;
NSUInteger extensionRangesCount = descriptor.extensionRangesCount;
- NSArray *activeExtensions = [message sortedExtensionsInUse];
+ NSArray *activeExtensions = [[message extensionsCurrentlySet]
+ sortedArrayUsingSelector:@selector(compareByFieldNumber:)];
for (NSUInteger i = 0, j = 0; i < fieldCount || j < extensionRangesCount;) {
if (i == fieldCount) {
AppendTextFormatForMessageExtensionRange(
@@ -1699,12 +2144,23 @@ NSString *GPBDecodeTextFormatName(const uint8_t *decodeData, int32_t key,
return result;
}
-#pragma mark - GPBMessageSignatureProtocol
+#pragma clang diagnostic pop
-// A series of selectors that are used solely to get @encoding values
-// for them by the dynamic protobuf runtime code. An object using the protocol
-// needs to be declared for the protocol to be valid at runtime.
-@interface GPBMessageSignatureProtocol : NSObject<GPBMessageSignatureProtocol>
-@end
-@implementation GPBMessageSignatureProtocol
-@end
+BOOL GPBClassHasSel(Class aClass, SEL sel) {
+ // NOTE: We have to use class_copyMethodList, all other runtime method
+ // lookups actually also resolve the method implementation and this
+ // is called from within those methods.
+
+ BOOL result = NO;
+ unsigned int methodCount = 0;
+ Method *methodList = class_copyMethodList(aClass, &methodCount);
+ for (unsigned int i = 0; i < methodCount; ++i) {
+ SEL methodSelector = method_getName(methodList[i]);
+ if (methodSelector == sel) {
+ result = YES;
+ break;
+ }
+ }
+ free(methodList);
+ return result;
+}