blob: 0e1599dcc235d2a90301b99e5f48f131da87f638 [file] [log] [blame]
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc. All rights reserved.
3// https://developers.google.com/protocol-buffers/
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
8//
9// * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11// * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15// * Neither the name of Google Inc. nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31#import "GPBMessage_PackagePrivate.h"
32
33#import <objc/runtime.h>
34#import <objc/message.h>
35
36#import "GPBArray_PackagePrivate.h"
37#import "GPBCodedInputStream_PackagePrivate.h"
Thomas Van Lenten36650a02016-03-07 12:07:03 -050038#import "GPBCodedOutputStream_PackagePrivate.h"
Thomas Van Lenten30650d82015-05-01 08:57:16 -040039#import "GPBDescriptor_PackagePrivate.h"
40#import "GPBDictionary_PackagePrivate.h"
Thomas Van Lentend846b0b2015-06-08 16:24:57 -040041#import "GPBExtensionInternals.h"
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -040042#import "GPBExtensionRegistry.h"
43#import "GPBRootObject_PackagePrivate.h"
Thomas Van Lenten30650d82015-05-01 08:57:16 -040044#import "GPBUnknownFieldSet_PackagePrivate.h"
45#import "GPBUtilities_PackagePrivate.h"
46
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -040047NSString *const GPBMessageErrorDomain =
48 GPBNSStringifySymbol(GPBMessageErrorDomain);
49
Thomas Van Lenten30650d82015-05-01 08:57:16 -040050#ifdef DEBUG
51NSString *const GPBExceptionMessageKey =
52 GPBNSStringifySymbol(GPBExceptionMessage);
53#endif // DEBUG
54
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -040055static NSString *const kGPBDataCoderKey = @"GPBData";
56
Thomas Van Lenten30650d82015-05-01 08:57:16 -040057//
58// PLEASE REMEMBER:
59//
60// This is the base class for *all* messages generated, so any selector defined,
61// *public* or *private* could end up colliding with a proto message field. So
62// avoid using selectors that could match a property, use C functions to hide
63// them, etc.
64//
65
66@interface GPBMessage () {
67 @package
68 GPBUnknownFieldSet *unknownFields_;
69 NSMutableDictionary *extensionMap_;
70 NSMutableDictionary *autocreatedExtensionMap_;
71
72 // If the object was autocreated, we remember the creator so that if we get
73 // mutated, we can inform the creator to make our field visible.
74 GPBMessage *autocreator_;
75 GPBFieldDescriptor *autocreatorField_;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -040076 GPBExtensionDescriptor *autocreatorExtension_;
Thomas Van Lenten30650d82015-05-01 08:57:16 -040077}
78@end
79
80static id CreateArrayForField(GPBFieldDescriptor *field,
81 GPBMessage *autocreator)
82 __attribute__((ns_returns_retained));
83static id GetOrCreateArrayIvarWithField(GPBMessage *self,
84 GPBFieldDescriptor *field,
85 GPBFileSyntax syntax);
86static id GetArrayIvarWithField(GPBMessage *self, GPBFieldDescriptor *field);
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -040087static id CreateMapForField(GPBFieldDescriptor *field,
88 GPBMessage *autocreator)
89 __attribute__((ns_returns_retained));
Thomas Van Lenten30650d82015-05-01 08:57:16 -040090static id GetOrCreateMapIvarWithField(GPBMessage *self,
91 GPBFieldDescriptor *field,
92 GPBFileSyntax syntax);
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -040093static id GetMapIvarWithField(GPBMessage *self, GPBFieldDescriptor *field);
Thomas Van Lenten30650d82015-05-01 08:57:16 -040094static NSMutableDictionary *CloneExtensionMap(NSDictionary *extensionMap,
95 NSZone *zone)
96 __attribute__((ns_returns_retained));
97
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -040098static NSError *MessageError(NSInteger code, NSDictionary *userInfo) {
99 return [NSError errorWithDomain:GPBMessageErrorDomain
100 code:code
101 userInfo:userInfo];
102}
103
104static NSError *MessageErrorWithReason(NSInteger code, NSString *reason) {
105 NSDictionary *userInfo = nil;
106 if ([reason length]) {
107 userInfo = @{ @"Reason" : reason };
108 }
109 return MessageError(code, userInfo);
110}
111
112
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400113static void CheckExtension(GPBMessage *self,
114 GPBExtensionDescriptor *extension) {
115 if ([self class] != extension.containingMessageClass) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400116 [NSException
117 raise:NSInvalidArgumentException
118 format:@"Extension %@ used on wrong class (%@ instead of %@)",
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400119 extension.singletonName,
120 [self class], extension.containingMessageClass];
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400121 }
122}
123
124static NSMutableDictionary *CloneExtensionMap(NSDictionary *extensionMap,
125 NSZone *zone) {
126 if (extensionMap.count == 0) {
127 return nil;
128 }
129 NSMutableDictionary *result = [[NSMutableDictionary allocWithZone:zone]
130 initWithCapacity:extensionMap.count];
131
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400132 for (GPBExtensionDescriptor *extension in extensionMap) {
133 id value = [extensionMap objectForKey:extension];
134 BOOL isMessageExtension = GPBExtensionIsMessage(extension);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400135
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400136 if (extension.repeated) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400137 if (isMessageExtension) {
138 NSMutableArray *list =
139 [[NSMutableArray alloc] initWithCapacity:[value count]];
140 for (GPBMessage *listValue in value) {
141 GPBMessage *copiedValue = [listValue copyWithZone:zone];
142 [list addObject:copiedValue];
143 [copiedValue release];
144 }
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400145 [result setObject:list forKey:extension];
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400146 [list release];
147 } else {
148 NSMutableArray *copiedValue = [value mutableCopyWithZone:zone];
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400149 [result setObject:copiedValue forKey:extension];
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400150 [copiedValue release];
151 }
152 } else {
153 if (isMessageExtension) {
154 GPBMessage *copiedValue = [value copyWithZone:zone];
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400155 [result setObject:copiedValue forKey:extension];
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400156 [copiedValue release];
157 } else {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400158 [result setObject:value forKey:extension];
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400159 }
160 }
161 }
162
163 return result;
164}
165
166static id CreateArrayForField(GPBFieldDescriptor *field,
167 GPBMessage *autocreator) {
168 id result;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400169 GPBDataType fieldDataType = GPBGetFieldDataType(field);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400170 switch (fieldDataType) {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400171 case GPBDataTypeBool:
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400172 result = [[GPBBoolArray alloc] init];
173 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400174 case GPBDataTypeFixed32:
175 case GPBDataTypeUInt32:
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400176 result = [[GPBUInt32Array alloc] init];
177 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400178 case GPBDataTypeInt32:
179 case GPBDataTypeSFixed32:
180 case GPBDataTypeSInt32:
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400181 result = [[GPBInt32Array alloc] init];
182 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400183 case GPBDataTypeFixed64:
184 case GPBDataTypeUInt64:
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400185 result = [[GPBUInt64Array alloc] init];
186 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400187 case GPBDataTypeInt64:
188 case GPBDataTypeSFixed64:
189 case GPBDataTypeSInt64:
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400190 result = [[GPBInt64Array alloc] init];
191 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400192 case GPBDataTypeFloat:
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400193 result = [[GPBFloatArray alloc] init];
194 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400195 case GPBDataTypeDouble:
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400196 result = [[GPBDoubleArray alloc] init];
197 break;
198
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400199 case GPBDataTypeEnum:
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400200 result = [[GPBEnumArray alloc]
201 initWithValidationFunction:field.enumDescriptor.enumVerifier];
202 break;
203
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400204 case GPBDataTypeBytes:
205 case GPBDataTypeGroup:
206 case GPBDataTypeMessage:
207 case GPBDataTypeString:
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400208 if (autocreator) {
209 result = [[GPBAutocreatedArray alloc] init];
210 } else {
211 result = [[NSMutableArray alloc] init];
212 }
213 break;
214 }
215
216 if (autocreator) {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400217 if (GPBDataTypeIsObject(fieldDataType)) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400218 GPBAutocreatedArray *autoArray = result;
219 autoArray->_autocreator = autocreator;
220 } else {
221 GPBInt32Array *gpbArray = result;
222 gpbArray->_autocreator = autocreator;
223 }
224 }
225
226 return result;
227}
228
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400229static id CreateMapForField(GPBFieldDescriptor *field,
230 GPBMessage *autocreator) {
231 id result;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400232 GPBDataType keyDataType = field.mapKeyDataType;
233 GPBDataType valueDataType = GPBGetFieldDataType(field);
234 switch (keyDataType) {
235 case GPBDataTypeBool:
236 switch (valueDataType) {
237 case GPBDataTypeBool:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400238 result = [[GPBBoolBoolDictionary alloc] init];
239 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400240 case GPBDataTypeFixed32:
241 case GPBDataTypeUInt32:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400242 result = [[GPBBoolUInt32Dictionary alloc] init];
243 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400244 case GPBDataTypeInt32:
245 case GPBDataTypeSFixed32:
246 case GPBDataTypeSInt32:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400247 result = [[GPBBoolInt32Dictionary alloc] init];
248 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400249 case GPBDataTypeFixed64:
250 case GPBDataTypeUInt64:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400251 result = [[GPBBoolUInt64Dictionary alloc] init];
252 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400253 case GPBDataTypeInt64:
254 case GPBDataTypeSFixed64:
255 case GPBDataTypeSInt64:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400256 result = [[GPBBoolInt64Dictionary alloc] init];
257 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400258 case GPBDataTypeFloat:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400259 result = [[GPBBoolFloatDictionary alloc] init];
260 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400261 case GPBDataTypeDouble:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400262 result = [[GPBBoolDoubleDictionary alloc] init];
263 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400264 case GPBDataTypeEnum:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400265 result = [[GPBBoolEnumDictionary alloc]
266 initWithValidationFunction:field.enumDescriptor.enumVerifier];
267 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400268 case GPBDataTypeBytes:
269 case GPBDataTypeMessage:
270 case GPBDataTypeString:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400271 result = [[GPBBoolObjectDictionary alloc] init];
272 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400273 case GPBDataTypeGroup:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400274 NSCAssert(NO, @"shouldn't happen");
275 return nil;
276 }
277 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400278 case GPBDataTypeFixed32:
279 case GPBDataTypeUInt32:
280 switch (valueDataType) {
281 case GPBDataTypeBool:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400282 result = [[GPBUInt32BoolDictionary alloc] init];
283 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400284 case GPBDataTypeFixed32:
285 case GPBDataTypeUInt32:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400286 result = [[GPBUInt32UInt32Dictionary alloc] init];
287 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400288 case GPBDataTypeInt32:
289 case GPBDataTypeSFixed32:
290 case GPBDataTypeSInt32:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400291 result = [[GPBUInt32Int32Dictionary alloc] init];
292 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400293 case GPBDataTypeFixed64:
294 case GPBDataTypeUInt64:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400295 result = [[GPBUInt32UInt64Dictionary alloc] init];
296 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400297 case GPBDataTypeInt64:
298 case GPBDataTypeSFixed64:
299 case GPBDataTypeSInt64:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400300 result = [[GPBUInt32Int64Dictionary alloc] init];
301 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400302 case GPBDataTypeFloat:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400303 result = [[GPBUInt32FloatDictionary alloc] init];
304 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400305 case GPBDataTypeDouble:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400306 result = [[GPBUInt32DoubleDictionary alloc] init];
307 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400308 case GPBDataTypeEnum:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400309 result = [[GPBUInt32EnumDictionary alloc]
310 initWithValidationFunction:field.enumDescriptor.enumVerifier];
311 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400312 case GPBDataTypeBytes:
313 case GPBDataTypeMessage:
314 case GPBDataTypeString:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400315 result = [[GPBUInt32ObjectDictionary alloc] init];
316 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400317 case GPBDataTypeGroup:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400318 NSCAssert(NO, @"shouldn't happen");
319 return nil;
320 }
321 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400322 case GPBDataTypeInt32:
323 case GPBDataTypeSFixed32:
324 case GPBDataTypeSInt32:
325 switch (valueDataType) {
326 case GPBDataTypeBool:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400327 result = [[GPBInt32BoolDictionary alloc] init];
328 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400329 case GPBDataTypeFixed32:
330 case GPBDataTypeUInt32:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400331 result = [[GPBInt32UInt32Dictionary alloc] init];
332 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400333 case GPBDataTypeInt32:
334 case GPBDataTypeSFixed32:
335 case GPBDataTypeSInt32:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400336 result = [[GPBInt32Int32Dictionary alloc] init];
337 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400338 case GPBDataTypeFixed64:
339 case GPBDataTypeUInt64:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400340 result = [[GPBInt32UInt64Dictionary alloc] init];
341 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400342 case GPBDataTypeInt64:
343 case GPBDataTypeSFixed64:
344 case GPBDataTypeSInt64:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400345 result = [[GPBInt32Int64Dictionary alloc] init];
346 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400347 case GPBDataTypeFloat:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400348 result = [[GPBInt32FloatDictionary alloc] init];
349 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400350 case GPBDataTypeDouble:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400351 result = [[GPBInt32DoubleDictionary alloc] init];
352 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400353 case GPBDataTypeEnum:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400354 result = [[GPBInt32EnumDictionary alloc]
355 initWithValidationFunction:field.enumDescriptor.enumVerifier];
356 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400357 case GPBDataTypeBytes:
358 case GPBDataTypeMessage:
359 case GPBDataTypeString:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400360 result = [[GPBInt32ObjectDictionary alloc] init];
361 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400362 case GPBDataTypeGroup:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400363 NSCAssert(NO, @"shouldn't happen");
364 return nil;
365 }
366 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400367 case GPBDataTypeFixed64:
368 case GPBDataTypeUInt64:
369 switch (valueDataType) {
370 case GPBDataTypeBool:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400371 result = [[GPBUInt64BoolDictionary alloc] init];
372 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400373 case GPBDataTypeFixed32:
374 case GPBDataTypeUInt32:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400375 result = [[GPBUInt64UInt32Dictionary alloc] init];
376 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400377 case GPBDataTypeInt32:
378 case GPBDataTypeSFixed32:
379 case GPBDataTypeSInt32:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400380 result = [[GPBUInt64Int32Dictionary alloc] init];
381 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400382 case GPBDataTypeFixed64:
383 case GPBDataTypeUInt64:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400384 result = [[GPBUInt64UInt64Dictionary alloc] init];
385 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400386 case GPBDataTypeInt64:
387 case GPBDataTypeSFixed64:
388 case GPBDataTypeSInt64:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400389 result = [[GPBUInt64Int64Dictionary alloc] init];
390 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400391 case GPBDataTypeFloat:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400392 result = [[GPBUInt64FloatDictionary alloc] init];
393 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400394 case GPBDataTypeDouble:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400395 result = [[GPBUInt64DoubleDictionary alloc] init];
396 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400397 case GPBDataTypeEnum:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400398 result = [[GPBUInt64EnumDictionary alloc]
399 initWithValidationFunction:field.enumDescriptor.enumVerifier];
400 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400401 case GPBDataTypeBytes:
402 case GPBDataTypeMessage:
403 case GPBDataTypeString:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400404 result = [[GPBUInt64ObjectDictionary alloc] init];
405 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400406 case GPBDataTypeGroup:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400407 NSCAssert(NO, @"shouldn't happen");
408 return nil;
409 }
410 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400411 case GPBDataTypeInt64:
412 case GPBDataTypeSFixed64:
413 case GPBDataTypeSInt64:
414 switch (valueDataType) {
415 case GPBDataTypeBool:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400416 result = [[GPBInt64BoolDictionary alloc] init];
417 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400418 case GPBDataTypeFixed32:
419 case GPBDataTypeUInt32:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400420 result = [[GPBInt64UInt32Dictionary alloc] init];
421 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400422 case GPBDataTypeInt32:
423 case GPBDataTypeSFixed32:
424 case GPBDataTypeSInt32:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400425 result = [[GPBInt64Int32Dictionary alloc] init];
426 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400427 case GPBDataTypeFixed64:
428 case GPBDataTypeUInt64:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400429 result = [[GPBInt64UInt64Dictionary alloc] init];
430 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400431 case GPBDataTypeInt64:
432 case GPBDataTypeSFixed64:
433 case GPBDataTypeSInt64:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400434 result = [[GPBInt64Int64Dictionary alloc] init];
435 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400436 case GPBDataTypeFloat:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400437 result = [[GPBInt64FloatDictionary alloc] init];
438 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400439 case GPBDataTypeDouble:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400440 result = [[GPBInt64DoubleDictionary alloc] init];
441 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400442 case GPBDataTypeEnum:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400443 result = [[GPBInt64EnumDictionary alloc]
444 initWithValidationFunction:field.enumDescriptor.enumVerifier];
445 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400446 case GPBDataTypeBytes:
447 case GPBDataTypeMessage:
448 case GPBDataTypeString:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400449 result = [[GPBInt64ObjectDictionary alloc] init];
450 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400451 case GPBDataTypeGroup:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400452 NSCAssert(NO, @"shouldn't happen");
453 return nil;
454 }
455 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400456 case GPBDataTypeString:
457 switch (valueDataType) {
458 case GPBDataTypeBool:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400459 result = [[GPBStringBoolDictionary alloc] init];
460 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400461 case GPBDataTypeFixed32:
462 case GPBDataTypeUInt32:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400463 result = [[GPBStringUInt32Dictionary alloc] init];
464 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400465 case GPBDataTypeInt32:
466 case GPBDataTypeSFixed32:
467 case GPBDataTypeSInt32:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400468 result = [[GPBStringInt32Dictionary alloc] init];
469 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400470 case GPBDataTypeFixed64:
471 case GPBDataTypeUInt64:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400472 result = [[GPBStringUInt64Dictionary alloc] init];
473 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400474 case GPBDataTypeInt64:
475 case GPBDataTypeSFixed64:
476 case GPBDataTypeSInt64:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400477 result = [[GPBStringInt64Dictionary alloc] init];
478 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400479 case GPBDataTypeFloat:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400480 result = [[GPBStringFloatDictionary alloc] init];
481 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400482 case GPBDataTypeDouble:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400483 result = [[GPBStringDoubleDictionary alloc] init];
484 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400485 case GPBDataTypeEnum:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400486 result = [[GPBStringEnumDictionary alloc]
487 initWithValidationFunction:field.enumDescriptor.enumVerifier];
488 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400489 case GPBDataTypeBytes:
490 case GPBDataTypeMessage:
491 case GPBDataTypeString:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400492 if (autocreator) {
493 result = [[GPBAutocreatedDictionary alloc] init];
494 } else {
495 result = [[NSMutableDictionary alloc] init];
496 }
497 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400498 case GPBDataTypeGroup:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400499 NSCAssert(NO, @"shouldn't happen");
500 return nil;
501 }
502 break;
503
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400504 case GPBDataTypeFloat:
505 case GPBDataTypeDouble:
506 case GPBDataTypeEnum:
507 case GPBDataTypeBytes:
508 case GPBDataTypeGroup:
509 case GPBDataTypeMessage:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400510 NSCAssert(NO, @"shouldn't happen");
511 return nil;
512 }
513
514 if (autocreator) {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400515 if ((keyDataType == GPBDataTypeString) &&
516 GPBDataTypeIsObject(valueDataType)) {
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400517 GPBAutocreatedDictionary *autoDict = result;
518 autoDict->_autocreator = autocreator;
519 } else {
520 GPBInt32Int32Dictionary *gpbDict = result;
521 gpbDict->_autocreator = autocreator;
522 }
523 }
524
525 return result;
526}
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400527
528#if !defined(__clang_analyzer__)
529// These functions are blocked from the analyzer because the analyzer sees the
530// GPBSetRetainedObjectIvarWithFieldInternal() call as consuming the array/map,
531// so use of the array/map after the call returns is flagged as a use after
532// free.
533// But GPBSetRetainedObjectIvarWithFieldInternal() is "consuming" the retain
534// count be holding onto the object (it is transfering it), the object is
535// still valid after returning from the call. The other way to avoid this
536// would be to add a -retain/-autorelease, but that would force every
537// repeated/map field parsed into the autorelease pool which is both a memory
538// and performance hit.
539
540static id GetOrCreateArrayIvarWithField(GPBMessage *self,
541 GPBFieldDescriptor *field,
542 GPBFileSyntax syntax) {
543 id array = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
544 if (!array) {
545 // No lock needed, this is called from places expecting to mutate
546 // so no threading protection is needed.
547 array = CreateArrayForField(field, nil);
548 GPBSetRetainedObjectIvarWithFieldInternal(self, field, array, syntax);
549 }
550 return array;
551}
552
553// This is like GPBGetObjectIvarWithField(), but for arrays, it should
554// only be used to wire the method into the class.
555static id GetArrayIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) {
556 id array = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
557 if (!array) {
558 // Check again after getting the lock.
Thomas Van Lentenbd41a392016-03-21 11:11:14 -0400559 GPBPrepareReadOnlySemaphore(self);
Thomas Van Lentend6590d62015-12-17 14:35:44 -0500560 dispatch_semaphore_wait(self->readOnlySemaphore_, DISPATCH_TIME_FOREVER);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400561 array = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
562 if (!array) {
563 array = CreateArrayForField(field, self);
564 GPBSetAutocreatedRetainedObjectIvarWithField(self, field, array);
565 }
Thomas Van Lentend6590d62015-12-17 14:35:44 -0500566 dispatch_semaphore_signal(self->readOnlySemaphore_);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400567 }
568 return array;
569}
570
571static id GetOrCreateMapIvarWithField(GPBMessage *self,
572 GPBFieldDescriptor *field,
573 GPBFileSyntax syntax) {
574 id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
575 if (!dict) {
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400576 // No lock needed, this is called from places expecting to mutate
577 // so no threading protection is needed.
578 dict = CreateMapForField(field, nil);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400579 GPBSetRetainedObjectIvarWithFieldInternal(self, field, dict, syntax);
580 }
581 return dict;
582}
583
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400584// This is like GPBGetObjectIvarWithField(), but for maps, it should
585// only be used to wire the method into the class.
586static id GetMapIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) {
587 id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
588 if (!dict) {
589 // Check again after getting the lock.
Thomas Van Lentenbd41a392016-03-21 11:11:14 -0400590 GPBPrepareReadOnlySemaphore(self);
Thomas Van Lentend6590d62015-12-17 14:35:44 -0500591 dispatch_semaphore_wait(self->readOnlySemaphore_, DISPATCH_TIME_FOREVER);
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400592 dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
593 if (!dict) {
594 dict = CreateMapForField(field, self);
595 GPBSetAutocreatedRetainedObjectIvarWithField(self, field, dict);
596 }
Thomas Van Lentend6590d62015-12-17 14:35:44 -0500597 dispatch_semaphore_signal(self->readOnlySemaphore_);
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400598 }
599 return dict;
600}
601
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400602#endif // !defined(__clang_analyzer__)
603
604GPBMessage *GPBCreateMessageWithAutocreator(Class msgClass,
605 GPBMessage *autocreator,
606 GPBFieldDescriptor *field) {
607 GPBMessage *message = [[msgClass alloc] init];
608 message->autocreator_ = autocreator;
609 message->autocreatorField_ = [field retain];
610 return message;
611}
612
613static GPBMessage *CreateMessageWithAutocreatorForExtension(
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400614 Class msgClass, GPBMessage *autocreator, GPBExtensionDescriptor *extension)
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400615 __attribute__((ns_returns_retained));
616
617static GPBMessage *CreateMessageWithAutocreatorForExtension(
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400618 Class msgClass, GPBMessage *autocreator,
619 GPBExtensionDescriptor *extension) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400620 GPBMessage *message = [[msgClass alloc] init];
621 message->autocreator_ = autocreator;
622 message->autocreatorExtension_ = [extension retain];
623 return message;
624}
625
626BOOL GPBWasMessageAutocreatedBy(GPBMessage *message, GPBMessage *parent) {
627 return (message->autocreator_ == parent);
628}
629
630void GPBBecomeVisibleToAutocreator(GPBMessage *self) {
631 // Message objects that are implicitly created by accessing a message field
632 // are initially not visible via the hasX selector. This method makes them
633 // visible.
634 if (self->autocreator_) {
635 // This will recursively make all parent messages visible until it reaches a
636 // super-creator that's visible.
637 if (self->autocreatorField_) {
638 GPBFileSyntax syntax = [self->autocreator_ descriptor].file.syntax;
639 GPBSetObjectIvarWithFieldInternal(self->autocreator_,
640 self->autocreatorField_, self, syntax);
641 } else {
642 [self->autocreator_ setExtension:self->autocreatorExtension_ value:self];
643 }
644 }
645}
646
647void GPBAutocreatedArrayModified(GPBMessage *self, id array) {
648 // When one of our autocreated arrays adds elements, make it visible.
649 GPBDescriptor *descriptor = [[self class] descriptor];
650 for (GPBFieldDescriptor *field in descriptor->fields_) {
651 if (field.fieldType == GPBFieldTypeRepeated) {
652 id curArray = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
653 if (curArray == array) {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400654 if (GPBFieldDataTypeIsObject(field)) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400655 GPBAutocreatedArray *autoArray = array;
656 autoArray->_autocreator = nil;
657 } else {
658 GPBInt32Array *gpbArray = array;
659 gpbArray->_autocreator = nil;
660 }
661 GPBBecomeVisibleToAutocreator(self);
662 return;
663 }
664 }
665 }
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400666 NSCAssert(NO, @"Unknown autocreated %@ for %@.", [array class], self);
667}
668
669void GPBAutocreatedDictionaryModified(GPBMessage *self, id dictionary) {
670 // When one of our autocreated dicts adds elements, make it visible.
671 GPBDescriptor *descriptor = [[self class] descriptor];
672 for (GPBFieldDescriptor *field in descriptor->fields_) {
673 if (field.fieldType == GPBFieldTypeMap) {
674 id curDict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
675 if (curDict == dictionary) {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400676 if ((field.mapKeyDataType == GPBDataTypeString) &&
677 GPBFieldDataTypeIsObject(field)) {
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400678 GPBAutocreatedDictionary *autoDict = dictionary;
679 autoDict->_autocreator = nil;
680 } else {
681 GPBInt32Int32Dictionary *gpbDict = dictionary;
682 gpbDict->_autocreator = nil;
683 }
684 GPBBecomeVisibleToAutocreator(self);
685 return;
686 }
687 }
688 }
689 NSCAssert(NO, @"Unknown autocreated %@ for %@.", [dictionary class], self);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400690}
691
692void GPBClearMessageAutocreator(GPBMessage *self) {
693 if ((self == nil) || !self->autocreator_) {
694 return;
695 }
696
697#if DEBUG && !defined(NS_BLOCK_ASSERTIONS)
698 // Either the autocreator must have its "has" flag set to YES, or it must be
699 // NO and not equal to ourselves.
700 BOOL autocreatorHas =
701 (self->autocreatorField_
702 ? GPBGetHasIvarField(self->autocreator_, self->autocreatorField_)
703 : [self->autocreator_ hasExtension:self->autocreatorExtension_]);
704 GPBMessage *autocreatorFieldValue =
705 (self->autocreatorField_
706 ? GPBGetObjectIvarWithFieldNoAutocreate(self->autocreator_,
707 self->autocreatorField_)
708 : [self->autocreator_->autocreatedExtensionMap_
709 objectForKey:self->autocreatorExtension_]);
710 NSCAssert(autocreatorHas || autocreatorFieldValue != self,
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400711 @"Cannot clear autocreator because it still refers to self, self: %@.",
712 self);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400713
714#endif // DEBUG && !defined(NS_BLOCK_ASSERTIONS)
715
716 self->autocreator_ = nil;
717 [self->autocreatorField_ release];
718 self->autocreatorField_ = nil;
719 [self->autocreatorExtension_ release];
720 self->autocreatorExtension_ = nil;
721}
722
723static GPBUnknownFieldSet *GetOrMakeUnknownFields(GPBMessage *self) {
724 if (!self->unknownFields_) {
725 self->unknownFields_ = [[GPBUnknownFieldSet alloc] init];
726 GPBBecomeVisibleToAutocreator(self);
727 }
728 return self->unknownFields_;
729}
730
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400731@implementation GPBMessage
732
733+ (void)initialize {
734 Class pbMessageClass = [GPBMessage class];
735 if ([self class] == pbMessageClass) {
736 // This is here to start up the "base" class descriptor.
737 [self descriptor];
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400738 // Message shares extension method resolving with GPBRootObject so insure
739 // it is started up at the same time.
740 (void)[GPBRootObject class];
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400741 } else if ([self superclass] == pbMessageClass) {
742 // This is here to start up all the "message" subclasses. Just needs to be
743 // done for the messages, not any of the subclasses.
744 // This must be done in initialize to enforce thread safety of start up of
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400745 // the protocol buffer library.
746 // Note: The generated code for -descriptor calls
747 // +[GPBDescriptor allocDescriptorForClass:...], passing the GPBRootObject
748 // subclass for the file. That call chain is what ensures that *Root class
749 // is started up to support extension resolution off the message class
750 // (+resolveClassMethod: below) in a thread safe manner.
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400751 [self descriptor];
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400752 }
753}
754
755+ (instancetype)allocWithZone:(NSZone *)zone {
756 // Override alloc to allocate our classes with the additional storage
757 // required for the instance variables.
758 GPBDescriptor *descriptor = [self descriptor];
759 return NSAllocateObject(self, descriptor->storageSize_, zone);
760}
761
762+ (instancetype)alloc {
763 return [self allocWithZone:nil];
764}
765
766+ (GPBDescriptor *)descriptor {
767 // This is thread safe because it is called from +initialize.
768 static GPBDescriptor *descriptor = NULL;
769 static GPBFileDescriptor *fileDescriptor = NULL;
770 if (!descriptor) {
771 // Use a dummy file that marks it as proto2 syntax so when used generically
772 // it supports unknowns/etc.
773 fileDescriptor =
774 [[GPBFileDescriptor alloc] initWithPackage:@"internal"
775 syntax:GPBFileSyntaxProto2];
776
777 descriptor = [GPBDescriptor allocDescriptorForClass:[GPBMessage class]
778 rootClass:Nil
779 file:fileDescriptor
780 fields:NULL
781 fieldCount:0
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400782 storageSize:0
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400783 flags:0];
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400784 }
785 return descriptor;
786}
787
788+ (instancetype)message {
789 return [[[self alloc] init] autorelease];
790}
791
792- (instancetype)init {
793 if ((self = [super init])) {
794 messageStorage_ = (GPBMessage_StoragePtr)(
795 ((uint8_t *)self) + class_getInstanceSize([self class]));
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400796 }
797
798 return self;
799}
800
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400801- (instancetype)initWithData:(NSData *)data error:(NSError **)errorPtr {
802 return [self initWithData:data extensionRegistry:nil error:errorPtr];
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400803}
804
805- (instancetype)initWithData:(NSData *)data
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400806 extensionRegistry:(GPBExtensionRegistry *)extensionRegistry
807 error:(NSError **)errorPtr {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400808 if ((self = [self init])) {
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400809 @try {
810 [self mergeFromData:data extensionRegistry:extensionRegistry];
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400811 if (errorPtr) {
812 *errorPtr = nil;
813 }
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400814 }
815 @catch (NSException *exception) {
816 [self release];
817 self = nil;
818 if (errorPtr) {
819 *errorPtr = MessageErrorWithReason(GPBMessageErrorCodeMalformedData,
820 exception.reason);
821 }
822 }
823#ifdef DEBUG
824 if (self && !self.initialized) {
825 [self release];
826 self = nil;
827 if (errorPtr) {
828 *errorPtr = MessageError(GPBMessageErrorCodeMissingRequiredField, nil);
829 }
830 }
831#endif
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400832 }
833 return self;
834}
835
836- (instancetype)initWithCodedInputStream:(GPBCodedInputStream *)input
837 extensionRegistry:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400838 (GPBExtensionRegistry *)extensionRegistry
839 error:(NSError **)errorPtr {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400840 if ((self = [self init])) {
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400841 @try {
842 [self mergeFromCodedInputStream:input extensionRegistry:extensionRegistry];
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400843 if (errorPtr) {
844 *errorPtr = nil;
845 }
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400846 }
847 @catch (NSException *exception) {
848 [self release];
849 self = nil;
850 if (errorPtr) {
851 *errorPtr = MessageErrorWithReason(GPBMessageErrorCodeMalformedData,
852 exception.reason);
853 }
854 }
855#ifdef DEBUG
856 if (self && !self.initialized) {
857 [self release];
858 self = nil;
859 if (errorPtr) {
860 *errorPtr = MessageError(GPBMessageErrorCodeMissingRequiredField, nil);
861 }
862 }
863#endif
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400864 }
865 return self;
866}
867
868- (void)dealloc {
869 [self internalClear:NO];
870 NSCAssert(!autocreator_, @"Autocreator was not cleared before dealloc.");
Thomas Van Lentenbd41a392016-03-21 11:11:14 -0400871 if (readOnlySemaphore_) {
872 dispatch_release(readOnlySemaphore_);
873 }
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400874 [super dealloc];
875}
876
877- (void)copyFieldsInto:(GPBMessage *)message
878 zone:(NSZone *)zone
879 descriptor:(GPBDescriptor *)descriptor {
880 // Copy all the storage...
881 memcpy(message->messageStorage_, messageStorage_, descriptor->storageSize_);
882
883 GPBFileSyntax syntax = descriptor.file.syntax;
884
885 // Loop over the fields doing fixup...
886 for (GPBFieldDescriptor *field in descriptor->fields_) {
887 if (GPBFieldIsMapOrArray(field)) {
888 id value = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
889 if (value) {
890 // We need to copy the array/map, but the catch is for message fields,
891 // we also need to ensure all the messages as those need copying also.
892 id newValue;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400893 if (GPBFieldDataTypeIsMessage(field)) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400894 if (field.fieldType == GPBFieldTypeRepeated) {
895 NSArray *existingArray = (NSArray *)value;
896 NSMutableArray *newArray =
897 [[NSMutableArray alloc] initWithCapacity:existingArray.count];
898 newValue = newArray;
899 for (GPBMessage *msg in existingArray) {
900 GPBMessage *copiedMsg = [msg copyWithZone:zone];
901 [newArray addObject:copiedMsg];
902 [copiedMsg release];
903 }
904 } else {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400905 if (field.mapKeyDataType == GPBDataTypeString) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400906 // Map is an NSDictionary.
907 NSDictionary *existingDict = value;
908 NSMutableDictionary *newDict = [[NSMutableDictionary alloc]
909 initWithCapacity:existingDict.count];
910 newValue = newDict;
911 [existingDict enumerateKeysAndObjectsUsingBlock:^(NSString *key,
912 GPBMessage *msg,
913 BOOL *stop) {
914#pragma unused(stop)
915 GPBMessage *copiedMsg = [msg copyWithZone:zone];
916 [newDict setObject:copiedMsg forKey:key];
917 [copiedMsg release];
918 }];
919 } else {
920 // Is one of the GPB*ObjectDictionary classes. Type doesn't
921 // matter, just need one to invoke the selector.
922 GPBInt32ObjectDictionary *existingDict = value;
923 newValue = [existingDict deepCopyWithZone:zone];
924 }
925 }
926 } else {
927 // Not messages (but is a map/array)...
928 if (field.fieldType == GPBFieldTypeRepeated) {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400929 if (GPBFieldDataTypeIsObject(field)) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400930 // NSArray
931 newValue = [value mutableCopyWithZone:zone];
932 } else {
933 // GPB*Array
934 newValue = [value copyWithZone:zone];
935 }
936 } else {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400937 if (field.mapKeyDataType == GPBDataTypeString) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400938 // NSDictionary
939 newValue = [value mutableCopyWithZone:zone];
940 } else {
941 // Is one of the GPB*Dictionary classes. Type doesn't matter,
942 // just need one to invoke the selector.
943 GPBInt32Int32Dictionary *existingDict = value;
944 newValue = [existingDict copyWithZone:zone];
945 }
946 }
947 }
948 // We retain here because the memcpy picked up the pointer value and
949 // the next call to SetRetainedObject... will release the current value.
950 [value retain];
951 GPBSetRetainedObjectIvarWithFieldInternal(message, field, newValue,
952 syntax);
953 }
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400954 } else if (GPBFieldDataTypeIsMessage(field)) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400955 // For object types, if we have a value, copy it. If we don't,
956 // zero it to remove the pointer to something that was autocreated
957 // (and the ptr just got memcpyed).
958 if (GPBGetHasIvarField(self, field)) {
959 GPBMessage *value = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
960 GPBMessage *newValue = [value copyWithZone:zone];
961 // We retain here because the memcpy picked up the pointer value and
962 // the next call to SetRetainedObject... will release the current value.
963 [value retain];
964 GPBSetRetainedObjectIvarWithFieldInternal(message, field, newValue,
965 syntax);
966 } else {
967 uint8_t *storage = (uint8_t *)message->messageStorage_;
968 id *typePtr = (id *)&storage[field->description_->offset];
969 *typePtr = NULL;
970 }
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400971 } else if (GPBFieldDataTypeIsObject(field) &&
972 GPBGetHasIvarField(self, field)) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400973 // A set string/data value (message picked off above), copy it.
974 id value = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
975 id newValue = [value copyWithZone:zone];
976 // We retain here because the memcpy picked up the pointer value and
977 // the next call to SetRetainedObject... will release the current value.
978 [value retain];
979 GPBSetRetainedObjectIvarWithFieldInternal(message, field, newValue,
980 syntax);
981 } else {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400982 // memcpy took care of the rest of the primitive fields if they were set.
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400983 }
984 } // for (field in descriptor->fields_)
985}
986
987- (id)copyWithZone:(NSZone *)zone {
988 GPBDescriptor *descriptor = [self descriptor];
989 GPBMessage *result = [[descriptor.messageClass allocWithZone:zone] init];
990
991 [self copyFieldsInto:result zone:zone descriptor:descriptor];
992 // Make immutable copies of the extra bits.
993 result->unknownFields_ = [unknownFields_ copyWithZone:zone];
994 result->extensionMap_ = CloneExtensionMap(extensionMap_, zone);
995 return result;
996}
997
998- (void)clear {
999 [self internalClear:YES];
1000}
1001
1002- (void)internalClear:(BOOL)zeroStorage {
1003 GPBDescriptor *descriptor = [self descriptor];
1004 for (GPBFieldDescriptor *field in descriptor->fields_) {
1005 if (GPBFieldIsMapOrArray(field)) {
1006 id arrayOrMap = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1007 if (arrayOrMap) {
1008 if (field.fieldType == GPBFieldTypeRepeated) {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001009 if (GPBFieldDataTypeIsObject(field)) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001010 GPBAutocreatedArray *autoArray = arrayOrMap;
1011 if (autoArray->_autocreator == self) {
1012 autoArray->_autocreator = nil;
1013 }
1014 } else {
1015 // Type doesn't matter, it is a GPB*Array.
1016 GPBInt32Array *gpbArray = arrayOrMap;
1017 if (gpbArray->_autocreator == self) {
1018 gpbArray->_autocreator = nil;
1019 }
1020 }
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04001021 } else {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001022 if ((field.mapKeyDataType == GPBDataTypeString) &&
1023 GPBFieldDataTypeIsObject(field)) {
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04001024 GPBAutocreatedDictionary *autoDict = arrayOrMap;
1025 if (autoDict->_autocreator == self) {
1026 autoDict->_autocreator = nil;
1027 }
1028 } else {
1029 // Type doesn't matter, it is a GPB*Dictionary.
1030 GPBInt32Int32Dictionary *gpbDict = arrayOrMap;
1031 if (gpbDict->_autocreator == self) {
1032 gpbDict->_autocreator = nil;
1033 }
1034 }
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001035 }
1036 [arrayOrMap release];
1037 }
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001038 } else if (GPBFieldDataTypeIsMessage(field)) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001039 GPBClearAutocreatedMessageIvarWithField(self, field);
1040 GPBMessage *value = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1041 [value release];
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001042 } else if (GPBFieldDataTypeIsObject(field) &&
1043 GPBGetHasIvarField(self, field)) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001044 id value = GPBGetObjectIvarWithField(self, field);
1045 [value release];
1046 }
1047 }
1048
1049 // GPBClearMessageAutocreator() expects that its caller has already been
1050 // removed from autocreatedExtensionMap_ so we set to nil first.
1051 NSArray *autocreatedValues = [autocreatedExtensionMap_ allValues];
1052 [autocreatedExtensionMap_ release];
1053 autocreatedExtensionMap_ = nil;
1054
1055 // Since we're clearing all of our extensions, make sure that we clear the
1056 // autocreator on any that we've created so they no longer refer to us.
1057 for (GPBMessage *value in autocreatedValues) {
1058 NSCAssert(GPBWasMessageAutocreatedBy(value, self),
1059 @"Autocreated extension does not refer back to self.");
1060 GPBClearMessageAutocreator(value);
1061 }
1062
1063 [extensionMap_ release];
1064 extensionMap_ = nil;
1065 [unknownFields_ release];
1066 unknownFields_ = nil;
1067
1068 // Note that clearing does not affect autocreator_. If we are being cleared
1069 // because of a dealloc, then autocreator_ should be nil anyway. If we are
1070 // being cleared because someone explicitly clears us, we don't want to
1071 // sever our relationship with our autocreator.
1072
1073 if (zeroStorage) {
1074 memset(messageStorage_, 0, descriptor->storageSize_);
1075 }
1076}
1077
1078- (BOOL)isInitialized {
1079 GPBDescriptor *descriptor = [self descriptor];
1080 for (GPBFieldDescriptor *field in descriptor->fields_) {
1081 if (field.isRequired) {
1082 if (!GPBGetHasIvarField(self, field)) {
1083 return NO;
1084 }
1085 }
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001086 if (GPBFieldDataTypeIsMessage(field)) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001087 GPBFieldType fieldType = field.fieldType;
1088 if (fieldType == GPBFieldTypeSingle) {
1089 if (field.isRequired) {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001090 GPBMessage *message = GPBGetMessageMessageField(self, field);
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001091 if (!message.initialized) {
1092 return NO;
1093 }
1094 } else {
1095 NSAssert(field.isOptional,
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04001096 @"%@: Single message field %@ not required or optional?",
1097 [self class], field.name);
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001098 if (GPBGetHasIvarField(self, field)) {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001099 GPBMessage *message = GPBGetMessageMessageField(self, field);
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001100 if (!message.initialized) {
1101 return NO;
1102 }
1103 }
1104 }
1105 } else if (fieldType == GPBFieldTypeRepeated) {
1106 NSArray *array = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1107 for (GPBMessage *message in array) {
1108 if (!message.initialized) {
1109 return NO;
1110 }
1111 }
1112 } else { // fieldType == GPBFieldTypeMap
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001113 if (field.mapKeyDataType == GPBDataTypeString) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001114 NSDictionary *map =
1115 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1116 if (map && !GPBDictionaryIsInitializedInternalHelper(map, field)) {
1117 return NO;
1118 }
1119 } else {
1120 // Real type is GPB*ObjectDictionary, exact type doesn't matter.
1121 GPBInt32ObjectDictionary *map =
1122 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1123 if (map && ![map isInitialized]) {
1124 return NO;
1125 }
1126 }
1127 }
1128 }
1129 }
1130
1131 __block BOOL result = YES;
1132 [extensionMap_
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001133 enumerateKeysAndObjectsUsingBlock:^(GPBExtensionDescriptor *extension,
1134 id obj,
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001135 BOOL *stop) {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001136 if (GPBExtensionIsMessage(extension)) {
1137 if (extension.isRepeated) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001138 for (GPBMessage *msg in obj) {
1139 if (!msg.initialized) {
1140 result = NO;
1141 *stop = YES;
1142 break;
1143 }
1144 }
1145 } else {
1146 GPBMessage *asMsg = obj;
1147 if (!asMsg.initialized) {
1148 result = NO;
1149 *stop = YES;
1150 }
1151 }
1152 }
1153 }];
1154 return result;
1155}
1156
1157- (GPBDescriptor *)descriptor {
1158 return [[self class] descriptor];
1159}
1160
1161- (NSData *)data {
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04001162#ifdef DEBUG
1163 if (!self.initialized) {
1164 return nil;
1165 }
1166#endif
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001167 NSMutableData *data = [NSMutableData dataWithLength:[self serializedSize]];
1168 GPBCodedOutputStream *stream =
1169 [[GPBCodedOutputStream alloc] initWithData:data];
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04001170 @try {
1171 [self writeToCodedOutputStream:stream];
1172 }
1173 @catch (NSException *exception) {
1174 // This really shouldn't happen. The only way writeToCodedOutputStream:
1175 // could throw is if something in the library has a bug and the
1176 // serializedSize was wrong.
1177#ifdef DEBUG
1178 NSLog(@"%@: Internal exception while building message data: %@",
1179 [self class], exception);
1180#endif
1181 data = nil;
1182 }
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001183 [stream release];
1184 return data;
1185}
1186
1187- (NSData *)delimitedData {
1188 size_t serializedSize = [self serializedSize];
1189 size_t varintSize = GPBComputeRawVarint32SizeForInteger(serializedSize);
1190 NSMutableData *data =
1191 [NSMutableData dataWithLength:(serializedSize + varintSize)];
1192 GPBCodedOutputStream *stream =
1193 [[GPBCodedOutputStream alloc] initWithData:data];
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04001194 @try {
1195 [self writeDelimitedToCodedOutputStream:stream];
1196 }
1197 @catch (NSException *exception) {
1198 // This really shouldn't happen. The only way writeToCodedOutputStream:
1199 // could throw is if something in the library has a bug and the
1200 // serializedSize was wrong.
1201#ifdef DEBUG
1202 NSLog(@"%@: Internal exception while building message delimitedData: %@",
1203 [self class], exception);
1204#endif
Thomas Van Lentenc27833b2015-12-07 10:49:30 -05001205 // If it happens, truncate.
1206 data.length = 0;
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04001207 }
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001208 [stream release];
1209 return data;
1210}
1211
1212- (void)writeToOutputStream:(NSOutputStream *)output {
1213 GPBCodedOutputStream *stream =
1214 [[GPBCodedOutputStream alloc] initWithOutputStream:output];
1215 [self writeToCodedOutputStream:stream];
1216 [stream release];
1217}
1218
1219- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)output {
1220 GPBDescriptor *descriptor = [self descriptor];
1221 NSArray *fieldsArray = descriptor->fields_;
1222 NSUInteger fieldCount = fieldsArray.count;
1223 const GPBExtensionRange *extensionRanges = descriptor.extensionRanges;
1224 NSUInteger extensionRangesCount = descriptor.extensionRangesCount;
1225 for (NSUInteger i = 0, j = 0; i < fieldCount || j < extensionRangesCount;) {
1226 if (i == fieldCount) {
1227 [self writeExtensionsToCodedOutputStream:output
1228 range:extensionRanges[j++]];
1229 } else if (j == extensionRangesCount ||
1230 GPBFieldNumber(fieldsArray[i]) < extensionRanges[j].start) {
1231 [self writeField:fieldsArray[i++] toCodedOutputStream:output];
1232 } else {
1233 [self writeExtensionsToCodedOutputStream:output
1234 range:extensionRanges[j++]];
1235 }
1236 }
1237 if (descriptor.isWireFormat) {
1238 [unknownFields_ writeAsMessageSetTo:output];
1239 } else {
1240 [unknownFields_ writeToCodedOutputStream:output];
1241 }
1242}
1243
1244- (void)writeDelimitedToOutputStream:(NSOutputStream *)output {
1245 GPBCodedOutputStream *codedOutput =
1246 [[GPBCodedOutputStream alloc] initWithOutputStream:output];
1247 [self writeDelimitedToCodedOutputStream:codedOutput];
1248 [codedOutput release];
1249}
1250
1251- (void)writeDelimitedToCodedOutputStream:(GPBCodedOutputStream *)output {
1252 [output writeRawVarintSizeTAs32:[self serializedSize]];
1253 [self writeToCodedOutputStream:output];
1254}
1255
1256- (void)writeField:(GPBFieldDescriptor *)field
1257 toCodedOutputStream:(GPBCodedOutputStream *)output {
1258 GPBFieldType fieldType = field.fieldType;
1259 if (fieldType == GPBFieldTypeSingle) {
1260 BOOL has = GPBGetHasIvarField(self, field);
1261 if (!has) {
1262 return;
1263 }
1264 }
1265 uint32_t fieldNumber = GPBFieldNumber(field);
1266
1267//%PDDM-DEFINE FIELD_CASE(TYPE, REAL_TYPE)
1268//%FIELD_CASE_FULL(TYPE, REAL_TYPE, REAL_TYPE)
1269//%PDDM-DEFINE FIELD_CASE_FULL(TYPE, REAL_TYPE, ARRAY_TYPE)
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001270//% case GPBDataType##TYPE:
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001271//% if (fieldType == GPBFieldTypeRepeated) {
1272//% uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1273//% GPB##ARRAY_TYPE##Array *array =
1274//% GPBGetObjectIvarWithFieldNoAutocreate(self, field);
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001275//% [output write##TYPE##Array:fieldNumber values:array tag:tag];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001276//% } else if (fieldType == GPBFieldTypeSingle) {
1277//% [output write##TYPE:fieldNumber
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001278//% TYPE$S value:GPBGetMessage##REAL_TYPE##Field(self, field)];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001279//% } else { // fieldType == GPBFieldTypeMap
1280//% // Exact type here doesn't matter.
1281//% GPBInt32##ARRAY_TYPE##Dictionary *dict =
1282//% GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1283//% [dict writeToCodedOutputStream:output asField:field];
1284//% }
1285//% break;
1286//%
1287//%PDDM-DEFINE FIELD_CASE2(TYPE)
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001288//% case GPBDataType##TYPE:
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001289//% if (fieldType == GPBFieldTypeRepeated) {
1290//% NSArray *array = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001291//% [output write##TYPE##Array:fieldNumber values:array];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001292//% } else if (fieldType == GPBFieldTypeSingle) {
1293//% // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has check
1294//% // again.
1295//% [output write##TYPE:fieldNumber
1296//% TYPE$S value:GPBGetObjectIvarWithFieldNoAutocreate(self, field)];
1297//% } else { // fieldType == GPBFieldTypeMap
1298//% // Exact type here doesn't matter.
1299//% id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001300//% GPBDataType mapKeyDataType = field.mapKeyDataType;
1301//% if (mapKeyDataType == GPBDataTypeString) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001302//% GPBDictionaryWriteToStreamInternalHelper(output, dict, field);
1303//% } else {
1304//% [dict writeToCodedOutputStream:output asField:field];
1305//% }
1306//% }
1307//% break;
1308//%
1309
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001310 switch (GPBGetFieldDataType(field)) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001311
1312//%PDDM-EXPAND FIELD_CASE(Bool, Bool)
1313// This block of code is generated, do not edit it directly.
1314
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001315 case GPBDataTypeBool:
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001316 if (fieldType == GPBFieldTypeRepeated) {
1317 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1318 GPBBoolArray *array =
1319 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001320 [output writeBoolArray:fieldNumber values:array tag:tag];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001321 } else if (fieldType == GPBFieldTypeSingle) {
1322 [output writeBool:fieldNumber
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001323 value:GPBGetMessageBoolField(self, field)];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001324 } else { // fieldType == GPBFieldTypeMap
1325 // Exact type here doesn't matter.
1326 GPBInt32BoolDictionary *dict =
1327 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1328 [dict writeToCodedOutputStream:output asField:field];
1329 }
1330 break;
1331
1332//%PDDM-EXPAND FIELD_CASE(Fixed32, UInt32)
1333// This block of code is generated, do not edit it directly.
1334
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001335 case GPBDataTypeFixed32:
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001336 if (fieldType == GPBFieldTypeRepeated) {
1337 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1338 GPBUInt32Array *array =
1339 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001340 [output writeFixed32Array:fieldNumber values:array tag:tag];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001341 } else if (fieldType == GPBFieldTypeSingle) {
1342 [output writeFixed32:fieldNumber
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001343 value:GPBGetMessageUInt32Field(self, field)];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001344 } else { // fieldType == GPBFieldTypeMap
1345 // Exact type here doesn't matter.
1346 GPBInt32UInt32Dictionary *dict =
1347 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1348 [dict writeToCodedOutputStream:output asField:field];
1349 }
1350 break;
1351
1352//%PDDM-EXPAND FIELD_CASE(SFixed32, Int32)
1353// This block of code is generated, do not edit it directly.
1354
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001355 case GPBDataTypeSFixed32:
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001356 if (fieldType == GPBFieldTypeRepeated) {
1357 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1358 GPBInt32Array *array =
1359 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001360 [output writeSFixed32Array:fieldNumber values:array tag:tag];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001361 } else if (fieldType == GPBFieldTypeSingle) {
1362 [output writeSFixed32:fieldNumber
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001363 value:GPBGetMessageInt32Field(self, field)];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001364 } else { // fieldType == GPBFieldTypeMap
1365 // Exact type here doesn't matter.
1366 GPBInt32Int32Dictionary *dict =
1367 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1368 [dict writeToCodedOutputStream:output asField:field];
1369 }
1370 break;
1371
1372//%PDDM-EXPAND FIELD_CASE(Float, Float)
1373// This block of code is generated, do not edit it directly.
1374
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001375 case GPBDataTypeFloat:
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001376 if (fieldType == GPBFieldTypeRepeated) {
1377 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1378 GPBFloatArray *array =
1379 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001380 [output writeFloatArray:fieldNumber values:array tag:tag];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001381 } else if (fieldType == GPBFieldTypeSingle) {
1382 [output writeFloat:fieldNumber
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001383 value:GPBGetMessageFloatField(self, field)];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001384 } else { // fieldType == GPBFieldTypeMap
1385 // Exact type here doesn't matter.
1386 GPBInt32FloatDictionary *dict =
1387 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1388 [dict writeToCodedOutputStream:output asField:field];
1389 }
1390 break;
1391
1392//%PDDM-EXPAND FIELD_CASE(Fixed64, UInt64)
1393// This block of code is generated, do not edit it directly.
1394
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001395 case GPBDataTypeFixed64:
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001396 if (fieldType == GPBFieldTypeRepeated) {
1397 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1398 GPBUInt64Array *array =
1399 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001400 [output writeFixed64Array:fieldNumber values:array tag:tag];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001401 } else if (fieldType == GPBFieldTypeSingle) {
1402 [output writeFixed64:fieldNumber
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001403 value:GPBGetMessageUInt64Field(self, field)];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001404 } else { // fieldType == GPBFieldTypeMap
1405 // Exact type here doesn't matter.
1406 GPBInt32UInt64Dictionary *dict =
1407 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1408 [dict writeToCodedOutputStream:output asField:field];
1409 }
1410 break;
1411
1412//%PDDM-EXPAND FIELD_CASE(SFixed64, Int64)
1413// This block of code is generated, do not edit it directly.
1414
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001415 case GPBDataTypeSFixed64:
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001416 if (fieldType == GPBFieldTypeRepeated) {
1417 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1418 GPBInt64Array *array =
1419 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001420 [output writeSFixed64Array:fieldNumber values:array tag:tag];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001421 } else if (fieldType == GPBFieldTypeSingle) {
1422 [output writeSFixed64:fieldNumber
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001423 value:GPBGetMessageInt64Field(self, field)];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001424 } else { // fieldType == GPBFieldTypeMap
1425 // Exact type here doesn't matter.
1426 GPBInt32Int64Dictionary *dict =
1427 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1428 [dict writeToCodedOutputStream:output asField:field];
1429 }
1430 break;
1431
1432//%PDDM-EXPAND FIELD_CASE(Double, Double)
1433// This block of code is generated, do not edit it directly.
1434
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001435 case GPBDataTypeDouble:
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001436 if (fieldType == GPBFieldTypeRepeated) {
1437 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1438 GPBDoubleArray *array =
1439 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001440 [output writeDoubleArray:fieldNumber values:array tag:tag];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001441 } else if (fieldType == GPBFieldTypeSingle) {
1442 [output writeDouble:fieldNumber
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001443 value:GPBGetMessageDoubleField(self, field)];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001444 } else { // fieldType == GPBFieldTypeMap
1445 // Exact type here doesn't matter.
1446 GPBInt32DoubleDictionary *dict =
1447 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1448 [dict writeToCodedOutputStream:output asField:field];
1449 }
1450 break;
1451
1452//%PDDM-EXPAND FIELD_CASE(Int32, Int32)
1453// This block of code is generated, do not edit it directly.
1454
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001455 case GPBDataTypeInt32:
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001456 if (fieldType == GPBFieldTypeRepeated) {
1457 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1458 GPBInt32Array *array =
1459 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001460 [output writeInt32Array:fieldNumber values:array tag:tag];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001461 } else if (fieldType == GPBFieldTypeSingle) {
1462 [output writeInt32:fieldNumber
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001463 value:GPBGetMessageInt32Field(self, field)];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001464 } else { // fieldType == GPBFieldTypeMap
1465 // Exact type here doesn't matter.
1466 GPBInt32Int32Dictionary *dict =
1467 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1468 [dict writeToCodedOutputStream:output asField:field];
1469 }
1470 break;
1471
1472//%PDDM-EXPAND FIELD_CASE(Int64, Int64)
1473// This block of code is generated, do not edit it directly.
1474
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001475 case GPBDataTypeInt64:
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001476 if (fieldType == GPBFieldTypeRepeated) {
1477 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1478 GPBInt64Array *array =
1479 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001480 [output writeInt64Array:fieldNumber values:array tag:tag];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001481 } else if (fieldType == GPBFieldTypeSingle) {
1482 [output writeInt64:fieldNumber
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001483 value:GPBGetMessageInt64Field(self, field)];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001484 } else { // fieldType == GPBFieldTypeMap
1485 // Exact type here doesn't matter.
1486 GPBInt32Int64Dictionary *dict =
1487 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1488 [dict writeToCodedOutputStream:output asField:field];
1489 }
1490 break;
1491
1492//%PDDM-EXPAND FIELD_CASE(SInt32, Int32)
1493// This block of code is generated, do not edit it directly.
1494
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001495 case GPBDataTypeSInt32:
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001496 if (fieldType == GPBFieldTypeRepeated) {
1497 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1498 GPBInt32Array *array =
1499 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001500 [output writeSInt32Array:fieldNumber values:array tag:tag];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001501 } else if (fieldType == GPBFieldTypeSingle) {
1502 [output writeSInt32:fieldNumber
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001503 value:GPBGetMessageInt32Field(self, field)];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001504 } else { // fieldType == GPBFieldTypeMap
1505 // Exact type here doesn't matter.
1506 GPBInt32Int32Dictionary *dict =
1507 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1508 [dict writeToCodedOutputStream:output asField:field];
1509 }
1510 break;
1511
1512//%PDDM-EXPAND FIELD_CASE(SInt64, Int64)
1513// This block of code is generated, do not edit it directly.
1514
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001515 case GPBDataTypeSInt64:
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001516 if (fieldType == GPBFieldTypeRepeated) {
1517 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1518 GPBInt64Array *array =
1519 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001520 [output writeSInt64Array:fieldNumber values:array tag:tag];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001521 } else if (fieldType == GPBFieldTypeSingle) {
1522 [output writeSInt64:fieldNumber
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001523 value:GPBGetMessageInt64Field(self, field)];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001524 } else { // fieldType == GPBFieldTypeMap
1525 // Exact type here doesn't matter.
1526 GPBInt32Int64Dictionary *dict =
1527 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1528 [dict writeToCodedOutputStream:output asField:field];
1529 }
1530 break;
1531
1532//%PDDM-EXPAND FIELD_CASE(UInt32, UInt32)
1533// This block of code is generated, do not edit it directly.
1534
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001535 case GPBDataTypeUInt32:
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001536 if (fieldType == GPBFieldTypeRepeated) {
1537 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1538 GPBUInt32Array *array =
1539 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001540 [output writeUInt32Array:fieldNumber values:array tag:tag];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001541 } else if (fieldType == GPBFieldTypeSingle) {
1542 [output writeUInt32:fieldNumber
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001543 value:GPBGetMessageUInt32Field(self, field)];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001544 } else { // fieldType == GPBFieldTypeMap
1545 // Exact type here doesn't matter.
1546 GPBInt32UInt32Dictionary *dict =
1547 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1548 [dict writeToCodedOutputStream:output asField:field];
1549 }
1550 break;
1551
1552//%PDDM-EXPAND FIELD_CASE(UInt64, UInt64)
1553// This block of code is generated, do not edit it directly.
1554
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001555 case GPBDataTypeUInt64:
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001556 if (fieldType == GPBFieldTypeRepeated) {
1557 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1558 GPBUInt64Array *array =
1559 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001560 [output writeUInt64Array:fieldNumber values:array tag:tag];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001561 } else if (fieldType == GPBFieldTypeSingle) {
1562 [output writeUInt64:fieldNumber
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001563 value:GPBGetMessageUInt64Field(self, field)];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001564 } else { // fieldType == GPBFieldTypeMap
1565 // Exact type here doesn't matter.
1566 GPBInt32UInt64Dictionary *dict =
1567 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1568 [dict writeToCodedOutputStream:output asField:field];
1569 }
1570 break;
1571
1572//%PDDM-EXPAND FIELD_CASE_FULL(Enum, Int32, Enum)
1573// This block of code is generated, do not edit it directly.
1574
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001575 case GPBDataTypeEnum:
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001576 if (fieldType == GPBFieldTypeRepeated) {
1577 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1578 GPBEnumArray *array =
1579 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001580 [output writeEnumArray:fieldNumber values:array tag:tag];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001581 } else if (fieldType == GPBFieldTypeSingle) {
1582 [output writeEnum:fieldNumber
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001583 value:GPBGetMessageInt32Field(self, field)];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001584 } else { // fieldType == GPBFieldTypeMap
1585 // Exact type here doesn't matter.
1586 GPBInt32EnumDictionary *dict =
1587 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1588 [dict writeToCodedOutputStream:output asField:field];
1589 }
1590 break;
1591
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001592//%PDDM-EXPAND FIELD_CASE2(Bytes)
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001593// This block of code is generated, do not edit it directly.
1594
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001595 case GPBDataTypeBytes:
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001596 if (fieldType == GPBFieldTypeRepeated) {
1597 NSArray *array = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001598 [output writeBytesArray:fieldNumber values:array];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001599 } else if (fieldType == GPBFieldTypeSingle) {
1600 // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has check
1601 // again.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001602 [output writeBytes:fieldNumber
1603 value:GPBGetObjectIvarWithFieldNoAutocreate(self, field)];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001604 } else { // fieldType == GPBFieldTypeMap
1605 // Exact type here doesn't matter.
1606 id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001607 GPBDataType mapKeyDataType = field.mapKeyDataType;
1608 if (mapKeyDataType == GPBDataTypeString) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001609 GPBDictionaryWriteToStreamInternalHelper(output, dict, field);
1610 } else {
1611 [dict writeToCodedOutputStream:output asField:field];
1612 }
1613 }
1614 break;
1615
1616//%PDDM-EXPAND FIELD_CASE2(String)
1617// This block of code is generated, do not edit it directly.
1618
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001619 case GPBDataTypeString:
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001620 if (fieldType == GPBFieldTypeRepeated) {
1621 NSArray *array = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001622 [output writeStringArray:fieldNumber values:array];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001623 } else if (fieldType == GPBFieldTypeSingle) {
1624 // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has check
1625 // again.
1626 [output writeString:fieldNumber
1627 value:GPBGetObjectIvarWithFieldNoAutocreate(self, field)];
1628 } else { // fieldType == GPBFieldTypeMap
1629 // Exact type here doesn't matter.
1630 id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001631 GPBDataType mapKeyDataType = field.mapKeyDataType;
1632 if (mapKeyDataType == GPBDataTypeString) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001633 GPBDictionaryWriteToStreamInternalHelper(output, dict, field);
1634 } else {
1635 [dict writeToCodedOutputStream:output asField:field];
1636 }
1637 }
1638 break;
1639
1640//%PDDM-EXPAND FIELD_CASE2(Message)
1641// This block of code is generated, do not edit it directly.
1642
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001643 case GPBDataTypeMessage:
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001644 if (fieldType == GPBFieldTypeRepeated) {
1645 NSArray *array = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001646 [output writeMessageArray:fieldNumber values:array];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001647 } else if (fieldType == GPBFieldTypeSingle) {
1648 // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has check
1649 // again.
1650 [output writeMessage:fieldNumber
1651 value:GPBGetObjectIvarWithFieldNoAutocreate(self, field)];
1652 } else { // fieldType == GPBFieldTypeMap
1653 // Exact type here doesn't matter.
1654 id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001655 GPBDataType mapKeyDataType = field.mapKeyDataType;
1656 if (mapKeyDataType == GPBDataTypeString) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001657 GPBDictionaryWriteToStreamInternalHelper(output, dict, field);
1658 } else {
1659 [dict writeToCodedOutputStream:output asField:field];
1660 }
1661 }
1662 break;
1663
1664//%PDDM-EXPAND FIELD_CASE2(Group)
1665// This block of code is generated, do not edit it directly.
1666
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001667 case GPBDataTypeGroup:
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001668 if (fieldType == GPBFieldTypeRepeated) {
1669 NSArray *array = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001670 [output writeGroupArray:fieldNumber values:array];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001671 } else if (fieldType == GPBFieldTypeSingle) {
1672 // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has check
1673 // again.
1674 [output writeGroup:fieldNumber
1675 value:GPBGetObjectIvarWithFieldNoAutocreate(self, field)];
1676 } else { // fieldType == GPBFieldTypeMap
1677 // Exact type here doesn't matter.
1678 id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001679 GPBDataType mapKeyDataType = field.mapKeyDataType;
1680 if (mapKeyDataType == GPBDataTypeString) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001681 GPBDictionaryWriteToStreamInternalHelper(output, dict, field);
1682 } else {
1683 [dict writeToCodedOutputStream:output asField:field];
1684 }
1685 }
1686 break;
1687
1688//%PDDM-EXPAND-END (18 expansions)
1689 }
1690}
1691
1692#pragma mark - Extensions
1693
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001694- (id)getExtension:(GPBExtensionDescriptor *)extension {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001695 CheckExtension(self, extension);
1696 id value = [extensionMap_ objectForKey:extension];
1697 if (value != nil) {
1698 return value;
1699 }
1700
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001701 // No default for repeated.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001702 if (extension.isRepeated) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001703 return nil;
1704 }
1705 // Non messages get their default.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001706 if (!GPBExtensionIsMessage(extension)) {
1707 return extension.defaultValue;
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001708 }
1709
1710 // Check for an autocreated value.
Thomas Van Lentenbd41a392016-03-21 11:11:14 -04001711 GPBPrepareReadOnlySemaphore(self);
Thomas Van Lentend6590d62015-12-17 14:35:44 -05001712 dispatch_semaphore_wait(readOnlySemaphore_, DISPATCH_TIME_FOREVER);
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001713 value = [autocreatedExtensionMap_ objectForKey:extension];
1714 if (!value) {
1715 // Auto create the message extensions to match normal fields.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001716 value = CreateMessageWithAutocreatorForExtension(extension.msgClass, self,
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001717 extension);
1718
1719 if (autocreatedExtensionMap_ == nil) {
1720 autocreatedExtensionMap_ = [[NSMutableDictionary alloc] init];
1721 }
1722
1723 // We can't simply call setExtension here because that would clear the new
1724 // value's autocreator.
1725 [autocreatedExtensionMap_ setObject:value forKey:extension];
1726 [value release];
1727 }
1728
Thomas Van Lentend6590d62015-12-17 14:35:44 -05001729 dispatch_semaphore_signal(readOnlySemaphore_);
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001730 return value;
1731}
1732
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001733- (id)getExistingExtension:(GPBExtensionDescriptor *)extension {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001734 // This is an internal method so we don't need to call CheckExtension().
1735 return [extensionMap_ objectForKey:extension];
1736}
1737
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001738- (BOOL)hasExtension:(GPBExtensionDescriptor *)extension {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001739#if DEBUG
1740 CheckExtension(self, extension);
1741#endif // DEBUG
1742 return nil != [extensionMap_ objectForKey:extension];
1743}
1744
1745- (NSArray *)extensionsCurrentlySet {
1746 return [extensionMap_ allKeys];
1747}
1748
1749- (void)writeExtensionsToCodedOutputStream:(GPBCodedOutputStream *)output
1750 range:(GPBExtensionRange)range {
1751 NSArray *sortedExtensions = [[extensionMap_ allKeys]
1752 sortedArrayUsingSelector:@selector(compareByFieldNumber:)];
1753 uint32_t start = range.start;
1754 uint32_t end = range.end;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001755 for (GPBExtensionDescriptor *extension in sortedExtensions) {
1756 uint32_t fieldNumber = extension.fieldNumber;
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001757 if (fieldNumber >= start && fieldNumber < end) {
1758 id value = [extensionMap_ objectForKey:extension];
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001759 GPBWriteExtensionValueToOutputStream(extension, value, output);
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001760 }
1761 }
1762}
1763
1764- (NSArray *)sortedExtensionsInUse {
1765 return [[extensionMap_ allKeys]
1766 sortedArrayUsingSelector:@selector(compareByFieldNumber:)];
1767}
1768
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001769- (void)setExtension:(GPBExtensionDescriptor *)extension value:(id)value {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001770 if (!value) {
1771 [self clearExtension:extension];
1772 return;
1773 }
1774
1775 CheckExtension(self, extension);
1776
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001777 if (extension.repeated) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001778 [NSException raise:NSInvalidArgumentException
1779 format:@"Must call addExtension() for repeated types."];
1780 }
1781
1782 if (extensionMap_ == nil) {
1783 extensionMap_ = [[NSMutableDictionary alloc] init];
1784 }
1785
Thomas Van Lentenc27833b2015-12-07 10:49:30 -05001786 // This pointless cast is for CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION.
1787 // Without it, the compiler complains we're passing an id nullable when
1788 // setObject:forKey: requires a id nonnull for the value. The check for
1789 // !value at the start of the method ensures it isn't nil, but the check
1790 // isn't smart enough to realize that.
1791 [extensionMap_ setObject:(id)value forKey:extension];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001792
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001793 GPBExtensionDescriptor *descriptor = extension;
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001794
1795 if (GPBExtensionIsMessage(descriptor) && !descriptor.isRepeated) {
1796 GPBMessage *autocreatedValue =
1797 [[autocreatedExtensionMap_ objectForKey:extension] retain];
1798 // Must remove from the map before calling GPBClearMessageAutocreator() so
1799 // that GPBClearMessageAutocreator() knows its safe to clear.
1800 [autocreatedExtensionMap_ removeObjectForKey:extension];
1801 GPBClearMessageAutocreator(autocreatedValue);
1802 [autocreatedValue release];
1803 }
1804
1805 GPBBecomeVisibleToAutocreator(self);
1806}
1807
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001808- (void)addExtension:(GPBExtensionDescriptor *)extension value:(id)value {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001809 CheckExtension(self, extension);
1810
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001811 if (!extension.repeated) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001812 [NSException raise:NSInvalidArgumentException
1813 format:@"Must call setExtension() for singular types."];
1814 }
1815
1816 if (extensionMap_ == nil) {
1817 extensionMap_ = [[NSMutableDictionary alloc] init];
1818 }
1819 NSMutableArray *list = [extensionMap_ objectForKey:extension];
1820 if (list == nil) {
1821 list = [NSMutableArray array];
1822 [extensionMap_ setObject:list forKey:extension];
1823 }
1824
1825 [list addObject:value];
1826 GPBBecomeVisibleToAutocreator(self);
1827}
1828
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001829- (void)setExtension:(GPBExtensionDescriptor *)extension
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001830 index:(NSUInteger)idx
1831 value:(id)value {
1832 CheckExtension(self, extension);
1833
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001834 if (!extension.repeated) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001835 [NSException raise:NSInvalidArgumentException
1836 format:@"Must call setExtension() for singular types."];
1837 }
1838
1839 if (extensionMap_ == nil) {
1840 extensionMap_ = [[NSMutableDictionary alloc] init];
1841 }
1842
1843 NSMutableArray *list = [extensionMap_ objectForKey:extension];
1844
1845 [list replaceObjectAtIndex:idx withObject:value];
1846 GPBBecomeVisibleToAutocreator(self);
1847}
1848
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001849- (void)clearExtension:(GPBExtensionDescriptor *)extension {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001850 CheckExtension(self, extension);
1851
1852 // Only become visible if there was actually a value to clear.
1853 if ([extensionMap_ objectForKey:extension]) {
1854 [extensionMap_ removeObjectForKey:extension];
1855 GPBBecomeVisibleToAutocreator(self);
1856 }
1857}
1858
1859#pragma mark - mergeFrom
1860
1861- (void)mergeFromData:(NSData *)data
1862 extensionRegistry:(GPBExtensionRegistry *)extensionRegistry {
1863 GPBCodedInputStream *input = [[GPBCodedInputStream alloc] initWithData:data];
1864 [self mergeFromCodedInputStream:input extensionRegistry:extensionRegistry];
1865 [input checkLastTagWas:0];
1866 [input release];
1867}
1868
1869#pragma mark - mergeDelimitedFrom
1870
1871- (void)mergeDelimitedFromCodedInputStream:(GPBCodedInputStream *)input
1872 extensionRegistry:(GPBExtensionRegistry *)extensionRegistry {
1873 GPBCodedInputStreamState *state = &input->state_;
1874 if (GPBCodedInputStreamIsAtEnd(state)) {
1875 return;
1876 }
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001877 NSData *data = GPBCodedInputStreamReadRetainedBytesNoCopy(state);
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001878 if (data == nil) {
1879 return;
1880 }
1881 [self mergeFromData:data extensionRegistry:extensionRegistry];
1882 [data release];
1883}
1884
1885#pragma mark - Parse From Data Support
1886
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04001887+ (instancetype)parseFromData:(NSData *)data error:(NSError **)errorPtr {
1888 return [self parseFromData:data extensionRegistry:nil error:errorPtr];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001889}
1890
1891+ (instancetype)parseFromData:(NSData *)data
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04001892 extensionRegistry:(GPBExtensionRegistry *)extensionRegistry
1893 error:(NSError **)errorPtr {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001894 return [[[self alloc] initWithData:data
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04001895 extensionRegistry:extensionRegistry
1896 error:errorPtr] autorelease];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001897}
1898
1899+ (instancetype)parseFromCodedInputStream:(GPBCodedInputStream *)input
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04001900 extensionRegistry:(GPBExtensionRegistry *)extensionRegistry
1901 error:(NSError **)errorPtr {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001902 return
1903 [[[self alloc] initWithCodedInputStream:input
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04001904 extensionRegistry:extensionRegistry
1905 error:errorPtr] autorelease];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001906}
1907
1908#pragma mark - Parse Delimited From Data Support
1909
1910+ (instancetype)parseDelimitedFromCodedInputStream:(GPBCodedInputStream *)input
1911 extensionRegistry:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04001912 (GPBExtensionRegistry *)extensionRegistry
1913 error:(NSError **)errorPtr {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001914 GPBMessage *message = [[[self alloc] init] autorelease];
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04001915 @try {
1916 [message mergeDelimitedFromCodedInputStream:input
1917 extensionRegistry:extensionRegistry];
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001918 if (errorPtr) {
1919 *errorPtr = nil;
1920 }
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04001921 }
1922 @catch (NSException *exception) {
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04001923 message = nil;
1924 if (errorPtr) {
1925 *errorPtr = MessageErrorWithReason(GPBMessageErrorCodeMalformedData,
1926 exception.reason);
1927 }
1928 }
1929#ifdef DEBUG
1930 if (message && !message.initialized) {
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04001931 message = nil;
1932 if (errorPtr) {
1933 *errorPtr = MessageError(GPBMessageErrorCodeMissingRequiredField, nil);
1934 }
1935 }
1936#endif
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001937 return message;
1938}
1939
1940#pragma mark - Unknown Field Support
1941
1942- (GPBUnknownFieldSet *)unknownFields {
1943 return unknownFields_;
1944}
1945
1946- (void)setUnknownFields:(GPBUnknownFieldSet *)unknownFields {
1947 if (unknownFields != unknownFields_) {
1948 [unknownFields_ release];
1949 unknownFields_ = [unknownFields copy];
1950 GPBBecomeVisibleToAutocreator(self);
1951 }
1952}
1953
1954- (void)parseMessageSet:(GPBCodedInputStream *)input
1955 extensionRegistry:(GPBExtensionRegistry *)extensionRegistry {
1956 uint32_t typeId = 0;
1957 NSData *rawBytes = nil;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001958 GPBExtensionDescriptor *extension = nil;
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001959 GPBCodedInputStreamState *state = &input->state_;
1960 while (true) {
1961 uint32_t tag = GPBCodedInputStreamReadTag(state);
1962 if (tag == 0) {
1963 break;
1964 }
1965
1966 if (tag == GPBWireFormatMessageSetTypeIdTag) {
1967 typeId = GPBCodedInputStreamReadUInt32(state);
1968 if (typeId != 0) {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001969 extension = [extensionRegistry extensionForDescriptor:[self descriptor]
1970 fieldNumber:typeId];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001971 }
1972 } else if (tag == GPBWireFormatMessageSetMessageTag) {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001973 rawBytes =
1974 [GPBCodedInputStreamReadRetainedBytesNoCopy(state) autorelease];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001975 } else {
1976 if (![input skipField:tag]) {
1977 break;
1978 }
1979 }
1980 }
1981
1982 [input checkLastTagWas:GPBWireFormatMessageSetItemEndTag];
1983
1984 if (rawBytes != nil && typeId != 0) {
1985 if (extension != nil) {
1986 GPBCodedInputStream *newInput =
1987 [[GPBCodedInputStream alloc] initWithData:rawBytes];
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001988 GPBExtensionMergeFromInputStream(extension,
1989 extension.packable,
1990 newInput,
1991 extensionRegistry,
1992 self);
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001993 [newInput release];
1994 } else {
1995 GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self);
1996 [unknownFields mergeMessageSetMessage:typeId data:rawBytes];
1997 }
1998 }
1999}
2000
2001- (BOOL)parseUnknownField:(GPBCodedInputStream *)input
2002 extensionRegistry:(GPBExtensionRegistry *)extensionRegistry
2003 tag:(uint32_t)tag {
2004 GPBWireFormat wireType = GPBWireFormatGetTagWireType(tag);
2005 int32_t fieldNumber = GPBWireFormatGetTagFieldNumber(tag);
2006
2007 GPBDescriptor *descriptor = [self descriptor];
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002008 GPBExtensionDescriptor *extension =
2009 [extensionRegistry extensionForDescriptor:descriptor
2010 fieldNumber:fieldNumber];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002011 if (extension == nil) {
2012 if (descriptor.wireFormat && GPBWireFormatMessageSetItemTag == tag) {
2013 [self parseMessageSet:input extensionRegistry:extensionRegistry];
2014 return YES;
2015 }
2016 } else {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002017 if (extension.wireType == wireType) {
2018 GPBExtensionMergeFromInputStream(extension,
2019 extension.packable,
2020 input,
2021 extensionRegistry,
2022 self);
2023 return YES;
2024 }
2025 // Primitive, repeated types can be packed on unpacked on the wire, and are
2026 // parsed either way.
2027 if ([extension isRepeated] &&
2028 !GPBDataTypeIsObject(extension->description_->dataType) &&
2029 (extension.alternateWireType == wireType)) {
2030 GPBExtensionMergeFromInputStream(extension,
2031 !extension.packable,
2032 input,
2033 extensionRegistry,
2034 self);
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002035 return YES;
2036 }
2037 }
2038 if ([GPBUnknownFieldSet isFieldTag:tag]) {
2039 GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self);
2040 return [unknownFields mergeFieldFrom:tag input:input];
2041 } else {
2042 return NO;
2043 }
2044}
2045
2046- (void)addUnknownMapEntry:(int32_t)fieldNum value:(NSData *)data {
2047 GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self);
2048 [unknownFields addUnknownMapEntry:fieldNum value:data];
2049}
2050
2051#pragma mark - MergeFromCodedInputStream Support
2052
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002053static void MergeSingleFieldFromCodedInputStream(
2054 GPBMessage *self, GPBFieldDescriptor *field, GPBFileSyntax syntax,
2055 GPBCodedInputStream *input, GPBExtensionRegistry *extensionRegistry) {
2056 GPBDataType fieldDataType = GPBGetFieldDataType(field);
2057 switch (fieldDataType) {
2058#define CASE_SINGLE_POD(NAME, TYPE, FUNC_TYPE) \
2059 case GPBDataType##NAME: { \
2060 TYPE val = GPBCodedInputStreamRead##NAME(&input->state_); \
2061 GPBSet##FUNC_TYPE##IvarWithFieldInternal(self, field, val, syntax); \
2062 break; \
2063 }
2064#define CASE_SINGLE_OBJECT(NAME) \
2065 case GPBDataType##NAME: { \
2066 id val = GPBCodedInputStreamReadRetained##NAME(&input->state_); \
2067 GPBSetRetainedObjectIvarWithFieldInternal(self, field, val, syntax); \
2068 break; \
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002069 }
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002070 CASE_SINGLE_POD(Bool, BOOL, Bool)
2071 CASE_SINGLE_POD(Fixed32, uint32_t, UInt32)
2072 CASE_SINGLE_POD(SFixed32, int32_t, Int32)
2073 CASE_SINGLE_POD(Float, float, Float)
2074 CASE_SINGLE_POD(Fixed64, uint64_t, UInt64)
2075 CASE_SINGLE_POD(SFixed64, int64_t, Int64)
2076 CASE_SINGLE_POD(Double, double, Double)
2077 CASE_SINGLE_POD(Int32, int32_t, Int32)
2078 CASE_SINGLE_POD(Int64, int64_t, Int64)
2079 CASE_SINGLE_POD(SInt32, int32_t, Int32)
2080 CASE_SINGLE_POD(SInt64, int64_t, Int64)
2081 CASE_SINGLE_POD(UInt32, uint32_t, UInt32)
2082 CASE_SINGLE_POD(UInt64, uint64_t, UInt64)
2083 CASE_SINGLE_OBJECT(Bytes)
2084 CASE_SINGLE_OBJECT(String)
2085#undef CASE_SINGLE_POD
2086#undef CASE_SINGLE_OBJECT
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002087
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002088 case GPBDataTypeMessage: {
2089 if (GPBGetHasIvarField(self, field)) {
2090 // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has
2091 // check again.
2092 GPBMessage *message =
2093 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
2094 [input readMessage:message extensionRegistry:extensionRegistry];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002095 } else {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002096 GPBMessage *message = [[field.msgClass alloc] init];
2097 [input readMessage:message extensionRegistry:extensionRegistry];
2098 GPBSetRetainedObjectIvarWithFieldInternal(self, field, message, syntax);
2099 }
2100 break;
2101 }
2102
2103 case GPBDataTypeGroup: {
2104 if (GPBGetHasIvarField(self, field)) {
2105 // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has
2106 // check again.
2107 GPBMessage *message =
2108 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
2109 [input readGroup:GPBFieldNumber(field)
2110 message:message
2111 extensionRegistry:extensionRegistry];
2112 } else {
2113 GPBMessage *message = [[field.msgClass alloc] init];
2114 [input readGroup:GPBFieldNumber(field)
2115 message:message
2116 extensionRegistry:extensionRegistry];
2117 GPBSetRetainedObjectIvarWithFieldInternal(self, field, message, syntax);
2118 }
2119 break;
2120 }
2121
2122 case GPBDataTypeEnum: {
2123 int32_t val = GPBCodedInputStreamReadEnum(&input->state_);
2124 if (GPBHasPreservingUnknownEnumSemantics(syntax) ||
2125 [field isValidEnumValue:val]) {
2126 GPBSetInt32IvarWithFieldInternal(self, field, val, syntax);
2127 } else {
2128 GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self);
2129 [unknownFields mergeVarintField:GPBFieldNumber(field) value:val];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002130 }
2131 }
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002132 } // switch
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002133}
2134
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002135static void MergeRepeatedPackedFieldFromCodedInputStream(
2136 GPBMessage *self, GPBFieldDescriptor *field, GPBFileSyntax syntax,
2137 GPBCodedInputStream *input) {
2138 GPBDataType fieldDataType = GPBGetFieldDataType(field);
2139 GPBCodedInputStreamState *state = &input->state_;
2140 id genericArray = GetOrCreateArrayIvarWithField(self, field, syntax);
2141 int32_t length = GPBCodedInputStreamReadInt32(state);
2142 size_t limit = GPBCodedInputStreamPushLimit(state, length);
2143 while (GPBCodedInputStreamBytesUntilLimit(state) > 0) {
2144 switch (fieldDataType) {
2145#define CASE_REPEATED_PACKED_POD(NAME, TYPE, ARRAY_TYPE) \
2146 case GPBDataType##NAME: { \
2147 TYPE val = GPBCodedInputStreamRead##NAME(state); \
2148 [(GPB##ARRAY_TYPE##Array *)genericArray addValue:val]; \
2149 break; \
2150 }
2151 CASE_REPEATED_PACKED_POD(Bool, BOOL, Bool)
2152 CASE_REPEATED_PACKED_POD(Fixed32, uint32_t, UInt32)
2153 CASE_REPEATED_PACKED_POD(SFixed32, int32_t, Int32)
2154 CASE_REPEATED_PACKED_POD(Float, float, Float)
2155 CASE_REPEATED_PACKED_POD(Fixed64, uint64_t, UInt64)
2156 CASE_REPEATED_PACKED_POD(SFixed64, int64_t, Int64)
2157 CASE_REPEATED_PACKED_POD(Double, double, Double)
2158 CASE_REPEATED_PACKED_POD(Int32, int32_t, Int32)
2159 CASE_REPEATED_PACKED_POD(Int64, int64_t, Int64)
2160 CASE_REPEATED_PACKED_POD(SInt32, int32_t, Int32)
2161 CASE_REPEATED_PACKED_POD(SInt64, int64_t, Int64)
2162 CASE_REPEATED_PACKED_POD(UInt32, uint32_t, UInt32)
2163 CASE_REPEATED_PACKED_POD(UInt64, uint64_t, UInt64)
2164#undef CASE_REPEATED_PACKED_POD
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002165
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002166 case GPBDataTypeBytes:
2167 case GPBDataTypeString:
2168 case GPBDataTypeMessage:
2169 case GPBDataTypeGroup:
2170 NSCAssert(NO, @"Non primitive types can't be packed");
2171 break;
2172
2173 case GPBDataTypeEnum: {
2174 int32_t val = GPBCodedInputStreamReadEnum(state);
2175 if (GPBHasPreservingUnknownEnumSemantics(syntax) ||
2176 [field isValidEnumValue:val]) {
2177 [(GPBEnumArray*)genericArray addRawValue:val];
2178 } else {
2179 GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self);
2180 [unknownFields mergeVarintField:GPBFieldNumber(field) value:val];
2181 }
2182 break;
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002183 }
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002184 } // switch
2185 } // while(BytesUntilLimit() > 0)
2186 GPBCodedInputStreamPopLimit(state, limit);
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002187}
2188
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002189static void MergeRepeatedNotPackedFieldFromCodedInputStream(
2190 GPBMessage *self, GPBFieldDescriptor *field, GPBFileSyntax syntax,
2191 GPBCodedInputStream *input, GPBExtensionRegistry *extensionRegistry) {
2192 GPBCodedInputStreamState *state = &input->state_;
2193 id genericArray = GetOrCreateArrayIvarWithField(self, field, syntax);
2194 switch (GPBGetFieldDataType(field)) {
2195#define CASE_REPEATED_NOT_PACKED_POD(NAME, TYPE, ARRAY_TYPE) \
2196 case GPBDataType##NAME: { \
2197 TYPE val = GPBCodedInputStreamRead##NAME(state); \
2198 [(GPB##ARRAY_TYPE##Array *)genericArray addValue:val]; \
2199 break; \
2200 }
2201#define CASE_REPEATED_NOT_PACKED_OBJECT(NAME) \
2202 case GPBDataType##NAME: { \
2203 id val = GPBCodedInputStreamReadRetained##NAME(state); \
2204 [(NSMutableArray*)genericArray addObject:val]; \
2205 [val release]; \
2206 break; \
2207 }
2208 CASE_REPEATED_NOT_PACKED_POD(Bool, BOOL, Bool)
2209 CASE_REPEATED_NOT_PACKED_POD(Fixed32, uint32_t, UInt32)
2210 CASE_REPEATED_NOT_PACKED_POD(SFixed32, int32_t, Int32)
2211 CASE_REPEATED_NOT_PACKED_POD(Float, float, Float)
2212 CASE_REPEATED_NOT_PACKED_POD(Fixed64, uint64_t, UInt64)
2213 CASE_REPEATED_NOT_PACKED_POD(SFixed64, int64_t, Int64)
2214 CASE_REPEATED_NOT_PACKED_POD(Double, double, Double)
2215 CASE_REPEATED_NOT_PACKED_POD(Int32, int32_t, Int32)
2216 CASE_REPEATED_NOT_PACKED_POD(Int64, int64_t, Int64)
2217 CASE_REPEATED_NOT_PACKED_POD(SInt32, int32_t, Int32)
2218 CASE_REPEATED_NOT_PACKED_POD(SInt64, int64_t, Int64)
2219 CASE_REPEATED_NOT_PACKED_POD(UInt32, uint32_t, UInt32)
2220 CASE_REPEATED_NOT_PACKED_POD(UInt64, uint64_t, UInt64)
2221 CASE_REPEATED_NOT_PACKED_OBJECT(Bytes)
2222 CASE_REPEATED_NOT_PACKED_OBJECT(String)
2223#undef CASE_REPEATED_NOT_PACKED_POD
2224#undef CASE_NOT_PACKED_OBJECT
2225 case GPBDataTypeMessage: {
2226 GPBMessage *message = [[field.msgClass alloc] init];
2227 [input readMessage:message extensionRegistry:extensionRegistry];
2228 [(NSMutableArray*)genericArray addObject:message];
2229 [message release];
2230 break;
2231 }
2232 case GPBDataTypeGroup: {
2233 GPBMessage *message = [[field.msgClass alloc] init];
2234 [input readGroup:GPBFieldNumber(field)
2235 message:message
2236 extensionRegistry:extensionRegistry];
2237 [(NSMutableArray*)genericArray addObject:message];
2238 [message release];
2239 break;
2240 }
2241 case GPBDataTypeEnum: {
2242 int32_t val = GPBCodedInputStreamReadEnum(state);
2243 if (GPBHasPreservingUnknownEnumSemantics(syntax) ||
2244 [field isValidEnumValue:val]) {
2245 [(GPBEnumArray*)genericArray addRawValue:val];
2246 } else {
2247 GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self);
2248 [unknownFields mergeVarintField:GPBFieldNumber(field) value:val];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002249 }
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002250 break;
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002251 }
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002252 } // switch
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002253}
2254
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002255- (void)mergeFromCodedInputStream:(GPBCodedInputStream *)input
2256 extensionRegistry:(GPBExtensionRegistry *)extensionRegistry {
2257 GPBDescriptor *descriptor = [self descriptor];
2258 GPBFileSyntax syntax = descriptor.file.syntax;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002259 GPBCodedInputStreamState *state = &input->state_;
2260 uint32_t tag = 0;
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002261 NSUInteger startingIndex = 0;
2262 NSArray *fields = descriptor->fields_;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002263 NSUInteger numFields = fields.count;
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002264 while (YES) {
2265 BOOL merged = NO;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002266 tag = GPBCodedInputStreamReadTag(state);
2267 for (NSUInteger i = 0; i < numFields; ++i) {
2268 if (startingIndex >= numFields) startingIndex = 0;
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002269 GPBFieldDescriptor *fieldDescriptor = fields[startingIndex];
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002270 if (GPBFieldTag(fieldDescriptor) == tag) {
2271 GPBFieldType fieldType = fieldDescriptor.fieldType;
2272 if (fieldType == GPBFieldTypeSingle) {
2273 MergeSingleFieldFromCodedInputStream(self, fieldDescriptor, syntax,
2274 input, extensionRegistry);
2275 // Well formed protos will only have a single field once, advance
2276 // the starting index to the next field.
2277 startingIndex += 1;
2278 } else if (fieldType == GPBFieldTypeRepeated) {
2279 if (fieldDescriptor.isPackable) {
2280 MergeRepeatedPackedFieldFromCodedInputStream(
2281 self, fieldDescriptor, syntax, input);
2282 // Well formed protos will only have a repeated field that is
2283 // packed once, advance the starting index to the next field.
2284 startingIndex += 1;
2285 } else {
2286 MergeRepeatedNotPackedFieldFromCodedInputStream(
2287 self, fieldDescriptor, syntax, input, extensionRegistry);
2288 }
2289 } else { // fieldType == GPBFieldTypeMap
2290 // GPB*Dictionary or NSDictionary, exact type doesn't matter at this
2291 // point.
2292 id map = GetOrCreateMapIvarWithField(self, fieldDescriptor, syntax);
2293 [input readMapEntry:map
2294 extensionRegistry:extensionRegistry
2295 field:fieldDescriptor
2296 parentMessage:self];
2297 }
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002298 merged = YES;
2299 break;
2300 } else {
2301 startingIndex += 1;
2302 }
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002303 } // for(i < numFields)
2304
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002305 if (!merged) {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002306 // Primitive, repeated types can be packed on unpacked on the wire, and
2307 // are parsed either way. The above loop covered tag in the preferred
2308 // for, so this need to check the alternate form.
2309 for (NSUInteger i = 0; i < numFields; ++i) {
2310 if (startingIndex >= numFields) startingIndex = 0;
2311 GPBFieldDescriptor *fieldDescriptor = fields[startingIndex];
2312 if ((fieldDescriptor.fieldType == GPBFieldTypeRepeated) &&
2313 !GPBFieldDataTypeIsObject(fieldDescriptor) &&
2314 (GPBFieldAlternateTag(fieldDescriptor) == tag)) {
2315 BOOL alternateIsPacked = !fieldDescriptor.isPackable;
2316 if (alternateIsPacked) {
2317 MergeRepeatedPackedFieldFromCodedInputStream(
2318 self, fieldDescriptor, syntax, input);
2319 // Well formed protos will only have a repeated field that is
2320 // packed once, advance the starting index to the next field.
2321 startingIndex += 1;
2322 } else {
2323 MergeRepeatedNotPackedFieldFromCodedInputStream(
2324 self, fieldDescriptor, syntax, input, extensionRegistry);
2325 }
2326 merged = YES;
2327 break;
2328 } else {
2329 startingIndex += 1;
2330 }
2331 }
2332 }
2333
2334 if (!merged) {
2335 if (tag == 0) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002336 // zero signals EOF / limit reached
2337 return;
2338 } else {
2339 if (GPBPreserveUnknownFields(syntax)) {
2340 if (![self parseUnknownField:input
2341 extensionRegistry:extensionRegistry
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002342 tag:tag]) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002343 // it's an endgroup tag
2344 return;
2345 }
2346 } else {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002347 if (![input skipField:tag]) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002348 return;
2349 }
2350 }
2351 }
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002352 } // if(!merged)
2353
2354 } // while(YES)
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002355}
2356
2357#pragma mark - MergeFrom Support
2358
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002359- (void)mergeFrom:(GPBMessage *)other {
2360 Class selfClass = [self class];
2361 Class otherClass = [other class];
2362 if (!([selfClass isSubclassOfClass:otherClass] ||
2363 [otherClass isSubclassOfClass:selfClass])) {
2364 [NSException raise:NSInvalidArgumentException
2365 format:@"Classes must match %@ != %@", selfClass, otherClass];
2366 }
2367
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002368 // We assume something will be done and become visible.
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002369 GPBBecomeVisibleToAutocreator(self);
2370
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002371 GPBDescriptor *descriptor = [[self class] descriptor];
2372 GPBFileSyntax syntax = descriptor.file.syntax;
2373
2374 for (GPBFieldDescriptor *field in descriptor->fields_) {
2375 GPBFieldType fieldType = field.fieldType;
2376 if (fieldType == GPBFieldTypeSingle) {
2377 int32_t hasIndex = GPBFieldHasIndex(field);
2378 uint32_t fieldNumber = GPBFieldNumber(field);
2379 if (!GPBGetHasIvar(other, hasIndex, fieldNumber)) {
2380 // Other doesn't have the field set, on to the next.
2381 continue;
2382 }
2383 GPBDataType fieldDataType = GPBGetFieldDataType(field);
2384 switch (fieldDataType) {
2385 case GPBDataTypeBool:
2386 GPBSetBoolIvarWithFieldInternal(
2387 self, field, GPBGetMessageBoolField(other, field), syntax);
2388 break;
2389 case GPBDataTypeSFixed32:
2390 case GPBDataTypeEnum:
2391 case GPBDataTypeInt32:
2392 case GPBDataTypeSInt32:
2393 GPBSetInt32IvarWithFieldInternal(
2394 self, field, GPBGetMessageInt32Field(other, field), syntax);
2395 break;
2396 case GPBDataTypeFixed32:
2397 case GPBDataTypeUInt32:
2398 GPBSetUInt32IvarWithFieldInternal(
2399 self, field, GPBGetMessageUInt32Field(other, field), syntax);
2400 break;
2401 case GPBDataTypeSFixed64:
2402 case GPBDataTypeInt64:
2403 case GPBDataTypeSInt64:
2404 GPBSetInt64IvarWithFieldInternal(
2405 self, field, GPBGetMessageInt64Field(other, field), syntax);
2406 break;
2407 case GPBDataTypeFixed64:
2408 case GPBDataTypeUInt64:
2409 GPBSetUInt64IvarWithFieldInternal(
2410 self, field, GPBGetMessageUInt64Field(other, field), syntax);
2411 break;
2412 case GPBDataTypeFloat:
2413 GPBSetFloatIvarWithFieldInternal(
2414 self, field, GPBGetMessageFloatField(other, field), syntax);
2415 break;
2416 case GPBDataTypeDouble:
2417 GPBSetDoubleIvarWithFieldInternal(
2418 self, field, GPBGetMessageDoubleField(other, field), syntax);
2419 break;
2420 case GPBDataTypeBytes:
2421 case GPBDataTypeString: {
2422 id otherVal = GPBGetObjectIvarWithFieldNoAutocreate(other, field);
2423 GPBSetObjectIvarWithFieldInternal(self, field, otherVal, syntax);
2424 break;
2425 }
2426 case GPBDataTypeMessage:
2427 case GPBDataTypeGroup: {
2428 id otherVal = GPBGetObjectIvarWithFieldNoAutocreate(other, field);
2429 if (GPBGetHasIvar(self, hasIndex, fieldNumber)) {
2430 GPBMessage *message =
2431 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
2432 [message mergeFrom:otherVal];
2433 } else {
2434 GPBMessage *message = [otherVal copy];
2435 GPBSetRetainedObjectIvarWithFieldInternal(self, field, message,
2436 syntax);
2437 }
2438 break;
2439 }
2440 } // switch()
2441 } else if (fieldType == GPBFieldTypeRepeated) {
2442 // In the case of a list, they need to be appended, and there is no
2443 // _hasIvar to worry about setting.
2444 id otherArray =
2445 GPBGetObjectIvarWithFieldNoAutocreate(other, field);
2446 if (otherArray) {
2447 GPBDataType fieldDataType = field->description_->dataType;
2448 if (GPBDataTypeIsObject(fieldDataType)) {
2449 NSMutableArray *resultArray =
2450 GetOrCreateArrayIvarWithField(self, field, syntax);
2451 [resultArray addObjectsFromArray:otherArray];
2452 } else if (fieldDataType == GPBDataTypeEnum) {
2453 GPBEnumArray *resultArray =
2454 GetOrCreateArrayIvarWithField(self, field, syntax);
2455 [resultArray addRawValuesFromArray:otherArray];
2456 } else {
2457 // The array type doesn't matter, that all implment
2458 // -addValuesFromArray:.
2459 GPBInt32Array *resultArray =
2460 GetOrCreateArrayIvarWithField(self, field, syntax);
2461 [resultArray addValuesFromArray:otherArray];
2462 }
2463 }
2464 } else { // fieldType = GPBFieldTypeMap
2465 // In the case of a map, they need to be merged, and there is no
2466 // _hasIvar to worry about setting.
2467 id otherDict = GPBGetObjectIvarWithFieldNoAutocreate(other, field);
2468 if (otherDict) {
2469 GPBDataType keyDataType = field.mapKeyDataType;
2470 GPBDataType valueDataType = field->description_->dataType;
2471 if (GPBDataTypeIsObject(keyDataType) &&
2472 GPBDataTypeIsObject(valueDataType)) {
2473 NSMutableDictionary *resultDict =
2474 GetOrCreateMapIvarWithField(self, field, syntax);
2475 [resultDict addEntriesFromDictionary:otherDict];
2476 } else if (valueDataType == GPBDataTypeEnum) {
2477 // The exact type doesn't matter, just need to know it is a
2478 // GPB*EnumDictionary.
2479 GPBInt32EnumDictionary *resultDict =
2480 GetOrCreateMapIvarWithField(self, field, syntax);
2481 [resultDict addRawEntriesFromDictionary:otherDict];
2482 } else {
2483 // The exact type doesn't matter, they all implement
2484 // -addEntriesFromDictionary:.
2485 GPBInt32Int32Dictionary *resultDict =
2486 GetOrCreateMapIvarWithField(self, field, syntax);
2487 [resultDict addEntriesFromDictionary:otherDict];
2488 }
2489 }
2490 } // if (fieldType)..else if...else
2491 } // for(fields)
2492
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002493 // Unknown fields.
2494 if (!unknownFields_) {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002495 [self setUnknownFields:other.unknownFields];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002496 } else {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002497 [unknownFields_ mergeUnknownFields:other.unknownFields];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002498 }
2499
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002500 // Extensions
2501
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002502 if (other->extensionMap_.count == 0) {
2503 return;
2504 }
2505
2506 if (extensionMap_ == nil) {
2507 extensionMap_ =
2508 CloneExtensionMap(other->extensionMap_, NSZoneFromPointer(self));
2509 } else {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002510 for (GPBExtensionDescriptor *extension in other->extensionMap_) {
2511 id otherValue = [other->extensionMap_ objectForKey:extension];
2512 id value = [extensionMap_ objectForKey:extension];
2513 BOOL isMessageExtension = GPBExtensionIsMessage(extension);
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002514
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002515 if (extension.repeated) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002516 NSMutableArray *list = value;
2517 if (list == nil) {
2518 list = [[NSMutableArray alloc] init];
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002519 [extensionMap_ setObject:list forKey:extension];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002520 [list release];
2521 }
2522 if (isMessageExtension) {
2523 for (GPBMessage *otherListValue in otherValue) {
2524 GPBMessage *copiedValue = [otherListValue copy];
2525 [list addObject:copiedValue];
2526 [copiedValue release];
2527 }
2528 } else {
2529 [list addObjectsFromArray:otherValue];
2530 }
2531 } else {
2532 if (isMessageExtension) {
2533 if (value) {
2534 [(GPBMessage *)value mergeFrom:(GPBMessage *)otherValue];
2535 } else {
2536 GPBMessage *copiedValue = [otherValue copy];
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002537 [extensionMap_ setObject:copiedValue forKey:extension];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002538 [copiedValue release];
2539 }
2540 } else {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002541 [extensionMap_ setObject:otherValue forKey:extension];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002542 }
2543 }
2544
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002545 if (isMessageExtension && !extension.isRepeated) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002546 GPBMessage *autocreatedValue =
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002547 [[autocreatedExtensionMap_ objectForKey:extension] retain];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002548 // Must remove from the map before calling GPBClearMessageAutocreator()
2549 // so that GPBClearMessageAutocreator() knows its safe to clear.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002550 [autocreatedExtensionMap_ removeObjectForKey:extension];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002551 GPBClearMessageAutocreator(autocreatedValue);
2552 [autocreatedValue release];
2553 }
2554 }
2555 }
2556}
2557
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002558#pragma mark - isEqual: & hash Support
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002559
2560- (BOOL)isEqual:(GPBMessage *)other {
2561 if (other == self) {
2562 return YES;
2563 }
2564 if (![other isKindOfClass:[self class]] &&
2565 ![self isKindOfClass:[other class]]) {
2566 return NO;
2567 }
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002568
2569 GPBDescriptor *descriptor = [[self class] descriptor];
2570 uint8_t *selfStorage = (uint8_t *)messageStorage_;
2571 uint8_t *otherStorage = (uint8_t *)other->messageStorage_;
2572
2573 for (GPBFieldDescriptor *field in descriptor->fields_) {
2574 if (GPBFieldIsMapOrArray(field)) {
2575 // In the case of a list or map, there is no _hasIvar to worry about.
2576 // NOTE: These are NSArray/GPB*Array or NSDictionary/GPB*Dictionary, but
2577 // the type doesn't really matter as the objects all support -count and
2578 // -isEqual:.
2579 NSArray *resultMapOrArray =
2580 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
2581 NSArray *otherMapOrArray =
2582 GPBGetObjectIvarWithFieldNoAutocreate(other, field);
2583 // nil and empty are equal
2584 if (resultMapOrArray.count != 0 || otherMapOrArray.count != 0) {
2585 if (![resultMapOrArray isEqual:otherMapOrArray]) {
2586 return NO;
2587 }
2588 }
2589 } else { // Single field
2590 int32_t hasIndex = GPBFieldHasIndex(field);
2591 uint32_t fieldNum = GPBFieldNumber(field);
2592 BOOL selfHas = GPBGetHasIvar(self, hasIndex, fieldNum);
2593 BOOL otherHas = GPBGetHasIvar(other, hasIndex, fieldNum);
2594 if (selfHas != otherHas) {
2595 return NO; // Differing has values, not equal.
2596 }
2597 if (!selfHas) {
2598 // Same has values, was no, nothing else to check for this field.
2599 continue;
2600 }
2601 // Now compare the values.
2602 GPBDataType fieldDataType = GPBGetFieldDataType(field);
2603 size_t fieldOffset = field->description_->offset;
2604 switch (fieldDataType) {
2605 case GPBDataTypeBool: {
2606 BOOL *selfValPtr = (BOOL *)&selfStorage[fieldOffset];
2607 BOOL *otherValPtr = (BOOL *)&otherStorage[fieldOffset];
2608 if (*selfValPtr != *otherValPtr) {
2609 return NO;
2610 }
2611 break;
2612 }
2613 case GPBDataTypeSFixed32:
2614 case GPBDataTypeInt32:
2615 case GPBDataTypeSInt32:
2616 case GPBDataTypeEnum:
2617 case GPBDataTypeFixed32:
2618 case GPBDataTypeUInt32:
2619 case GPBDataTypeFloat: {
2620 _GPBCompileAssert(sizeof(float) == sizeof(uint32_t), float_not_32_bits);
2621 // These are all 32bit, signed/unsigned doesn't matter for equality.
2622 uint32_t *selfValPtr = (uint32_t *)&selfStorage[fieldOffset];
2623 uint32_t *otherValPtr = (uint32_t *)&otherStorage[fieldOffset];
2624 if (*selfValPtr != *otherValPtr) {
2625 return NO;
2626 }
2627 break;
2628 }
2629 case GPBDataTypeSFixed64:
2630 case GPBDataTypeInt64:
2631 case GPBDataTypeSInt64:
2632 case GPBDataTypeFixed64:
2633 case GPBDataTypeUInt64:
2634 case GPBDataTypeDouble: {
2635 _GPBCompileAssert(sizeof(double) == sizeof(uint64_t), double_not_64_bits);
2636 // These are all 64bit, signed/unsigned doesn't matter for equality.
2637 uint64_t *selfValPtr = (uint64_t *)&selfStorage[fieldOffset];
2638 uint64_t *otherValPtr = (uint64_t *)&otherStorage[fieldOffset];
2639 if (*selfValPtr != *otherValPtr) {
2640 return NO;
2641 }
2642 break;
2643 }
2644 case GPBDataTypeBytes:
2645 case GPBDataTypeString:
2646 case GPBDataTypeMessage:
2647 case GPBDataTypeGroup: {
2648 // Type doesn't matter here, they all implement -isEqual:.
2649 id *selfValPtr = (id *)&selfStorage[fieldOffset];
2650 id *otherValPtr = (id *)&otherStorage[fieldOffset];
2651 if (![*selfValPtr isEqual:*otherValPtr]) {
2652 return NO;
2653 }
2654 break;
2655 }
2656 } // switch()
2657 } // if(mapOrArray)...else
2658 } // for(fields)
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002659
2660 // nil and empty are equal
2661 if (extensionMap_.count != 0 || other->extensionMap_.count != 0) {
2662 if (![extensionMap_ isEqual:other->extensionMap_]) {
2663 return NO;
2664 }
2665 }
2666
2667 // nil and empty are equal
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002668 GPBUnknownFieldSet *otherUnknowns = other->unknownFields_;
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002669 if ([unknownFields_ countOfFields] != 0 ||
2670 [otherUnknowns countOfFields] != 0) {
2671 if (![unknownFields_ isEqual:otherUnknowns]) {
2672 return NO;
2673 }
2674 }
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002675
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002676 return YES;
2677}
2678
2679// It is very difficult to implement a generic hash for ProtoBuf messages that
2680// will perform well. If you need hashing on your ProtoBufs (eg you are using
2681// them as dictionary keys) you will probably want to implement a ProtoBuf
2682// message specific hash as a category on your protobuf class. Do not make it a
2683// category on GPBMessage as you will conflict with this hash, and will possibly
2684// override hash for all generated protobufs. A good implementation of hash will
2685// be really fast, so we would recommend only hashing protobufs that have an
2686// identifier field of some kind that you can easily hash. If you implement
2687// hash, we would strongly recommend overriding isEqual: in your category as
2688// well, as the default implementation of isEqual: is extremely slow, and may
2689// drastically affect performance in large sets.
2690- (NSUInteger)hash {
2691 GPBDescriptor *descriptor = [[self class] descriptor];
2692 const NSUInteger prime = 19;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002693 uint8_t *storage = (uint8_t *)messageStorage_;
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002694
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002695 // Start with the descriptor and then mix it with some instance info.
2696 // Hopefully that will give a spread based on classes and what fields are set.
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002697 NSUInteger result = (NSUInteger)descriptor;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002698
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002699 for (GPBFieldDescriptor *field in descriptor->fields_) {
2700 if (GPBFieldIsMapOrArray(field)) {
2701 // Exact type doesn't matter, just check if there are any elements.
2702 NSArray *mapOrArray = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002703 NSUInteger count = mapOrArray.count;
2704 if (count) {
2705 // NSArray/NSDictionary use count, use the field number and the count.
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002706 result = prime * result + GPBFieldNumber(field);
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002707 result = prime * result + count;
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002708 }
2709 } else if (GPBGetHasIvarField(self, field)) {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002710 // Just using the field number seemed simple/fast, but then a small
2711 // message class where all the same fields are always set (to different
2712 // things would end up all with the same hash, so pull in some data).
2713 GPBDataType fieldDataType = GPBGetFieldDataType(field);
2714 size_t fieldOffset = field->description_->offset;
2715 switch (fieldDataType) {
2716 case GPBDataTypeBool: {
2717 BOOL *valPtr = (BOOL *)&storage[fieldOffset];
2718 result = prime * result + *valPtr;
2719 break;
2720 }
2721 case GPBDataTypeSFixed32:
2722 case GPBDataTypeInt32:
2723 case GPBDataTypeSInt32:
2724 case GPBDataTypeEnum:
2725 case GPBDataTypeFixed32:
2726 case GPBDataTypeUInt32:
2727 case GPBDataTypeFloat: {
2728 _GPBCompileAssert(sizeof(float) == sizeof(uint32_t), float_not_32_bits);
2729 // These are all 32bit, just mix it in.
2730 uint32_t *valPtr = (uint32_t *)&storage[fieldOffset];
2731 result = prime * result + *valPtr;
2732 break;
2733 }
2734 case GPBDataTypeSFixed64:
2735 case GPBDataTypeInt64:
2736 case GPBDataTypeSInt64:
2737 case GPBDataTypeFixed64:
2738 case GPBDataTypeUInt64:
2739 case GPBDataTypeDouble: {
2740 _GPBCompileAssert(sizeof(double) == sizeof(uint64_t), double_not_64_bits);
2741 // These are all 64bit, just mix what fits into an NSUInteger in.
2742 uint64_t *valPtr = (uint64_t *)&storage[fieldOffset];
2743 result = prime * result + (NSUInteger)(*valPtr);
2744 break;
2745 }
2746 case GPBDataTypeBytes:
2747 case GPBDataTypeString: {
2748 // Type doesn't matter here, they both implement -hash:.
2749 id *valPtr = (id *)&storage[fieldOffset];
2750 result = prime * result + [*valPtr hash];
2751 break;
2752 }
2753
2754 case GPBDataTypeMessage:
2755 case GPBDataTypeGroup: {
2756 GPBMessage **valPtr = (GPBMessage **)&storage[fieldOffset];
2757 // Could call -hash on the sub message, but that could recurse pretty
2758 // deep; follow the lead of NSArray/NSDictionary and don't really
2759 // recurse for hash, instead use the field number and the descriptor
2760 // of the sub message. Yes, this could suck for a bunch of messages
2761 // where they all only differ in the sub messages, but if you are
2762 // using a message with sub messages for something that needs -hash,
2763 // odds are you are also copying them as keys, and that deep copy
2764 // will also suck.
2765 result = prime * result + GPBFieldNumber(field);
2766 result = prime * result + (NSUInteger)[[*valPtr class] descriptor];
2767 break;
2768 }
2769 } // switch()
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002770 }
2771 }
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002772
2773 // Unknowns and extensions are not included.
2774
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002775 return result;
2776}
2777
2778#pragma mark - Description Support
2779
2780- (NSString *)description {
2781 NSString *textFormat = GPBTextFormatForMessage(self, @" ");
2782 NSString *description = [NSString
2783 stringWithFormat:@"<%@ %p>: {\n%@}", [self class], self, textFormat];
2784 return description;
2785}
2786
2787#if DEBUG
2788
2789// Xcode 5.1 added support for custom quick look info.
2790// https://developer.apple.com/library/ios/documentation/IDEs/Conceptual/CustomClassDisplay_in_QuickLook/CH01-quick_look_for_custom_objects/CH01-quick_look_for_custom_objects.html#//apple_ref/doc/uid/TP40014001-CH2-SW1
2791- (id)debugQuickLookObject {
2792 return GPBTextFormatForMessage(self, nil);
2793}
2794
2795#endif // DEBUG
2796
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002797#pragma mark - SerializedSize
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002798
2799- (size_t)serializedSize {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002800 GPBDescriptor *descriptor = [[self class] descriptor];
2801 size_t result = 0;
2802
2803 // Has check is done explicitly, so GPBGetObjectIvarWithFieldNoAutocreate()
2804 // avoids doing the has check again.
2805
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002806 // Fields.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002807 for (GPBFieldDescriptor *fieldDescriptor in descriptor->fields_) {
2808 GPBFieldType fieldType = fieldDescriptor.fieldType;
2809 GPBDataType fieldDataType = GPBGetFieldDataType(fieldDescriptor);
2810
2811 // Single Fields
2812 if (fieldType == GPBFieldTypeSingle) {
2813 BOOL selfHas = GPBGetHasIvarField(self, fieldDescriptor);
2814 if (!selfHas) {
2815 continue; // Nothing to do.
2816 }
2817
2818 uint32_t fieldNumber = GPBFieldNumber(fieldDescriptor);
2819
2820 switch (fieldDataType) {
2821#define CASE_SINGLE_POD(NAME, TYPE, FUNC_TYPE) \
2822 case GPBDataType##NAME: { \
2823 TYPE fieldVal = GPBGetMessage##FUNC_TYPE##Field(self, fieldDescriptor); \
2824 result += GPBCompute##NAME##Size(fieldNumber, fieldVal); \
2825 break; \
2826 }
2827#define CASE_SINGLE_OBJECT(NAME) \
2828 case GPBDataType##NAME: { \
2829 id fieldVal = GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor); \
2830 result += GPBCompute##NAME##Size(fieldNumber, fieldVal); \
2831 break; \
2832 }
2833 CASE_SINGLE_POD(Bool, BOOL, Bool)
2834 CASE_SINGLE_POD(Fixed32, uint32_t, UInt32)
2835 CASE_SINGLE_POD(SFixed32, int32_t, Int32)
2836 CASE_SINGLE_POD(Float, float, Float)
2837 CASE_SINGLE_POD(Fixed64, uint64_t, UInt64)
2838 CASE_SINGLE_POD(SFixed64, int64_t, Int64)
2839 CASE_SINGLE_POD(Double, double, Double)
2840 CASE_SINGLE_POD(Int32, int32_t, Int32)
2841 CASE_SINGLE_POD(Int64, int64_t, Int64)
2842 CASE_SINGLE_POD(SInt32, int32_t, Int32)
2843 CASE_SINGLE_POD(SInt64, int64_t, Int64)
2844 CASE_SINGLE_POD(UInt32, uint32_t, UInt32)
2845 CASE_SINGLE_POD(UInt64, uint64_t, UInt64)
2846 CASE_SINGLE_OBJECT(Bytes)
2847 CASE_SINGLE_OBJECT(String)
2848 CASE_SINGLE_OBJECT(Message)
2849 CASE_SINGLE_OBJECT(Group)
2850 CASE_SINGLE_POD(Enum, int32_t, Int32)
2851#undef CASE_SINGLE_POD
2852#undef CASE_SINGLE_OBJECT
2853 }
2854
2855 // Repeated Fields
2856 } else if (fieldType == GPBFieldTypeRepeated) {
2857 id genericArray =
2858 GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor);
2859 NSUInteger count = [genericArray count];
2860 if (count == 0) {
2861 continue; // Nothing to add.
2862 }
2863 __block size_t dataSize = 0;
2864
2865 switch (fieldDataType) {
2866#define CASE_REPEATED_POD(NAME, TYPE, ARRAY_TYPE) \
2867 CASE_REPEATED_POD_EXTRA(NAME, TYPE, ARRAY_TYPE, )
2868#define CASE_REPEATED_POD_EXTRA(NAME, TYPE, ARRAY_TYPE, ARRAY_ACCESSOR_NAME) \
2869 case GPBDataType##NAME: { \
2870 GPB##ARRAY_TYPE##Array *array = genericArray; \
2871 [array enumerate##ARRAY_ACCESSOR_NAME##ValuesWithBlock:^(TYPE value, NSUInteger idx, BOOL *stop) { \
2872 _Pragma("unused(idx, stop)"); \
2873 dataSize += GPBCompute##NAME##SizeNoTag(value); \
2874 }]; \
2875 break; \
2876 }
2877#define CASE_REPEATED_OBJECT(NAME) \
2878 case GPBDataType##NAME: { \
2879 for (id value in genericArray) { \
2880 dataSize += GPBCompute##NAME##SizeNoTag(value); \
2881 } \
2882 break; \
2883 }
2884 CASE_REPEATED_POD(Bool, BOOL, Bool)
2885 CASE_REPEATED_POD(Fixed32, uint32_t, UInt32)
2886 CASE_REPEATED_POD(SFixed32, int32_t, Int32)
2887 CASE_REPEATED_POD(Float, float, Float)
2888 CASE_REPEATED_POD(Fixed64, uint64_t, UInt64)
2889 CASE_REPEATED_POD(SFixed64, int64_t, Int64)
2890 CASE_REPEATED_POD(Double, double, Double)
2891 CASE_REPEATED_POD(Int32, int32_t, Int32)
2892 CASE_REPEATED_POD(Int64, int64_t, Int64)
2893 CASE_REPEATED_POD(SInt32, int32_t, Int32)
2894 CASE_REPEATED_POD(SInt64, int64_t, Int64)
2895 CASE_REPEATED_POD(UInt32, uint32_t, UInt32)
2896 CASE_REPEATED_POD(UInt64, uint64_t, UInt64)
2897 CASE_REPEATED_OBJECT(Bytes)
2898 CASE_REPEATED_OBJECT(String)
2899 CASE_REPEATED_OBJECT(Message)
2900 CASE_REPEATED_OBJECT(Group)
2901 CASE_REPEATED_POD_EXTRA(Enum, int32_t, Enum, Raw)
2902#undef CASE_REPEATED_POD
2903#undef CASE_REPEATED_POD_EXTRA
2904#undef CASE_REPEATED_OBJECT
2905 } // switch
2906 result += dataSize;
2907 size_t tagSize = GPBComputeTagSize(GPBFieldNumber(fieldDescriptor));
2908 if (fieldDataType == GPBDataTypeGroup) {
2909 // Groups have both a start and an end tag.
2910 tagSize *= 2;
2911 }
2912 if (fieldDescriptor.isPackable) {
2913 result += tagSize;
2914 result += GPBComputeSizeTSizeAsInt32NoTag(dataSize);
2915 } else {
2916 result += count * tagSize;
2917 }
2918
2919 // Map<> Fields
2920 } else { // fieldType == GPBFieldTypeMap
2921 if (GPBDataTypeIsObject(fieldDataType) &&
2922 (fieldDescriptor.mapKeyDataType == GPBDataTypeString)) {
2923 // If key type was string, then the map is an NSDictionary.
2924 NSDictionary *map =
2925 GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor);
2926 if (map) {
2927 result += GPBDictionaryComputeSizeInternalHelper(map, fieldDescriptor);
2928 }
2929 } else {
2930 // Type will be GPB*GroupDictionary, exact type doesn't matter.
2931 GPBInt32Int32Dictionary *map =
2932 GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor);
2933 result += [map computeSerializedSizeAsField:fieldDescriptor];
2934 }
2935 }
2936 } // for(fields)
2937
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002938 // Add any unknown fields.
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002939 if (descriptor.wireFormat) {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002940 result += [unknownFields_ serializedSizeAsMessageSet];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002941 } else {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002942 result += [unknownFields_ serializedSize];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002943 }
2944
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002945 // Add any extensions.
2946 for (GPBExtensionDescriptor *extension in extensionMap_) {
2947 id value = [extensionMap_ objectForKey:extension];
2948 result += GPBComputeExtensionSerializedSizeIncludingTag(extension, value);
2949 }
2950
2951 return result;
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002952}
2953
2954#pragma mark - Resolve Methods Support
2955
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002956typedef struct ResolveIvarAccessorMethodResult {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002957 IMP impToAdd;
2958 SEL encodingSelector;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002959} ResolveIvarAccessorMethodResult;
Thomas Van Lenten30650d82015-05-01 08:57:16 -04002960
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04002961static void ResolveIvarGet(GPBFieldDescriptor *field,
2962 ResolveIvarAccessorMethodResult *result) {
2963 GPBDataType fieldDataType = GPBGetFieldDataType(field);
2964 switch (fieldDataType) {
2965#define CASE_GET(NAME, TYPE, TRUE_NAME) \
2966 case GPBDataType##NAME: { \
2967 result->impToAdd = imp_implementationWithBlock(^(id obj) { \
2968 return GPBGetMessage##TRUE_NAME##Field(obj, field); \
2969 }); \
2970 result->encodingSelector = @selector(get##NAME); \
2971 break; \
2972 }
2973#define CASE_GET_OBJECT(NAME, TYPE, TRUE_NAME) \
2974 case GPBDataType##NAME: { \
2975 result->impToAdd = imp_implementationWithBlock(^(id obj) { \
2976 return GPBGetObjectIvarWithField(obj, field); \
2977 }); \
2978 result->encodingSelector = @selector(get##NAME); \
2979 break; \
2980 }
2981 CASE_GET(Bool, BOOL, Bool)
2982 CASE_GET(Fixed32, uint32_t, UInt32)
2983 CASE_GET(SFixed32, int32_t, Int32)
2984 CASE_GET(Float, float, Float)
2985 CASE_GET(Fixed64, uint64_t, UInt64)
2986 CASE_GET(SFixed64, int64_t, Int64)
2987 CASE_GET(Double, double, Double)
2988 CASE_GET(Int32, int32_t, Int32)
2989 CASE_GET(Int64, int64_t, Int64)
2990 CASE_GET(SInt32, int32_t, Int32)
2991 CASE_GET(SInt64, int64_t, Int64)
2992 CASE_GET(UInt32, uint32_t, UInt32)
2993 CASE_GET(UInt64, uint64_t, UInt64)
2994 CASE_GET_OBJECT(Bytes, id, Object)
2995 CASE_GET_OBJECT(String, id, Object)
2996 CASE_GET_OBJECT(Message, id, Object)
2997 CASE_GET_OBJECT(Group, id, Object)
2998 CASE_GET(Enum, int32_t, Enum)
2999#undef CASE_GET
3000 }
Thomas Van Lenten30650d82015-05-01 08:57:16 -04003001}
3002
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04003003static void ResolveIvarSet(GPBFieldDescriptor *field,
3004 GPBFileSyntax syntax,
3005 ResolveIvarAccessorMethodResult *result) {
3006 GPBDataType fieldDataType = GPBGetFieldDataType(field);
3007 switch (fieldDataType) {
3008#define CASE_SET(NAME, TYPE, TRUE_NAME) \
3009 case GPBDataType##NAME: { \
3010 result->impToAdd = imp_implementationWithBlock(^(id obj, TYPE value) { \
3011 return GPBSet##TRUE_NAME##IvarWithFieldInternal(obj, field, value, syntax); \
3012 }); \
3013 result->encodingSelector = @selector(set##NAME:); \
3014 break; \
3015 }
3016 CASE_SET(Bool, BOOL, Bool)
3017 CASE_SET(Fixed32, uint32_t, UInt32)
3018 CASE_SET(SFixed32, int32_t, Int32)
3019 CASE_SET(Float, float, Float)
3020 CASE_SET(Fixed64, uint64_t, UInt64)
3021 CASE_SET(SFixed64, int64_t, Int64)
3022 CASE_SET(Double, double, Double)
3023 CASE_SET(Int32, int32_t, Int32)
3024 CASE_SET(Int64, int64_t, Int64)
3025 CASE_SET(SInt32, int32_t, Int32)
3026 CASE_SET(SInt64, int64_t, Int64)
3027 CASE_SET(UInt32, uint32_t, UInt32)
3028 CASE_SET(UInt64, uint64_t, UInt64)
3029 CASE_SET(Bytes, id, Object)
3030 CASE_SET(String, id, Object)
3031 CASE_SET(Message, id, Object)
3032 CASE_SET(Group, id, Object)
3033 CASE_SET(Enum, int32_t, Enum)
3034#undef CASE_SET
3035 }
Thomas Van Lenten30650d82015-05-01 08:57:16 -04003036}
3037
3038+ (BOOL)resolveInstanceMethod:(SEL)sel {
3039 const GPBDescriptor *descriptor = [self descriptor];
3040 if (!descriptor) {
3041 return NO;
3042 }
3043
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04003044 // NOTE: hasOrCountSel_/setHasSel_ will be NULL if the field for the given
3045 // message should not have has support (done in GPBDescriptor.m), so there is
3046 // no need for checks here to see if has*/setHas* are allowed.
Thomas Van Lenten30650d82015-05-01 08:57:16 -04003047
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04003048 ResolveIvarAccessorMethodResult result = {NULL, NULL};
Thomas Van Lenten30650d82015-05-01 08:57:16 -04003049 for (GPBFieldDescriptor *field in descriptor->fields_) {
3050 BOOL isMapOrArray = GPBFieldIsMapOrArray(field);
3051 if (!isMapOrArray) {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04003052 // Single fields.
Thomas Van Lenten30650d82015-05-01 08:57:16 -04003053 if (sel == field->getSel_) {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04003054 ResolveIvarGet(field, &result);
Thomas Van Lenten30650d82015-05-01 08:57:16 -04003055 break;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04003056 } else if (sel == field->setSel_) {
3057 ResolveIvarSet(field, descriptor.file.syntax, &result);
3058 break;
3059 } else if (sel == field->hasOrCountSel_) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04003060 int32_t index = GPBFieldHasIndex(field);
3061 uint32_t fieldNum = GPBFieldNumber(field);
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04003062 result.impToAdd = imp_implementationWithBlock(^(id obj) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04003063 return GPBGetHasIvar(obj, index, fieldNum);
3064 });
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04003065 result.encodingSelector = @selector(getBool);
Thomas Van Lenten30650d82015-05-01 08:57:16 -04003066 break;
3067 } else if (sel == field->setHasSel_) {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04003068 result.impToAdd = imp_implementationWithBlock(^(id obj, BOOL value) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04003069 if (value) {
3070 [NSException raise:NSInvalidArgumentException
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04003071 format:@"%@: %@ can only be set to NO (to clear field).",
3072 [obj class],
3073 NSStringFromSelector(field->setHasSel_)];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04003074 }
3075 GPBClearMessageField(obj, field);
3076 });
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04003077 result.encodingSelector = @selector(setBool:);
Thomas Van Lenten30650d82015-05-01 08:57:16 -04003078 break;
3079 } else {
3080 GPBOneofDescriptor *oneof = field->containingOneof_;
3081 if (oneof && (sel == oneof->caseSel_)) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -04003082 int32_t index = GPBFieldHasIndex(field);
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04003083 result.impToAdd = imp_implementationWithBlock(^(id obj) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04003084 return GPBGetHasOneof(obj, index);
3085 });
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04003086 result.encodingSelector = @selector(getEnum);
Thomas Van Lenten30650d82015-05-01 08:57:16 -04003087 break;
3088 }
3089 }
3090 } else {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04003091 // map<>/repeated fields.
Thomas Van Lenten30650d82015-05-01 08:57:16 -04003092 if (sel == field->getSel_) {
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04003093 if (field.fieldType == GPBFieldTypeRepeated) {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04003094 result.impToAdd = imp_implementationWithBlock(^(id obj) {
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04003095 return GetArrayIvarWithField(obj, field);
3096 });
3097 } else {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04003098 result.impToAdd = imp_implementationWithBlock(^(id obj) {
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04003099 return GetMapIvarWithField(obj, field);
3100 });
3101 }
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04003102 result.encodingSelector = @selector(getArray);
Thomas Van Lenten30650d82015-05-01 08:57:16 -04003103 break;
3104 } else if (sel == field->setSel_) {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04003105 // Local for syntax so the block can directly capture it and not the
3106 // full lookup.
3107 const GPBFileSyntax syntax = descriptor.file.syntax;
3108 result.impToAdd = imp_implementationWithBlock(^(id obj, id value) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04003109 return GPBSetObjectIvarWithFieldInternal(obj, field, value, syntax);
3110 });
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04003111 result.encodingSelector = @selector(setArray:);
3112 break;
3113 } else if (sel == field->hasOrCountSel_) {
3114 result.impToAdd = imp_implementationWithBlock(^(id obj) {
3115 // Type doesn't matter, all *Array and *Dictionary types support
3116 // -count.
3117 NSArray *arrayOrMap =
3118 GPBGetObjectIvarWithFieldNoAutocreate(obj, field);
3119 return [arrayOrMap count];
3120 });
3121 result.encodingSelector = @selector(getArrayCount);
Thomas Van Lenten30650d82015-05-01 08:57:16 -04003122 break;
3123 }
3124 }
3125 }
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04003126 if (result.impToAdd) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04003127 const char *encoding =
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04003128 GPBMessageEncodingForSelector(result.encodingSelector, YES);
Thomas Van Lenten30650d82015-05-01 08:57:16 -04003129 BOOL methodAdded = class_addMethod(descriptor.messageClass, sel,
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04003130 result.impToAdd, encoding);
Thomas Van Lenten30650d82015-05-01 08:57:16 -04003131 return methodAdded;
3132 }
3133 return [super resolveInstanceMethod:sel];
3134}
3135
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04003136+ (BOOL)resolveClassMethod:(SEL)sel {
3137 // Extensions scoped to a Message and looked up via class methods.
3138 if (GPBResolveExtensionClassMethod(self, sel)) {
3139 return YES;
3140 }
3141 return [super resolveClassMethod:sel];
3142}
3143
Thomas Van Lenten30650d82015-05-01 08:57:16 -04003144#pragma mark - NSCoding Support
3145
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04003146+ (BOOL)supportsSecureCoding {
3147 return YES;
3148}
3149
Thomas Van Lenten30650d82015-05-01 08:57:16 -04003150- (instancetype)initWithCoder:(NSCoder *)aDecoder {
3151 self = [self init];
3152 if (self) {
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04003153 NSData *data =
3154 [aDecoder decodeObjectOfClass:[NSData class] forKey:kGPBDataCoderKey];
3155 if (data.length) {
3156 [self mergeFromData:data extensionRegistry:nil];
3157 }
Thomas Van Lenten30650d82015-05-01 08:57:16 -04003158 }
3159 return self;
3160}
3161
3162- (void)encodeWithCoder:(NSCoder *)aCoder {
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04003163 NSData *data = [self data];
3164 if (data.length) {
3165 [aCoder encodeObject:data forKey:kGPBDataCoderKey];
3166 }
Thomas Van Lenten30650d82015-05-01 08:57:16 -04003167}
3168
3169#pragma mark - KVC Support
3170
3171+ (BOOL)accessInstanceVariablesDirectly {
3172 // Make sure KVC doesn't use instance variables.
3173 return NO;
3174}
3175
3176@end