xref: /aosp_15_r20/external/protobuf/objectivec/GPBMessage.m (revision 1b3f573f81763fcece89efc2b6a5209149e44ab8)
1*1b3f573fSAndroid Build Coastguard Worker// Protocol Buffers - Google's data interchange format
2*1b3f573fSAndroid Build Coastguard Worker// Copyright 2008 Google Inc.  All rights reserved.
3*1b3f573fSAndroid Build Coastguard Worker// https://developers.google.com/protocol-buffers/
4*1b3f573fSAndroid Build Coastguard Worker//
5*1b3f573fSAndroid Build Coastguard Worker// Redistribution and use in source and binary forms, with or without
6*1b3f573fSAndroid Build Coastguard Worker// modification, are permitted provided that the following conditions are
7*1b3f573fSAndroid Build Coastguard Worker// met:
8*1b3f573fSAndroid Build Coastguard Worker//
9*1b3f573fSAndroid Build Coastguard Worker//     * Redistributions of source code must retain the above copyright
10*1b3f573fSAndroid Build Coastguard Worker// notice, this list of conditions and the following disclaimer.
11*1b3f573fSAndroid Build Coastguard Worker//     * Redistributions in binary form must reproduce the above
12*1b3f573fSAndroid Build Coastguard Worker// copyright notice, this list of conditions and the following disclaimer
13*1b3f573fSAndroid Build Coastguard Worker// in the documentation and/or other materials provided with the
14*1b3f573fSAndroid Build Coastguard Worker// distribution.
15*1b3f573fSAndroid Build Coastguard Worker//     * Neither the name of Google Inc. nor the names of its
16*1b3f573fSAndroid Build Coastguard Worker// contributors may be used to endorse or promote products derived from
17*1b3f573fSAndroid Build Coastguard Worker// this software without specific prior written permission.
18*1b3f573fSAndroid Build Coastguard Worker//
19*1b3f573fSAndroid Build Coastguard Worker// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20*1b3f573fSAndroid Build Coastguard Worker// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21*1b3f573fSAndroid Build Coastguard Worker// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22*1b3f573fSAndroid Build Coastguard Worker// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23*1b3f573fSAndroid Build Coastguard Worker// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24*1b3f573fSAndroid Build Coastguard Worker// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25*1b3f573fSAndroid Build Coastguard Worker// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26*1b3f573fSAndroid Build Coastguard Worker// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27*1b3f573fSAndroid Build Coastguard Worker// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28*1b3f573fSAndroid Build Coastguard Worker// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29*1b3f573fSAndroid Build Coastguard Worker// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30*1b3f573fSAndroid Build Coastguard Worker
31*1b3f573fSAndroid Build Coastguard Worker#import "GPBMessage_PackagePrivate.h"
32*1b3f573fSAndroid Build Coastguard Worker
33*1b3f573fSAndroid Build Coastguard Worker#import <objc/runtime.h>
34*1b3f573fSAndroid Build Coastguard Worker#import <objc/message.h>
35*1b3f573fSAndroid Build Coastguard Worker#import <stdatomic.h>
36*1b3f573fSAndroid Build Coastguard Worker
37*1b3f573fSAndroid Build Coastguard Worker#import "GPBArray_PackagePrivate.h"
38*1b3f573fSAndroid Build Coastguard Worker#import "GPBCodedInputStream_PackagePrivate.h"
39*1b3f573fSAndroid Build Coastguard Worker#import "GPBCodedOutputStream_PackagePrivate.h"
40*1b3f573fSAndroid Build Coastguard Worker#import "GPBDescriptor_PackagePrivate.h"
41*1b3f573fSAndroid Build Coastguard Worker#import "GPBDictionary_PackagePrivate.h"
42*1b3f573fSAndroid Build Coastguard Worker#import "GPBExtensionInternals.h"
43*1b3f573fSAndroid Build Coastguard Worker#import "GPBExtensionRegistry.h"
44*1b3f573fSAndroid Build Coastguard Worker#import "GPBRootObject_PackagePrivate.h"
45*1b3f573fSAndroid Build Coastguard Worker#import "GPBUnknownFieldSet_PackagePrivate.h"
46*1b3f573fSAndroid Build Coastguard Worker#import "GPBUtilities_PackagePrivate.h"
47*1b3f573fSAndroid Build Coastguard Worker
48*1b3f573fSAndroid Build Coastguard Worker// Direct access is use for speed, to avoid even internally declaring things
49*1b3f573fSAndroid Build Coastguard Worker// read/write, etc. The warning is enabled in the project to ensure code calling
50*1b3f573fSAndroid Build Coastguard Worker// protos can turn on -Wdirect-ivar-access without issues.
51*1b3f573fSAndroid Build Coastguard Worker#pragma clang diagnostic push
52*1b3f573fSAndroid Build Coastguard Worker#pragma clang diagnostic ignored "-Wdirect-ivar-access"
53*1b3f573fSAndroid Build Coastguard Worker
54*1b3f573fSAndroid Build Coastguard WorkerNSString *const GPBMessageErrorDomain =
55*1b3f573fSAndroid Build Coastguard Worker    GPBNSStringifySymbol(GPBMessageErrorDomain);
56*1b3f573fSAndroid Build Coastguard Worker
57*1b3f573fSAndroid Build Coastguard WorkerNSString *const GPBErrorReasonKey = @"Reason";
58*1b3f573fSAndroid Build Coastguard Worker
59*1b3f573fSAndroid Build Coastguard Workerstatic NSString *const kGPBDataCoderKey = @"GPBData";
60*1b3f573fSAndroid Build Coastguard Worker
61*1b3f573fSAndroid Build Coastguard Worker//
62*1b3f573fSAndroid Build Coastguard Worker// PLEASE REMEMBER:
63*1b3f573fSAndroid Build Coastguard Worker//
64*1b3f573fSAndroid Build Coastguard Worker// This is the base class for *all* messages generated, so any selector defined,
65*1b3f573fSAndroid Build Coastguard Worker// *public* or *private* could end up colliding with a proto message field. So
66*1b3f573fSAndroid Build Coastguard Worker// avoid using selectors that could match a property, use C functions to hide
67*1b3f573fSAndroid Build Coastguard Worker// them, etc.
68*1b3f573fSAndroid Build Coastguard Worker//
69*1b3f573fSAndroid Build Coastguard Worker
70*1b3f573fSAndroid Build Coastguard Worker@interface GPBMessage () {
71*1b3f573fSAndroid Build Coastguard Worker @package
72*1b3f573fSAndroid Build Coastguard Worker  GPBUnknownFieldSet *unknownFields_;
73*1b3f573fSAndroid Build Coastguard Worker  NSMutableDictionary *extensionMap_;
74*1b3f573fSAndroid Build Coastguard Worker  // Readonly access to autocreatedExtensionMap_ is protected via
75*1b3f573fSAndroid Build Coastguard Worker  // readOnlySemaphore_.
76*1b3f573fSAndroid Build Coastguard Worker  NSMutableDictionary *autocreatedExtensionMap_;
77*1b3f573fSAndroid Build Coastguard Worker
78*1b3f573fSAndroid Build Coastguard Worker  // If the object was autocreated, we remember the creator so that if we get
79*1b3f573fSAndroid Build Coastguard Worker  // mutated, we can inform the creator to make our field visible.
80*1b3f573fSAndroid Build Coastguard Worker  GPBMessage *autocreator_;
81*1b3f573fSAndroid Build Coastguard Worker  GPBFieldDescriptor *autocreatorField_;
82*1b3f573fSAndroid Build Coastguard Worker  GPBExtensionDescriptor *autocreatorExtension_;
83*1b3f573fSAndroid Build Coastguard Worker
84*1b3f573fSAndroid Build Coastguard Worker  // Message can only be mutated from one thread. But some *readonly* operations
85*1b3f573fSAndroid Build Coastguard Worker  // modify internal state because they autocreate things. The
86*1b3f573fSAndroid Build Coastguard Worker  // autocreatedExtensionMap_ is one such structure. Access during readonly
87*1b3f573fSAndroid Build Coastguard Worker  // operations is protected via this semaphore.
88*1b3f573fSAndroid Build Coastguard Worker  // NOTE: OSSpinLock may seem like a good fit here but Apple engineers have
89*1b3f573fSAndroid Build Coastguard Worker  // pointed out that they are vulnerable to live locking on iOS in cases of
90*1b3f573fSAndroid Build Coastguard Worker  // priority inversion:
91*1b3f573fSAndroid Build Coastguard Worker  //   http://mjtsai.com/blog/2015/12/16/osspinlock-is-unsafe/
92*1b3f573fSAndroid Build Coastguard Worker  //   https://lists.swift.org/pipermail/swift-dev/Week-of-Mon-20151214/000372.html
93*1b3f573fSAndroid Build Coastguard Worker  // Use of readOnlySemaphore_ must be prefaced by a call to
94*1b3f573fSAndroid Build Coastguard Worker  // GPBPrepareReadOnlySemaphore to ensure it has been created. This allows
95*1b3f573fSAndroid Build Coastguard Worker  // readOnlySemaphore_ to be only created when actually needed.
96*1b3f573fSAndroid Build Coastguard Worker  _Atomic(dispatch_semaphore_t) readOnlySemaphore_;
97*1b3f573fSAndroid Build Coastguard Worker}
98*1b3f573fSAndroid Build Coastguard Worker@end
99*1b3f573fSAndroid Build Coastguard Worker
100*1b3f573fSAndroid Build Coastguard Workerstatic id CreateArrayForField(GPBFieldDescriptor *field,
101*1b3f573fSAndroid Build Coastguard Worker                              GPBMessage *autocreator)
102*1b3f573fSAndroid Build Coastguard Worker    __attribute__((ns_returns_retained));
103*1b3f573fSAndroid Build Coastguard Workerstatic id GetOrCreateArrayIvarWithField(GPBMessage *self,
104*1b3f573fSAndroid Build Coastguard Worker                                        GPBFieldDescriptor *field);
105*1b3f573fSAndroid Build Coastguard Workerstatic id GetArrayIvarWithField(GPBMessage *self, GPBFieldDescriptor *field);
106*1b3f573fSAndroid Build Coastguard Workerstatic id CreateMapForField(GPBFieldDescriptor *field,
107*1b3f573fSAndroid Build Coastguard Worker                            GPBMessage *autocreator)
108*1b3f573fSAndroid Build Coastguard Worker    __attribute__((ns_returns_retained));
109*1b3f573fSAndroid Build Coastguard Workerstatic id GetOrCreateMapIvarWithField(GPBMessage *self,
110*1b3f573fSAndroid Build Coastguard Worker                                      GPBFieldDescriptor *field);
111*1b3f573fSAndroid Build Coastguard Workerstatic id GetMapIvarWithField(GPBMessage *self, GPBFieldDescriptor *field);
112*1b3f573fSAndroid Build Coastguard Workerstatic NSMutableDictionary *CloneExtensionMap(NSDictionary *extensionMap,
113*1b3f573fSAndroid Build Coastguard Worker                                              NSZone *zone)
114*1b3f573fSAndroid Build Coastguard Worker    __attribute__((ns_returns_retained));
115*1b3f573fSAndroid Build Coastguard Worker
116*1b3f573fSAndroid Build Coastguard Worker#ifdef DEBUG
117*1b3f573fSAndroid Build Coastguard Workerstatic NSError *MessageError(NSInteger code, NSDictionary *userInfo) {
118*1b3f573fSAndroid Build Coastguard Worker  return [NSError errorWithDomain:GPBMessageErrorDomain
119*1b3f573fSAndroid Build Coastguard Worker                             code:code
120*1b3f573fSAndroid Build Coastguard Worker                         userInfo:userInfo];
121*1b3f573fSAndroid Build Coastguard Worker}
122*1b3f573fSAndroid Build Coastguard Worker#endif
123*1b3f573fSAndroid Build Coastguard Worker
124*1b3f573fSAndroid Build Coastguard Workerstatic NSError *ErrorFromException(NSException *exception) {
125*1b3f573fSAndroid Build Coastguard Worker  NSError *error = nil;
126*1b3f573fSAndroid Build Coastguard Worker
127*1b3f573fSAndroid Build Coastguard Worker  if ([exception.name isEqual:GPBCodedInputStreamException]) {
128*1b3f573fSAndroid Build Coastguard Worker    NSDictionary *exceptionInfo = exception.userInfo;
129*1b3f573fSAndroid Build Coastguard Worker    error = exceptionInfo[GPBCodedInputStreamUnderlyingErrorKey];
130*1b3f573fSAndroid Build Coastguard Worker  }
131*1b3f573fSAndroid Build Coastguard Worker
132*1b3f573fSAndroid Build Coastguard Worker  if (!error) {
133*1b3f573fSAndroid Build Coastguard Worker    NSString *reason = exception.reason;
134*1b3f573fSAndroid Build Coastguard Worker    NSDictionary *userInfo = nil;
135*1b3f573fSAndroid Build Coastguard Worker    if ([reason length]) {
136*1b3f573fSAndroid Build Coastguard Worker      userInfo = @{ GPBErrorReasonKey : reason };
137*1b3f573fSAndroid Build Coastguard Worker    }
138*1b3f573fSAndroid Build Coastguard Worker
139*1b3f573fSAndroid Build Coastguard Worker    error = [NSError errorWithDomain:GPBMessageErrorDomain
140*1b3f573fSAndroid Build Coastguard Worker                                code:GPBMessageErrorCodeOther
141*1b3f573fSAndroid Build Coastguard Worker                            userInfo:userInfo];
142*1b3f573fSAndroid Build Coastguard Worker  }
143*1b3f573fSAndroid Build Coastguard Worker  return error;
144*1b3f573fSAndroid Build Coastguard Worker}
145*1b3f573fSAndroid Build Coastguard Worker
146*1b3f573fSAndroid Build Coastguard Workerstatic void CheckExtension(GPBMessage *self,
147*1b3f573fSAndroid Build Coastguard Worker                           GPBExtensionDescriptor *extension) {
148*1b3f573fSAndroid Build Coastguard Worker  if (![self isKindOfClass:extension.containingMessageClass]) {
149*1b3f573fSAndroid Build Coastguard Worker    [NSException
150*1b3f573fSAndroid Build Coastguard Worker         raise:NSInvalidArgumentException
151*1b3f573fSAndroid Build Coastguard Worker        format:@"Extension %@ used on wrong class (%@ instead of %@)",
152*1b3f573fSAndroid Build Coastguard Worker               extension.singletonName,
153*1b3f573fSAndroid Build Coastguard Worker               [self class], extension.containingMessageClass];
154*1b3f573fSAndroid Build Coastguard Worker  }
155*1b3f573fSAndroid Build Coastguard Worker}
156*1b3f573fSAndroid Build Coastguard Worker
157*1b3f573fSAndroid Build Coastguard Workerstatic NSMutableDictionary *CloneExtensionMap(NSDictionary *extensionMap,
158*1b3f573fSAndroid Build Coastguard Worker                                              NSZone *zone) {
159*1b3f573fSAndroid Build Coastguard Worker  if (extensionMap.count == 0) {
160*1b3f573fSAndroid Build Coastguard Worker    return nil;
161*1b3f573fSAndroid Build Coastguard Worker  }
162*1b3f573fSAndroid Build Coastguard Worker  NSMutableDictionary *result = [[NSMutableDictionary allocWithZone:zone]
163*1b3f573fSAndroid Build Coastguard Worker      initWithCapacity:extensionMap.count];
164*1b3f573fSAndroid Build Coastguard Worker
165*1b3f573fSAndroid Build Coastguard Worker  for (GPBExtensionDescriptor *extension in extensionMap) {
166*1b3f573fSAndroid Build Coastguard Worker    id value = [extensionMap objectForKey:extension];
167*1b3f573fSAndroid Build Coastguard Worker    BOOL isMessageExtension = GPBExtensionIsMessage(extension);
168*1b3f573fSAndroid Build Coastguard Worker
169*1b3f573fSAndroid Build Coastguard Worker    if (extension.repeated) {
170*1b3f573fSAndroid Build Coastguard Worker      if (isMessageExtension) {
171*1b3f573fSAndroid Build Coastguard Worker        NSMutableArray *list =
172*1b3f573fSAndroid Build Coastguard Worker            [[NSMutableArray alloc] initWithCapacity:[value count]];
173*1b3f573fSAndroid Build Coastguard Worker        for (GPBMessage *listValue in value) {
174*1b3f573fSAndroid Build Coastguard Worker          GPBMessage *copiedValue = [listValue copyWithZone:zone];
175*1b3f573fSAndroid Build Coastguard Worker          [list addObject:copiedValue];
176*1b3f573fSAndroid Build Coastguard Worker          [copiedValue release];
177*1b3f573fSAndroid Build Coastguard Worker        }
178*1b3f573fSAndroid Build Coastguard Worker        [result setObject:list forKey:extension];
179*1b3f573fSAndroid Build Coastguard Worker        [list release];
180*1b3f573fSAndroid Build Coastguard Worker      } else {
181*1b3f573fSAndroid Build Coastguard Worker        NSMutableArray *copiedValue = [value mutableCopyWithZone:zone];
182*1b3f573fSAndroid Build Coastguard Worker        [result setObject:copiedValue forKey:extension];
183*1b3f573fSAndroid Build Coastguard Worker        [copiedValue release];
184*1b3f573fSAndroid Build Coastguard Worker      }
185*1b3f573fSAndroid Build Coastguard Worker    } else {
186*1b3f573fSAndroid Build Coastguard Worker      if (isMessageExtension) {
187*1b3f573fSAndroid Build Coastguard Worker        GPBMessage *copiedValue = [value copyWithZone:zone];
188*1b3f573fSAndroid Build Coastguard Worker        [result setObject:copiedValue forKey:extension];
189*1b3f573fSAndroid Build Coastguard Worker        [copiedValue release];
190*1b3f573fSAndroid Build Coastguard Worker      } else {
191*1b3f573fSAndroid Build Coastguard Worker        [result setObject:value forKey:extension];
192*1b3f573fSAndroid Build Coastguard Worker      }
193*1b3f573fSAndroid Build Coastguard Worker    }
194*1b3f573fSAndroid Build Coastguard Worker  }
195*1b3f573fSAndroid Build Coastguard Worker
196*1b3f573fSAndroid Build Coastguard Worker  return result;
197*1b3f573fSAndroid Build Coastguard Worker}
198*1b3f573fSAndroid Build Coastguard Worker
199*1b3f573fSAndroid Build Coastguard Workerstatic id CreateArrayForField(GPBFieldDescriptor *field,
200*1b3f573fSAndroid Build Coastguard Worker                              GPBMessage *autocreator) {
201*1b3f573fSAndroid Build Coastguard Worker  id result;
202*1b3f573fSAndroid Build Coastguard Worker  GPBDataType fieldDataType = GPBGetFieldDataType(field);
203*1b3f573fSAndroid Build Coastguard Worker  switch (fieldDataType) {
204*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeBool:
205*1b3f573fSAndroid Build Coastguard Worker      result = [[GPBBoolArray alloc] init];
206*1b3f573fSAndroid Build Coastguard Worker      break;
207*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeFixed32:
208*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeUInt32:
209*1b3f573fSAndroid Build Coastguard Worker      result = [[GPBUInt32Array alloc] init];
210*1b3f573fSAndroid Build Coastguard Worker      break;
211*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeInt32:
212*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeSFixed32:
213*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeSInt32:
214*1b3f573fSAndroid Build Coastguard Worker      result = [[GPBInt32Array alloc] init];
215*1b3f573fSAndroid Build Coastguard Worker      break;
216*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeFixed64:
217*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeUInt64:
218*1b3f573fSAndroid Build Coastguard Worker      result = [[GPBUInt64Array alloc] init];
219*1b3f573fSAndroid Build Coastguard Worker      break;
220*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeInt64:
221*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeSFixed64:
222*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeSInt64:
223*1b3f573fSAndroid Build Coastguard Worker      result = [[GPBInt64Array alloc] init];
224*1b3f573fSAndroid Build Coastguard Worker      break;
225*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeFloat:
226*1b3f573fSAndroid Build Coastguard Worker      result = [[GPBFloatArray alloc] init];
227*1b3f573fSAndroid Build Coastguard Worker      break;
228*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeDouble:
229*1b3f573fSAndroid Build Coastguard Worker      result = [[GPBDoubleArray alloc] init];
230*1b3f573fSAndroid Build Coastguard Worker      break;
231*1b3f573fSAndroid Build Coastguard Worker
232*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeEnum:
233*1b3f573fSAndroid Build Coastguard Worker      result = [[GPBEnumArray alloc]
234*1b3f573fSAndroid Build Coastguard Worker                  initWithValidationFunction:field.enumDescriptor.enumVerifier];
235*1b3f573fSAndroid Build Coastguard Worker      break;
236*1b3f573fSAndroid Build Coastguard Worker
237*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeBytes:
238*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeGroup:
239*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeMessage:
240*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeString:
241*1b3f573fSAndroid Build Coastguard Worker      if (autocreator) {
242*1b3f573fSAndroid Build Coastguard Worker        result = [[GPBAutocreatedArray alloc] init];
243*1b3f573fSAndroid Build Coastguard Worker      } else {
244*1b3f573fSAndroid Build Coastguard Worker        result = [[NSMutableArray alloc] init];
245*1b3f573fSAndroid Build Coastguard Worker      }
246*1b3f573fSAndroid Build Coastguard Worker      break;
247*1b3f573fSAndroid Build Coastguard Worker  }
248*1b3f573fSAndroid Build Coastguard Worker
249*1b3f573fSAndroid Build Coastguard Worker  if (autocreator) {
250*1b3f573fSAndroid Build Coastguard Worker    if (GPBDataTypeIsObject(fieldDataType)) {
251*1b3f573fSAndroid Build Coastguard Worker      GPBAutocreatedArray *autoArray = result;
252*1b3f573fSAndroid Build Coastguard Worker      autoArray->_autocreator =  autocreator;
253*1b3f573fSAndroid Build Coastguard Worker    } else {
254*1b3f573fSAndroid Build Coastguard Worker      GPBInt32Array *gpbArray = result;
255*1b3f573fSAndroid Build Coastguard Worker      gpbArray->_autocreator = autocreator;
256*1b3f573fSAndroid Build Coastguard Worker    }
257*1b3f573fSAndroid Build Coastguard Worker  }
258*1b3f573fSAndroid Build Coastguard Worker
259*1b3f573fSAndroid Build Coastguard Worker  return result;
260*1b3f573fSAndroid Build Coastguard Worker}
261*1b3f573fSAndroid Build Coastguard Worker
262*1b3f573fSAndroid Build Coastguard Workerstatic id CreateMapForField(GPBFieldDescriptor *field,
263*1b3f573fSAndroid Build Coastguard Worker                            GPBMessage *autocreator) {
264*1b3f573fSAndroid Build Coastguard Worker  id result;
265*1b3f573fSAndroid Build Coastguard Worker  GPBDataType keyDataType = field.mapKeyDataType;
266*1b3f573fSAndroid Build Coastguard Worker  GPBDataType valueDataType = GPBGetFieldDataType(field);
267*1b3f573fSAndroid Build Coastguard Worker  switch (keyDataType) {
268*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeBool:
269*1b3f573fSAndroid Build Coastguard Worker      switch (valueDataType) {
270*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeBool:
271*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBBoolBoolDictionary alloc] init];
272*1b3f573fSAndroid Build Coastguard Worker          break;
273*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeFixed32:
274*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeUInt32:
275*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBBoolUInt32Dictionary alloc] init];
276*1b3f573fSAndroid Build Coastguard Worker          break;
277*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeInt32:
278*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeSFixed32:
279*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeSInt32:
280*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBBoolInt32Dictionary alloc] init];
281*1b3f573fSAndroid Build Coastguard Worker          break;
282*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeFixed64:
283*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeUInt64:
284*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBBoolUInt64Dictionary alloc] init];
285*1b3f573fSAndroid Build Coastguard Worker          break;
286*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeInt64:
287*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeSFixed64:
288*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeSInt64:
289*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBBoolInt64Dictionary alloc] init];
290*1b3f573fSAndroid Build Coastguard Worker          break;
291*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeFloat:
292*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBBoolFloatDictionary alloc] init];
293*1b3f573fSAndroid Build Coastguard Worker          break;
294*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeDouble:
295*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBBoolDoubleDictionary alloc] init];
296*1b3f573fSAndroid Build Coastguard Worker          break;
297*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeEnum:
298*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBBoolEnumDictionary alloc]
299*1b3f573fSAndroid Build Coastguard Worker              initWithValidationFunction:field.enumDescriptor.enumVerifier];
300*1b3f573fSAndroid Build Coastguard Worker          break;
301*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeBytes:
302*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeMessage:
303*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeString:
304*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBBoolObjectDictionary alloc] init];
305*1b3f573fSAndroid Build Coastguard Worker          break;
306*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeGroup:
307*1b3f573fSAndroid Build Coastguard Worker          NSCAssert(NO, @"shouldn't happen");
308*1b3f573fSAndroid Build Coastguard Worker          return nil;
309*1b3f573fSAndroid Build Coastguard Worker      }
310*1b3f573fSAndroid Build Coastguard Worker      break;
311*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeFixed32:
312*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeUInt32:
313*1b3f573fSAndroid Build Coastguard Worker      switch (valueDataType) {
314*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeBool:
315*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBUInt32BoolDictionary alloc] init];
316*1b3f573fSAndroid Build Coastguard Worker          break;
317*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeFixed32:
318*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeUInt32:
319*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBUInt32UInt32Dictionary alloc] init];
320*1b3f573fSAndroid Build Coastguard Worker          break;
321*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeInt32:
322*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeSFixed32:
323*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeSInt32:
324*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBUInt32Int32Dictionary alloc] init];
325*1b3f573fSAndroid Build Coastguard Worker          break;
326*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeFixed64:
327*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeUInt64:
328*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBUInt32UInt64Dictionary alloc] init];
329*1b3f573fSAndroid Build Coastguard Worker          break;
330*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeInt64:
331*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeSFixed64:
332*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeSInt64:
333*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBUInt32Int64Dictionary alloc] init];
334*1b3f573fSAndroid Build Coastguard Worker          break;
335*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeFloat:
336*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBUInt32FloatDictionary alloc] init];
337*1b3f573fSAndroid Build Coastguard Worker          break;
338*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeDouble:
339*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBUInt32DoubleDictionary alloc] init];
340*1b3f573fSAndroid Build Coastguard Worker          break;
341*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeEnum:
342*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBUInt32EnumDictionary alloc]
343*1b3f573fSAndroid Build Coastguard Worker              initWithValidationFunction:field.enumDescriptor.enumVerifier];
344*1b3f573fSAndroid Build Coastguard Worker          break;
345*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeBytes:
346*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeMessage:
347*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeString:
348*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBUInt32ObjectDictionary alloc] init];
349*1b3f573fSAndroid Build Coastguard Worker          break;
350*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeGroup:
351*1b3f573fSAndroid Build Coastguard Worker          NSCAssert(NO, @"shouldn't happen");
352*1b3f573fSAndroid Build Coastguard Worker          return nil;
353*1b3f573fSAndroid Build Coastguard Worker      }
354*1b3f573fSAndroid Build Coastguard Worker      break;
355*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeInt32:
356*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeSFixed32:
357*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeSInt32:
358*1b3f573fSAndroid Build Coastguard Worker      switch (valueDataType) {
359*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeBool:
360*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBInt32BoolDictionary alloc] init];
361*1b3f573fSAndroid Build Coastguard Worker          break;
362*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeFixed32:
363*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeUInt32:
364*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBInt32UInt32Dictionary alloc] init];
365*1b3f573fSAndroid Build Coastguard Worker          break;
366*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeInt32:
367*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeSFixed32:
368*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeSInt32:
369*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBInt32Int32Dictionary alloc] init];
370*1b3f573fSAndroid Build Coastguard Worker          break;
371*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeFixed64:
372*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeUInt64:
373*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBInt32UInt64Dictionary alloc] init];
374*1b3f573fSAndroid Build Coastguard Worker          break;
375*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeInt64:
376*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeSFixed64:
377*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeSInt64:
378*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBInt32Int64Dictionary alloc] init];
379*1b3f573fSAndroid Build Coastguard Worker          break;
380*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeFloat:
381*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBInt32FloatDictionary alloc] init];
382*1b3f573fSAndroid Build Coastguard Worker          break;
383*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeDouble:
384*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBInt32DoubleDictionary alloc] init];
385*1b3f573fSAndroid Build Coastguard Worker          break;
386*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeEnum:
387*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBInt32EnumDictionary alloc]
388*1b3f573fSAndroid Build Coastguard Worker              initWithValidationFunction:field.enumDescriptor.enumVerifier];
389*1b3f573fSAndroid Build Coastguard Worker          break;
390*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeBytes:
391*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeMessage:
392*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeString:
393*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBInt32ObjectDictionary alloc] init];
394*1b3f573fSAndroid Build Coastguard Worker          break;
395*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeGroup:
396*1b3f573fSAndroid Build Coastguard Worker          NSCAssert(NO, @"shouldn't happen");
397*1b3f573fSAndroid Build Coastguard Worker          return nil;
398*1b3f573fSAndroid Build Coastguard Worker      }
399*1b3f573fSAndroid Build Coastguard Worker      break;
400*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeFixed64:
401*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeUInt64:
402*1b3f573fSAndroid Build Coastguard Worker      switch (valueDataType) {
403*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeBool:
404*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBUInt64BoolDictionary alloc] init];
405*1b3f573fSAndroid Build Coastguard Worker          break;
406*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeFixed32:
407*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeUInt32:
408*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBUInt64UInt32Dictionary alloc] init];
409*1b3f573fSAndroid Build Coastguard Worker          break;
410*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeInt32:
411*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeSFixed32:
412*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeSInt32:
413*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBUInt64Int32Dictionary alloc] init];
414*1b3f573fSAndroid Build Coastguard Worker          break;
415*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeFixed64:
416*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeUInt64:
417*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBUInt64UInt64Dictionary alloc] init];
418*1b3f573fSAndroid Build Coastguard Worker          break;
419*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeInt64:
420*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeSFixed64:
421*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeSInt64:
422*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBUInt64Int64Dictionary alloc] init];
423*1b3f573fSAndroid Build Coastguard Worker          break;
424*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeFloat:
425*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBUInt64FloatDictionary alloc] init];
426*1b3f573fSAndroid Build Coastguard Worker          break;
427*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeDouble:
428*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBUInt64DoubleDictionary alloc] init];
429*1b3f573fSAndroid Build Coastguard Worker          break;
430*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeEnum:
431*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBUInt64EnumDictionary alloc]
432*1b3f573fSAndroid Build Coastguard Worker              initWithValidationFunction:field.enumDescriptor.enumVerifier];
433*1b3f573fSAndroid Build Coastguard Worker          break;
434*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeBytes:
435*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeMessage:
436*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeString:
437*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBUInt64ObjectDictionary alloc] init];
438*1b3f573fSAndroid Build Coastguard Worker          break;
439*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeGroup:
440*1b3f573fSAndroid Build Coastguard Worker          NSCAssert(NO, @"shouldn't happen");
441*1b3f573fSAndroid Build Coastguard Worker          return nil;
442*1b3f573fSAndroid Build Coastguard Worker      }
443*1b3f573fSAndroid Build Coastguard Worker      break;
444*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeInt64:
445*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeSFixed64:
446*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeSInt64:
447*1b3f573fSAndroid Build Coastguard Worker      switch (valueDataType) {
448*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeBool:
449*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBInt64BoolDictionary alloc] init];
450*1b3f573fSAndroid Build Coastguard Worker          break;
451*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeFixed32:
452*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeUInt32:
453*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBInt64UInt32Dictionary alloc] init];
454*1b3f573fSAndroid Build Coastguard Worker          break;
455*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeInt32:
456*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeSFixed32:
457*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeSInt32:
458*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBInt64Int32Dictionary alloc] init];
459*1b3f573fSAndroid Build Coastguard Worker          break;
460*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeFixed64:
461*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeUInt64:
462*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBInt64UInt64Dictionary alloc] init];
463*1b3f573fSAndroid Build Coastguard Worker          break;
464*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeInt64:
465*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeSFixed64:
466*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeSInt64:
467*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBInt64Int64Dictionary alloc] init];
468*1b3f573fSAndroid Build Coastguard Worker          break;
469*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeFloat:
470*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBInt64FloatDictionary alloc] init];
471*1b3f573fSAndroid Build Coastguard Worker          break;
472*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeDouble:
473*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBInt64DoubleDictionary alloc] init];
474*1b3f573fSAndroid Build Coastguard Worker          break;
475*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeEnum:
476*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBInt64EnumDictionary alloc]
477*1b3f573fSAndroid Build Coastguard Worker              initWithValidationFunction:field.enumDescriptor.enumVerifier];
478*1b3f573fSAndroid Build Coastguard Worker          break;
479*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeBytes:
480*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeMessage:
481*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeString:
482*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBInt64ObjectDictionary alloc] init];
483*1b3f573fSAndroid Build Coastguard Worker          break;
484*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeGroup:
485*1b3f573fSAndroid Build Coastguard Worker          NSCAssert(NO, @"shouldn't happen");
486*1b3f573fSAndroid Build Coastguard Worker          return nil;
487*1b3f573fSAndroid Build Coastguard Worker      }
488*1b3f573fSAndroid Build Coastguard Worker      break;
489*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeString:
490*1b3f573fSAndroid Build Coastguard Worker      switch (valueDataType) {
491*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeBool:
492*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBStringBoolDictionary alloc] init];
493*1b3f573fSAndroid Build Coastguard Worker          break;
494*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeFixed32:
495*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeUInt32:
496*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBStringUInt32Dictionary alloc] init];
497*1b3f573fSAndroid Build Coastguard Worker          break;
498*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeInt32:
499*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeSFixed32:
500*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeSInt32:
501*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBStringInt32Dictionary alloc] init];
502*1b3f573fSAndroid Build Coastguard Worker          break;
503*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeFixed64:
504*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeUInt64:
505*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBStringUInt64Dictionary alloc] init];
506*1b3f573fSAndroid Build Coastguard Worker          break;
507*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeInt64:
508*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeSFixed64:
509*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeSInt64:
510*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBStringInt64Dictionary alloc] init];
511*1b3f573fSAndroid Build Coastguard Worker          break;
512*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeFloat:
513*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBStringFloatDictionary alloc] init];
514*1b3f573fSAndroid Build Coastguard Worker          break;
515*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeDouble:
516*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBStringDoubleDictionary alloc] init];
517*1b3f573fSAndroid Build Coastguard Worker          break;
518*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeEnum:
519*1b3f573fSAndroid Build Coastguard Worker          result = [[GPBStringEnumDictionary alloc]
520*1b3f573fSAndroid Build Coastguard Worker              initWithValidationFunction:field.enumDescriptor.enumVerifier];
521*1b3f573fSAndroid Build Coastguard Worker          break;
522*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeBytes:
523*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeMessage:
524*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeString:
525*1b3f573fSAndroid Build Coastguard Worker          if (autocreator) {
526*1b3f573fSAndroid Build Coastguard Worker            result = [[GPBAutocreatedDictionary alloc] init];
527*1b3f573fSAndroid Build Coastguard Worker          } else {
528*1b3f573fSAndroid Build Coastguard Worker            result = [[NSMutableDictionary alloc] init];
529*1b3f573fSAndroid Build Coastguard Worker          }
530*1b3f573fSAndroid Build Coastguard Worker          break;
531*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeGroup:
532*1b3f573fSAndroid Build Coastguard Worker          NSCAssert(NO, @"shouldn't happen");
533*1b3f573fSAndroid Build Coastguard Worker          return nil;
534*1b3f573fSAndroid Build Coastguard Worker      }
535*1b3f573fSAndroid Build Coastguard Worker      break;
536*1b3f573fSAndroid Build Coastguard Worker
537*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeFloat:
538*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeDouble:
539*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeEnum:
540*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeBytes:
541*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeGroup:
542*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeMessage:
543*1b3f573fSAndroid Build Coastguard Worker      NSCAssert(NO, @"shouldn't happen");
544*1b3f573fSAndroid Build Coastguard Worker      return nil;
545*1b3f573fSAndroid Build Coastguard Worker  }
546*1b3f573fSAndroid Build Coastguard Worker
547*1b3f573fSAndroid Build Coastguard Worker  if (autocreator) {
548*1b3f573fSAndroid Build Coastguard Worker    if ((keyDataType == GPBDataTypeString) &&
549*1b3f573fSAndroid Build Coastguard Worker        GPBDataTypeIsObject(valueDataType)) {
550*1b3f573fSAndroid Build Coastguard Worker      GPBAutocreatedDictionary *autoDict = result;
551*1b3f573fSAndroid Build Coastguard Worker      autoDict->_autocreator =  autocreator;
552*1b3f573fSAndroid Build Coastguard Worker    } else {
553*1b3f573fSAndroid Build Coastguard Worker      GPBInt32Int32Dictionary *gpbDict = result;
554*1b3f573fSAndroid Build Coastguard Worker      gpbDict->_autocreator = autocreator;
555*1b3f573fSAndroid Build Coastguard Worker    }
556*1b3f573fSAndroid Build Coastguard Worker  }
557*1b3f573fSAndroid Build Coastguard Worker
558*1b3f573fSAndroid Build Coastguard Worker  return result;
559*1b3f573fSAndroid Build Coastguard Worker}
560*1b3f573fSAndroid Build Coastguard Worker
561*1b3f573fSAndroid Build Coastguard Worker#if !defined(__clang_analyzer__)
562*1b3f573fSAndroid Build Coastguard Worker// These functions are blocked from the analyzer because the analyzer sees the
563*1b3f573fSAndroid Build Coastguard Worker// GPBSetRetainedObjectIvarWithFieldPrivate() call as consuming the array/map,
564*1b3f573fSAndroid Build Coastguard Worker// so use of the array/map after the call returns is flagged as a use after
565*1b3f573fSAndroid Build Coastguard Worker// free.
566*1b3f573fSAndroid Build Coastguard Worker// But GPBSetRetainedObjectIvarWithFieldPrivate() is "consuming" the retain
567*1b3f573fSAndroid Build Coastguard Worker// count be holding onto the object (it is transferring it), the object is
568*1b3f573fSAndroid Build Coastguard Worker// still valid after returning from the call.  The other way to avoid this
569*1b3f573fSAndroid Build Coastguard Worker// would be to add a -retain/-autorelease, but that would force every
570*1b3f573fSAndroid Build Coastguard Worker// repeated/map field parsed into the autorelease pool which is both a memory
571*1b3f573fSAndroid Build Coastguard Worker// and performance hit.
572*1b3f573fSAndroid Build Coastguard Worker
573*1b3f573fSAndroid Build Coastguard Workerstatic id GetOrCreateArrayIvarWithField(GPBMessage *self,
574*1b3f573fSAndroid Build Coastguard Worker                                        GPBFieldDescriptor *field) {
575*1b3f573fSAndroid Build Coastguard Worker  id array = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
576*1b3f573fSAndroid Build Coastguard Worker  if (!array) {
577*1b3f573fSAndroid Build Coastguard Worker    // No lock needed, this is called from places expecting to mutate
578*1b3f573fSAndroid Build Coastguard Worker    // so no threading protection is needed.
579*1b3f573fSAndroid Build Coastguard Worker    array = CreateArrayForField(field, nil);
580*1b3f573fSAndroid Build Coastguard Worker    GPBSetRetainedObjectIvarWithFieldPrivate(self, field, array);
581*1b3f573fSAndroid Build Coastguard Worker  }
582*1b3f573fSAndroid Build Coastguard Worker  return array;
583*1b3f573fSAndroid Build Coastguard Worker}
584*1b3f573fSAndroid Build Coastguard Worker
585*1b3f573fSAndroid Build Coastguard Worker// This is like GPBGetObjectIvarWithField(), but for arrays, it should
586*1b3f573fSAndroid Build Coastguard Worker// only be used to wire the method into the class.
587*1b3f573fSAndroid Build Coastguard Workerstatic id GetArrayIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) {
588*1b3f573fSAndroid Build Coastguard Worker  uint8_t *storage = (uint8_t *)self->messageStorage_;
589*1b3f573fSAndroid Build Coastguard Worker  _Atomic(id) *typePtr = (_Atomic(id) *)&storage[field->description_->offset];
590*1b3f573fSAndroid Build Coastguard Worker  id array = atomic_load(typePtr);
591*1b3f573fSAndroid Build Coastguard Worker  if (array) {
592*1b3f573fSAndroid Build Coastguard Worker    return array;
593*1b3f573fSAndroid Build Coastguard Worker  }
594*1b3f573fSAndroid Build Coastguard Worker
595*1b3f573fSAndroid Build Coastguard Worker  id expected = nil;
596*1b3f573fSAndroid Build Coastguard Worker  id autocreated = CreateArrayForField(field, self);
597*1b3f573fSAndroid Build Coastguard Worker  if (atomic_compare_exchange_strong(typePtr, &expected, autocreated)) {
598*1b3f573fSAndroid Build Coastguard Worker    // Value was set, return it.
599*1b3f573fSAndroid Build Coastguard Worker    return autocreated;
600*1b3f573fSAndroid Build Coastguard Worker  }
601*1b3f573fSAndroid Build Coastguard Worker
602*1b3f573fSAndroid Build Coastguard Worker  // Some other thread set it, release the one created and return what got set.
603*1b3f573fSAndroid Build Coastguard Worker  if (GPBFieldDataTypeIsObject(field)) {
604*1b3f573fSAndroid Build Coastguard Worker    GPBAutocreatedArray *autoArray = autocreated;
605*1b3f573fSAndroid Build Coastguard Worker    autoArray->_autocreator = nil;
606*1b3f573fSAndroid Build Coastguard Worker  } else {
607*1b3f573fSAndroid Build Coastguard Worker    GPBInt32Array *gpbArray = autocreated;
608*1b3f573fSAndroid Build Coastguard Worker    gpbArray->_autocreator = nil;
609*1b3f573fSAndroid Build Coastguard Worker  }
610*1b3f573fSAndroid Build Coastguard Worker  [autocreated release];
611*1b3f573fSAndroid Build Coastguard Worker  return expected;
612*1b3f573fSAndroid Build Coastguard Worker}
613*1b3f573fSAndroid Build Coastguard Worker
614*1b3f573fSAndroid Build Coastguard Workerstatic id GetOrCreateMapIvarWithField(GPBMessage *self,
615*1b3f573fSAndroid Build Coastguard Worker                                      GPBFieldDescriptor *field) {
616*1b3f573fSAndroid Build Coastguard Worker  id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
617*1b3f573fSAndroid Build Coastguard Worker  if (!dict) {
618*1b3f573fSAndroid Build Coastguard Worker    // No lock needed, this is called from places expecting to mutate
619*1b3f573fSAndroid Build Coastguard Worker    // so no threading protection is needed.
620*1b3f573fSAndroid Build Coastguard Worker    dict = CreateMapForField(field, nil);
621*1b3f573fSAndroid Build Coastguard Worker    GPBSetRetainedObjectIvarWithFieldPrivate(self, field, dict);
622*1b3f573fSAndroid Build Coastguard Worker  }
623*1b3f573fSAndroid Build Coastguard Worker  return dict;
624*1b3f573fSAndroid Build Coastguard Worker}
625*1b3f573fSAndroid Build Coastguard Worker
626*1b3f573fSAndroid Build Coastguard Worker// This is like GPBGetObjectIvarWithField(), but for maps, it should
627*1b3f573fSAndroid Build Coastguard Worker// only be used to wire the method into the class.
628*1b3f573fSAndroid Build Coastguard Workerstatic id GetMapIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) {
629*1b3f573fSAndroid Build Coastguard Worker  uint8_t *storage = (uint8_t *)self->messageStorage_;
630*1b3f573fSAndroid Build Coastguard Worker  _Atomic(id) *typePtr = (_Atomic(id) *)&storage[field->description_->offset];
631*1b3f573fSAndroid Build Coastguard Worker  id dict = atomic_load(typePtr);
632*1b3f573fSAndroid Build Coastguard Worker  if (dict) {
633*1b3f573fSAndroid Build Coastguard Worker    return dict;
634*1b3f573fSAndroid Build Coastguard Worker  }
635*1b3f573fSAndroid Build Coastguard Worker
636*1b3f573fSAndroid Build Coastguard Worker  id expected = nil;
637*1b3f573fSAndroid Build Coastguard Worker  id autocreated = CreateMapForField(field, self);
638*1b3f573fSAndroid Build Coastguard Worker  if (atomic_compare_exchange_strong(typePtr, &expected, autocreated)) {
639*1b3f573fSAndroid Build Coastguard Worker    // Value was set, return it.
640*1b3f573fSAndroid Build Coastguard Worker    return autocreated;
641*1b3f573fSAndroid Build Coastguard Worker  }
642*1b3f573fSAndroid Build Coastguard Worker
643*1b3f573fSAndroid Build Coastguard Worker  // Some other thread set it, release the one created and return what got set.
644*1b3f573fSAndroid Build Coastguard Worker  if ((field.mapKeyDataType == GPBDataTypeString) &&
645*1b3f573fSAndroid Build Coastguard Worker      GPBFieldDataTypeIsObject(field)) {
646*1b3f573fSAndroid Build Coastguard Worker    GPBAutocreatedDictionary *autoDict = autocreated;
647*1b3f573fSAndroid Build Coastguard Worker    autoDict->_autocreator = nil;
648*1b3f573fSAndroid Build Coastguard Worker  } else {
649*1b3f573fSAndroid Build Coastguard Worker    GPBInt32Int32Dictionary *gpbDict = autocreated;
650*1b3f573fSAndroid Build Coastguard Worker    gpbDict->_autocreator = nil;
651*1b3f573fSAndroid Build Coastguard Worker  }
652*1b3f573fSAndroid Build Coastguard Worker  [autocreated release];
653*1b3f573fSAndroid Build Coastguard Worker  return expected;
654*1b3f573fSAndroid Build Coastguard Worker}
655*1b3f573fSAndroid Build Coastguard Worker
656*1b3f573fSAndroid Build Coastguard Worker#endif  // !defined(__clang_analyzer__)
657*1b3f573fSAndroid Build Coastguard Worker
658*1b3f573fSAndroid Build Coastguard WorkerGPBMessage *GPBCreateMessageWithAutocreator(Class msgClass,
659*1b3f573fSAndroid Build Coastguard Worker                                            GPBMessage *autocreator,
660*1b3f573fSAndroid Build Coastguard Worker                                            GPBFieldDescriptor *field) {
661*1b3f573fSAndroid Build Coastguard Worker  GPBMessage *message = [[msgClass alloc] init];
662*1b3f573fSAndroid Build Coastguard Worker  message->autocreator_ = autocreator;
663*1b3f573fSAndroid Build Coastguard Worker  message->autocreatorField_ = [field retain];
664*1b3f573fSAndroid Build Coastguard Worker  return message;
665*1b3f573fSAndroid Build Coastguard Worker}
666*1b3f573fSAndroid Build Coastguard Worker
667*1b3f573fSAndroid Build Coastguard Workerstatic GPBMessage *CreateMessageWithAutocreatorForExtension(
668*1b3f573fSAndroid Build Coastguard Worker    Class msgClass, GPBMessage *autocreator, GPBExtensionDescriptor *extension)
669*1b3f573fSAndroid Build Coastguard Worker    __attribute__((ns_returns_retained));
670*1b3f573fSAndroid Build Coastguard Worker
671*1b3f573fSAndroid Build Coastguard Workerstatic GPBMessage *CreateMessageWithAutocreatorForExtension(
672*1b3f573fSAndroid Build Coastguard Worker    Class msgClass, GPBMessage *autocreator,
673*1b3f573fSAndroid Build Coastguard Worker    GPBExtensionDescriptor *extension) {
674*1b3f573fSAndroid Build Coastguard Worker  GPBMessage *message = [[msgClass alloc] init];
675*1b3f573fSAndroid Build Coastguard Worker  message->autocreator_ = autocreator;
676*1b3f573fSAndroid Build Coastguard Worker  message->autocreatorExtension_ = [extension retain];
677*1b3f573fSAndroid Build Coastguard Worker  return message;
678*1b3f573fSAndroid Build Coastguard Worker}
679*1b3f573fSAndroid Build Coastguard Worker
680*1b3f573fSAndroid Build Coastguard WorkerBOOL GPBWasMessageAutocreatedBy(GPBMessage *message, GPBMessage *parent) {
681*1b3f573fSAndroid Build Coastguard Worker  return (message->autocreator_ == parent);
682*1b3f573fSAndroid Build Coastguard Worker}
683*1b3f573fSAndroid Build Coastguard Worker
684*1b3f573fSAndroid Build Coastguard Workervoid GPBBecomeVisibleToAutocreator(GPBMessage *self) {
685*1b3f573fSAndroid Build Coastguard Worker  // Message objects that are implicitly created by accessing a message field
686*1b3f573fSAndroid Build Coastguard Worker  // are initially not visible via the hasX selector. This method makes them
687*1b3f573fSAndroid Build Coastguard Worker  // visible.
688*1b3f573fSAndroid Build Coastguard Worker  if (self->autocreator_) {
689*1b3f573fSAndroid Build Coastguard Worker    // This will recursively make all parent messages visible until it reaches a
690*1b3f573fSAndroid Build Coastguard Worker    // super-creator that's visible.
691*1b3f573fSAndroid Build Coastguard Worker    if (self->autocreatorField_) {
692*1b3f573fSAndroid Build Coastguard Worker      GPBSetObjectIvarWithFieldPrivate(self->autocreator_,
693*1b3f573fSAndroid Build Coastguard Worker                                        self->autocreatorField_, self);
694*1b3f573fSAndroid Build Coastguard Worker    } else {
695*1b3f573fSAndroid Build Coastguard Worker      [self->autocreator_ setExtension:self->autocreatorExtension_ value:self];
696*1b3f573fSAndroid Build Coastguard Worker    }
697*1b3f573fSAndroid Build Coastguard Worker  }
698*1b3f573fSAndroid Build Coastguard Worker}
699*1b3f573fSAndroid Build Coastguard Worker
700*1b3f573fSAndroid Build Coastguard Workervoid GPBAutocreatedArrayModified(GPBMessage *self, id array) {
701*1b3f573fSAndroid Build Coastguard Worker  // When one of our autocreated arrays adds elements, make it visible.
702*1b3f573fSAndroid Build Coastguard Worker  GPBDescriptor *descriptor = [[self class] descriptor];
703*1b3f573fSAndroid Build Coastguard Worker  for (GPBFieldDescriptor *field in descriptor->fields_) {
704*1b3f573fSAndroid Build Coastguard Worker    if (field.fieldType == GPBFieldTypeRepeated) {
705*1b3f573fSAndroid Build Coastguard Worker      id curArray = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
706*1b3f573fSAndroid Build Coastguard Worker      if (curArray == array) {
707*1b3f573fSAndroid Build Coastguard Worker        if (GPBFieldDataTypeIsObject(field)) {
708*1b3f573fSAndroid Build Coastguard Worker          GPBAutocreatedArray *autoArray = array;
709*1b3f573fSAndroid Build Coastguard Worker          autoArray->_autocreator = nil;
710*1b3f573fSAndroid Build Coastguard Worker        } else {
711*1b3f573fSAndroid Build Coastguard Worker          GPBInt32Array *gpbArray = array;
712*1b3f573fSAndroid Build Coastguard Worker          gpbArray->_autocreator = nil;
713*1b3f573fSAndroid Build Coastguard Worker        }
714*1b3f573fSAndroid Build Coastguard Worker        GPBBecomeVisibleToAutocreator(self);
715*1b3f573fSAndroid Build Coastguard Worker        return;
716*1b3f573fSAndroid Build Coastguard Worker      }
717*1b3f573fSAndroid Build Coastguard Worker    }
718*1b3f573fSAndroid Build Coastguard Worker  }
719*1b3f573fSAndroid Build Coastguard Worker  NSCAssert(NO, @"Unknown autocreated %@ for %@.", [array class], self);
720*1b3f573fSAndroid Build Coastguard Worker}
721*1b3f573fSAndroid Build Coastguard Worker
722*1b3f573fSAndroid Build Coastguard Workervoid GPBAutocreatedDictionaryModified(GPBMessage *self, id dictionary) {
723*1b3f573fSAndroid Build Coastguard Worker  // When one of our autocreated dicts adds elements, make it visible.
724*1b3f573fSAndroid Build Coastguard Worker  GPBDescriptor *descriptor = [[self class] descriptor];
725*1b3f573fSAndroid Build Coastguard Worker  for (GPBFieldDescriptor *field in descriptor->fields_) {
726*1b3f573fSAndroid Build Coastguard Worker    if (field.fieldType == GPBFieldTypeMap) {
727*1b3f573fSAndroid Build Coastguard Worker      id curDict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
728*1b3f573fSAndroid Build Coastguard Worker      if (curDict == dictionary) {
729*1b3f573fSAndroid Build Coastguard Worker        if ((field.mapKeyDataType == GPBDataTypeString) &&
730*1b3f573fSAndroid Build Coastguard Worker            GPBFieldDataTypeIsObject(field)) {
731*1b3f573fSAndroid Build Coastguard Worker          GPBAutocreatedDictionary *autoDict = dictionary;
732*1b3f573fSAndroid Build Coastguard Worker          autoDict->_autocreator = nil;
733*1b3f573fSAndroid Build Coastguard Worker        } else {
734*1b3f573fSAndroid Build Coastguard Worker          GPBInt32Int32Dictionary *gpbDict = dictionary;
735*1b3f573fSAndroid Build Coastguard Worker          gpbDict->_autocreator = nil;
736*1b3f573fSAndroid Build Coastguard Worker        }
737*1b3f573fSAndroid Build Coastguard Worker        GPBBecomeVisibleToAutocreator(self);
738*1b3f573fSAndroid Build Coastguard Worker        return;
739*1b3f573fSAndroid Build Coastguard Worker      }
740*1b3f573fSAndroid Build Coastguard Worker    }
741*1b3f573fSAndroid Build Coastguard Worker  }
742*1b3f573fSAndroid Build Coastguard Worker  NSCAssert(NO, @"Unknown autocreated %@ for %@.", [dictionary class], self);
743*1b3f573fSAndroid Build Coastguard Worker}
744*1b3f573fSAndroid Build Coastguard Worker
745*1b3f573fSAndroid Build Coastguard Workervoid GPBClearMessageAutocreator(GPBMessage *self) {
746*1b3f573fSAndroid Build Coastguard Worker  if ((self == nil) || !self->autocreator_) {
747*1b3f573fSAndroid Build Coastguard Worker    return;
748*1b3f573fSAndroid Build Coastguard Worker  }
749*1b3f573fSAndroid Build Coastguard Worker
750*1b3f573fSAndroid Build Coastguard Worker#if defined(DEBUG) && DEBUG && !defined(NS_BLOCK_ASSERTIONS)
751*1b3f573fSAndroid Build Coastguard Worker  // Either the autocreator must have its "has" flag set to YES, or it must be
752*1b3f573fSAndroid Build Coastguard Worker  // NO and not equal to ourselves.
753*1b3f573fSAndroid Build Coastguard Worker  BOOL autocreatorHas =
754*1b3f573fSAndroid Build Coastguard Worker      (self->autocreatorField_
755*1b3f573fSAndroid Build Coastguard Worker           ? GPBGetHasIvarField(self->autocreator_, self->autocreatorField_)
756*1b3f573fSAndroid Build Coastguard Worker           : [self->autocreator_ hasExtension:self->autocreatorExtension_]);
757*1b3f573fSAndroid Build Coastguard Worker  GPBMessage *autocreatorFieldValue =
758*1b3f573fSAndroid Build Coastguard Worker      (self->autocreatorField_
759*1b3f573fSAndroid Build Coastguard Worker           ? GPBGetObjectIvarWithFieldNoAutocreate(self->autocreator_,
760*1b3f573fSAndroid Build Coastguard Worker                                                   self->autocreatorField_)
761*1b3f573fSAndroid Build Coastguard Worker           : [self->autocreator_->autocreatedExtensionMap_
762*1b3f573fSAndroid Build Coastguard Worker                 objectForKey:self->autocreatorExtension_]);
763*1b3f573fSAndroid Build Coastguard Worker  NSCAssert(autocreatorHas || autocreatorFieldValue != self,
764*1b3f573fSAndroid Build Coastguard Worker            @"Cannot clear autocreator because it still refers to self, self: %@.",
765*1b3f573fSAndroid Build Coastguard Worker            self);
766*1b3f573fSAndroid Build Coastguard Worker
767*1b3f573fSAndroid Build Coastguard Worker#endif  // DEBUG && !defined(NS_BLOCK_ASSERTIONS)
768*1b3f573fSAndroid Build Coastguard Worker
769*1b3f573fSAndroid Build Coastguard Worker  self->autocreator_ = nil;
770*1b3f573fSAndroid Build Coastguard Worker  [self->autocreatorField_ release];
771*1b3f573fSAndroid Build Coastguard Worker  self->autocreatorField_ = nil;
772*1b3f573fSAndroid Build Coastguard Worker  [self->autocreatorExtension_ release];
773*1b3f573fSAndroid Build Coastguard Worker  self->autocreatorExtension_ = nil;
774*1b3f573fSAndroid Build Coastguard Worker}
775*1b3f573fSAndroid Build Coastguard Worker
776*1b3f573fSAndroid Build Coastguard Worker// Call this before using the readOnlySemaphore_. This ensures it is created only once.
777*1b3f573fSAndroid Build Coastguard Workervoid GPBPrepareReadOnlySemaphore(GPBMessage *self) {
778*1b3f573fSAndroid Build Coastguard Worker#pragma clang diagnostic push
779*1b3f573fSAndroid Build Coastguard Worker#pragma clang diagnostic ignored "-Wdirect-ivar-access"
780*1b3f573fSAndroid Build Coastguard Worker
781*1b3f573fSAndroid Build Coastguard Worker  // Create the semaphore on demand (rather than init) as developers might not cause them
782*1b3f573fSAndroid Build Coastguard Worker  // to be needed, and the heap usage can add up.  The atomic swap is used to avoid needing
783*1b3f573fSAndroid Build Coastguard Worker  // another lock around creating it.
784*1b3f573fSAndroid Build Coastguard Worker  if (self->readOnlySemaphore_ == nil) {
785*1b3f573fSAndroid Build Coastguard Worker    dispatch_semaphore_t worker = dispatch_semaphore_create(1);
786*1b3f573fSAndroid Build Coastguard Worker    dispatch_semaphore_t expected = nil;
787*1b3f573fSAndroid Build Coastguard Worker    if (!atomic_compare_exchange_strong(&self->readOnlySemaphore_, &expected, worker)) {
788*1b3f573fSAndroid Build Coastguard Worker      dispatch_release(worker);
789*1b3f573fSAndroid Build Coastguard Worker    }
790*1b3f573fSAndroid Build Coastguard Worker#if defined(__clang_analyzer__)
791*1b3f573fSAndroid Build Coastguard Worker    // The Xcode 9.2 (and 9.3 beta) static analyzer thinks worker is leaked
792*1b3f573fSAndroid Build Coastguard Worker    // (doesn't seem to know about atomic_compare_exchange_strong); so just
793*1b3f573fSAndroid Build Coastguard Worker    // for the analyzer, let it think worker is also released in this case.
794*1b3f573fSAndroid Build Coastguard Worker    else { dispatch_release(worker); }
795*1b3f573fSAndroid Build Coastguard Worker#endif
796*1b3f573fSAndroid Build Coastguard Worker  }
797*1b3f573fSAndroid Build Coastguard Worker
798*1b3f573fSAndroid Build Coastguard Worker#pragma clang diagnostic pop
799*1b3f573fSAndroid Build Coastguard Worker}
800*1b3f573fSAndroid Build Coastguard Worker
801*1b3f573fSAndroid Build Coastguard Workerstatic GPBUnknownFieldSet *GetOrMakeUnknownFields(GPBMessage *self) {
802*1b3f573fSAndroid Build Coastguard Worker  if (!self->unknownFields_) {
803*1b3f573fSAndroid Build Coastguard Worker    self->unknownFields_ = [[GPBUnknownFieldSet alloc] init];
804*1b3f573fSAndroid Build Coastguard Worker    GPBBecomeVisibleToAutocreator(self);
805*1b3f573fSAndroid Build Coastguard Worker  }
806*1b3f573fSAndroid Build Coastguard Worker  return self->unknownFields_;
807*1b3f573fSAndroid Build Coastguard Worker}
808*1b3f573fSAndroid Build Coastguard Worker
809*1b3f573fSAndroid Build Coastguard Worker@implementation GPBMessage
810*1b3f573fSAndroid Build Coastguard Worker
811*1b3f573fSAndroid Build Coastguard Worker+ (void)initialize {
812*1b3f573fSAndroid Build Coastguard Worker  Class pbMessageClass = [GPBMessage class];
813*1b3f573fSAndroid Build Coastguard Worker  if ([self class] == pbMessageClass) {
814*1b3f573fSAndroid Build Coastguard Worker    // This is here to start up the "base" class descriptor.
815*1b3f573fSAndroid Build Coastguard Worker    [self descriptor];
816*1b3f573fSAndroid Build Coastguard Worker    // Message shares extension method resolving with GPBRootObject so insure
817*1b3f573fSAndroid Build Coastguard Worker    // it is started up at the same time.
818*1b3f573fSAndroid Build Coastguard Worker    (void)[GPBRootObject class];
819*1b3f573fSAndroid Build Coastguard Worker  } else if ([self superclass] == pbMessageClass) {
820*1b3f573fSAndroid Build Coastguard Worker    // This is here to start up all the "message" subclasses. Just needs to be
821*1b3f573fSAndroid Build Coastguard Worker    // done for the messages, not any of the subclasses.
822*1b3f573fSAndroid Build Coastguard Worker    // This must be done in initialize to enforce thread safety of start up of
823*1b3f573fSAndroid Build Coastguard Worker    // the protocol buffer library.
824*1b3f573fSAndroid Build Coastguard Worker    // Note: The generated code for -descriptor calls
825*1b3f573fSAndroid Build Coastguard Worker    // +[GPBDescriptor allocDescriptorForClass:...], passing the GPBRootObject
826*1b3f573fSAndroid Build Coastguard Worker    // subclass for the file.  That call chain is what ensures that *Root class
827*1b3f573fSAndroid Build Coastguard Worker    // is started up to support extension resolution off the message class
828*1b3f573fSAndroid Build Coastguard Worker    // (+resolveClassMethod: below) in a thread safe manner.
829*1b3f573fSAndroid Build Coastguard Worker    [self descriptor];
830*1b3f573fSAndroid Build Coastguard Worker  }
831*1b3f573fSAndroid Build Coastguard Worker}
832*1b3f573fSAndroid Build Coastguard Worker
833*1b3f573fSAndroid Build Coastguard Worker+ (instancetype)allocWithZone:(NSZone *)zone {
834*1b3f573fSAndroid Build Coastguard Worker  // Override alloc to allocate our classes with the additional storage
835*1b3f573fSAndroid Build Coastguard Worker  // required for the instance variables.
836*1b3f573fSAndroid Build Coastguard Worker  GPBDescriptor *descriptor = [self descriptor];
837*1b3f573fSAndroid Build Coastguard Worker  return NSAllocateObject(self, descriptor->storageSize_, zone);
838*1b3f573fSAndroid Build Coastguard Worker}
839*1b3f573fSAndroid Build Coastguard Worker
840*1b3f573fSAndroid Build Coastguard Worker+ (instancetype)alloc {
841*1b3f573fSAndroid Build Coastguard Worker  return [self allocWithZone:nil];
842*1b3f573fSAndroid Build Coastguard Worker}
843*1b3f573fSAndroid Build Coastguard Worker
844*1b3f573fSAndroid Build Coastguard Worker+ (GPBDescriptor *)descriptor {
845*1b3f573fSAndroid Build Coastguard Worker  // This is thread safe because it is called from +initialize.
846*1b3f573fSAndroid Build Coastguard Worker  static GPBDescriptor *descriptor = NULL;
847*1b3f573fSAndroid Build Coastguard Worker  static GPBFileDescriptor *fileDescriptor = NULL;
848*1b3f573fSAndroid Build Coastguard Worker  if (!descriptor) {
849*1b3f573fSAndroid Build Coastguard Worker    // Use a dummy file that marks it as proto2 syntax so when used generically
850*1b3f573fSAndroid Build Coastguard Worker    // it supports unknowns/etc.
851*1b3f573fSAndroid Build Coastguard Worker    fileDescriptor =
852*1b3f573fSAndroid Build Coastguard Worker        [[GPBFileDescriptor alloc] initWithPackage:@"internal"
853*1b3f573fSAndroid Build Coastguard Worker                                            syntax:GPBFileSyntaxProto2];
854*1b3f573fSAndroid Build Coastguard Worker
855*1b3f573fSAndroid Build Coastguard Worker    descriptor = [GPBDescriptor allocDescriptorForClass:[GPBMessage class]
856*1b3f573fSAndroid Build Coastguard Worker                                              rootClass:Nil
857*1b3f573fSAndroid Build Coastguard Worker                                                   file:fileDescriptor
858*1b3f573fSAndroid Build Coastguard Worker                                                 fields:NULL
859*1b3f573fSAndroid Build Coastguard Worker                                             fieldCount:0
860*1b3f573fSAndroid Build Coastguard Worker                                            storageSize:0
861*1b3f573fSAndroid Build Coastguard Worker                                                  flags:0];
862*1b3f573fSAndroid Build Coastguard Worker  }
863*1b3f573fSAndroid Build Coastguard Worker  return descriptor;
864*1b3f573fSAndroid Build Coastguard Worker}
865*1b3f573fSAndroid Build Coastguard Worker
866*1b3f573fSAndroid Build Coastguard Worker+ (instancetype)message {
867*1b3f573fSAndroid Build Coastguard Worker  return [[[self alloc] init] autorelease];
868*1b3f573fSAndroid Build Coastguard Worker}
869*1b3f573fSAndroid Build Coastguard Worker
870*1b3f573fSAndroid Build Coastguard Worker- (instancetype)init {
871*1b3f573fSAndroid Build Coastguard Worker  if ((self = [super init])) {
872*1b3f573fSAndroid Build Coastguard Worker    messageStorage_ = (GPBMessage_StoragePtr)(
873*1b3f573fSAndroid Build Coastguard Worker        ((uint8_t *)self) + class_getInstanceSize([self class]));
874*1b3f573fSAndroid Build Coastguard Worker  }
875*1b3f573fSAndroid Build Coastguard Worker
876*1b3f573fSAndroid Build Coastguard Worker  return self;
877*1b3f573fSAndroid Build Coastguard Worker}
878*1b3f573fSAndroid Build Coastguard Worker
879*1b3f573fSAndroid Build Coastguard Worker- (instancetype)initWithData:(NSData *)data error:(NSError **)errorPtr {
880*1b3f573fSAndroid Build Coastguard Worker  return [self initWithData:data extensionRegistry:nil error:errorPtr];
881*1b3f573fSAndroid Build Coastguard Worker}
882*1b3f573fSAndroid Build Coastguard Worker
883*1b3f573fSAndroid Build Coastguard Worker- (instancetype)initWithData:(NSData *)data
884*1b3f573fSAndroid Build Coastguard Worker           extensionRegistry:(GPBExtensionRegistry *)extensionRegistry
885*1b3f573fSAndroid Build Coastguard Worker                       error:(NSError **)errorPtr {
886*1b3f573fSAndroid Build Coastguard Worker  if ((self = [self init])) {
887*1b3f573fSAndroid Build Coastguard Worker    @try {
888*1b3f573fSAndroid Build Coastguard Worker      [self mergeFromData:data extensionRegistry:extensionRegistry];
889*1b3f573fSAndroid Build Coastguard Worker      if (errorPtr) {
890*1b3f573fSAndroid Build Coastguard Worker        *errorPtr = nil;
891*1b3f573fSAndroid Build Coastguard Worker      }
892*1b3f573fSAndroid Build Coastguard Worker    }
893*1b3f573fSAndroid Build Coastguard Worker    @catch (NSException *exception) {
894*1b3f573fSAndroid Build Coastguard Worker      [self release];
895*1b3f573fSAndroid Build Coastguard Worker      self = nil;
896*1b3f573fSAndroid Build Coastguard Worker      if (errorPtr) {
897*1b3f573fSAndroid Build Coastguard Worker        *errorPtr = ErrorFromException(exception);
898*1b3f573fSAndroid Build Coastguard Worker      }
899*1b3f573fSAndroid Build Coastguard Worker    }
900*1b3f573fSAndroid Build Coastguard Worker#ifdef DEBUG
901*1b3f573fSAndroid Build Coastguard Worker    if (self && !self.initialized) {
902*1b3f573fSAndroid Build Coastguard Worker      [self release];
903*1b3f573fSAndroid Build Coastguard Worker      self = nil;
904*1b3f573fSAndroid Build Coastguard Worker      if (errorPtr) {
905*1b3f573fSAndroid Build Coastguard Worker        *errorPtr = MessageError(GPBMessageErrorCodeMissingRequiredField, nil);
906*1b3f573fSAndroid Build Coastguard Worker      }
907*1b3f573fSAndroid Build Coastguard Worker    }
908*1b3f573fSAndroid Build Coastguard Worker#endif
909*1b3f573fSAndroid Build Coastguard Worker  }
910*1b3f573fSAndroid Build Coastguard Worker  return self;
911*1b3f573fSAndroid Build Coastguard Worker}
912*1b3f573fSAndroid Build Coastguard Worker
913*1b3f573fSAndroid Build Coastguard Worker- (instancetype)initWithCodedInputStream:(GPBCodedInputStream *)input
914*1b3f573fSAndroid Build Coastguard Worker                       extensionRegistry:
915*1b3f573fSAndroid Build Coastguard Worker                           (GPBExtensionRegistry *)extensionRegistry
916*1b3f573fSAndroid Build Coastguard Worker                                   error:(NSError **)errorPtr {
917*1b3f573fSAndroid Build Coastguard Worker  if ((self = [self init])) {
918*1b3f573fSAndroid Build Coastguard Worker    @try {
919*1b3f573fSAndroid Build Coastguard Worker      [self mergeFromCodedInputStream:input extensionRegistry:extensionRegistry];
920*1b3f573fSAndroid Build Coastguard Worker      if (errorPtr) {
921*1b3f573fSAndroid Build Coastguard Worker        *errorPtr = nil;
922*1b3f573fSAndroid Build Coastguard Worker      }
923*1b3f573fSAndroid Build Coastguard Worker    }
924*1b3f573fSAndroid Build Coastguard Worker    @catch (NSException *exception) {
925*1b3f573fSAndroid Build Coastguard Worker      [self release];
926*1b3f573fSAndroid Build Coastguard Worker      self = nil;
927*1b3f573fSAndroid Build Coastguard Worker      if (errorPtr) {
928*1b3f573fSAndroid Build Coastguard Worker        *errorPtr = ErrorFromException(exception);
929*1b3f573fSAndroid Build Coastguard Worker      }
930*1b3f573fSAndroid Build Coastguard Worker    }
931*1b3f573fSAndroid Build Coastguard Worker#ifdef DEBUG
932*1b3f573fSAndroid Build Coastguard Worker    if (self && !self.initialized) {
933*1b3f573fSAndroid Build Coastguard Worker      [self release];
934*1b3f573fSAndroid Build Coastguard Worker      self = nil;
935*1b3f573fSAndroid Build Coastguard Worker      if (errorPtr) {
936*1b3f573fSAndroid Build Coastguard Worker        *errorPtr = MessageError(GPBMessageErrorCodeMissingRequiredField, nil);
937*1b3f573fSAndroid Build Coastguard Worker      }
938*1b3f573fSAndroid Build Coastguard Worker    }
939*1b3f573fSAndroid Build Coastguard Worker#endif
940*1b3f573fSAndroid Build Coastguard Worker  }
941*1b3f573fSAndroid Build Coastguard Worker  return self;
942*1b3f573fSAndroid Build Coastguard Worker}
943*1b3f573fSAndroid Build Coastguard Worker
944*1b3f573fSAndroid Build Coastguard Worker- (void)dealloc {
945*1b3f573fSAndroid Build Coastguard Worker  [self internalClear:NO];
946*1b3f573fSAndroid Build Coastguard Worker  NSCAssert(!autocreator_, @"Autocreator was not cleared before dealloc.");
947*1b3f573fSAndroid Build Coastguard Worker  if (readOnlySemaphore_) {
948*1b3f573fSAndroid Build Coastguard Worker    dispatch_release(readOnlySemaphore_);
949*1b3f573fSAndroid Build Coastguard Worker  }
950*1b3f573fSAndroid Build Coastguard Worker  [super dealloc];
951*1b3f573fSAndroid Build Coastguard Worker}
952*1b3f573fSAndroid Build Coastguard Worker
953*1b3f573fSAndroid Build Coastguard Worker- (void)copyFieldsInto:(GPBMessage *)message
954*1b3f573fSAndroid Build Coastguard Worker                  zone:(NSZone *)zone
955*1b3f573fSAndroid Build Coastguard Worker            descriptor:(GPBDescriptor *)descriptor {
956*1b3f573fSAndroid Build Coastguard Worker  // Copy all the storage...
957*1b3f573fSAndroid Build Coastguard Worker  memcpy(message->messageStorage_, messageStorage_, descriptor->storageSize_);
958*1b3f573fSAndroid Build Coastguard Worker
959*1b3f573fSAndroid Build Coastguard Worker  // Loop over the fields doing fixup...
960*1b3f573fSAndroid Build Coastguard Worker  for (GPBFieldDescriptor *field in descriptor->fields_) {
961*1b3f573fSAndroid Build Coastguard Worker    if (GPBFieldIsMapOrArray(field)) {
962*1b3f573fSAndroid Build Coastguard Worker      id value = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
963*1b3f573fSAndroid Build Coastguard Worker      if (value) {
964*1b3f573fSAndroid Build Coastguard Worker        // We need to copy the array/map, but the catch is for message fields,
965*1b3f573fSAndroid Build Coastguard Worker        // we also need to ensure all the messages as those need copying also.
966*1b3f573fSAndroid Build Coastguard Worker        id newValue;
967*1b3f573fSAndroid Build Coastguard Worker        if (GPBFieldDataTypeIsMessage(field)) {
968*1b3f573fSAndroid Build Coastguard Worker          if (field.fieldType == GPBFieldTypeRepeated) {
969*1b3f573fSAndroid Build Coastguard Worker            NSArray *existingArray = (NSArray *)value;
970*1b3f573fSAndroid Build Coastguard Worker            NSMutableArray *newArray =
971*1b3f573fSAndroid Build Coastguard Worker                [[NSMutableArray alloc] initWithCapacity:existingArray.count];
972*1b3f573fSAndroid Build Coastguard Worker            newValue = newArray;
973*1b3f573fSAndroid Build Coastguard Worker            for (GPBMessage *msg in existingArray) {
974*1b3f573fSAndroid Build Coastguard Worker              GPBMessage *copiedMsg = [msg copyWithZone:zone];
975*1b3f573fSAndroid Build Coastguard Worker              [newArray addObject:copiedMsg];
976*1b3f573fSAndroid Build Coastguard Worker              [copiedMsg release];
977*1b3f573fSAndroid Build Coastguard Worker            }
978*1b3f573fSAndroid Build Coastguard Worker          } else {
979*1b3f573fSAndroid Build Coastguard Worker            if (field.mapKeyDataType == GPBDataTypeString) {
980*1b3f573fSAndroid Build Coastguard Worker              // Map is an NSDictionary.
981*1b3f573fSAndroid Build Coastguard Worker              NSDictionary *existingDict = value;
982*1b3f573fSAndroid Build Coastguard Worker              NSMutableDictionary *newDict = [[NSMutableDictionary alloc]
983*1b3f573fSAndroid Build Coastguard Worker                  initWithCapacity:existingDict.count];
984*1b3f573fSAndroid Build Coastguard Worker              newValue = newDict;
985*1b3f573fSAndroid Build Coastguard Worker              [existingDict enumerateKeysAndObjectsUsingBlock:^(NSString *key,
986*1b3f573fSAndroid Build Coastguard Worker                                                                GPBMessage *msg,
987*1b3f573fSAndroid Build Coastguard Worker                                                                BOOL *stop) {
988*1b3f573fSAndroid Build Coastguard Worker#pragma unused(stop)
989*1b3f573fSAndroid Build Coastguard Worker                GPBMessage *copiedMsg = [msg copyWithZone:zone];
990*1b3f573fSAndroid Build Coastguard Worker                [newDict setObject:copiedMsg forKey:key];
991*1b3f573fSAndroid Build Coastguard Worker                [copiedMsg release];
992*1b3f573fSAndroid Build Coastguard Worker              }];
993*1b3f573fSAndroid Build Coastguard Worker            } else {
994*1b3f573fSAndroid Build Coastguard Worker              // Is one of the GPB*ObjectDictionary classes.  Type doesn't
995*1b3f573fSAndroid Build Coastguard Worker              // matter, just need one to invoke the selector.
996*1b3f573fSAndroid Build Coastguard Worker              GPBInt32ObjectDictionary *existingDict = value;
997*1b3f573fSAndroid Build Coastguard Worker              newValue = [existingDict deepCopyWithZone:zone];
998*1b3f573fSAndroid Build Coastguard Worker            }
999*1b3f573fSAndroid Build Coastguard Worker          }
1000*1b3f573fSAndroid Build Coastguard Worker        } else {
1001*1b3f573fSAndroid Build Coastguard Worker          // Not messages (but is a map/array)...
1002*1b3f573fSAndroid Build Coastguard Worker          if (field.fieldType == GPBFieldTypeRepeated) {
1003*1b3f573fSAndroid Build Coastguard Worker            if (GPBFieldDataTypeIsObject(field)) {
1004*1b3f573fSAndroid Build Coastguard Worker              // NSArray
1005*1b3f573fSAndroid Build Coastguard Worker              newValue = [value mutableCopyWithZone:zone];
1006*1b3f573fSAndroid Build Coastguard Worker            } else {
1007*1b3f573fSAndroid Build Coastguard Worker              // GPB*Array
1008*1b3f573fSAndroid Build Coastguard Worker              newValue = [value copyWithZone:zone];
1009*1b3f573fSAndroid Build Coastguard Worker            }
1010*1b3f573fSAndroid Build Coastguard Worker          } else {
1011*1b3f573fSAndroid Build Coastguard Worker            if ((field.mapKeyDataType == GPBDataTypeString) &&
1012*1b3f573fSAndroid Build Coastguard Worker                GPBFieldDataTypeIsObject(field)) {
1013*1b3f573fSAndroid Build Coastguard Worker              // NSDictionary
1014*1b3f573fSAndroid Build Coastguard Worker              newValue = [value mutableCopyWithZone:zone];
1015*1b3f573fSAndroid Build Coastguard Worker            } else {
1016*1b3f573fSAndroid Build Coastguard Worker              // Is one of the GPB*Dictionary classes.  Type doesn't matter,
1017*1b3f573fSAndroid Build Coastguard Worker              // just need one to invoke the selector.
1018*1b3f573fSAndroid Build Coastguard Worker              GPBInt32Int32Dictionary *existingDict = value;
1019*1b3f573fSAndroid Build Coastguard Worker              newValue = [existingDict copyWithZone:zone];
1020*1b3f573fSAndroid Build Coastguard Worker            }
1021*1b3f573fSAndroid Build Coastguard Worker          }
1022*1b3f573fSAndroid Build Coastguard Worker        }
1023*1b3f573fSAndroid Build Coastguard Worker        // We retain here because the memcpy picked up the pointer value and
1024*1b3f573fSAndroid Build Coastguard Worker        // the next call to SetRetainedObject... will release the current value.
1025*1b3f573fSAndroid Build Coastguard Worker        [value retain];
1026*1b3f573fSAndroid Build Coastguard Worker        GPBSetRetainedObjectIvarWithFieldPrivate(message, field, newValue);
1027*1b3f573fSAndroid Build Coastguard Worker      }
1028*1b3f573fSAndroid Build Coastguard Worker    } else if (GPBFieldDataTypeIsMessage(field)) {
1029*1b3f573fSAndroid Build Coastguard Worker      // For object types, if we have a value, copy it.  If we don't,
1030*1b3f573fSAndroid Build Coastguard Worker      // zero it to remove the pointer to something that was autocreated
1031*1b3f573fSAndroid Build Coastguard Worker      // (and the ptr just got memcpyed).
1032*1b3f573fSAndroid Build Coastguard Worker      if (GPBGetHasIvarField(self, field)) {
1033*1b3f573fSAndroid Build Coastguard Worker        GPBMessage *value = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1034*1b3f573fSAndroid Build Coastguard Worker        GPBMessage *newValue = [value copyWithZone:zone];
1035*1b3f573fSAndroid Build Coastguard Worker        // We retain here because the memcpy picked up the pointer value and
1036*1b3f573fSAndroid Build Coastguard Worker        // the next call to SetRetainedObject... will release the current value.
1037*1b3f573fSAndroid Build Coastguard Worker        [value retain];
1038*1b3f573fSAndroid Build Coastguard Worker        GPBSetRetainedObjectIvarWithFieldPrivate(message, field, newValue);
1039*1b3f573fSAndroid Build Coastguard Worker      } else {
1040*1b3f573fSAndroid Build Coastguard Worker        uint8_t *storage = (uint8_t *)message->messageStorage_;
1041*1b3f573fSAndroid Build Coastguard Worker        id *typePtr = (id *)&storage[field->description_->offset];
1042*1b3f573fSAndroid Build Coastguard Worker        *typePtr = NULL;
1043*1b3f573fSAndroid Build Coastguard Worker      }
1044*1b3f573fSAndroid Build Coastguard Worker    } else if (GPBFieldDataTypeIsObject(field) &&
1045*1b3f573fSAndroid Build Coastguard Worker               GPBGetHasIvarField(self, field)) {
1046*1b3f573fSAndroid Build Coastguard Worker      // A set string/data value (message picked off above), copy it.
1047*1b3f573fSAndroid Build Coastguard Worker      id value = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1048*1b3f573fSAndroid Build Coastguard Worker      id newValue = [value copyWithZone:zone];
1049*1b3f573fSAndroid Build Coastguard Worker      // We retain here because the memcpy picked up the pointer value and
1050*1b3f573fSAndroid Build Coastguard Worker      // the next call to SetRetainedObject... will release the current value.
1051*1b3f573fSAndroid Build Coastguard Worker      [value retain];
1052*1b3f573fSAndroid Build Coastguard Worker      GPBSetRetainedObjectIvarWithFieldPrivate(message, field, newValue);
1053*1b3f573fSAndroid Build Coastguard Worker    } else {
1054*1b3f573fSAndroid Build Coastguard Worker      // memcpy took care of the rest of the primitive fields if they were set.
1055*1b3f573fSAndroid Build Coastguard Worker    }
1056*1b3f573fSAndroid Build Coastguard Worker  }  // for (field in descriptor->fields_)
1057*1b3f573fSAndroid Build Coastguard Worker}
1058*1b3f573fSAndroid Build Coastguard Worker
1059*1b3f573fSAndroid Build Coastguard Worker- (id)copyWithZone:(NSZone *)zone {
1060*1b3f573fSAndroid Build Coastguard Worker  GPBDescriptor *descriptor = [self descriptor];
1061*1b3f573fSAndroid Build Coastguard Worker  GPBMessage *result = [[descriptor.messageClass allocWithZone:zone] init];
1062*1b3f573fSAndroid Build Coastguard Worker
1063*1b3f573fSAndroid Build Coastguard Worker  [self copyFieldsInto:result zone:zone descriptor:descriptor];
1064*1b3f573fSAndroid Build Coastguard Worker  // Make immutable copies of the extra bits.
1065*1b3f573fSAndroid Build Coastguard Worker  result->unknownFields_ = [unknownFields_ copyWithZone:zone];
1066*1b3f573fSAndroid Build Coastguard Worker  result->extensionMap_ = CloneExtensionMap(extensionMap_, zone);
1067*1b3f573fSAndroid Build Coastguard Worker  return result;
1068*1b3f573fSAndroid Build Coastguard Worker}
1069*1b3f573fSAndroid Build Coastguard Worker
1070*1b3f573fSAndroid Build Coastguard Worker- (void)clear {
1071*1b3f573fSAndroid Build Coastguard Worker  [self internalClear:YES];
1072*1b3f573fSAndroid Build Coastguard Worker}
1073*1b3f573fSAndroid Build Coastguard Worker
1074*1b3f573fSAndroid Build Coastguard Worker- (void)internalClear:(BOOL)zeroStorage {
1075*1b3f573fSAndroid Build Coastguard Worker  GPBDescriptor *descriptor = [self descriptor];
1076*1b3f573fSAndroid Build Coastguard Worker  for (GPBFieldDescriptor *field in descriptor->fields_) {
1077*1b3f573fSAndroid Build Coastguard Worker    if (GPBFieldIsMapOrArray(field)) {
1078*1b3f573fSAndroid Build Coastguard Worker      id arrayOrMap = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1079*1b3f573fSAndroid Build Coastguard Worker      if (arrayOrMap) {
1080*1b3f573fSAndroid Build Coastguard Worker        if (field.fieldType == GPBFieldTypeRepeated) {
1081*1b3f573fSAndroid Build Coastguard Worker          if (GPBFieldDataTypeIsObject(field)) {
1082*1b3f573fSAndroid Build Coastguard Worker            if ([arrayOrMap isKindOfClass:[GPBAutocreatedArray class]]) {
1083*1b3f573fSAndroid Build Coastguard Worker              GPBAutocreatedArray *autoArray = arrayOrMap;
1084*1b3f573fSAndroid Build Coastguard Worker              if (autoArray->_autocreator == self) {
1085*1b3f573fSAndroid Build Coastguard Worker                autoArray->_autocreator = nil;
1086*1b3f573fSAndroid Build Coastguard Worker              }
1087*1b3f573fSAndroid Build Coastguard Worker            }
1088*1b3f573fSAndroid Build Coastguard Worker          } else {
1089*1b3f573fSAndroid Build Coastguard Worker            // Type doesn't matter, it is a GPB*Array.
1090*1b3f573fSAndroid Build Coastguard Worker            GPBInt32Array *gpbArray = arrayOrMap;
1091*1b3f573fSAndroid Build Coastguard Worker            if (gpbArray->_autocreator == self) {
1092*1b3f573fSAndroid Build Coastguard Worker              gpbArray->_autocreator = nil;
1093*1b3f573fSAndroid Build Coastguard Worker            }
1094*1b3f573fSAndroid Build Coastguard Worker          }
1095*1b3f573fSAndroid Build Coastguard Worker        } else {
1096*1b3f573fSAndroid Build Coastguard Worker          if ((field.mapKeyDataType == GPBDataTypeString) &&
1097*1b3f573fSAndroid Build Coastguard Worker              GPBFieldDataTypeIsObject(field)) {
1098*1b3f573fSAndroid Build Coastguard Worker            if ([arrayOrMap isKindOfClass:[GPBAutocreatedDictionary class]]) {
1099*1b3f573fSAndroid Build Coastguard Worker              GPBAutocreatedDictionary *autoDict = arrayOrMap;
1100*1b3f573fSAndroid Build Coastguard Worker              if (autoDict->_autocreator == self) {
1101*1b3f573fSAndroid Build Coastguard Worker                autoDict->_autocreator = nil;
1102*1b3f573fSAndroid Build Coastguard Worker              }
1103*1b3f573fSAndroid Build Coastguard Worker            }
1104*1b3f573fSAndroid Build Coastguard Worker          } else {
1105*1b3f573fSAndroid Build Coastguard Worker            // Type doesn't matter, it is a GPB*Dictionary.
1106*1b3f573fSAndroid Build Coastguard Worker            GPBInt32Int32Dictionary *gpbDict = arrayOrMap;
1107*1b3f573fSAndroid Build Coastguard Worker            if (gpbDict->_autocreator == self) {
1108*1b3f573fSAndroid Build Coastguard Worker              gpbDict->_autocreator = nil;
1109*1b3f573fSAndroid Build Coastguard Worker            }
1110*1b3f573fSAndroid Build Coastguard Worker          }
1111*1b3f573fSAndroid Build Coastguard Worker        }
1112*1b3f573fSAndroid Build Coastguard Worker        [arrayOrMap release];
1113*1b3f573fSAndroid Build Coastguard Worker      }
1114*1b3f573fSAndroid Build Coastguard Worker    } else if (GPBFieldDataTypeIsMessage(field)) {
1115*1b3f573fSAndroid Build Coastguard Worker      GPBClearAutocreatedMessageIvarWithField(self, field);
1116*1b3f573fSAndroid Build Coastguard Worker      GPBMessage *value = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1117*1b3f573fSAndroid Build Coastguard Worker      [value release];
1118*1b3f573fSAndroid Build Coastguard Worker    } else if (GPBFieldDataTypeIsObject(field) &&
1119*1b3f573fSAndroid Build Coastguard Worker               GPBGetHasIvarField(self, field)) {
1120*1b3f573fSAndroid Build Coastguard Worker      id value = GPBGetObjectIvarWithField(self, field);
1121*1b3f573fSAndroid Build Coastguard Worker      [value release];
1122*1b3f573fSAndroid Build Coastguard Worker    }
1123*1b3f573fSAndroid Build Coastguard Worker  }
1124*1b3f573fSAndroid Build Coastguard Worker
1125*1b3f573fSAndroid Build Coastguard Worker  // GPBClearMessageAutocreator() expects that its caller has already been
1126*1b3f573fSAndroid Build Coastguard Worker  // removed from autocreatedExtensionMap_ so we set to nil first.
1127*1b3f573fSAndroid Build Coastguard Worker  NSArray *autocreatedValues = [autocreatedExtensionMap_ allValues];
1128*1b3f573fSAndroid Build Coastguard Worker  [autocreatedExtensionMap_ release];
1129*1b3f573fSAndroid Build Coastguard Worker  autocreatedExtensionMap_ = nil;
1130*1b3f573fSAndroid Build Coastguard Worker
1131*1b3f573fSAndroid Build Coastguard Worker  // Since we're clearing all of our extensions, make sure that we clear the
1132*1b3f573fSAndroid Build Coastguard Worker  // autocreator on any that we've created so they no longer refer to us.
1133*1b3f573fSAndroid Build Coastguard Worker  for (GPBMessage *value in autocreatedValues) {
1134*1b3f573fSAndroid Build Coastguard Worker    NSCAssert(GPBWasMessageAutocreatedBy(value, self),
1135*1b3f573fSAndroid Build Coastguard Worker              @"Autocreated extension does not refer back to self.");
1136*1b3f573fSAndroid Build Coastguard Worker    GPBClearMessageAutocreator(value);
1137*1b3f573fSAndroid Build Coastguard Worker  }
1138*1b3f573fSAndroid Build Coastguard Worker
1139*1b3f573fSAndroid Build Coastguard Worker  [extensionMap_ release];
1140*1b3f573fSAndroid Build Coastguard Worker  extensionMap_ = nil;
1141*1b3f573fSAndroid Build Coastguard Worker  [unknownFields_ release];
1142*1b3f573fSAndroid Build Coastguard Worker  unknownFields_ = nil;
1143*1b3f573fSAndroid Build Coastguard Worker
1144*1b3f573fSAndroid Build Coastguard Worker  // Note that clearing does not affect autocreator_. If we are being cleared
1145*1b3f573fSAndroid Build Coastguard Worker  // because of a dealloc, then autocreator_ should be nil anyway. If we are
1146*1b3f573fSAndroid Build Coastguard Worker  // being cleared because someone explicitly clears us, we don't want to
1147*1b3f573fSAndroid Build Coastguard Worker  // sever our relationship with our autocreator.
1148*1b3f573fSAndroid Build Coastguard Worker
1149*1b3f573fSAndroid Build Coastguard Worker  if (zeroStorage) {
1150*1b3f573fSAndroid Build Coastguard Worker    memset(messageStorage_, 0, descriptor->storageSize_);
1151*1b3f573fSAndroid Build Coastguard Worker  }
1152*1b3f573fSAndroid Build Coastguard Worker}
1153*1b3f573fSAndroid Build Coastguard Worker
1154*1b3f573fSAndroid Build Coastguard Worker- (BOOL)isInitialized {
1155*1b3f573fSAndroid Build Coastguard Worker  GPBDescriptor *descriptor = [self descriptor];
1156*1b3f573fSAndroid Build Coastguard Worker  for (GPBFieldDescriptor *field in descriptor->fields_) {
1157*1b3f573fSAndroid Build Coastguard Worker    if (field.isRequired) {
1158*1b3f573fSAndroid Build Coastguard Worker      if (!GPBGetHasIvarField(self, field)) {
1159*1b3f573fSAndroid Build Coastguard Worker        return NO;
1160*1b3f573fSAndroid Build Coastguard Worker      }
1161*1b3f573fSAndroid Build Coastguard Worker    }
1162*1b3f573fSAndroid Build Coastguard Worker    if (GPBFieldDataTypeIsMessage(field)) {
1163*1b3f573fSAndroid Build Coastguard Worker      GPBFieldType fieldType = field.fieldType;
1164*1b3f573fSAndroid Build Coastguard Worker      if (fieldType == GPBFieldTypeSingle) {
1165*1b3f573fSAndroid Build Coastguard Worker        if (field.isRequired) {
1166*1b3f573fSAndroid Build Coastguard Worker          GPBMessage *message = GPBGetMessageMessageField(self, field);
1167*1b3f573fSAndroid Build Coastguard Worker          if (!message.initialized) {
1168*1b3f573fSAndroid Build Coastguard Worker            return NO;
1169*1b3f573fSAndroid Build Coastguard Worker          }
1170*1b3f573fSAndroid Build Coastguard Worker        } else {
1171*1b3f573fSAndroid Build Coastguard Worker          NSAssert(field.isOptional,
1172*1b3f573fSAndroid Build Coastguard Worker                   @"%@: Single message field %@ not required or optional?",
1173*1b3f573fSAndroid Build Coastguard Worker                   [self class], field.name);
1174*1b3f573fSAndroid Build Coastguard Worker          if (GPBGetHasIvarField(self, field)) {
1175*1b3f573fSAndroid Build Coastguard Worker            GPBMessage *message = GPBGetMessageMessageField(self, field);
1176*1b3f573fSAndroid Build Coastguard Worker            if (!message.initialized) {
1177*1b3f573fSAndroid Build Coastguard Worker              return NO;
1178*1b3f573fSAndroid Build Coastguard Worker            }
1179*1b3f573fSAndroid Build Coastguard Worker          }
1180*1b3f573fSAndroid Build Coastguard Worker        }
1181*1b3f573fSAndroid Build Coastguard Worker      } else if (fieldType == GPBFieldTypeRepeated) {
1182*1b3f573fSAndroid Build Coastguard Worker        NSArray *array = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1183*1b3f573fSAndroid Build Coastguard Worker        for (GPBMessage *message in array) {
1184*1b3f573fSAndroid Build Coastguard Worker          if (!message.initialized) {
1185*1b3f573fSAndroid Build Coastguard Worker            return NO;
1186*1b3f573fSAndroid Build Coastguard Worker          }
1187*1b3f573fSAndroid Build Coastguard Worker        }
1188*1b3f573fSAndroid Build Coastguard Worker      } else {  // fieldType == GPBFieldTypeMap
1189*1b3f573fSAndroid Build Coastguard Worker        if (field.mapKeyDataType == GPBDataTypeString) {
1190*1b3f573fSAndroid Build Coastguard Worker          NSDictionary *map =
1191*1b3f573fSAndroid Build Coastguard Worker              GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1192*1b3f573fSAndroid Build Coastguard Worker          if (map && !GPBDictionaryIsInitializedInternalHelper(map, field)) {
1193*1b3f573fSAndroid Build Coastguard Worker            return NO;
1194*1b3f573fSAndroid Build Coastguard Worker          }
1195*1b3f573fSAndroid Build Coastguard Worker        } else {
1196*1b3f573fSAndroid Build Coastguard Worker          // Real type is GPB*ObjectDictionary, exact type doesn't matter.
1197*1b3f573fSAndroid Build Coastguard Worker          GPBInt32ObjectDictionary *map =
1198*1b3f573fSAndroid Build Coastguard Worker              GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1199*1b3f573fSAndroid Build Coastguard Worker          if (map && ![map isInitialized]) {
1200*1b3f573fSAndroid Build Coastguard Worker            return NO;
1201*1b3f573fSAndroid Build Coastguard Worker          }
1202*1b3f573fSAndroid Build Coastguard Worker        }
1203*1b3f573fSAndroid Build Coastguard Worker      }
1204*1b3f573fSAndroid Build Coastguard Worker    }
1205*1b3f573fSAndroid Build Coastguard Worker  }
1206*1b3f573fSAndroid Build Coastguard Worker
1207*1b3f573fSAndroid Build Coastguard Worker  __block BOOL result = YES;
1208*1b3f573fSAndroid Build Coastguard Worker  [extensionMap_
1209*1b3f573fSAndroid Build Coastguard Worker      enumerateKeysAndObjectsUsingBlock:^(GPBExtensionDescriptor *extension,
1210*1b3f573fSAndroid Build Coastguard Worker                                          id obj,
1211*1b3f573fSAndroid Build Coastguard Worker                                          BOOL *stop) {
1212*1b3f573fSAndroid Build Coastguard Worker        if (GPBExtensionIsMessage(extension)) {
1213*1b3f573fSAndroid Build Coastguard Worker          if (extension.isRepeated) {
1214*1b3f573fSAndroid Build Coastguard Worker            for (GPBMessage *msg in obj) {
1215*1b3f573fSAndroid Build Coastguard Worker              if (!msg.initialized) {
1216*1b3f573fSAndroid Build Coastguard Worker                result = NO;
1217*1b3f573fSAndroid Build Coastguard Worker                *stop = YES;
1218*1b3f573fSAndroid Build Coastguard Worker                break;
1219*1b3f573fSAndroid Build Coastguard Worker              }
1220*1b3f573fSAndroid Build Coastguard Worker            }
1221*1b3f573fSAndroid Build Coastguard Worker          } else {
1222*1b3f573fSAndroid Build Coastguard Worker            GPBMessage *asMsg = obj;
1223*1b3f573fSAndroid Build Coastguard Worker            if (!asMsg.initialized) {
1224*1b3f573fSAndroid Build Coastguard Worker              result = NO;
1225*1b3f573fSAndroid Build Coastguard Worker              *stop = YES;
1226*1b3f573fSAndroid Build Coastguard Worker            }
1227*1b3f573fSAndroid Build Coastguard Worker          }
1228*1b3f573fSAndroid Build Coastguard Worker        }
1229*1b3f573fSAndroid Build Coastguard Worker      }];
1230*1b3f573fSAndroid Build Coastguard Worker  return result;
1231*1b3f573fSAndroid Build Coastguard Worker}
1232*1b3f573fSAndroid Build Coastguard Worker
1233*1b3f573fSAndroid Build Coastguard Worker- (GPBDescriptor *)descriptor {
1234*1b3f573fSAndroid Build Coastguard Worker  return [[self class] descriptor];
1235*1b3f573fSAndroid Build Coastguard Worker}
1236*1b3f573fSAndroid Build Coastguard Worker
1237*1b3f573fSAndroid Build Coastguard Worker- (NSData *)data {
1238*1b3f573fSAndroid Build Coastguard Worker#ifdef DEBUG
1239*1b3f573fSAndroid Build Coastguard Worker  if (!self.initialized) {
1240*1b3f573fSAndroid Build Coastguard Worker    return nil;
1241*1b3f573fSAndroid Build Coastguard Worker  }
1242*1b3f573fSAndroid Build Coastguard Worker#endif
1243*1b3f573fSAndroid Build Coastguard Worker  NSMutableData *data = [NSMutableData dataWithLength:[self serializedSize]];
1244*1b3f573fSAndroid Build Coastguard Worker  GPBCodedOutputStream *stream =
1245*1b3f573fSAndroid Build Coastguard Worker      [[GPBCodedOutputStream alloc] initWithData:data];
1246*1b3f573fSAndroid Build Coastguard Worker  @try {
1247*1b3f573fSAndroid Build Coastguard Worker    [self writeToCodedOutputStream:stream];
1248*1b3f573fSAndroid Build Coastguard Worker  }
1249*1b3f573fSAndroid Build Coastguard Worker  @catch (NSException *exception) {
1250*1b3f573fSAndroid Build Coastguard Worker    // This really shouldn't happen. The only way writeToCodedOutputStream:
1251*1b3f573fSAndroid Build Coastguard Worker    // could throw is if something in the library has a bug and the
1252*1b3f573fSAndroid Build Coastguard Worker    // serializedSize was wrong.
1253*1b3f573fSAndroid Build Coastguard Worker#ifdef DEBUG
1254*1b3f573fSAndroid Build Coastguard Worker    NSLog(@"%@: Internal exception while building message data: %@",
1255*1b3f573fSAndroid Build Coastguard Worker          [self class], exception);
1256*1b3f573fSAndroid Build Coastguard Worker#endif
1257*1b3f573fSAndroid Build Coastguard Worker    data = nil;
1258*1b3f573fSAndroid Build Coastguard Worker  }
1259*1b3f573fSAndroid Build Coastguard Worker  [stream release];
1260*1b3f573fSAndroid Build Coastguard Worker  return data;
1261*1b3f573fSAndroid Build Coastguard Worker}
1262*1b3f573fSAndroid Build Coastguard Worker
1263*1b3f573fSAndroid Build Coastguard Worker- (NSData *)delimitedData {
1264*1b3f573fSAndroid Build Coastguard Worker  size_t serializedSize = [self serializedSize];
1265*1b3f573fSAndroid Build Coastguard Worker  size_t varintSize = GPBComputeRawVarint32SizeForInteger(serializedSize);
1266*1b3f573fSAndroid Build Coastguard Worker  NSMutableData *data =
1267*1b3f573fSAndroid Build Coastguard Worker      [NSMutableData dataWithLength:(serializedSize + varintSize)];
1268*1b3f573fSAndroid Build Coastguard Worker  GPBCodedOutputStream *stream =
1269*1b3f573fSAndroid Build Coastguard Worker      [[GPBCodedOutputStream alloc] initWithData:data];
1270*1b3f573fSAndroid Build Coastguard Worker  @try {
1271*1b3f573fSAndroid Build Coastguard Worker    [self writeDelimitedToCodedOutputStream:stream];
1272*1b3f573fSAndroid Build Coastguard Worker  }
1273*1b3f573fSAndroid Build Coastguard Worker  @catch (NSException *exception) {
1274*1b3f573fSAndroid Build Coastguard Worker    // This really shouldn't happen.  The only way writeToCodedOutputStream:
1275*1b3f573fSAndroid Build Coastguard Worker    // could throw is if something in the library has a bug and the
1276*1b3f573fSAndroid Build Coastguard Worker    // serializedSize was wrong.
1277*1b3f573fSAndroid Build Coastguard Worker#ifdef DEBUG
1278*1b3f573fSAndroid Build Coastguard Worker    NSLog(@"%@: Internal exception while building message delimitedData: %@",
1279*1b3f573fSAndroid Build Coastguard Worker          [self class], exception);
1280*1b3f573fSAndroid Build Coastguard Worker#endif
1281*1b3f573fSAndroid Build Coastguard Worker    // If it happens, truncate.
1282*1b3f573fSAndroid Build Coastguard Worker    data.length = 0;
1283*1b3f573fSAndroid Build Coastguard Worker  }
1284*1b3f573fSAndroid Build Coastguard Worker  [stream release];
1285*1b3f573fSAndroid Build Coastguard Worker  return data;
1286*1b3f573fSAndroid Build Coastguard Worker}
1287*1b3f573fSAndroid Build Coastguard Worker
1288*1b3f573fSAndroid Build Coastguard Worker- (void)writeToOutputStream:(NSOutputStream *)output {
1289*1b3f573fSAndroid Build Coastguard Worker  GPBCodedOutputStream *stream =
1290*1b3f573fSAndroid Build Coastguard Worker      [[GPBCodedOutputStream alloc] initWithOutputStream:output];
1291*1b3f573fSAndroid Build Coastguard Worker  [self writeToCodedOutputStream:stream];
1292*1b3f573fSAndroid Build Coastguard Worker  [stream release];
1293*1b3f573fSAndroid Build Coastguard Worker}
1294*1b3f573fSAndroid Build Coastguard Worker
1295*1b3f573fSAndroid Build Coastguard Worker- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)output {
1296*1b3f573fSAndroid Build Coastguard Worker  GPBDescriptor *descriptor = [self descriptor];
1297*1b3f573fSAndroid Build Coastguard Worker  NSArray *fieldsArray = descriptor->fields_;
1298*1b3f573fSAndroid Build Coastguard Worker  NSUInteger fieldCount = fieldsArray.count;
1299*1b3f573fSAndroid Build Coastguard Worker  const GPBExtensionRange *extensionRanges = descriptor.extensionRanges;
1300*1b3f573fSAndroid Build Coastguard Worker  NSUInteger extensionRangesCount = descriptor.extensionRangesCount;
1301*1b3f573fSAndroid Build Coastguard Worker  NSArray *sortedExtensions =
1302*1b3f573fSAndroid Build Coastguard Worker      [[extensionMap_ allKeys] sortedArrayUsingSelector:@selector(compareByFieldNumber:)];
1303*1b3f573fSAndroid Build Coastguard Worker  for (NSUInteger i = 0, j = 0; i < fieldCount || j < extensionRangesCount;) {
1304*1b3f573fSAndroid Build Coastguard Worker    if (i == fieldCount) {
1305*1b3f573fSAndroid Build Coastguard Worker      [self writeExtensionsToCodedOutputStream:output
1306*1b3f573fSAndroid Build Coastguard Worker                                         range:extensionRanges[j++]
1307*1b3f573fSAndroid Build Coastguard Worker                              sortedExtensions:sortedExtensions];
1308*1b3f573fSAndroid Build Coastguard Worker    } else if (j == extensionRangesCount ||
1309*1b3f573fSAndroid Build Coastguard Worker               GPBFieldNumber(fieldsArray[i]) < extensionRanges[j].start) {
1310*1b3f573fSAndroid Build Coastguard Worker      [self writeField:fieldsArray[i++] toCodedOutputStream:output];
1311*1b3f573fSAndroid Build Coastguard Worker    } else {
1312*1b3f573fSAndroid Build Coastguard Worker      [self writeExtensionsToCodedOutputStream:output
1313*1b3f573fSAndroid Build Coastguard Worker                                         range:extensionRanges[j++]
1314*1b3f573fSAndroid Build Coastguard Worker                              sortedExtensions:sortedExtensions];
1315*1b3f573fSAndroid Build Coastguard Worker    }
1316*1b3f573fSAndroid Build Coastguard Worker  }
1317*1b3f573fSAndroid Build Coastguard Worker  if (descriptor.isWireFormat) {
1318*1b3f573fSAndroid Build Coastguard Worker    [unknownFields_ writeAsMessageSetTo:output];
1319*1b3f573fSAndroid Build Coastguard Worker  } else {
1320*1b3f573fSAndroid Build Coastguard Worker    [unknownFields_ writeToCodedOutputStream:output];
1321*1b3f573fSAndroid Build Coastguard Worker  }
1322*1b3f573fSAndroid Build Coastguard Worker}
1323*1b3f573fSAndroid Build Coastguard Worker
1324*1b3f573fSAndroid Build Coastguard Worker- (void)writeDelimitedToOutputStream:(NSOutputStream *)output {
1325*1b3f573fSAndroid Build Coastguard Worker  GPBCodedOutputStream *codedOutput =
1326*1b3f573fSAndroid Build Coastguard Worker      [[GPBCodedOutputStream alloc] initWithOutputStream:output];
1327*1b3f573fSAndroid Build Coastguard Worker  [self writeDelimitedToCodedOutputStream:codedOutput];
1328*1b3f573fSAndroid Build Coastguard Worker  [codedOutput release];
1329*1b3f573fSAndroid Build Coastguard Worker}
1330*1b3f573fSAndroid Build Coastguard Worker
1331*1b3f573fSAndroid Build Coastguard Worker- (void)writeDelimitedToCodedOutputStream:(GPBCodedOutputStream *)output {
1332*1b3f573fSAndroid Build Coastguard Worker  [output writeRawVarintSizeTAs32:[self serializedSize]];
1333*1b3f573fSAndroid Build Coastguard Worker  [self writeToCodedOutputStream:output];
1334*1b3f573fSAndroid Build Coastguard Worker}
1335*1b3f573fSAndroid Build Coastguard Worker
1336*1b3f573fSAndroid Build Coastguard Worker- (void)writeField:(GPBFieldDescriptor *)field
1337*1b3f573fSAndroid Build Coastguard Worker    toCodedOutputStream:(GPBCodedOutputStream *)output {
1338*1b3f573fSAndroid Build Coastguard Worker  GPBFieldType fieldType = field.fieldType;
1339*1b3f573fSAndroid Build Coastguard Worker  if (fieldType == GPBFieldTypeSingle) {
1340*1b3f573fSAndroid Build Coastguard Worker    BOOL has = GPBGetHasIvarField(self, field);
1341*1b3f573fSAndroid Build Coastguard Worker    if (!has) {
1342*1b3f573fSAndroid Build Coastguard Worker      return;
1343*1b3f573fSAndroid Build Coastguard Worker    }
1344*1b3f573fSAndroid Build Coastguard Worker  }
1345*1b3f573fSAndroid Build Coastguard Worker  uint32_t fieldNumber = GPBFieldNumber(field);
1346*1b3f573fSAndroid Build Coastguard Worker
1347*1b3f573fSAndroid Build Coastguard Worker//%PDDM-DEFINE FIELD_CASE(TYPE, REAL_TYPE)
1348*1b3f573fSAndroid Build Coastguard Worker//%FIELD_CASE_FULL(TYPE, REAL_TYPE, REAL_TYPE)
1349*1b3f573fSAndroid Build Coastguard Worker//%PDDM-DEFINE FIELD_CASE_FULL(TYPE, REAL_TYPE, ARRAY_TYPE)
1350*1b3f573fSAndroid Build Coastguard Worker//%    case GPBDataType##TYPE:
1351*1b3f573fSAndroid Build Coastguard Worker//%      if (fieldType == GPBFieldTypeRepeated) {
1352*1b3f573fSAndroid Build Coastguard Worker//%        uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1353*1b3f573fSAndroid Build Coastguard Worker//%        GPB##ARRAY_TYPE##Array *array =
1354*1b3f573fSAndroid Build Coastguard Worker//%            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1355*1b3f573fSAndroid Build Coastguard Worker//%        [output write##TYPE##Array:fieldNumber values:array tag:tag];
1356*1b3f573fSAndroid Build Coastguard Worker//%      } else if (fieldType == GPBFieldTypeSingle) {
1357*1b3f573fSAndroid Build Coastguard Worker//%        [output write##TYPE:fieldNumber
1358*1b3f573fSAndroid Build Coastguard Worker//%              TYPE$S  value:GPBGetMessage##REAL_TYPE##Field(self, field)];
1359*1b3f573fSAndroid Build Coastguard Worker//%      } else {  // fieldType == GPBFieldTypeMap
1360*1b3f573fSAndroid Build Coastguard Worker//%        // Exact type here doesn't matter.
1361*1b3f573fSAndroid Build Coastguard Worker//%        GPBInt32##ARRAY_TYPE##Dictionary *dict =
1362*1b3f573fSAndroid Build Coastguard Worker//%            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1363*1b3f573fSAndroid Build Coastguard Worker//%        [dict writeToCodedOutputStream:output asField:field];
1364*1b3f573fSAndroid Build Coastguard Worker//%      }
1365*1b3f573fSAndroid Build Coastguard Worker//%      break;
1366*1b3f573fSAndroid Build Coastguard Worker//%
1367*1b3f573fSAndroid Build Coastguard Worker//%PDDM-DEFINE FIELD_CASE2(TYPE)
1368*1b3f573fSAndroid Build Coastguard Worker//%    case GPBDataType##TYPE:
1369*1b3f573fSAndroid Build Coastguard Worker//%      if (fieldType == GPBFieldTypeRepeated) {
1370*1b3f573fSAndroid Build Coastguard Worker//%        NSArray *array = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1371*1b3f573fSAndroid Build Coastguard Worker//%        [output write##TYPE##Array:fieldNumber values:array];
1372*1b3f573fSAndroid Build Coastguard Worker//%      } else if (fieldType == GPBFieldTypeSingle) {
1373*1b3f573fSAndroid Build Coastguard Worker//%        // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has check
1374*1b3f573fSAndroid Build Coastguard Worker//%        // again.
1375*1b3f573fSAndroid Build Coastguard Worker//%        [output write##TYPE:fieldNumber
1376*1b3f573fSAndroid Build Coastguard Worker//%              TYPE$S  value:GPBGetObjectIvarWithFieldNoAutocreate(self, field)];
1377*1b3f573fSAndroid Build Coastguard Worker//%      } else {  // fieldType == GPBFieldTypeMap
1378*1b3f573fSAndroid Build Coastguard Worker//%        // Exact type here doesn't matter.
1379*1b3f573fSAndroid Build Coastguard Worker//%        id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1380*1b3f573fSAndroid Build Coastguard Worker//%        GPBDataType mapKeyDataType = field.mapKeyDataType;
1381*1b3f573fSAndroid Build Coastguard Worker//%        if (mapKeyDataType == GPBDataTypeString) {
1382*1b3f573fSAndroid Build Coastguard Worker//%          GPBDictionaryWriteToStreamInternalHelper(output, dict, field);
1383*1b3f573fSAndroid Build Coastguard Worker//%        } else {
1384*1b3f573fSAndroid Build Coastguard Worker//%          [dict writeToCodedOutputStream:output asField:field];
1385*1b3f573fSAndroid Build Coastguard Worker//%        }
1386*1b3f573fSAndroid Build Coastguard Worker//%      }
1387*1b3f573fSAndroid Build Coastguard Worker//%      break;
1388*1b3f573fSAndroid Build Coastguard Worker//%
1389*1b3f573fSAndroid Build Coastguard Worker
1390*1b3f573fSAndroid Build Coastguard Worker  switch (GPBGetFieldDataType(field)) {
1391*1b3f573fSAndroid Build Coastguard Worker
1392*1b3f573fSAndroid Build Coastguard Worker//%PDDM-EXPAND FIELD_CASE(Bool, Bool)
1393*1b3f573fSAndroid Build Coastguard Worker// This block of code is generated, do not edit it directly.
1394*1b3f573fSAndroid Build Coastguard Worker// clang-format off
1395*1b3f573fSAndroid Build Coastguard Worker
1396*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeBool:
1397*1b3f573fSAndroid Build Coastguard Worker      if (fieldType == GPBFieldTypeRepeated) {
1398*1b3f573fSAndroid Build Coastguard Worker        uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1399*1b3f573fSAndroid Build Coastguard Worker        GPBBoolArray *array =
1400*1b3f573fSAndroid Build Coastguard Worker            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1401*1b3f573fSAndroid Build Coastguard Worker        [output writeBoolArray:fieldNumber values:array tag:tag];
1402*1b3f573fSAndroid Build Coastguard Worker      } else if (fieldType == GPBFieldTypeSingle) {
1403*1b3f573fSAndroid Build Coastguard Worker        [output writeBool:fieldNumber
1404*1b3f573fSAndroid Build Coastguard Worker                    value:GPBGetMessageBoolField(self, field)];
1405*1b3f573fSAndroid Build Coastguard Worker      } else {  // fieldType == GPBFieldTypeMap
1406*1b3f573fSAndroid Build Coastguard Worker        // Exact type here doesn't matter.
1407*1b3f573fSAndroid Build Coastguard Worker        GPBInt32BoolDictionary *dict =
1408*1b3f573fSAndroid Build Coastguard Worker            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1409*1b3f573fSAndroid Build Coastguard Worker        [dict writeToCodedOutputStream:output asField:field];
1410*1b3f573fSAndroid Build Coastguard Worker      }
1411*1b3f573fSAndroid Build Coastguard Worker      break;
1412*1b3f573fSAndroid Build Coastguard Worker
1413*1b3f573fSAndroid Build Coastguard Worker// clang-format on
1414*1b3f573fSAndroid Build Coastguard Worker//%PDDM-EXPAND FIELD_CASE(Fixed32, UInt32)
1415*1b3f573fSAndroid Build Coastguard Worker// This block of code is generated, do not edit it directly.
1416*1b3f573fSAndroid Build Coastguard Worker// clang-format off
1417*1b3f573fSAndroid Build Coastguard Worker
1418*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeFixed32:
1419*1b3f573fSAndroid Build Coastguard Worker      if (fieldType == GPBFieldTypeRepeated) {
1420*1b3f573fSAndroid Build Coastguard Worker        uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1421*1b3f573fSAndroid Build Coastguard Worker        GPBUInt32Array *array =
1422*1b3f573fSAndroid Build Coastguard Worker            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1423*1b3f573fSAndroid Build Coastguard Worker        [output writeFixed32Array:fieldNumber values:array tag:tag];
1424*1b3f573fSAndroid Build Coastguard Worker      } else if (fieldType == GPBFieldTypeSingle) {
1425*1b3f573fSAndroid Build Coastguard Worker        [output writeFixed32:fieldNumber
1426*1b3f573fSAndroid Build Coastguard Worker                       value:GPBGetMessageUInt32Field(self, field)];
1427*1b3f573fSAndroid Build Coastguard Worker      } else {  // fieldType == GPBFieldTypeMap
1428*1b3f573fSAndroid Build Coastguard Worker        // Exact type here doesn't matter.
1429*1b3f573fSAndroid Build Coastguard Worker        GPBInt32UInt32Dictionary *dict =
1430*1b3f573fSAndroid Build Coastguard Worker            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1431*1b3f573fSAndroid Build Coastguard Worker        [dict writeToCodedOutputStream:output asField:field];
1432*1b3f573fSAndroid Build Coastguard Worker      }
1433*1b3f573fSAndroid Build Coastguard Worker      break;
1434*1b3f573fSAndroid Build Coastguard Worker
1435*1b3f573fSAndroid Build Coastguard Worker// clang-format on
1436*1b3f573fSAndroid Build Coastguard Worker//%PDDM-EXPAND FIELD_CASE(SFixed32, Int32)
1437*1b3f573fSAndroid Build Coastguard Worker// This block of code is generated, do not edit it directly.
1438*1b3f573fSAndroid Build Coastguard Worker// clang-format off
1439*1b3f573fSAndroid Build Coastguard Worker
1440*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeSFixed32:
1441*1b3f573fSAndroid Build Coastguard Worker      if (fieldType == GPBFieldTypeRepeated) {
1442*1b3f573fSAndroid Build Coastguard Worker        uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1443*1b3f573fSAndroid Build Coastguard Worker        GPBInt32Array *array =
1444*1b3f573fSAndroid Build Coastguard Worker            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1445*1b3f573fSAndroid Build Coastguard Worker        [output writeSFixed32Array:fieldNumber values:array tag:tag];
1446*1b3f573fSAndroid Build Coastguard Worker      } else if (fieldType == GPBFieldTypeSingle) {
1447*1b3f573fSAndroid Build Coastguard Worker        [output writeSFixed32:fieldNumber
1448*1b3f573fSAndroid Build Coastguard Worker                        value:GPBGetMessageInt32Field(self, field)];
1449*1b3f573fSAndroid Build Coastguard Worker      } else {  // fieldType == GPBFieldTypeMap
1450*1b3f573fSAndroid Build Coastguard Worker        // Exact type here doesn't matter.
1451*1b3f573fSAndroid Build Coastguard Worker        GPBInt32Int32Dictionary *dict =
1452*1b3f573fSAndroid Build Coastguard Worker            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1453*1b3f573fSAndroid Build Coastguard Worker        [dict writeToCodedOutputStream:output asField:field];
1454*1b3f573fSAndroid Build Coastguard Worker      }
1455*1b3f573fSAndroid Build Coastguard Worker      break;
1456*1b3f573fSAndroid Build Coastguard Worker
1457*1b3f573fSAndroid Build Coastguard Worker// clang-format on
1458*1b3f573fSAndroid Build Coastguard Worker//%PDDM-EXPAND FIELD_CASE(Float, Float)
1459*1b3f573fSAndroid Build Coastguard Worker// This block of code is generated, do not edit it directly.
1460*1b3f573fSAndroid Build Coastguard Worker// clang-format off
1461*1b3f573fSAndroid Build Coastguard Worker
1462*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeFloat:
1463*1b3f573fSAndroid Build Coastguard Worker      if (fieldType == GPBFieldTypeRepeated) {
1464*1b3f573fSAndroid Build Coastguard Worker        uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1465*1b3f573fSAndroid Build Coastguard Worker        GPBFloatArray *array =
1466*1b3f573fSAndroid Build Coastguard Worker            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1467*1b3f573fSAndroid Build Coastguard Worker        [output writeFloatArray:fieldNumber values:array tag:tag];
1468*1b3f573fSAndroid Build Coastguard Worker      } else if (fieldType == GPBFieldTypeSingle) {
1469*1b3f573fSAndroid Build Coastguard Worker        [output writeFloat:fieldNumber
1470*1b3f573fSAndroid Build Coastguard Worker                     value:GPBGetMessageFloatField(self, field)];
1471*1b3f573fSAndroid Build Coastguard Worker      } else {  // fieldType == GPBFieldTypeMap
1472*1b3f573fSAndroid Build Coastguard Worker        // Exact type here doesn't matter.
1473*1b3f573fSAndroid Build Coastguard Worker        GPBInt32FloatDictionary *dict =
1474*1b3f573fSAndroid Build Coastguard Worker            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1475*1b3f573fSAndroid Build Coastguard Worker        [dict writeToCodedOutputStream:output asField:field];
1476*1b3f573fSAndroid Build Coastguard Worker      }
1477*1b3f573fSAndroid Build Coastguard Worker      break;
1478*1b3f573fSAndroid Build Coastguard Worker
1479*1b3f573fSAndroid Build Coastguard Worker// clang-format on
1480*1b3f573fSAndroid Build Coastguard Worker//%PDDM-EXPAND FIELD_CASE(Fixed64, UInt64)
1481*1b3f573fSAndroid Build Coastguard Worker// This block of code is generated, do not edit it directly.
1482*1b3f573fSAndroid Build Coastguard Worker// clang-format off
1483*1b3f573fSAndroid Build Coastguard Worker
1484*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeFixed64:
1485*1b3f573fSAndroid Build Coastguard Worker      if (fieldType == GPBFieldTypeRepeated) {
1486*1b3f573fSAndroid Build Coastguard Worker        uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1487*1b3f573fSAndroid Build Coastguard Worker        GPBUInt64Array *array =
1488*1b3f573fSAndroid Build Coastguard Worker            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1489*1b3f573fSAndroid Build Coastguard Worker        [output writeFixed64Array:fieldNumber values:array tag:tag];
1490*1b3f573fSAndroid Build Coastguard Worker      } else if (fieldType == GPBFieldTypeSingle) {
1491*1b3f573fSAndroid Build Coastguard Worker        [output writeFixed64:fieldNumber
1492*1b3f573fSAndroid Build Coastguard Worker                       value:GPBGetMessageUInt64Field(self, field)];
1493*1b3f573fSAndroid Build Coastguard Worker      } else {  // fieldType == GPBFieldTypeMap
1494*1b3f573fSAndroid Build Coastguard Worker        // Exact type here doesn't matter.
1495*1b3f573fSAndroid Build Coastguard Worker        GPBInt32UInt64Dictionary *dict =
1496*1b3f573fSAndroid Build Coastguard Worker            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1497*1b3f573fSAndroid Build Coastguard Worker        [dict writeToCodedOutputStream:output asField:field];
1498*1b3f573fSAndroid Build Coastguard Worker      }
1499*1b3f573fSAndroid Build Coastguard Worker      break;
1500*1b3f573fSAndroid Build Coastguard Worker
1501*1b3f573fSAndroid Build Coastguard Worker// clang-format on
1502*1b3f573fSAndroid Build Coastguard Worker//%PDDM-EXPAND FIELD_CASE(SFixed64, Int64)
1503*1b3f573fSAndroid Build Coastguard Worker// This block of code is generated, do not edit it directly.
1504*1b3f573fSAndroid Build Coastguard Worker// clang-format off
1505*1b3f573fSAndroid Build Coastguard Worker
1506*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeSFixed64:
1507*1b3f573fSAndroid Build Coastguard Worker      if (fieldType == GPBFieldTypeRepeated) {
1508*1b3f573fSAndroid Build Coastguard Worker        uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1509*1b3f573fSAndroid Build Coastguard Worker        GPBInt64Array *array =
1510*1b3f573fSAndroid Build Coastguard Worker            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1511*1b3f573fSAndroid Build Coastguard Worker        [output writeSFixed64Array:fieldNumber values:array tag:tag];
1512*1b3f573fSAndroid Build Coastguard Worker      } else if (fieldType == GPBFieldTypeSingle) {
1513*1b3f573fSAndroid Build Coastguard Worker        [output writeSFixed64:fieldNumber
1514*1b3f573fSAndroid Build Coastguard Worker                        value:GPBGetMessageInt64Field(self, field)];
1515*1b3f573fSAndroid Build Coastguard Worker      } else {  // fieldType == GPBFieldTypeMap
1516*1b3f573fSAndroid Build Coastguard Worker        // Exact type here doesn't matter.
1517*1b3f573fSAndroid Build Coastguard Worker        GPBInt32Int64Dictionary *dict =
1518*1b3f573fSAndroid Build Coastguard Worker            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1519*1b3f573fSAndroid Build Coastguard Worker        [dict writeToCodedOutputStream:output asField:field];
1520*1b3f573fSAndroid Build Coastguard Worker      }
1521*1b3f573fSAndroid Build Coastguard Worker      break;
1522*1b3f573fSAndroid Build Coastguard Worker
1523*1b3f573fSAndroid Build Coastguard Worker// clang-format on
1524*1b3f573fSAndroid Build Coastguard Worker//%PDDM-EXPAND FIELD_CASE(Double, Double)
1525*1b3f573fSAndroid Build Coastguard Worker// This block of code is generated, do not edit it directly.
1526*1b3f573fSAndroid Build Coastguard Worker// clang-format off
1527*1b3f573fSAndroid Build Coastguard Worker
1528*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeDouble:
1529*1b3f573fSAndroid Build Coastguard Worker      if (fieldType == GPBFieldTypeRepeated) {
1530*1b3f573fSAndroid Build Coastguard Worker        uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1531*1b3f573fSAndroid Build Coastguard Worker        GPBDoubleArray *array =
1532*1b3f573fSAndroid Build Coastguard Worker            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1533*1b3f573fSAndroid Build Coastguard Worker        [output writeDoubleArray:fieldNumber values:array tag:tag];
1534*1b3f573fSAndroid Build Coastguard Worker      } else if (fieldType == GPBFieldTypeSingle) {
1535*1b3f573fSAndroid Build Coastguard Worker        [output writeDouble:fieldNumber
1536*1b3f573fSAndroid Build Coastguard Worker                      value:GPBGetMessageDoubleField(self, field)];
1537*1b3f573fSAndroid Build Coastguard Worker      } else {  // fieldType == GPBFieldTypeMap
1538*1b3f573fSAndroid Build Coastguard Worker        // Exact type here doesn't matter.
1539*1b3f573fSAndroid Build Coastguard Worker        GPBInt32DoubleDictionary *dict =
1540*1b3f573fSAndroid Build Coastguard Worker            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1541*1b3f573fSAndroid Build Coastguard Worker        [dict writeToCodedOutputStream:output asField:field];
1542*1b3f573fSAndroid Build Coastguard Worker      }
1543*1b3f573fSAndroid Build Coastguard Worker      break;
1544*1b3f573fSAndroid Build Coastguard Worker
1545*1b3f573fSAndroid Build Coastguard Worker// clang-format on
1546*1b3f573fSAndroid Build Coastguard Worker//%PDDM-EXPAND FIELD_CASE(Int32, Int32)
1547*1b3f573fSAndroid Build Coastguard Worker// This block of code is generated, do not edit it directly.
1548*1b3f573fSAndroid Build Coastguard Worker// clang-format off
1549*1b3f573fSAndroid Build Coastguard Worker
1550*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeInt32:
1551*1b3f573fSAndroid Build Coastguard Worker      if (fieldType == GPBFieldTypeRepeated) {
1552*1b3f573fSAndroid Build Coastguard Worker        uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1553*1b3f573fSAndroid Build Coastguard Worker        GPBInt32Array *array =
1554*1b3f573fSAndroid Build Coastguard Worker            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1555*1b3f573fSAndroid Build Coastguard Worker        [output writeInt32Array:fieldNumber values:array tag:tag];
1556*1b3f573fSAndroid Build Coastguard Worker      } else if (fieldType == GPBFieldTypeSingle) {
1557*1b3f573fSAndroid Build Coastguard Worker        [output writeInt32:fieldNumber
1558*1b3f573fSAndroid Build Coastguard Worker                     value:GPBGetMessageInt32Field(self, field)];
1559*1b3f573fSAndroid Build Coastguard Worker      } else {  // fieldType == GPBFieldTypeMap
1560*1b3f573fSAndroid Build Coastguard Worker        // Exact type here doesn't matter.
1561*1b3f573fSAndroid Build Coastguard Worker        GPBInt32Int32Dictionary *dict =
1562*1b3f573fSAndroid Build Coastguard Worker            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1563*1b3f573fSAndroid Build Coastguard Worker        [dict writeToCodedOutputStream:output asField:field];
1564*1b3f573fSAndroid Build Coastguard Worker      }
1565*1b3f573fSAndroid Build Coastguard Worker      break;
1566*1b3f573fSAndroid Build Coastguard Worker
1567*1b3f573fSAndroid Build Coastguard Worker// clang-format on
1568*1b3f573fSAndroid Build Coastguard Worker//%PDDM-EXPAND FIELD_CASE(Int64, Int64)
1569*1b3f573fSAndroid Build Coastguard Worker// This block of code is generated, do not edit it directly.
1570*1b3f573fSAndroid Build Coastguard Worker// clang-format off
1571*1b3f573fSAndroid Build Coastguard Worker
1572*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeInt64:
1573*1b3f573fSAndroid Build Coastguard Worker      if (fieldType == GPBFieldTypeRepeated) {
1574*1b3f573fSAndroid Build Coastguard Worker        uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1575*1b3f573fSAndroid Build Coastguard Worker        GPBInt64Array *array =
1576*1b3f573fSAndroid Build Coastguard Worker            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1577*1b3f573fSAndroid Build Coastguard Worker        [output writeInt64Array:fieldNumber values:array tag:tag];
1578*1b3f573fSAndroid Build Coastguard Worker      } else if (fieldType == GPBFieldTypeSingle) {
1579*1b3f573fSAndroid Build Coastguard Worker        [output writeInt64:fieldNumber
1580*1b3f573fSAndroid Build Coastguard Worker                     value:GPBGetMessageInt64Field(self, field)];
1581*1b3f573fSAndroid Build Coastguard Worker      } else {  // fieldType == GPBFieldTypeMap
1582*1b3f573fSAndroid Build Coastguard Worker        // Exact type here doesn't matter.
1583*1b3f573fSAndroid Build Coastguard Worker        GPBInt32Int64Dictionary *dict =
1584*1b3f573fSAndroid Build Coastguard Worker            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1585*1b3f573fSAndroid Build Coastguard Worker        [dict writeToCodedOutputStream:output asField:field];
1586*1b3f573fSAndroid Build Coastguard Worker      }
1587*1b3f573fSAndroid Build Coastguard Worker      break;
1588*1b3f573fSAndroid Build Coastguard Worker
1589*1b3f573fSAndroid Build Coastguard Worker// clang-format on
1590*1b3f573fSAndroid Build Coastguard Worker//%PDDM-EXPAND FIELD_CASE(SInt32, Int32)
1591*1b3f573fSAndroid Build Coastguard Worker// This block of code is generated, do not edit it directly.
1592*1b3f573fSAndroid Build Coastguard Worker// clang-format off
1593*1b3f573fSAndroid Build Coastguard Worker
1594*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeSInt32:
1595*1b3f573fSAndroid Build Coastguard Worker      if (fieldType == GPBFieldTypeRepeated) {
1596*1b3f573fSAndroid Build Coastguard Worker        uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1597*1b3f573fSAndroid Build Coastguard Worker        GPBInt32Array *array =
1598*1b3f573fSAndroid Build Coastguard Worker            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1599*1b3f573fSAndroid Build Coastguard Worker        [output writeSInt32Array:fieldNumber values:array tag:tag];
1600*1b3f573fSAndroid Build Coastguard Worker      } else if (fieldType == GPBFieldTypeSingle) {
1601*1b3f573fSAndroid Build Coastguard Worker        [output writeSInt32:fieldNumber
1602*1b3f573fSAndroid Build Coastguard Worker                      value:GPBGetMessageInt32Field(self, field)];
1603*1b3f573fSAndroid Build Coastguard Worker      } else {  // fieldType == GPBFieldTypeMap
1604*1b3f573fSAndroid Build Coastguard Worker        // Exact type here doesn't matter.
1605*1b3f573fSAndroid Build Coastguard Worker        GPBInt32Int32Dictionary *dict =
1606*1b3f573fSAndroid Build Coastguard Worker            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1607*1b3f573fSAndroid Build Coastguard Worker        [dict writeToCodedOutputStream:output asField:field];
1608*1b3f573fSAndroid Build Coastguard Worker      }
1609*1b3f573fSAndroid Build Coastguard Worker      break;
1610*1b3f573fSAndroid Build Coastguard Worker
1611*1b3f573fSAndroid Build Coastguard Worker// clang-format on
1612*1b3f573fSAndroid Build Coastguard Worker//%PDDM-EXPAND FIELD_CASE(SInt64, Int64)
1613*1b3f573fSAndroid Build Coastguard Worker// This block of code is generated, do not edit it directly.
1614*1b3f573fSAndroid Build Coastguard Worker// clang-format off
1615*1b3f573fSAndroid Build Coastguard Worker
1616*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeSInt64:
1617*1b3f573fSAndroid Build Coastguard Worker      if (fieldType == GPBFieldTypeRepeated) {
1618*1b3f573fSAndroid Build Coastguard Worker        uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1619*1b3f573fSAndroid Build Coastguard Worker        GPBInt64Array *array =
1620*1b3f573fSAndroid Build Coastguard Worker            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1621*1b3f573fSAndroid Build Coastguard Worker        [output writeSInt64Array:fieldNumber values:array tag:tag];
1622*1b3f573fSAndroid Build Coastguard Worker      } else if (fieldType == GPBFieldTypeSingle) {
1623*1b3f573fSAndroid Build Coastguard Worker        [output writeSInt64:fieldNumber
1624*1b3f573fSAndroid Build Coastguard Worker                      value:GPBGetMessageInt64Field(self, field)];
1625*1b3f573fSAndroid Build Coastguard Worker      } else {  // fieldType == GPBFieldTypeMap
1626*1b3f573fSAndroid Build Coastguard Worker        // Exact type here doesn't matter.
1627*1b3f573fSAndroid Build Coastguard Worker        GPBInt32Int64Dictionary *dict =
1628*1b3f573fSAndroid Build Coastguard Worker            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1629*1b3f573fSAndroid Build Coastguard Worker        [dict writeToCodedOutputStream:output asField:field];
1630*1b3f573fSAndroid Build Coastguard Worker      }
1631*1b3f573fSAndroid Build Coastguard Worker      break;
1632*1b3f573fSAndroid Build Coastguard Worker
1633*1b3f573fSAndroid Build Coastguard Worker// clang-format on
1634*1b3f573fSAndroid Build Coastguard Worker//%PDDM-EXPAND FIELD_CASE(UInt32, UInt32)
1635*1b3f573fSAndroid Build Coastguard Worker// This block of code is generated, do not edit it directly.
1636*1b3f573fSAndroid Build Coastguard Worker// clang-format off
1637*1b3f573fSAndroid Build Coastguard Worker
1638*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeUInt32:
1639*1b3f573fSAndroid Build Coastguard Worker      if (fieldType == GPBFieldTypeRepeated) {
1640*1b3f573fSAndroid Build Coastguard Worker        uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1641*1b3f573fSAndroid Build Coastguard Worker        GPBUInt32Array *array =
1642*1b3f573fSAndroid Build Coastguard Worker            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1643*1b3f573fSAndroid Build Coastguard Worker        [output writeUInt32Array:fieldNumber values:array tag:tag];
1644*1b3f573fSAndroid Build Coastguard Worker      } else if (fieldType == GPBFieldTypeSingle) {
1645*1b3f573fSAndroid Build Coastguard Worker        [output writeUInt32:fieldNumber
1646*1b3f573fSAndroid Build Coastguard Worker                      value:GPBGetMessageUInt32Field(self, field)];
1647*1b3f573fSAndroid Build Coastguard Worker      } else {  // fieldType == GPBFieldTypeMap
1648*1b3f573fSAndroid Build Coastguard Worker        // Exact type here doesn't matter.
1649*1b3f573fSAndroid Build Coastguard Worker        GPBInt32UInt32Dictionary *dict =
1650*1b3f573fSAndroid Build Coastguard Worker            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1651*1b3f573fSAndroid Build Coastguard Worker        [dict writeToCodedOutputStream:output asField:field];
1652*1b3f573fSAndroid Build Coastguard Worker      }
1653*1b3f573fSAndroid Build Coastguard Worker      break;
1654*1b3f573fSAndroid Build Coastguard Worker
1655*1b3f573fSAndroid Build Coastguard Worker// clang-format on
1656*1b3f573fSAndroid Build Coastguard Worker//%PDDM-EXPAND FIELD_CASE(UInt64, UInt64)
1657*1b3f573fSAndroid Build Coastguard Worker// This block of code is generated, do not edit it directly.
1658*1b3f573fSAndroid Build Coastguard Worker// clang-format off
1659*1b3f573fSAndroid Build Coastguard Worker
1660*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeUInt64:
1661*1b3f573fSAndroid Build Coastguard Worker      if (fieldType == GPBFieldTypeRepeated) {
1662*1b3f573fSAndroid Build Coastguard Worker        uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1663*1b3f573fSAndroid Build Coastguard Worker        GPBUInt64Array *array =
1664*1b3f573fSAndroid Build Coastguard Worker            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1665*1b3f573fSAndroid Build Coastguard Worker        [output writeUInt64Array:fieldNumber values:array tag:tag];
1666*1b3f573fSAndroid Build Coastguard Worker      } else if (fieldType == GPBFieldTypeSingle) {
1667*1b3f573fSAndroid Build Coastguard Worker        [output writeUInt64:fieldNumber
1668*1b3f573fSAndroid Build Coastguard Worker                      value:GPBGetMessageUInt64Field(self, field)];
1669*1b3f573fSAndroid Build Coastguard Worker      } else {  // fieldType == GPBFieldTypeMap
1670*1b3f573fSAndroid Build Coastguard Worker        // Exact type here doesn't matter.
1671*1b3f573fSAndroid Build Coastguard Worker        GPBInt32UInt64Dictionary *dict =
1672*1b3f573fSAndroid Build Coastguard Worker            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1673*1b3f573fSAndroid Build Coastguard Worker        [dict writeToCodedOutputStream:output asField:field];
1674*1b3f573fSAndroid Build Coastguard Worker      }
1675*1b3f573fSAndroid Build Coastguard Worker      break;
1676*1b3f573fSAndroid Build Coastguard Worker
1677*1b3f573fSAndroid Build Coastguard Worker// clang-format on
1678*1b3f573fSAndroid Build Coastguard Worker//%PDDM-EXPAND FIELD_CASE_FULL(Enum, Int32, Enum)
1679*1b3f573fSAndroid Build Coastguard Worker// This block of code is generated, do not edit it directly.
1680*1b3f573fSAndroid Build Coastguard Worker// clang-format off
1681*1b3f573fSAndroid Build Coastguard Worker
1682*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeEnum:
1683*1b3f573fSAndroid Build Coastguard Worker      if (fieldType == GPBFieldTypeRepeated) {
1684*1b3f573fSAndroid Build Coastguard Worker        uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1685*1b3f573fSAndroid Build Coastguard Worker        GPBEnumArray *array =
1686*1b3f573fSAndroid Build Coastguard Worker            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1687*1b3f573fSAndroid Build Coastguard Worker        [output writeEnumArray:fieldNumber values:array tag:tag];
1688*1b3f573fSAndroid Build Coastguard Worker      } else if (fieldType == GPBFieldTypeSingle) {
1689*1b3f573fSAndroid Build Coastguard Worker        [output writeEnum:fieldNumber
1690*1b3f573fSAndroid Build Coastguard Worker                    value:GPBGetMessageInt32Field(self, field)];
1691*1b3f573fSAndroid Build Coastguard Worker      } else {  // fieldType == GPBFieldTypeMap
1692*1b3f573fSAndroid Build Coastguard Worker        // Exact type here doesn't matter.
1693*1b3f573fSAndroid Build Coastguard Worker        GPBInt32EnumDictionary *dict =
1694*1b3f573fSAndroid Build Coastguard Worker            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1695*1b3f573fSAndroid Build Coastguard Worker        [dict writeToCodedOutputStream:output asField:field];
1696*1b3f573fSAndroid Build Coastguard Worker      }
1697*1b3f573fSAndroid Build Coastguard Worker      break;
1698*1b3f573fSAndroid Build Coastguard Worker
1699*1b3f573fSAndroid Build Coastguard Worker// clang-format on
1700*1b3f573fSAndroid Build Coastguard Worker//%PDDM-EXPAND FIELD_CASE2(Bytes)
1701*1b3f573fSAndroid Build Coastguard Worker// This block of code is generated, do not edit it directly.
1702*1b3f573fSAndroid Build Coastguard Worker// clang-format off
1703*1b3f573fSAndroid Build Coastguard Worker
1704*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeBytes:
1705*1b3f573fSAndroid Build Coastguard Worker      if (fieldType == GPBFieldTypeRepeated) {
1706*1b3f573fSAndroid Build Coastguard Worker        NSArray *array = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1707*1b3f573fSAndroid Build Coastguard Worker        [output writeBytesArray:fieldNumber values:array];
1708*1b3f573fSAndroid Build Coastguard Worker      } else if (fieldType == GPBFieldTypeSingle) {
1709*1b3f573fSAndroid Build Coastguard Worker        // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has check
1710*1b3f573fSAndroid Build Coastguard Worker        // again.
1711*1b3f573fSAndroid Build Coastguard Worker        [output writeBytes:fieldNumber
1712*1b3f573fSAndroid Build Coastguard Worker                     value:GPBGetObjectIvarWithFieldNoAutocreate(self, field)];
1713*1b3f573fSAndroid Build Coastguard Worker      } else {  // fieldType == GPBFieldTypeMap
1714*1b3f573fSAndroid Build Coastguard Worker        // Exact type here doesn't matter.
1715*1b3f573fSAndroid Build Coastguard Worker        id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1716*1b3f573fSAndroid Build Coastguard Worker        GPBDataType mapKeyDataType = field.mapKeyDataType;
1717*1b3f573fSAndroid Build Coastguard Worker        if (mapKeyDataType == GPBDataTypeString) {
1718*1b3f573fSAndroid Build Coastguard Worker          GPBDictionaryWriteToStreamInternalHelper(output, dict, field);
1719*1b3f573fSAndroid Build Coastguard Worker        } else {
1720*1b3f573fSAndroid Build Coastguard Worker          [dict writeToCodedOutputStream:output asField:field];
1721*1b3f573fSAndroid Build Coastguard Worker        }
1722*1b3f573fSAndroid Build Coastguard Worker      }
1723*1b3f573fSAndroid Build Coastguard Worker      break;
1724*1b3f573fSAndroid Build Coastguard Worker
1725*1b3f573fSAndroid Build Coastguard Worker// clang-format on
1726*1b3f573fSAndroid Build Coastguard Worker//%PDDM-EXPAND FIELD_CASE2(String)
1727*1b3f573fSAndroid Build Coastguard Worker// This block of code is generated, do not edit it directly.
1728*1b3f573fSAndroid Build Coastguard Worker// clang-format off
1729*1b3f573fSAndroid Build Coastguard Worker
1730*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeString:
1731*1b3f573fSAndroid Build Coastguard Worker      if (fieldType == GPBFieldTypeRepeated) {
1732*1b3f573fSAndroid Build Coastguard Worker        NSArray *array = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1733*1b3f573fSAndroid Build Coastguard Worker        [output writeStringArray:fieldNumber values:array];
1734*1b3f573fSAndroid Build Coastguard Worker      } else if (fieldType == GPBFieldTypeSingle) {
1735*1b3f573fSAndroid Build Coastguard Worker        // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has check
1736*1b3f573fSAndroid Build Coastguard Worker        // again.
1737*1b3f573fSAndroid Build Coastguard Worker        [output writeString:fieldNumber
1738*1b3f573fSAndroid Build Coastguard Worker                      value:GPBGetObjectIvarWithFieldNoAutocreate(self, field)];
1739*1b3f573fSAndroid Build Coastguard Worker      } else {  // fieldType == GPBFieldTypeMap
1740*1b3f573fSAndroid Build Coastguard Worker        // Exact type here doesn't matter.
1741*1b3f573fSAndroid Build Coastguard Worker        id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1742*1b3f573fSAndroid Build Coastguard Worker        GPBDataType mapKeyDataType = field.mapKeyDataType;
1743*1b3f573fSAndroid Build Coastguard Worker        if (mapKeyDataType == GPBDataTypeString) {
1744*1b3f573fSAndroid Build Coastguard Worker          GPBDictionaryWriteToStreamInternalHelper(output, dict, field);
1745*1b3f573fSAndroid Build Coastguard Worker        } else {
1746*1b3f573fSAndroid Build Coastguard Worker          [dict writeToCodedOutputStream:output asField:field];
1747*1b3f573fSAndroid Build Coastguard Worker        }
1748*1b3f573fSAndroid Build Coastguard Worker      }
1749*1b3f573fSAndroid Build Coastguard Worker      break;
1750*1b3f573fSAndroid Build Coastguard Worker
1751*1b3f573fSAndroid Build Coastguard Worker// clang-format on
1752*1b3f573fSAndroid Build Coastguard Worker//%PDDM-EXPAND FIELD_CASE2(Message)
1753*1b3f573fSAndroid Build Coastguard Worker// This block of code is generated, do not edit it directly.
1754*1b3f573fSAndroid Build Coastguard Worker// clang-format off
1755*1b3f573fSAndroid Build Coastguard Worker
1756*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeMessage:
1757*1b3f573fSAndroid Build Coastguard Worker      if (fieldType == GPBFieldTypeRepeated) {
1758*1b3f573fSAndroid Build Coastguard Worker        NSArray *array = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1759*1b3f573fSAndroid Build Coastguard Worker        [output writeMessageArray:fieldNumber values:array];
1760*1b3f573fSAndroid Build Coastguard Worker      } else if (fieldType == GPBFieldTypeSingle) {
1761*1b3f573fSAndroid Build Coastguard Worker        // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has check
1762*1b3f573fSAndroid Build Coastguard Worker        // again.
1763*1b3f573fSAndroid Build Coastguard Worker        [output writeMessage:fieldNumber
1764*1b3f573fSAndroid Build Coastguard Worker                       value:GPBGetObjectIvarWithFieldNoAutocreate(self, field)];
1765*1b3f573fSAndroid Build Coastguard Worker      } else {  // fieldType == GPBFieldTypeMap
1766*1b3f573fSAndroid Build Coastguard Worker        // Exact type here doesn't matter.
1767*1b3f573fSAndroid Build Coastguard Worker        id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1768*1b3f573fSAndroid Build Coastguard Worker        GPBDataType mapKeyDataType = field.mapKeyDataType;
1769*1b3f573fSAndroid Build Coastguard Worker        if (mapKeyDataType == GPBDataTypeString) {
1770*1b3f573fSAndroid Build Coastguard Worker          GPBDictionaryWriteToStreamInternalHelper(output, dict, field);
1771*1b3f573fSAndroid Build Coastguard Worker        } else {
1772*1b3f573fSAndroid Build Coastguard Worker          [dict writeToCodedOutputStream:output asField:field];
1773*1b3f573fSAndroid Build Coastguard Worker        }
1774*1b3f573fSAndroid Build Coastguard Worker      }
1775*1b3f573fSAndroid Build Coastguard Worker      break;
1776*1b3f573fSAndroid Build Coastguard Worker
1777*1b3f573fSAndroid Build Coastguard Worker// clang-format on
1778*1b3f573fSAndroid Build Coastguard Worker//%PDDM-EXPAND FIELD_CASE2(Group)
1779*1b3f573fSAndroid Build Coastguard Worker// This block of code is generated, do not edit it directly.
1780*1b3f573fSAndroid Build Coastguard Worker// clang-format off
1781*1b3f573fSAndroid Build Coastguard Worker
1782*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeGroup:
1783*1b3f573fSAndroid Build Coastguard Worker      if (fieldType == GPBFieldTypeRepeated) {
1784*1b3f573fSAndroid Build Coastguard Worker        NSArray *array = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1785*1b3f573fSAndroid Build Coastguard Worker        [output writeGroupArray:fieldNumber values:array];
1786*1b3f573fSAndroid Build Coastguard Worker      } else if (fieldType == GPBFieldTypeSingle) {
1787*1b3f573fSAndroid Build Coastguard Worker        // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has check
1788*1b3f573fSAndroid Build Coastguard Worker        // again.
1789*1b3f573fSAndroid Build Coastguard Worker        [output writeGroup:fieldNumber
1790*1b3f573fSAndroid Build Coastguard Worker                     value:GPBGetObjectIvarWithFieldNoAutocreate(self, field)];
1791*1b3f573fSAndroid Build Coastguard Worker      } else {  // fieldType == GPBFieldTypeMap
1792*1b3f573fSAndroid Build Coastguard Worker        // Exact type here doesn't matter.
1793*1b3f573fSAndroid Build Coastguard Worker        id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1794*1b3f573fSAndroid Build Coastguard Worker        GPBDataType mapKeyDataType = field.mapKeyDataType;
1795*1b3f573fSAndroid Build Coastguard Worker        if (mapKeyDataType == GPBDataTypeString) {
1796*1b3f573fSAndroid Build Coastguard Worker          GPBDictionaryWriteToStreamInternalHelper(output, dict, field);
1797*1b3f573fSAndroid Build Coastguard Worker        } else {
1798*1b3f573fSAndroid Build Coastguard Worker          [dict writeToCodedOutputStream:output asField:field];
1799*1b3f573fSAndroid Build Coastguard Worker        }
1800*1b3f573fSAndroid Build Coastguard Worker      }
1801*1b3f573fSAndroid Build Coastguard Worker      break;
1802*1b3f573fSAndroid Build Coastguard Worker
1803*1b3f573fSAndroid Build Coastguard Worker// clang-format on
1804*1b3f573fSAndroid Build Coastguard Worker//%PDDM-EXPAND-END (18 expansions)
1805*1b3f573fSAndroid Build Coastguard Worker  }
1806*1b3f573fSAndroid Build Coastguard Worker}
1807*1b3f573fSAndroid Build Coastguard Worker
1808*1b3f573fSAndroid Build Coastguard Worker#pragma mark - Extensions
1809*1b3f573fSAndroid Build Coastguard Worker
1810*1b3f573fSAndroid Build Coastguard Worker- (id)getExtension:(GPBExtensionDescriptor *)extension {
1811*1b3f573fSAndroid Build Coastguard Worker  CheckExtension(self, extension);
1812*1b3f573fSAndroid Build Coastguard Worker  id value = [extensionMap_ objectForKey:extension];
1813*1b3f573fSAndroid Build Coastguard Worker  if (value != nil) {
1814*1b3f573fSAndroid Build Coastguard Worker    return value;
1815*1b3f573fSAndroid Build Coastguard Worker  }
1816*1b3f573fSAndroid Build Coastguard Worker
1817*1b3f573fSAndroid Build Coastguard Worker  // No default for repeated.
1818*1b3f573fSAndroid Build Coastguard Worker  if (extension.isRepeated) {
1819*1b3f573fSAndroid Build Coastguard Worker    return nil;
1820*1b3f573fSAndroid Build Coastguard Worker  }
1821*1b3f573fSAndroid Build Coastguard Worker  // Non messages get their default.
1822*1b3f573fSAndroid Build Coastguard Worker  if (!GPBExtensionIsMessage(extension)) {
1823*1b3f573fSAndroid Build Coastguard Worker    return extension.defaultValue;
1824*1b3f573fSAndroid Build Coastguard Worker  }
1825*1b3f573fSAndroid Build Coastguard Worker
1826*1b3f573fSAndroid Build Coastguard Worker  // Check for an autocreated value.
1827*1b3f573fSAndroid Build Coastguard Worker  GPBPrepareReadOnlySemaphore(self);
1828*1b3f573fSAndroid Build Coastguard Worker  dispatch_semaphore_wait(readOnlySemaphore_, DISPATCH_TIME_FOREVER);
1829*1b3f573fSAndroid Build Coastguard Worker  value = [autocreatedExtensionMap_ objectForKey:extension];
1830*1b3f573fSAndroid Build Coastguard Worker  if (!value) {
1831*1b3f573fSAndroid Build Coastguard Worker    // Auto create the message extensions to match normal fields.
1832*1b3f573fSAndroid Build Coastguard Worker    value = CreateMessageWithAutocreatorForExtension(extension.msgClass, self,
1833*1b3f573fSAndroid Build Coastguard Worker                                                     extension);
1834*1b3f573fSAndroid Build Coastguard Worker
1835*1b3f573fSAndroid Build Coastguard Worker    if (autocreatedExtensionMap_ == nil) {
1836*1b3f573fSAndroid Build Coastguard Worker      autocreatedExtensionMap_ = [[NSMutableDictionary alloc] init];
1837*1b3f573fSAndroid Build Coastguard Worker    }
1838*1b3f573fSAndroid Build Coastguard Worker
1839*1b3f573fSAndroid Build Coastguard Worker    // We can't simply call setExtension here because that would clear the new
1840*1b3f573fSAndroid Build Coastguard Worker    // value's autocreator.
1841*1b3f573fSAndroid Build Coastguard Worker    [autocreatedExtensionMap_ setObject:value forKey:extension];
1842*1b3f573fSAndroid Build Coastguard Worker    [value release];
1843*1b3f573fSAndroid Build Coastguard Worker  }
1844*1b3f573fSAndroid Build Coastguard Worker
1845*1b3f573fSAndroid Build Coastguard Worker  dispatch_semaphore_signal(readOnlySemaphore_);
1846*1b3f573fSAndroid Build Coastguard Worker  return value;
1847*1b3f573fSAndroid Build Coastguard Worker}
1848*1b3f573fSAndroid Build Coastguard Worker
1849*1b3f573fSAndroid Build Coastguard Worker- (id)getExistingExtension:(GPBExtensionDescriptor *)extension {
1850*1b3f573fSAndroid Build Coastguard Worker  // This is an internal method so we don't need to call CheckExtension().
1851*1b3f573fSAndroid Build Coastguard Worker  return [extensionMap_ objectForKey:extension];
1852*1b3f573fSAndroid Build Coastguard Worker}
1853*1b3f573fSAndroid Build Coastguard Worker
1854*1b3f573fSAndroid Build Coastguard Worker- (BOOL)hasExtension:(GPBExtensionDescriptor *)extension {
1855*1b3f573fSAndroid Build Coastguard Worker#if defined(DEBUG) && DEBUG
1856*1b3f573fSAndroid Build Coastguard Worker  CheckExtension(self, extension);
1857*1b3f573fSAndroid Build Coastguard Worker#endif  // DEBUG
1858*1b3f573fSAndroid Build Coastguard Worker  return nil != [extensionMap_ objectForKey:extension];
1859*1b3f573fSAndroid Build Coastguard Worker}
1860*1b3f573fSAndroid Build Coastguard Worker
1861*1b3f573fSAndroid Build Coastguard Worker- (NSArray *)extensionsCurrentlySet {
1862*1b3f573fSAndroid Build Coastguard Worker  return [extensionMap_ allKeys];
1863*1b3f573fSAndroid Build Coastguard Worker}
1864*1b3f573fSAndroid Build Coastguard Worker
1865*1b3f573fSAndroid Build Coastguard Worker- (void)writeExtensionsToCodedOutputStream:(GPBCodedOutputStream *)output
1866*1b3f573fSAndroid Build Coastguard Worker                                     range:(GPBExtensionRange)range
1867*1b3f573fSAndroid Build Coastguard Worker                          sortedExtensions:(NSArray *)sortedExtensions {
1868*1b3f573fSAndroid Build Coastguard Worker  uint32_t start = range.start;
1869*1b3f573fSAndroid Build Coastguard Worker  uint32_t end = range.end;
1870*1b3f573fSAndroid Build Coastguard Worker  for (GPBExtensionDescriptor *extension in sortedExtensions) {
1871*1b3f573fSAndroid Build Coastguard Worker    uint32_t fieldNumber = extension.fieldNumber;
1872*1b3f573fSAndroid Build Coastguard Worker    if (fieldNumber < start) {
1873*1b3f573fSAndroid Build Coastguard Worker      continue;
1874*1b3f573fSAndroid Build Coastguard Worker    }
1875*1b3f573fSAndroid Build Coastguard Worker    if (fieldNumber >= end) {
1876*1b3f573fSAndroid Build Coastguard Worker      break;
1877*1b3f573fSAndroid Build Coastguard Worker    }
1878*1b3f573fSAndroid Build Coastguard Worker    id value = [extensionMap_ objectForKey:extension];
1879*1b3f573fSAndroid Build Coastguard Worker    GPBWriteExtensionValueToOutputStream(extension, value, output);
1880*1b3f573fSAndroid Build Coastguard Worker  }
1881*1b3f573fSAndroid Build Coastguard Worker}
1882*1b3f573fSAndroid Build Coastguard Worker
1883*1b3f573fSAndroid Build Coastguard Worker- (void)setExtension:(GPBExtensionDescriptor *)extension value:(id)value {
1884*1b3f573fSAndroid Build Coastguard Worker  if (!value) {
1885*1b3f573fSAndroid Build Coastguard Worker    [self clearExtension:extension];
1886*1b3f573fSAndroid Build Coastguard Worker    return;
1887*1b3f573fSAndroid Build Coastguard Worker  }
1888*1b3f573fSAndroid Build Coastguard Worker
1889*1b3f573fSAndroid Build Coastguard Worker  CheckExtension(self, extension);
1890*1b3f573fSAndroid Build Coastguard Worker
1891*1b3f573fSAndroid Build Coastguard Worker  if (extension.repeated) {
1892*1b3f573fSAndroid Build Coastguard Worker    [NSException raise:NSInvalidArgumentException
1893*1b3f573fSAndroid Build Coastguard Worker                format:@"Must call addExtension() for repeated types."];
1894*1b3f573fSAndroid Build Coastguard Worker  }
1895*1b3f573fSAndroid Build Coastguard Worker
1896*1b3f573fSAndroid Build Coastguard Worker  if (extensionMap_ == nil) {
1897*1b3f573fSAndroid Build Coastguard Worker    extensionMap_ = [[NSMutableDictionary alloc] init];
1898*1b3f573fSAndroid Build Coastguard Worker  }
1899*1b3f573fSAndroid Build Coastguard Worker
1900*1b3f573fSAndroid Build Coastguard Worker  // This pointless cast is for CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION.
1901*1b3f573fSAndroid Build Coastguard Worker  // Without it, the compiler complains we're passing an id nullable when
1902*1b3f573fSAndroid Build Coastguard Worker  // setObject:forKey: requires a id nonnull for the value. The check for
1903*1b3f573fSAndroid Build Coastguard Worker  // !value at the start of the method ensures it isn't nil, but the check
1904*1b3f573fSAndroid Build Coastguard Worker  // isn't smart enough to realize that.
1905*1b3f573fSAndroid Build Coastguard Worker  [extensionMap_ setObject:(id)value forKey:extension];
1906*1b3f573fSAndroid Build Coastguard Worker
1907*1b3f573fSAndroid Build Coastguard Worker  GPBExtensionDescriptor *descriptor = extension;
1908*1b3f573fSAndroid Build Coastguard Worker
1909*1b3f573fSAndroid Build Coastguard Worker  if (GPBExtensionIsMessage(descriptor) && !descriptor.isRepeated) {
1910*1b3f573fSAndroid Build Coastguard Worker    GPBMessage *autocreatedValue =
1911*1b3f573fSAndroid Build Coastguard Worker        [[autocreatedExtensionMap_ objectForKey:extension] retain];
1912*1b3f573fSAndroid Build Coastguard Worker    // Must remove from the map before calling GPBClearMessageAutocreator() so
1913*1b3f573fSAndroid Build Coastguard Worker    // that GPBClearMessageAutocreator() knows its safe to clear.
1914*1b3f573fSAndroid Build Coastguard Worker    [autocreatedExtensionMap_ removeObjectForKey:extension];
1915*1b3f573fSAndroid Build Coastguard Worker    GPBClearMessageAutocreator(autocreatedValue);
1916*1b3f573fSAndroid Build Coastguard Worker    [autocreatedValue release];
1917*1b3f573fSAndroid Build Coastguard Worker  }
1918*1b3f573fSAndroid Build Coastguard Worker
1919*1b3f573fSAndroid Build Coastguard Worker  GPBBecomeVisibleToAutocreator(self);
1920*1b3f573fSAndroid Build Coastguard Worker}
1921*1b3f573fSAndroid Build Coastguard Worker
1922*1b3f573fSAndroid Build Coastguard Worker- (void)addExtension:(GPBExtensionDescriptor *)extension value:(id)value {
1923*1b3f573fSAndroid Build Coastguard Worker  CheckExtension(self, extension);
1924*1b3f573fSAndroid Build Coastguard Worker
1925*1b3f573fSAndroid Build Coastguard Worker  if (!extension.repeated) {
1926*1b3f573fSAndroid Build Coastguard Worker    [NSException raise:NSInvalidArgumentException
1927*1b3f573fSAndroid Build Coastguard Worker                format:@"Must call setExtension() for singular types."];
1928*1b3f573fSAndroid Build Coastguard Worker  }
1929*1b3f573fSAndroid Build Coastguard Worker
1930*1b3f573fSAndroid Build Coastguard Worker  if (extensionMap_ == nil) {
1931*1b3f573fSAndroid Build Coastguard Worker    extensionMap_ = [[NSMutableDictionary alloc] init];
1932*1b3f573fSAndroid Build Coastguard Worker  }
1933*1b3f573fSAndroid Build Coastguard Worker  NSMutableArray *list = [extensionMap_ objectForKey:extension];
1934*1b3f573fSAndroid Build Coastguard Worker  if (list == nil) {
1935*1b3f573fSAndroid Build Coastguard Worker    list = [NSMutableArray array];
1936*1b3f573fSAndroid Build Coastguard Worker    [extensionMap_ setObject:list forKey:extension];
1937*1b3f573fSAndroid Build Coastguard Worker  }
1938*1b3f573fSAndroid Build Coastguard Worker
1939*1b3f573fSAndroid Build Coastguard Worker  [list addObject:value];
1940*1b3f573fSAndroid Build Coastguard Worker  GPBBecomeVisibleToAutocreator(self);
1941*1b3f573fSAndroid Build Coastguard Worker}
1942*1b3f573fSAndroid Build Coastguard Worker
1943*1b3f573fSAndroid Build Coastguard Worker- (void)setExtension:(GPBExtensionDescriptor *)extension
1944*1b3f573fSAndroid Build Coastguard Worker               index:(NSUInteger)idx
1945*1b3f573fSAndroid Build Coastguard Worker               value:(id)value {
1946*1b3f573fSAndroid Build Coastguard Worker  CheckExtension(self, extension);
1947*1b3f573fSAndroid Build Coastguard Worker
1948*1b3f573fSAndroid Build Coastguard Worker  if (!extension.repeated) {
1949*1b3f573fSAndroid Build Coastguard Worker    [NSException raise:NSInvalidArgumentException
1950*1b3f573fSAndroid Build Coastguard Worker                format:@"Must call setExtension() for singular types."];
1951*1b3f573fSAndroid Build Coastguard Worker  }
1952*1b3f573fSAndroid Build Coastguard Worker
1953*1b3f573fSAndroid Build Coastguard Worker  if (extensionMap_ == nil) {
1954*1b3f573fSAndroid Build Coastguard Worker    extensionMap_ = [[NSMutableDictionary alloc] init];
1955*1b3f573fSAndroid Build Coastguard Worker  }
1956*1b3f573fSAndroid Build Coastguard Worker
1957*1b3f573fSAndroid Build Coastguard Worker  NSMutableArray *list = [extensionMap_ objectForKey:extension];
1958*1b3f573fSAndroid Build Coastguard Worker
1959*1b3f573fSAndroid Build Coastguard Worker  [list replaceObjectAtIndex:idx withObject:value];
1960*1b3f573fSAndroid Build Coastguard Worker  GPBBecomeVisibleToAutocreator(self);
1961*1b3f573fSAndroid Build Coastguard Worker}
1962*1b3f573fSAndroid Build Coastguard Worker
1963*1b3f573fSAndroid Build Coastguard Worker- (void)clearExtension:(GPBExtensionDescriptor *)extension {
1964*1b3f573fSAndroid Build Coastguard Worker  CheckExtension(self, extension);
1965*1b3f573fSAndroid Build Coastguard Worker
1966*1b3f573fSAndroid Build Coastguard Worker  // Only become visible if there was actually a value to clear.
1967*1b3f573fSAndroid Build Coastguard Worker  if ([extensionMap_ objectForKey:extension]) {
1968*1b3f573fSAndroid Build Coastguard Worker    [extensionMap_ removeObjectForKey:extension];
1969*1b3f573fSAndroid Build Coastguard Worker    GPBBecomeVisibleToAutocreator(self);
1970*1b3f573fSAndroid Build Coastguard Worker  }
1971*1b3f573fSAndroid Build Coastguard Worker}
1972*1b3f573fSAndroid Build Coastguard Worker
1973*1b3f573fSAndroid Build Coastguard Worker#pragma mark - mergeFrom
1974*1b3f573fSAndroid Build Coastguard Worker
1975*1b3f573fSAndroid Build Coastguard Worker- (void)mergeFromData:(NSData *)data
1976*1b3f573fSAndroid Build Coastguard Worker    extensionRegistry:(GPBExtensionRegistry *)extensionRegistry {
1977*1b3f573fSAndroid Build Coastguard Worker  GPBCodedInputStream *input = [[GPBCodedInputStream alloc] initWithData:data];
1978*1b3f573fSAndroid Build Coastguard Worker  [self mergeFromCodedInputStream:input extensionRegistry:extensionRegistry];
1979*1b3f573fSAndroid Build Coastguard Worker  [input checkLastTagWas:0];
1980*1b3f573fSAndroid Build Coastguard Worker  [input release];
1981*1b3f573fSAndroid Build Coastguard Worker}
1982*1b3f573fSAndroid Build Coastguard Worker
1983*1b3f573fSAndroid Build Coastguard Worker#pragma mark - mergeDelimitedFrom
1984*1b3f573fSAndroid Build Coastguard Worker
1985*1b3f573fSAndroid Build Coastguard Worker- (void)mergeDelimitedFromCodedInputStream:(GPBCodedInputStream *)input
1986*1b3f573fSAndroid Build Coastguard Worker                         extensionRegistry:(GPBExtensionRegistry *)extensionRegistry {
1987*1b3f573fSAndroid Build Coastguard Worker  GPBCodedInputStreamState *state = &input->state_;
1988*1b3f573fSAndroid Build Coastguard Worker  if (GPBCodedInputStreamIsAtEnd(state)) {
1989*1b3f573fSAndroid Build Coastguard Worker    return;
1990*1b3f573fSAndroid Build Coastguard Worker  }
1991*1b3f573fSAndroid Build Coastguard Worker  NSData *data = GPBCodedInputStreamReadRetainedBytesNoCopy(state);
1992*1b3f573fSAndroid Build Coastguard Worker  if (data == nil) {
1993*1b3f573fSAndroid Build Coastguard Worker    return;
1994*1b3f573fSAndroid Build Coastguard Worker  }
1995*1b3f573fSAndroid Build Coastguard Worker  [self mergeFromData:data extensionRegistry:extensionRegistry];
1996*1b3f573fSAndroid Build Coastguard Worker  [data release];
1997*1b3f573fSAndroid Build Coastguard Worker}
1998*1b3f573fSAndroid Build Coastguard Worker
1999*1b3f573fSAndroid Build Coastguard Worker#pragma mark - Parse From Data Support
2000*1b3f573fSAndroid Build Coastguard Worker
2001*1b3f573fSAndroid Build Coastguard Worker+ (instancetype)parseFromData:(NSData *)data error:(NSError **)errorPtr {
2002*1b3f573fSAndroid Build Coastguard Worker  return [self parseFromData:data extensionRegistry:nil error:errorPtr];
2003*1b3f573fSAndroid Build Coastguard Worker}
2004*1b3f573fSAndroid Build Coastguard Worker
2005*1b3f573fSAndroid Build Coastguard Worker+ (instancetype)parseFromData:(NSData *)data
2006*1b3f573fSAndroid Build Coastguard Worker            extensionRegistry:(GPBExtensionRegistry *)extensionRegistry
2007*1b3f573fSAndroid Build Coastguard Worker                        error:(NSError **)errorPtr {
2008*1b3f573fSAndroid Build Coastguard Worker  return [[[self alloc] initWithData:data
2009*1b3f573fSAndroid Build Coastguard Worker                   extensionRegistry:extensionRegistry
2010*1b3f573fSAndroid Build Coastguard Worker                               error:errorPtr] autorelease];
2011*1b3f573fSAndroid Build Coastguard Worker}
2012*1b3f573fSAndroid Build Coastguard Worker
2013*1b3f573fSAndroid Build Coastguard Worker+ (instancetype)parseFromCodedInputStream:(GPBCodedInputStream *)input
2014*1b3f573fSAndroid Build Coastguard Worker                        extensionRegistry:(GPBExtensionRegistry *)extensionRegistry
2015*1b3f573fSAndroid Build Coastguard Worker                                    error:(NSError **)errorPtr {
2016*1b3f573fSAndroid Build Coastguard Worker  return
2017*1b3f573fSAndroid Build Coastguard Worker      [[[self alloc] initWithCodedInputStream:input
2018*1b3f573fSAndroid Build Coastguard Worker                            extensionRegistry:extensionRegistry
2019*1b3f573fSAndroid Build Coastguard Worker                                        error:errorPtr] autorelease];
2020*1b3f573fSAndroid Build Coastguard Worker}
2021*1b3f573fSAndroid Build Coastguard Worker
2022*1b3f573fSAndroid Build Coastguard Worker#pragma mark - Parse Delimited From Data Support
2023*1b3f573fSAndroid Build Coastguard Worker
2024*1b3f573fSAndroid Build Coastguard Worker+ (instancetype)parseDelimitedFromCodedInputStream:(GPBCodedInputStream *)input
2025*1b3f573fSAndroid Build Coastguard Worker                                 extensionRegistry:
2026*1b3f573fSAndroid Build Coastguard Worker                                     (GPBExtensionRegistry *)extensionRegistry
2027*1b3f573fSAndroid Build Coastguard Worker                                             error:(NSError **)errorPtr {
2028*1b3f573fSAndroid Build Coastguard Worker  GPBMessage *message = [[[self alloc] init] autorelease];
2029*1b3f573fSAndroid Build Coastguard Worker  @try {
2030*1b3f573fSAndroid Build Coastguard Worker    [message mergeDelimitedFromCodedInputStream:input
2031*1b3f573fSAndroid Build Coastguard Worker                              extensionRegistry:extensionRegistry];
2032*1b3f573fSAndroid Build Coastguard Worker    if (errorPtr) {
2033*1b3f573fSAndroid Build Coastguard Worker      *errorPtr = nil;
2034*1b3f573fSAndroid Build Coastguard Worker    }
2035*1b3f573fSAndroid Build Coastguard Worker  }
2036*1b3f573fSAndroid Build Coastguard Worker  @catch (NSException *exception) {
2037*1b3f573fSAndroid Build Coastguard Worker    message = nil;
2038*1b3f573fSAndroid Build Coastguard Worker    if (errorPtr) {
2039*1b3f573fSAndroid Build Coastguard Worker      *errorPtr = ErrorFromException(exception);
2040*1b3f573fSAndroid Build Coastguard Worker    }
2041*1b3f573fSAndroid Build Coastguard Worker  }
2042*1b3f573fSAndroid Build Coastguard Worker#ifdef DEBUG
2043*1b3f573fSAndroid Build Coastguard Worker  if (message && !message.initialized) {
2044*1b3f573fSAndroid Build Coastguard Worker    message = nil;
2045*1b3f573fSAndroid Build Coastguard Worker    if (errorPtr) {
2046*1b3f573fSAndroid Build Coastguard Worker      *errorPtr = MessageError(GPBMessageErrorCodeMissingRequiredField, nil);
2047*1b3f573fSAndroid Build Coastguard Worker    }
2048*1b3f573fSAndroid Build Coastguard Worker  }
2049*1b3f573fSAndroid Build Coastguard Worker#endif
2050*1b3f573fSAndroid Build Coastguard Worker  return message;
2051*1b3f573fSAndroid Build Coastguard Worker}
2052*1b3f573fSAndroid Build Coastguard Worker
2053*1b3f573fSAndroid Build Coastguard Worker#pragma mark - Unknown Field Support
2054*1b3f573fSAndroid Build Coastguard Worker
2055*1b3f573fSAndroid Build Coastguard Worker- (GPBUnknownFieldSet *)unknownFields {
2056*1b3f573fSAndroid Build Coastguard Worker  return unknownFields_;
2057*1b3f573fSAndroid Build Coastguard Worker}
2058*1b3f573fSAndroid Build Coastguard Worker
2059*1b3f573fSAndroid Build Coastguard Worker- (void)setUnknownFields:(GPBUnknownFieldSet *)unknownFields {
2060*1b3f573fSAndroid Build Coastguard Worker  if (unknownFields != unknownFields_) {
2061*1b3f573fSAndroid Build Coastguard Worker    [unknownFields_ release];
2062*1b3f573fSAndroid Build Coastguard Worker    unknownFields_ = [unknownFields copy];
2063*1b3f573fSAndroid Build Coastguard Worker    GPBBecomeVisibleToAutocreator(self);
2064*1b3f573fSAndroid Build Coastguard Worker  }
2065*1b3f573fSAndroid Build Coastguard Worker}
2066*1b3f573fSAndroid Build Coastguard Worker
2067*1b3f573fSAndroid Build Coastguard Worker- (void)parseMessageSet:(GPBCodedInputStream *)input
2068*1b3f573fSAndroid Build Coastguard Worker      extensionRegistry:(GPBExtensionRegistry *)extensionRegistry {
2069*1b3f573fSAndroid Build Coastguard Worker  uint32_t typeId = 0;
2070*1b3f573fSAndroid Build Coastguard Worker  NSData *rawBytes = nil;
2071*1b3f573fSAndroid Build Coastguard Worker  GPBExtensionDescriptor *extension = nil;
2072*1b3f573fSAndroid Build Coastguard Worker  GPBCodedInputStreamState *state = &input->state_;
2073*1b3f573fSAndroid Build Coastguard Worker  while (true) {
2074*1b3f573fSAndroid Build Coastguard Worker    uint32_t tag = GPBCodedInputStreamReadTag(state);
2075*1b3f573fSAndroid Build Coastguard Worker    if (tag == 0) {
2076*1b3f573fSAndroid Build Coastguard Worker      break;
2077*1b3f573fSAndroid Build Coastguard Worker    }
2078*1b3f573fSAndroid Build Coastguard Worker
2079*1b3f573fSAndroid Build Coastguard Worker    if (tag == GPBWireFormatMessageSetTypeIdTag) {
2080*1b3f573fSAndroid Build Coastguard Worker      typeId = GPBCodedInputStreamReadUInt32(state);
2081*1b3f573fSAndroid Build Coastguard Worker      if (typeId != 0) {
2082*1b3f573fSAndroid Build Coastguard Worker        extension = [extensionRegistry extensionForDescriptor:[self descriptor]
2083*1b3f573fSAndroid Build Coastguard Worker                                                  fieldNumber:typeId];
2084*1b3f573fSAndroid Build Coastguard Worker      }
2085*1b3f573fSAndroid Build Coastguard Worker    } else if (tag == GPBWireFormatMessageSetMessageTag) {
2086*1b3f573fSAndroid Build Coastguard Worker      rawBytes =
2087*1b3f573fSAndroid Build Coastguard Worker          [GPBCodedInputStreamReadRetainedBytesNoCopy(state) autorelease];
2088*1b3f573fSAndroid Build Coastguard Worker    } else {
2089*1b3f573fSAndroid Build Coastguard Worker      if (![input skipField:tag]) {
2090*1b3f573fSAndroid Build Coastguard Worker        break;
2091*1b3f573fSAndroid Build Coastguard Worker      }
2092*1b3f573fSAndroid Build Coastguard Worker    }
2093*1b3f573fSAndroid Build Coastguard Worker  }
2094*1b3f573fSAndroid Build Coastguard Worker
2095*1b3f573fSAndroid Build Coastguard Worker  [input checkLastTagWas:GPBWireFormatMessageSetItemEndTag];
2096*1b3f573fSAndroid Build Coastguard Worker
2097*1b3f573fSAndroid Build Coastguard Worker  if (rawBytes != nil && typeId != 0) {
2098*1b3f573fSAndroid Build Coastguard Worker    if (extension != nil) {
2099*1b3f573fSAndroid Build Coastguard Worker      GPBCodedInputStream *newInput =
2100*1b3f573fSAndroid Build Coastguard Worker          [[GPBCodedInputStream alloc] initWithData:rawBytes];
2101*1b3f573fSAndroid Build Coastguard Worker      GPBExtensionMergeFromInputStream(extension,
2102*1b3f573fSAndroid Build Coastguard Worker                                       extension.packable,
2103*1b3f573fSAndroid Build Coastguard Worker                                       newInput,
2104*1b3f573fSAndroid Build Coastguard Worker                                       extensionRegistry,
2105*1b3f573fSAndroid Build Coastguard Worker                                       self);
2106*1b3f573fSAndroid Build Coastguard Worker      [newInput release];
2107*1b3f573fSAndroid Build Coastguard Worker    } else {
2108*1b3f573fSAndroid Build Coastguard Worker      GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self);
2109*1b3f573fSAndroid Build Coastguard Worker      // rawBytes was created via a NoCopy, so it can be reusing a
2110*1b3f573fSAndroid Build Coastguard Worker      // subrange of another NSData that might go out of scope as things
2111*1b3f573fSAndroid Build Coastguard Worker      // unwind, so a copy is needed to ensure what is saved in the
2112*1b3f573fSAndroid Build Coastguard Worker      // unknown fields stays valid.
2113*1b3f573fSAndroid Build Coastguard Worker      NSData *cloned = [NSData dataWithData:rawBytes];
2114*1b3f573fSAndroid Build Coastguard Worker      [unknownFields mergeMessageSetMessage:typeId data:cloned];
2115*1b3f573fSAndroid Build Coastguard Worker    }
2116*1b3f573fSAndroid Build Coastguard Worker  }
2117*1b3f573fSAndroid Build Coastguard Worker}
2118*1b3f573fSAndroid Build Coastguard Worker
2119*1b3f573fSAndroid Build Coastguard Worker- (BOOL)parseUnknownField:(GPBCodedInputStream *)input
2120*1b3f573fSAndroid Build Coastguard Worker        extensionRegistry:(GPBExtensionRegistry *)extensionRegistry
2121*1b3f573fSAndroid Build Coastguard Worker                      tag:(uint32_t)tag {
2122*1b3f573fSAndroid Build Coastguard Worker  GPBWireFormat wireType = GPBWireFormatGetTagWireType(tag);
2123*1b3f573fSAndroid Build Coastguard Worker  int32_t fieldNumber = GPBWireFormatGetTagFieldNumber(tag);
2124*1b3f573fSAndroid Build Coastguard Worker
2125*1b3f573fSAndroid Build Coastguard Worker  GPBDescriptor *descriptor = [self descriptor];
2126*1b3f573fSAndroid Build Coastguard Worker  GPBExtensionDescriptor *extension =
2127*1b3f573fSAndroid Build Coastguard Worker      [extensionRegistry extensionForDescriptor:descriptor
2128*1b3f573fSAndroid Build Coastguard Worker                                    fieldNumber:fieldNumber];
2129*1b3f573fSAndroid Build Coastguard Worker  if (extension == nil) {
2130*1b3f573fSAndroid Build Coastguard Worker    if (descriptor.wireFormat && GPBWireFormatMessageSetItemTag == tag) {
2131*1b3f573fSAndroid Build Coastguard Worker      [self parseMessageSet:input extensionRegistry:extensionRegistry];
2132*1b3f573fSAndroid Build Coastguard Worker      return YES;
2133*1b3f573fSAndroid Build Coastguard Worker    }
2134*1b3f573fSAndroid Build Coastguard Worker  } else {
2135*1b3f573fSAndroid Build Coastguard Worker    if (extension.wireType == wireType) {
2136*1b3f573fSAndroid Build Coastguard Worker      GPBExtensionMergeFromInputStream(extension,
2137*1b3f573fSAndroid Build Coastguard Worker                                       extension.packable,
2138*1b3f573fSAndroid Build Coastguard Worker                                       input,
2139*1b3f573fSAndroid Build Coastguard Worker                                       extensionRegistry,
2140*1b3f573fSAndroid Build Coastguard Worker                                       self);
2141*1b3f573fSAndroid Build Coastguard Worker      return YES;
2142*1b3f573fSAndroid Build Coastguard Worker    }
2143*1b3f573fSAndroid Build Coastguard Worker    // Primitive, repeated types can be packed on unpacked on the wire, and are
2144*1b3f573fSAndroid Build Coastguard Worker    // parsed either way.
2145*1b3f573fSAndroid Build Coastguard Worker    if ([extension isRepeated] &&
2146*1b3f573fSAndroid Build Coastguard Worker        !GPBDataTypeIsObject(extension->description_->dataType) &&
2147*1b3f573fSAndroid Build Coastguard Worker        (extension.alternateWireType == wireType)) {
2148*1b3f573fSAndroid Build Coastguard Worker      GPBExtensionMergeFromInputStream(extension,
2149*1b3f573fSAndroid Build Coastguard Worker                                       !extension.packable,
2150*1b3f573fSAndroid Build Coastguard Worker                                       input,
2151*1b3f573fSAndroid Build Coastguard Worker                                       extensionRegistry,
2152*1b3f573fSAndroid Build Coastguard Worker                                       self);
2153*1b3f573fSAndroid Build Coastguard Worker      return YES;
2154*1b3f573fSAndroid Build Coastguard Worker    }
2155*1b3f573fSAndroid Build Coastguard Worker  }
2156*1b3f573fSAndroid Build Coastguard Worker  if ([GPBUnknownFieldSet isFieldTag:tag]) {
2157*1b3f573fSAndroid Build Coastguard Worker    GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self);
2158*1b3f573fSAndroid Build Coastguard Worker    return [unknownFields mergeFieldFrom:tag input:input];
2159*1b3f573fSAndroid Build Coastguard Worker  } else {
2160*1b3f573fSAndroid Build Coastguard Worker    return NO;
2161*1b3f573fSAndroid Build Coastguard Worker  }
2162*1b3f573fSAndroid Build Coastguard Worker}
2163*1b3f573fSAndroid Build Coastguard Worker
2164*1b3f573fSAndroid Build Coastguard Worker- (void)addUnknownMapEntry:(int32_t)fieldNum value:(NSData *)data {
2165*1b3f573fSAndroid Build Coastguard Worker  GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self);
2166*1b3f573fSAndroid Build Coastguard Worker  [unknownFields addUnknownMapEntry:fieldNum value:data];
2167*1b3f573fSAndroid Build Coastguard Worker}
2168*1b3f573fSAndroid Build Coastguard Worker
2169*1b3f573fSAndroid Build Coastguard Worker#pragma mark - MergeFromCodedInputStream Support
2170*1b3f573fSAndroid Build Coastguard Worker
2171*1b3f573fSAndroid Build Coastguard Workerstatic void MergeSingleFieldFromCodedInputStream(
2172*1b3f573fSAndroid Build Coastguard Worker    GPBMessage *self, GPBFieldDescriptor *field, GPBFileSyntax syntax,
2173*1b3f573fSAndroid Build Coastguard Worker    GPBCodedInputStream *input, GPBExtensionRegistry *extensionRegistry) {
2174*1b3f573fSAndroid Build Coastguard Worker  GPBDataType fieldDataType = GPBGetFieldDataType(field);
2175*1b3f573fSAndroid Build Coastguard Worker  switch (fieldDataType) {
2176*1b3f573fSAndroid Build Coastguard Worker#define CASE_SINGLE_POD(NAME, TYPE, FUNC_TYPE)                             \
2177*1b3f573fSAndroid Build Coastguard Worker    case GPBDataType##NAME: {                                              \
2178*1b3f573fSAndroid Build Coastguard Worker      TYPE val = GPBCodedInputStreamRead##NAME(&input->state_);            \
2179*1b3f573fSAndroid Build Coastguard Worker      GPBSet##FUNC_TYPE##IvarWithFieldPrivate(self, field, val);           \
2180*1b3f573fSAndroid Build Coastguard Worker      break;                                                               \
2181*1b3f573fSAndroid Build Coastguard Worker            }
2182*1b3f573fSAndroid Build Coastguard Worker#define CASE_SINGLE_OBJECT(NAME)                                           \
2183*1b3f573fSAndroid Build Coastguard Worker    case GPBDataType##NAME: {                                              \
2184*1b3f573fSAndroid Build Coastguard Worker      id val = GPBCodedInputStreamReadRetained##NAME(&input->state_);      \
2185*1b3f573fSAndroid Build Coastguard Worker      GPBSetRetainedObjectIvarWithFieldPrivate(self, field, val);          \
2186*1b3f573fSAndroid Build Coastguard Worker      break;                                                               \
2187*1b3f573fSAndroid Build Coastguard Worker    }
2188*1b3f573fSAndroid Build Coastguard Worker      CASE_SINGLE_POD(Bool, BOOL, Bool)
2189*1b3f573fSAndroid Build Coastguard Worker      CASE_SINGLE_POD(Fixed32, uint32_t, UInt32)
2190*1b3f573fSAndroid Build Coastguard Worker      CASE_SINGLE_POD(SFixed32, int32_t, Int32)
2191*1b3f573fSAndroid Build Coastguard Worker      CASE_SINGLE_POD(Float, float, Float)
2192*1b3f573fSAndroid Build Coastguard Worker      CASE_SINGLE_POD(Fixed64, uint64_t, UInt64)
2193*1b3f573fSAndroid Build Coastguard Worker      CASE_SINGLE_POD(SFixed64, int64_t, Int64)
2194*1b3f573fSAndroid Build Coastguard Worker      CASE_SINGLE_POD(Double, double, Double)
2195*1b3f573fSAndroid Build Coastguard Worker      CASE_SINGLE_POD(Int32, int32_t, Int32)
2196*1b3f573fSAndroid Build Coastguard Worker      CASE_SINGLE_POD(Int64, int64_t, Int64)
2197*1b3f573fSAndroid Build Coastguard Worker      CASE_SINGLE_POD(SInt32, int32_t, Int32)
2198*1b3f573fSAndroid Build Coastguard Worker      CASE_SINGLE_POD(SInt64, int64_t, Int64)
2199*1b3f573fSAndroid Build Coastguard Worker      CASE_SINGLE_POD(UInt32, uint32_t, UInt32)
2200*1b3f573fSAndroid Build Coastguard Worker      CASE_SINGLE_POD(UInt64, uint64_t, UInt64)
2201*1b3f573fSAndroid Build Coastguard Worker      CASE_SINGLE_OBJECT(Bytes)
2202*1b3f573fSAndroid Build Coastguard Worker      CASE_SINGLE_OBJECT(String)
2203*1b3f573fSAndroid Build Coastguard Worker#undef CASE_SINGLE_POD
2204*1b3f573fSAndroid Build Coastguard Worker#undef CASE_SINGLE_OBJECT
2205*1b3f573fSAndroid Build Coastguard Worker
2206*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeMessage: {
2207*1b3f573fSAndroid Build Coastguard Worker      if (GPBGetHasIvarField(self, field)) {
2208*1b3f573fSAndroid Build Coastguard Worker        // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has
2209*1b3f573fSAndroid Build Coastguard Worker        // check again.
2210*1b3f573fSAndroid Build Coastguard Worker        GPBMessage *message =
2211*1b3f573fSAndroid Build Coastguard Worker            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
2212*1b3f573fSAndroid Build Coastguard Worker        [input readMessage:message extensionRegistry:extensionRegistry];
2213*1b3f573fSAndroid Build Coastguard Worker      } else {
2214*1b3f573fSAndroid Build Coastguard Worker        GPBMessage *message = [[field.msgClass alloc] init];
2215*1b3f573fSAndroid Build Coastguard Worker        [input readMessage:message extensionRegistry:extensionRegistry];
2216*1b3f573fSAndroid Build Coastguard Worker        GPBSetRetainedObjectIvarWithFieldPrivate(self, field, message);
2217*1b3f573fSAndroid Build Coastguard Worker      }
2218*1b3f573fSAndroid Build Coastguard Worker      break;
2219*1b3f573fSAndroid Build Coastguard Worker    }
2220*1b3f573fSAndroid Build Coastguard Worker
2221*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeGroup: {
2222*1b3f573fSAndroid Build Coastguard Worker      if (GPBGetHasIvarField(self, field)) {
2223*1b3f573fSAndroid Build Coastguard Worker        // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has
2224*1b3f573fSAndroid Build Coastguard Worker        // check again.
2225*1b3f573fSAndroid Build Coastguard Worker        GPBMessage *message =
2226*1b3f573fSAndroid Build Coastguard Worker            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
2227*1b3f573fSAndroid Build Coastguard Worker        [input readGroup:GPBFieldNumber(field)
2228*1b3f573fSAndroid Build Coastguard Worker                      message:message
2229*1b3f573fSAndroid Build Coastguard Worker            extensionRegistry:extensionRegistry];
2230*1b3f573fSAndroid Build Coastguard Worker      } else {
2231*1b3f573fSAndroid Build Coastguard Worker        GPBMessage *message = [[field.msgClass alloc] init];
2232*1b3f573fSAndroid Build Coastguard Worker        [input readGroup:GPBFieldNumber(field)
2233*1b3f573fSAndroid Build Coastguard Worker                      message:message
2234*1b3f573fSAndroid Build Coastguard Worker            extensionRegistry:extensionRegistry];
2235*1b3f573fSAndroid Build Coastguard Worker        GPBSetRetainedObjectIvarWithFieldPrivate(self, field, message);
2236*1b3f573fSAndroid Build Coastguard Worker      }
2237*1b3f573fSAndroid Build Coastguard Worker      break;
2238*1b3f573fSAndroid Build Coastguard Worker    }
2239*1b3f573fSAndroid Build Coastguard Worker
2240*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeEnum: {
2241*1b3f573fSAndroid Build Coastguard Worker      int32_t val = GPBCodedInputStreamReadEnum(&input->state_);
2242*1b3f573fSAndroid Build Coastguard Worker      if (GPBHasPreservingUnknownEnumSemantics(syntax) ||
2243*1b3f573fSAndroid Build Coastguard Worker          [field isValidEnumValue:val]) {
2244*1b3f573fSAndroid Build Coastguard Worker        GPBSetInt32IvarWithFieldPrivate(self, field, val);
2245*1b3f573fSAndroid Build Coastguard Worker      } else {
2246*1b3f573fSAndroid Build Coastguard Worker        GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self);
2247*1b3f573fSAndroid Build Coastguard Worker        [unknownFields mergeVarintField:GPBFieldNumber(field) value:val];
2248*1b3f573fSAndroid Build Coastguard Worker      }
2249*1b3f573fSAndroid Build Coastguard Worker    }
2250*1b3f573fSAndroid Build Coastguard Worker  }  // switch
2251*1b3f573fSAndroid Build Coastguard Worker}
2252*1b3f573fSAndroid Build Coastguard Worker
2253*1b3f573fSAndroid Build Coastguard Workerstatic void MergeRepeatedPackedFieldFromCodedInputStream(
2254*1b3f573fSAndroid Build Coastguard Worker    GPBMessage *self, GPBFieldDescriptor *field, GPBFileSyntax syntax,
2255*1b3f573fSAndroid Build Coastguard Worker    GPBCodedInputStream *input) {
2256*1b3f573fSAndroid Build Coastguard Worker  GPBDataType fieldDataType = GPBGetFieldDataType(field);
2257*1b3f573fSAndroid Build Coastguard Worker  GPBCodedInputStreamState *state = &input->state_;
2258*1b3f573fSAndroid Build Coastguard Worker  id genericArray = GetOrCreateArrayIvarWithField(self, field);
2259*1b3f573fSAndroid Build Coastguard Worker  int32_t length = GPBCodedInputStreamReadInt32(state);
2260*1b3f573fSAndroid Build Coastguard Worker  size_t limit = GPBCodedInputStreamPushLimit(state, length);
2261*1b3f573fSAndroid Build Coastguard Worker  while (GPBCodedInputStreamBytesUntilLimit(state) > 0) {
2262*1b3f573fSAndroid Build Coastguard Worker    switch (fieldDataType) {
2263*1b3f573fSAndroid Build Coastguard Worker#define CASE_REPEATED_PACKED_POD(NAME, TYPE, ARRAY_TYPE)      \
2264*1b3f573fSAndroid Build Coastguard Worker     case GPBDataType##NAME: {                                \
2265*1b3f573fSAndroid Build Coastguard Worker       TYPE val = GPBCodedInputStreamRead##NAME(state);       \
2266*1b3f573fSAndroid Build Coastguard Worker       [(GPB##ARRAY_TYPE##Array *)genericArray addValue:val]; \
2267*1b3f573fSAndroid Build Coastguard Worker       break;                                                 \
2268*1b3f573fSAndroid Build Coastguard Worker     }
2269*1b3f573fSAndroid Build Coastguard Worker        CASE_REPEATED_PACKED_POD(Bool, BOOL, Bool)
2270*1b3f573fSAndroid Build Coastguard Worker        CASE_REPEATED_PACKED_POD(Fixed32, uint32_t, UInt32)
2271*1b3f573fSAndroid Build Coastguard Worker        CASE_REPEATED_PACKED_POD(SFixed32, int32_t, Int32)
2272*1b3f573fSAndroid Build Coastguard Worker        CASE_REPEATED_PACKED_POD(Float, float, Float)
2273*1b3f573fSAndroid Build Coastguard Worker        CASE_REPEATED_PACKED_POD(Fixed64, uint64_t, UInt64)
2274*1b3f573fSAndroid Build Coastguard Worker        CASE_REPEATED_PACKED_POD(SFixed64, int64_t, Int64)
2275*1b3f573fSAndroid Build Coastguard Worker        CASE_REPEATED_PACKED_POD(Double, double, Double)
2276*1b3f573fSAndroid Build Coastguard Worker        CASE_REPEATED_PACKED_POD(Int32, int32_t, Int32)
2277*1b3f573fSAndroid Build Coastguard Worker        CASE_REPEATED_PACKED_POD(Int64, int64_t, Int64)
2278*1b3f573fSAndroid Build Coastguard Worker        CASE_REPEATED_PACKED_POD(SInt32, int32_t, Int32)
2279*1b3f573fSAndroid Build Coastguard Worker        CASE_REPEATED_PACKED_POD(SInt64, int64_t, Int64)
2280*1b3f573fSAndroid Build Coastguard Worker        CASE_REPEATED_PACKED_POD(UInt32, uint32_t, UInt32)
2281*1b3f573fSAndroid Build Coastguard Worker        CASE_REPEATED_PACKED_POD(UInt64, uint64_t, UInt64)
2282*1b3f573fSAndroid Build Coastguard Worker#undef CASE_REPEATED_PACKED_POD
2283*1b3f573fSAndroid Build Coastguard Worker
2284*1b3f573fSAndroid Build Coastguard Worker      case GPBDataTypeBytes:
2285*1b3f573fSAndroid Build Coastguard Worker      case GPBDataTypeString:
2286*1b3f573fSAndroid Build Coastguard Worker      case GPBDataTypeMessage:
2287*1b3f573fSAndroid Build Coastguard Worker      case GPBDataTypeGroup:
2288*1b3f573fSAndroid Build Coastguard Worker        NSCAssert(NO, @"Non primitive types can't be packed");
2289*1b3f573fSAndroid Build Coastguard Worker        break;
2290*1b3f573fSAndroid Build Coastguard Worker
2291*1b3f573fSAndroid Build Coastguard Worker      case GPBDataTypeEnum: {
2292*1b3f573fSAndroid Build Coastguard Worker        int32_t val = GPBCodedInputStreamReadEnum(state);
2293*1b3f573fSAndroid Build Coastguard Worker        if (GPBHasPreservingUnknownEnumSemantics(syntax) ||
2294*1b3f573fSAndroid Build Coastguard Worker            [field isValidEnumValue:val]) {
2295*1b3f573fSAndroid Build Coastguard Worker          [(GPBEnumArray*)genericArray addRawValue:val];
2296*1b3f573fSAndroid Build Coastguard Worker        } else {
2297*1b3f573fSAndroid Build Coastguard Worker          GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self);
2298*1b3f573fSAndroid Build Coastguard Worker          [unknownFields mergeVarintField:GPBFieldNumber(field) value:val];
2299*1b3f573fSAndroid Build Coastguard Worker        }
2300*1b3f573fSAndroid Build Coastguard Worker        break;
2301*1b3f573fSAndroid Build Coastguard Worker      }
2302*1b3f573fSAndroid Build Coastguard Worker    }  // switch
2303*1b3f573fSAndroid Build Coastguard Worker  }  // while(BytesUntilLimit() > 0)
2304*1b3f573fSAndroid Build Coastguard Worker  GPBCodedInputStreamPopLimit(state, limit);
2305*1b3f573fSAndroid Build Coastguard Worker}
2306*1b3f573fSAndroid Build Coastguard Worker
2307*1b3f573fSAndroid Build Coastguard Workerstatic void MergeRepeatedNotPackedFieldFromCodedInputStream(
2308*1b3f573fSAndroid Build Coastguard Worker    GPBMessage *self, GPBFieldDescriptor *field, GPBFileSyntax syntax,
2309*1b3f573fSAndroid Build Coastguard Worker    GPBCodedInputStream *input, GPBExtensionRegistry *extensionRegistry) {
2310*1b3f573fSAndroid Build Coastguard Worker  GPBCodedInputStreamState *state = &input->state_;
2311*1b3f573fSAndroid Build Coastguard Worker  id genericArray = GetOrCreateArrayIvarWithField(self, field);
2312*1b3f573fSAndroid Build Coastguard Worker  switch (GPBGetFieldDataType(field)) {
2313*1b3f573fSAndroid Build Coastguard Worker#define CASE_REPEATED_NOT_PACKED_POD(NAME, TYPE, ARRAY_TYPE) \
2314*1b3f573fSAndroid Build Coastguard Worker   case GPBDataType##NAME: {                                 \
2315*1b3f573fSAndroid Build Coastguard Worker     TYPE val = GPBCodedInputStreamRead##NAME(state);        \
2316*1b3f573fSAndroid Build Coastguard Worker     [(GPB##ARRAY_TYPE##Array *)genericArray addValue:val];  \
2317*1b3f573fSAndroid Build Coastguard Worker     break;                                                  \
2318*1b3f573fSAndroid Build Coastguard Worker   }
2319*1b3f573fSAndroid Build Coastguard Worker#define CASE_REPEATED_NOT_PACKED_OBJECT(NAME)                \
2320*1b3f573fSAndroid Build Coastguard Worker   case GPBDataType##NAME: {                                 \
2321*1b3f573fSAndroid Build Coastguard Worker     id val = GPBCodedInputStreamReadRetained##NAME(state);  \
2322*1b3f573fSAndroid Build Coastguard Worker     [(NSMutableArray*)genericArray addObject:val];          \
2323*1b3f573fSAndroid Build Coastguard Worker     [val release];                                          \
2324*1b3f573fSAndroid Build Coastguard Worker     break;                                                  \
2325*1b3f573fSAndroid Build Coastguard Worker   }
2326*1b3f573fSAndroid Build Coastguard Worker      CASE_REPEATED_NOT_PACKED_POD(Bool, BOOL, Bool)
2327*1b3f573fSAndroid Build Coastguard Worker      CASE_REPEATED_NOT_PACKED_POD(Fixed32, uint32_t, UInt32)
2328*1b3f573fSAndroid Build Coastguard Worker      CASE_REPEATED_NOT_PACKED_POD(SFixed32, int32_t, Int32)
2329*1b3f573fSAndroid Build Coastguard Worker      CASE_REPEATED_NOT_PACKED_POD(Float, float, Float)
2330*1b3f573fSAndroid Build Coastguard Worker      CASE_REPEATED_NOT_PACKED_POD(Fixed64, uint64_t, UInt64)
2331*1b3f573fSAndroid Build Coastguard Worker      CASE_REPEATED_NOT_PACKED_POD(SFixed64, int64_t, Int64)
2332*1b3f573fSAndroid Build Coastguard Worker      CASE_REPEATED_NOT_PACKED_POD(Double, double, Double)
2333*1b3f573fSAndroid Build Coastguard Worker      CASE_REPEATED_NOT_PACKED_POD(Int32, int32_t, Int32)
2334*1b3f573fSAndroid Build Coastguard Worker      CASE_REPEATED_NOT_PACKED_POD(Int64, int64_t, Int64)
2335*1b3f573fSAndroid Build Coastguard Worker      CASE_REPEATED_NOT_PACKED_POD(SInt32, int32_t, Int32)
2336*1b3f573fSAndroid Build Coastguard Worker      CASE_REPEATED_NOT_PACKED_POD(SInt64, int64_t, Int64)
2337*1b3f573fSAndroid Build Coastguard Worker      CASE_REPEATED_NOT_PACKED_POD(UInt32, uint32_t, UInt32)
2338*1b3f573fSAndroid Build Coastguard Worker      CASE_REPEATED_NOT_PACKED_POD(UInt64, uint64_t, UInt64)
2339*1b3f573fSAndroid Build Coastguard Worker      CASE_REPEATED_NOT_PACKED_OBJECT(Bytes)
2340*1b3f573fSAndroid Build Coastguard Worker      CASE_REPEATED_NOT_PACKED_OBJECT(String)
2341*1b3f573fSAndroid Build Coastguard Worker#undef CASE_REPEATED_NOT_PACKED_POD
2342*1b3f573fSAndroid Build Coastguard Worker#undef CASE_NOT_PACKED_OBJECT
2343*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeMessage: {
2344*1b3f573fSAndroid Build Coastguard Worker      GPBMessage *message = [[field.msgClass alloc] init];
2345*1b3f573fSAndroid Build Coastguard Worker      [input readMessage:message extensionRegistry:extensionRegistry];
2346*1b3f573fSAndroid Build Coastguard Worker      [(NSMutableArray*)genericArray addObject:message];
2347*1b3f573fSAndroid Build Coastguard Worker      [message release];
2348*1b3f573fSAndroid Build Coastguard Worker      break;
2349*1b3f573fSAndroid Build Coastguard Worker    }
2350*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeGroup: {
2351*1b3f573fSAndroid Build Coastguard Worker      GPBMessage *message = [[field.msgClass alloc] init];
2352*1b3f573fSAndroid Build Coastguard Worker      [input readGroup:GPBFieldNumber(field)
2353*1b3f573fSAndroid Build Coastguard Worker                    message:message
2354*1b3f573fSAndroid Build Coastguard Worker          extensionRegistry:extensionRegistry];
2355*1b3f573fSAndroid Build Coastguard Worker      [(NSMutableArray*)genericArray addObject:message];
2356*1b3f573fSAndroid Build Coastguard Worker      [message release];
2357*1b3f573fSAndroid Build Coastguard Worker      break;
2358*1b3f573fSAndroid Build Coastguard Worker    }
2359*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeEnum: {
2360*1b3f573fSAndroid Build Coastguard Worker      int32_t val = GPBCodedInputStreamReadEnum(state);
2361*1b3f573fSAndroid Build Coastguard Worker      if (GPBHasPreservingUnknownEnumSemantics(syntax) ||
2362*1b3f573fSAndroid Build Coastguard Worker          [field isValidEnumValue:val]) {
2363*1b3f573fSAndroid Build Coastguard Worker        [(GPBEnumArray*)genericArray addRawValue:val];
2364*1b3f573fSAndroid Build Coastguard Worker      } else {
2365*1b3f573fSAndroid Build Coastguard Worker        GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self);
2366*1b3f573fSAndroid Build Coastguard Worker        [unknownFields mergeVarintField:GPBFieldNumber(field) value:val];
2367*1b3f573fSAndroid Build Coastguard Worker      }
2368*1b3f573fSAndroid Build Coastguard Worker      break;
2369*1b3f573fSAndroid Build Coastguard Worker    }
2370*1b3f573fSAndroid Build Coastguard Worker  }  // switch
2371*1b3f573fSAndroid Build Coastguard Worker}
2372*1b3f573fSAndroid Build Coastguard Worker
2373*1b3f573fSAndroid Build Coastguard Worker- (void)mergeFromCodedInputStream:(GPBCodedInputStream *)input
2374*1b3f573fSAndroid Build Coastguard Worker                extensionRegistry:(GPBExtensionRegistry *)extensionRegistry {
2375*1b3f573fSAndroid Build Coastguard Worker  GPBDescriptor *descriptor = [self descriptor];
2376*1b3f573fSAndroid Build Coastguard Worker  GPBFileSyntax syntax = descriptor.file.syntax;
2377*1b3f573fSAndroid Build Coastguard Worker  GPBCodedInputStreamState *state = &input->state_;
2378*1b3f573fSAndroid Build Coastguard Worker  uint32_t tag = 0;
2379*1b3f573fSAndroid Build Coastguard Worker  NSUInteger startingIndex = 0;
2380*1b3f573fSAndroid Build Coastguard Worker  NSArray *fields = descriptor->fields_;
2381*1b3f573fSAndroid Build Coastguard Worker  NSUInteger numFields = fields.count;
2382*1b3f573fSAndroid Build Coastguard Worker  while (YES) {
2383*1b3f573fSAndroid Build Coastguard Worker    BOOL merged = NO;
2384*1b3f573fSAndroid Build Coastguard Worker    tag = GPBCodedInputStreamReadTag(state);
2385*1b3f573fSAndroid Build Coastguard Worker    if (tag == 0) {
2386*1b3f573fSAndroid Build Coastguard Worker      break;  // Reached end.
2387*1b3f573fSAndroid Build Coastguard Worker    }
2388*1b3f573fSAndroid Build Coastguard Worker    for (NSUInteger i = 0; i < numFields; ++i) {
2389*1b3f573fSAndroid Build Coastguard Worker      if (startingIndex >= numFields) startingIndex = 0;
2390*1b3f573fSAndroid Build Coastguard Worker      GPBFieldDescriptor *fieldDescriptor = fields[startingIndex];
2391*1b3f573fSAndroid Build Coastguard Worker      if (GPBFieldTag(fieldDescriptor) == tag) {
2392*1b3f573fSAndroid Build Coastguard Worker        GPBFieldType fieldType = fieldDescriptor.fieldType;
2393*1b3f573fSAndroid Build Coastguard Worker        if (fieldType == GPBFieldTypeSingle) {
2394*1b3f573fSAndroid Build Coastguard Worker          MergeSingleFieldFromCodedInputStream(self, fieldDescriptor, syntax,
2395*1b3f573fSAndroid Build Coastguard Worker                                               input, extensionRegistry);
2396*1b3f573fSAndroid Build Coastguard Worker          // Well formed protos will only have a single field once, advance
2397*1b3f573fSAndroid Build Coastguard Worker          // the starting index to the next field.
2398*1b3f573fSAndroid Build Coastguard Worker          startingIndex += 1;
2399*1b3f573fSAndroid Build Coastguard Worker        } else if (fieldType == GPBFieldTypeRepeated) {
2400*1b3f573fSAndroid Build Coastguard Worker          if (fieldDescriptor.isPackable) {
2401*1b3f573fSAndroid Build Coastguard Worker            MergeRepeatedPackedFieldFromCodedInputStream(
2402*1b3f573fSAndroid Build Coastguard Worker                self, fieldDescriptor, syntax, input);
2403*1b3f573fSAndroid Build Coastguard Worker            // Well formed protos will only have a repeated field that is
2404*1b3f573fSAndroid Build Coastguard Worker            // packed once, advance the starting index to the next field.
2405*1b3f573fSAndroid Build Coastguard Worker            startingIndex += 1;
2406*1b3f573fSAndroid Build Coastguard Worker          } else {
2407*1b3f573fSAndroid Build Coastguard Worker            MergeRepeatedNotPackedFieldFromCodedInputStream(
2408*1b3f573fSAndroid Build Coastguard Worker                self, fieldDescriptor, syntax, input, extensionRegistry);
2409*1b3f573fSAndroid Build Coastguard Worker          }
2410*1b3f573fSAndroid Build Coastguard Worker        } else {  // fieldType == GPBFieldTypeMap
2411*1b3f573fSAndroid Build Coastguard Worker          // GPB*Dictionary or NSDictionary, exact type doesn't matter at this
2412*1b3f573fSAndroid Build Coastguard Worker          // point.
2413*1b3f573fSAndroid Build Coastguard Worker          id map = GetOrCreateMapIvarWithField(self, fieldDescriptor);
2414*1b3f573fSAndroid Build Coastguard Worker          [input readMapEntry:map
2415*1b3f573fSAndroid Build Coastguard Worker            extensionRegistry:extensionRegistry
2416*1b3f573fSAndroid Build Coastguard Worker                        field:fieldDescriptor
2417*1b3f573fSAndroid Build Coastguard Worker                parentMessage:self];
2418*1b3f573fSAndroid Build Coastguard Worker        }
2419*1b3f573fSAndroid Build Coastguard Worker        merged = YES;
2420*1b3f573fSAndroid Build Coastguard Worker        break;
2421*1b3f573fSAndroid Build Coastguard Worker      } else {
2422*1b3f573fSAndroid Build Coastguard Worker        startingIndex += 1;
2423*1b3f573fSAndroid Build Coastguard Worker      }
2424*1b3f573fSAndroid Build Coastguard Worker    }  // for(i < numFields)
2425*1b3f573fSAndroid Build Coastguard Worker
2426*1b3f573fSAndroid Build Coastguard Worker    if (!merged && (tag != 0)) {
2427*1b3f573fSAndroid Build Coastguard Worker      // Primitive, repeated types can be packed on unpacked on the wire, and
2428*1b3f573fSAndroid Build Coastguard Worker      // are parsed either way.  The above loop covered tag in the preferred
2429*1b3f573fSAndroid Build Coastguard Worker      // for, so this need to check the alternate form.
2430*1b3f573fSAndroid Build Coastguard Worker      for (NSUInteger i = 0; i < numFields; ++i) {
2431*1b3f573fSAndroid Build Coastguard Worker        if (startingIndex >= numFields) startingIndex = 0;
2432*1b3f573fSAndroid Build Coastguard Worker        GPBFieldDescriptor *fieldDescriptor = fields[startingIndex];
2433*1b3f573fSAndroid Build Coastguard Worker        if ((fieldDescriptor.fieldType == GPBFieldTypeRepeated) &&
2434*1b3f573fSAndroid Build Coastguard Worker            !GPBFieldDataTypeIsObject(fieldDescriptor) &&
2435*1b3f573fSAndroid Build Coastguard Worker            (GPBFieldAlternateTag(fieldDescriptor) == tag)) {
2436*1b3f573fSAndroid Build Coastguard Worker          BOOL alternateIsPacked = !fieldDescriptor.isPackable;
2437*1b3f573fSAndroid Build Coastguard Worker          if (alternateIsPacked) {
2438*1b3f573fSAndroid Build Coastguard Worker            MergeRepeatedPackedFieldFromCodedInputStream(
2439*1b3f573fSAndroid Build Coastguard Worker                self, fieldDescriptor, syntax, input);
2440*1b3f573fSAndroid Build Coastguard Worker            // Well formed protos will only have a repeated field that is
2441*1b3f573fSAndroid Build Coastguard Worker            // packed once, advance the starting index to the next field.
2442*1b3f573fSAndroid Build Coastguard Worker            startingIndex += 1;
2443*1b3f573fSAndroid Build Coastguard Worker          } else {
2444*1b3f573fSAndroid Build Coastguard Worker            MergeRepeatedNotPackedFieldFromCodedInputStream(
2445*1b3f573fSAndroid Build Coastguard Worker                self, fieldDescriptor, syntax, input, extensionRegistry);
2446*1b3f573fSAndroid Build Coastguard Worker          }
2447*1b3f573fSAndroid Build Coastguard Worker          merged = YES;
2448*1b3f573fSAndroid Build Coastguard Worker          break;
2449*1b3f573fSAndroid Build Coastguard Worker        } else {
2450*1b3f573fSAndroid Build Coastguard Worker          startingIndex += 1;
2451*1b3f573fSAndroid Build Coastguard Worker        }
2452*1b3f573fSAndroid Build Coastguard Worker      }
2453*1b3f573fSAndroid Build Coastguard Worker    }
2454*1b3f573fSAndroid Build Coastguard Worker
2455*1b3f573fSAndroid Build Coastguard Worker    if (!merged) {
2456*1b3f573fSAndroid Build Coastguard Worker      if (tag == 0) {
2457*1b3f573fSAndroid Build Coastguard Worker        // zero signals EOF / limit reached
2458*1b3f573fSAndroid Build Coastguard Worker        return;
2459*1b3f573fSAndroid Build Coastguard Worker      } else {
2460*1b3f573fSAndroid Build Coastguard Worker        if (![self parseUnknownField:input
2461*1b3f573fSAndroid Build Coastguard Worker                   extensionRegistry:extensionRegistry
2462*1b3f573fSAndroid Build Coastguard Worker                                 tag:tag]) {
2463*1b3f573fSAndroid Build Coastguard Worker          // it's an endgroup tag
2464*1b3f573fSAndroid Build Coastguard Worker          return;
2465*1b3f573fSAndroid Build Coastguard Worker        }
2466*1b3f573fSAndroid Build Coastguard Worker      }
2467*1b3f573fSAndroid Build Coastguard Worker    }  // if(!merged)
2468*1b3f573fSAndroid Build Coastguard Worker
2469*1b3f573fSAndroid Build Coastguard Worker  }  // while(YES)
2470*1b3f573fSAndroid Build Coastguard Worker}
2471*1b3f573fSAndroid Build Coastguard Worker
2472*1b3f573fSAndroid Build Coastguard Worker#pragma mark - MergeFrom Support
2473*1b3f573fSAndroid Build Coastguard Worker
2474*1b3f573fSAndroid Build Coastguard Worker- (void)mergeFrom:(GPBMessage *)other {
2475*1b3f573fSAndroid Build Coastguard Worker  Class selfClass = [self class];
2476*1b3f573fSAndroid Build Coastguard Worker  Class otherClass = [other class];
2477*1b3f573fSAndroid Build Coastguard Worker  if (!([selfClass isSubclassOfClass:otherClass] ||
2478*1b3f573fSAndroid Build Coastguard Worker        [otherClass isSubclassOfClass:selfClass])) {
2479*1b3f573fSAndroid Build Coastguard Worker    [NSException raise:NSInvalidArgumentException
2480*1b3f573fSAndroid Build Coastguard Worker                format:@"Classes must match %@ != %@", selfClass, otherClass];
2481*1b3f573fSAndroid Build Coastguard Worker  }
2482*1b3f573fSAndroid Build Coastguard Worker
2483*1b3f573fSAndroid Build Coastguard Worker  // We assume something will be done and become visible.
2484*1b3f573fSAndroid Build Coastguard Worker  GPBBecomeVisibleToAutocreator(self);
2485*1b3f573fSAndroid Build Coastguard Worker
2486*1b3f573fSAndroid Build Coastguard Worker  GPBDescriptor *descriptor = [[self class] descriptor];
2487*1b3f573fSAndroid Build Coastguard Worker
2488*1b3f573fSAndroid Build Coastguard Worker  for (GPBFieldDescriptor *field in descriptor->fields_) {
2489*1b3f573fSAndroid Build Coastguard Worker    GPBFieldType fieldType = field.fieldType;
2490*1b3f573fSAndroid Build Coastguard Worker    if (fieldType == GPBFieldTypeSingle) {
2491*1b3f573fSAndroid Build Coastguard Worker      int32_t hasIndex = GPBFieldHasIndex(field);
2492*1b3f573fSAndroid Build Coastguard Worker      uint32_t fieldNumber = GPBFieldNumber(field);
2493*1b3f573fSAndroid Build Coastguard Worker      if (!GPBGetHasIvar(other, hasIndex, fieldNumber)) {
2494*1b3f573fSAndroid Build Coastguard Worker        // Other doesn't have the field set, on to the next.
2495*1b3f573fSAndroid Build Coastguard Worker        continue;
2496*1b3f573fSAndroid Build Coastguard Worker      }
2497*1b3f573fSAndroid Build Coastguard Worker      GPBDataType fieldDataType = GPBGetFieldDataType(field);
2498*1b3f573fSAndroid Build Coastguard Worker      switch (fieldDataType) {
2499*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeBool:
2500*1b3f573fSAndroid Build Coastguard Worker          GPBSetBoolIvarWithFieldPrivate(
2501*1b3f573fSAndroid Build Coastguard Worker              self, field, GPBGetMessageBoolField(other, field));
2502*1b3f573fSAndroid Build Coastguard Worker          break;
2503*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeSFixed32:
2504*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeEnum:
2505*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeInt32:
2506*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeSInt32:
2507*1b3f573fSAndroid Build Coastguard Worker          GPBSetInt32IvarWithFieldPrivate(
2508*1b3f573fSAndroid Build Coastguard Worker              self, field, GPBGetMessageInt32Field(other, field));
2509*1b3f573fSAndroid Build Coastguard Worker          break;
2510*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeFixed32:
2511*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeUInt32:
2512*1b3f573fSAndroid Build Coastguard Worker          GPBSetUInt32IvarWithFieldPrivate(
2513*1b3f573fSAndroid Build Coastguard Worker              self, field, GPBGetMessageUInt32Field(other, field));
2514*1b3f573fSAndroid Build Coastguard Worker          break;
2515*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeSFixed64:
2516*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeInt64:
2517*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeSInt64:
2518*1b3f573fSAndroid Build Coastguard Worker          GPBSetInt64IvarWithFieldPrivate(
2519*1b3f573fSAndroid Build Coastguard Worker              self, field, GPBGetMessageInt64Field(other, field));
2520*1b3f573fSAndroid Build Coastguard Worker          break;
2521*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeFixed64:
2522*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeUInt64:
2523*1b3f573fSAndroid Build Coastguard Worker          GPBSetUInt64IvarWithFieldPrivate(
2524*1b3f573fSAndroid Build Coastguard Worker              self, field, GPBGetMessageUInt64Field(other, field));
2525*1b3f573fSAndroid Build Coastguard Worker          break;
2526*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeFloat:
2527*1b3f573fSAndroid Build Coastguard Worker          GPBSetFloatIvarWithFieldPrivate(
2528*1b3f573fSAndroid Build Coastguard Worker              self, field, GPBGetMessageFloatField(other, field));
2529*1b3f573fSAndroid Build Coastguard Worker          break;
2530*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeDouble:
2531*1b3f573fSAndroid Build Coastguard Worker          GPBSetDoubleIvarWithFieldPrivate(
2532*1b3f573fSAndroid Build Coastguard Worker              self, field, GPBGetMessageDoubleField(other, field));
2533*1b3f573fSAndroid Build Coastguard Worker          break;
2534*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeBytes:
2535*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeString: {
2536*1b3f573fSAndroid Build Coastguard Worker          id otherVal = GPBGetObjectIvarWithFieldNoAutocreate(other, field);
2537*1b3f573fSAndroid Build Coastguard Worker          GPBSetObjectIvarWithFieldPrivate(self, field, otherVal);
2538*1b3f573fSAndroid Build Coastguard Worker          break;
2539*1b3f573fSAndroid Build Coastguard Worker        }
2540*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeMessage:
2541*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeGroup: {
2542*1b3f573fSAndroid Build Coastguard Worker          id otherVal = GPBGetObjectIvarWithFieldNoAutocreate(other, field);
2543*1b3f573fSAndroid Build Coastguard Worker          if (GPBGetHasIvar(self, hasIndex, fieldNumber)) {
2544*1b3f573fSAndroid Build Coastguard Worker            GPBMessage *message =
2545*1b3f573fSAndroid Build Coastguard Worker                GPBGetObjectIvarWithFieldNoAutocreate(self, field);
2546*1b3f573fSAndroid Build Coastguard Worker            [message mergeFrom:otherVal];
2547*1b3f573fSAndroid Build Coastguard Worker          } else {
2548*1b3f573fSAndroid Build Coastguard Worker            GPBMessage *message = [otherVal copy];
2549*1b3f573fSAndroid Build Coastguard Worker            GPBSetRetainedObjectIvarWithFieldPrivate(self, field, message);
2550*1b3f573fSAndroid Build Coastguard Worker          }
2551*1b3f573fSAndroid Build Coastguard Worker          break;
2552*1b3f573fSAndroid Build Coastguard Worker        }
2553*1b3f573fSAndroid Build Coastguard Worker      } // switch()
2554*1b3f573fSAndroid Build Coastguard Worker    } else if (fieldType == GPBFieldTypeRepeated) {
2555*1b3f573fSAndroid Build Coastguard Worker      // In the case of a list, they need to be appended, and there is no
2556*1b3f573fSAndroid Build Coastguard Worker      // _hasIvar to worry about setting.
2557*1b3f573fSAndroid Build Coastguard Worker      id otherArray =
2558*1b3f573fSAndroid Build Coastguard Worker          GPBGetObjectIvarWithFieldNoAutocreate(other, field);
2559*1b3f573fSAndroid Build Coastguard Worker      if (otherArray) {
2560*1b3f573fSAndroid Build Coastguard Worker        GPBDataType fieldDataType = field->description_->dataType;
2561*1b3f573fSAndroid Build Coastguard Worker        if (GPBDataTypeIsObject(fieldDataType)) {
2562*1b3f573fSAndroid Build Coastguard Worker          NSMutableArray *resultArray =
2563*1b3f573fSAndroid Build Coastguard Worker              GetOrCreateArrayIvarWithField(self, field);
2564*1b3f573fSAndroid Build Coastguard Worker          [resultArray addObjectsFromArray:otherArray];
2565*1b3f573fSAndroid Build Coastguard Worker        } else if (fieldDataType == GPBDataTypeEnum) {
2566*1b3f573fSAndroid Build Coastguard Worker          GPBEnumArray *resultArray =
2567*1b3f573fSAndroid Build Coastguard Worker              GetOrCreateArrayIvarWithField(self, field);
2568*1b3f573fSAndroid Build Coastguard Worker          [resultArray addRawValuesFromArray:otherArray];
2569*1b3f573fSAndroid Build Coastguard Worker        } else {
2570*1b3f573fSAndroid Build Coastguard Worker          // The array type doesn't matter, that all implement
2571*1b3f573fSAndroid Build Coastguard Worker          // -addValuesFromArray:.
2572*1b3f573fSAndroid Build Coastguard Worker          GPBInt32Array *resultArray =
2573*1b3f573fSAndroid Build Coastguard Worker              GetOrCreateArrayIvarWithField(self, field);
2574*1b3f573fSAndroid Build Coastguard Worker          [resultArray addValuesFromArray:otherArray];
2575*1b3f573fSAndroid Build Coastguard Worker        }
2576*1b3f573fSAndroid Build Coastguard Worker      }
2577*1b3f573fSAndroid Build Coastguard Worker    } else {  // fieldType = GPBFieldTypeMap
2578*1b3f573fSAndroid Build Coastguard Worker      // In the case of a map, they need to be merged, and there is no
2579*1b3f573fSAndroid Build Coastguard Worker      // _hasIvar to worry about setting.
2580*1b3f573fSAndroid Build Coastguard Worker      id otherDict = GPBGetObjectIvarWithFieldNoAutocreate(other, field);
2581*1b3f573fSAndroid Build Coastguard Worker      if (otherDict) {
2582*1b3f573fSAndroid Build Coastguard Worker        GPBDataType keyDataType = field.mapKeyDataType;
2583*1b3f573fSAndroid Build Coastguard Worker        GPBDataType valueDataType = field->description_->dataType;
2584*1b3f573fSAndroid Build Coastguard Worker        if (GPBDataTypeIsObject(keyDataType) &&
2585*1b3f573fSAndroid Build Coastguard Worker            GPBDataTypeIsObject(valueDataType)) {
2586*1b3f573fSAndroid Build Coastguard Worker          NSMutableDictionary *resultDict =
2587*1b3f573fSAndroid Build Coastguard Worker              GetOrCreateMapIvarWithField(self, field);
2588*1b3f573fSAndroid Build Coastguard Worker          [resultDict addEntriesFromDictionary:otherDict];
2589*1b3f573fSAndroid Build Coastguard Worker        } else if (valueDataType == GPBDataTypeEnum) {
2590*1b3f573fSAndroid Build Coastguard Worker          // The exact type doesn't matter, just need to know it is a
2591*1b3f573fSAndroid Build Coastguard Worker          // GPB*EnumDictionary.
2592*1b3f573fSAndroid Build Coastguard Worker          GPBInt32EnumDictionary *resultDict =
2593*1b3f573fSAndroid Build Coastguard Worker              GetOrCreateMapIvarWithField(self, field);
2594*1b3f573fSAndroid Build Coastguard Worker          [resultDict addRawEntriesFromDictionary:otherDict];
2595*1b3f573fSAndroid Build Coastguard Worker        } else {
2596*1b3f573fSAndroid Build Coastguard Worker          // The exact type doesn't matter, they all implement
2597*1b3f573fSAndroid Build Coastguard Worker          // -addEntriesFromDictionary:.
2598*1b3f573fSAndroid Build Coastguard Worker          GPBInt32Int32Dictionary *resultDict =
2599*1b3f573fSAndroid Build Coastguard Worker              GetOrCreateMapIvarWithField(self, field);
2600*1b3f573fSAndroid Build Coastguard Worker          [resultDict addEntriesFromDictionary:otherDict];
2601*1b3f573fSAndroid Build Coastguard Worker        }
2602*1b3f573fSAndroid Build Coastguard Worker      }
2603*1b3f573fSAndroid Build Coastguard Worker    }  // if (fieldType)..else if...else
2604*1b3f573fSAndroid Build Coastguard Worker  }  // for(fields)
2605*1b3f573fSAndroid Build Coastguard Worker
2606*1b3f573fSAndroid Build Coastguard Worker  // Unknown fields.
2607*1b3f573fSAndroid Build Coastguard Worker  if (!unknownFields_) {
2608*1b3f573fSAndroid Build Coastguard Worker    [self setUnknownFields:other.unknownFields];
2609*1b3f573fSAndroid Build Coastguard Worker  } else {
2610*1b3f573fSAndroid Build Coastguard Worker    [unknownFields_ mergeUnknownFields:other.unknownFields];
2611*1b3f573fSAndroid Build Coastguard Worker  }
2612*1b3f573fSAndroid Build Coastguard Worker
2613*1b3f573fSAndroid Build Coastguard Worker  // Extensions
2614*1b3f573fSAndroid Build Coastguard Worker
2615*1b3f573fSAndroid Build Coastguard Worker  if (other->extensionMap_.count == 0) {
2616*1b3f573fSAndroid Build Coastguard Worker    return;
2617*1b3f573fSAndroid Build Coastguard Worker  }
2618*1b3f573fSAndroid Build Coastguard Worker
2619*1b3f573fSAndroid Build Coastguard Worker  if (extensionMap_ == nil) {
2620*1b3f573fSAndroid Build Coastguard Worker    extensionMap_ =
2621*1b3f573fSAndroid Build Coastguard Worker        CloneExtensionMap(other->extensionMap_, NSZoneFromPointer(self));
2622*1b3f573fSAndroid Build Coastguard Worker  } else {
2623*1b3f573fSAndroid Build Coastguard Worker    for (GPBExtensionDescriptor *extension in other->extensionMap_) {
2624*1b3f573fSAndroid Build Coastguard Worker      id otherValue = [other->extensionMap_ objectForKey:extension];
2625*1b3f573fSAndroid Build Coastguard Worker      id value = [extensionMap_ objectForKey:extension];
2626*1b3f573fSAndroid Build Coastguard Worker      BOOL isMessageExtension = GPBExtensionIsMessage(extension);
2627*1b3f573fSAndroid Build Coastguard Worker
2628*1b3f573fSAndroid Build Coastguard Worker      if (extension.repeated) {
2629*1b3f573fSAndroid Build Coastguard Worker        NSMutableArray *list = value;
2630*1b3f573fSAndroid Build Coastguard Worker        if (list == nil) {
2631*1b3f573fSAndroid Build Coastguard Worker          list = [[NSMutableArray alloc] init];
2632*1b3f573fSAndroid Build Coastguard Worker          [extensionMap_ setObject:list forKey:extension];
2633*1b3f573fSAndroid Build Coastguard Worker          [list release];
2634*1b3f573fSAndroid Build Coastguard Worker        }
2635*1b3f573fSAndroid Build Coastguard Worker        if (isMessageExtension) {
2636*1b3f573fSAndroid Build Coastguard Worker          for (GPBMessage *otherListValue in otherValue) {
2637*1b3f573fSAndroid Build Coastguard Worker            GPBMessage *copiedValue = [otherListValue copy];
2638*1b3f573fSAndroid Build Coastguard Worker            [list addObject:copiedValue];
2639*1b3f573fSAndroid Build Coastguard Worker            [copiedValue release];
2640*1b3f573fSAndroid Build Coastguard Worker          }
2641*1b3f573fSAndroid Build Coastguard Worker        } else {
2642*1b3f573fSAndroid Build Coastguard Worker          [list addObjectsFromArray:otherValue];
2643*1b3f573fSAndroid Build Coastguard Worker        }
2644*1b3f573fSAndroid Build Coastguard Worker      } else {
2645*1b3f573fSAndroid Build Coastguard Worker        if (isMessageExtension) {
2646*1b3f573fSAndroid Build Coastguard Worker          if (value) {
2647*1b3f573fSAndroid Build Coastguard Worker            [(GPBMessage *)value mergeFrom:(GPBMessage *)otherValue];
2648*1b3f573fSAndroid Build Coastguard Worker          } else {
2649*1b3f573fSAndroid Build Coastguard Worker            GPBMessage *copiedValue = [otherValue copy];
2650*1b3f573fSAndroid Build Coastguard Worker            [extensionMap_ setObject:copiedValue forKey:extension];
2651*1b3f573fSAndroid Build Coastguard Worker            [copiedValue release];
2652*1b3f573fSAndroid Build Coastguard Worker          }
2653*1b3f573fSAndroid Build Coastguard Worker        } else {
2654*1b3f573fSAndroid Build Coastguard Worker          [extensionMap_ setObject:otherValue forKey:extension];
2655*1b3f573fSAndroid Build Coastguard Worker        }
2656*1b3f573fSAndroid Build Coastguard Worker      }
2657*1b3f573fSAndroid Build Coastguard Worker
2658*1b3f573fSAndroid Build Coastguard Worker      if (isMessageExtension && !extension.isRepeated) {
2659*1b3f573fSAndroid Build Coastguard Worker        GPBMessage *autocreatedValue =
2660*1b3f573fSAndroid Build Coastguard Worker            [[autocreatedExtensionMap_ objectForKey:extension] retain];
2661*1b3f573fSAndroid Build Coastguard Worker        // Must remove from the map before calling GPBClearMessageAutocreator()
2662*1b3f573fSAndroid Build Coastguard Worker        // so that GPBClearMessageAutocreator() knows its safe to clear.
2663*1b3f573fSAndroid Build Coastguard Worker        [autocreatedExtensionMap_ removeObjectForKey:extension];
2664*1b3f573fSAndroid Build Coastguard Worker        GPBClearMessageAutocreator(autocreatedValue);
2665*1b3f573fSAndroid Build Coastguard Worker        [autocreatedValue release];
2666*1b3f573fSAndroid Build Coastguard Worker      }
2667*1b3f573fSAndroid Build Coastguard Worker    }
2668*1b3f573fSAndroid Build Coastguard Worker  }
2669*1b3f573fSAndroid Build Coastguard Worker}
2670*1b3f573fSAndroid Build Coastguard Worker
2671*1b3f573fSAndroid Build Coastguard Worker#pragma mark - isEqual: & hash Support
2672*1b3f573fSAndroid Build Coastguard Worker
2673*1b3f573fSAndroid Build Coastguard Worker- (BOOL)isEqual:(id)other {
2674*1b3f573fSAndroid Build Coastguard Worker  if (other == self) {
2675*1b3f573fSAndroid Build Coastguard Worker    return YES;
2676*1b3f573fSAndroid Build Coastguard Worker  }
2677*1b3f573fSAndroid Build Coastguard Worker  if (![other isKindOfClass:[GPBMessage class]]) {
2678*1b3f573fSAndroid Build Coastguard Worker    return NO;
2679*1b3f573fSAndroid Build Coastguard Worker  }
2680*1b3f573fSAndroid Build Coastguard Worker  GPBMessage *otherMsg = other;
2681*1b3f573fSAndroid Build Coastguard Worker  GPBDescriptor *descriptor = [[self class] descriptor];
2682*1b3f573fSAndroid Build Coastguard Worker  if ([[otherMsg class] descriptor] != descriptor) {
2683*1b3f573fSAndroid Build Coastguard Worker    return NO;
2684*1b3f573fSAndroid Build Coastguard Worker  }
2685*1b3f573fSAndroid Build Coastguard Worker  uint8_t *selfStorage = (uint8_t *)messageStorage_;
2686*1b3f573fSAndroid Build Coastguard Worker  uint8_t *otherStorage = (uint8_t *)otherMsg->messageStorage_;
2687*1b3f573fSAndroid Build Coastguard Worker
2688*1b3f573fSAndroid Build Coastguard Worker  for (GPBFieldDescriptor *field in descriptor->fields_) {
2689*1b3f573fSAndroid Build Coastguard Worker    if (GPBFieldIsMapOrArray(field)) {
2690*1b3f573fSAndroid Build Coastguard Worker      // In the case of a list or map, there is no _hasIvar to worry about.
2691*1b3f573fSAndroid Build Coastguard Worker      // NOTE: These are NSArray/GPB*Array or NSDictionary/GPB*Dictionary, but
2692*1b3f573fSAndroid Build Coastguard Worker      // the type doesn't really matter as the objects all support -count and
2693*1b3f573fSAndroid Build Coastguard Worker      // -isEqual:.
2694*1b3f573fSAndroid Build Coastguard Worker      NSArray *resultMapOrArray =
2695*1b3f573fSAndroid Build Coastguard Worker          GPBGetObjectIvarWithFieldNoAutocreate(self, field);
2696*1b3f573fSAndroid Build Coastguard Worker      NSArray *otherMapOrArray =
2697*1b3f573fSAndroid Build Coastguard Worker          GPBGetObjectIvarWithFieldNoAutocreate(other, field);
2698*1b3f573fSAndroid Build Coastguard Worker      // nil and empty are equal
2699*1b3f573fSAndroid Build Coastguard Worker      if (resultMapOrArray.count != 0 || otherMapOrArray.count != 0) {
2700*1b3f573fSAndroid Build Coastguard Worker        if (![resultMapOrArray isEqual:otherMapOrArray]) {
2701*1b3f573fSAndroid Build Coastguard Worker          return NO;
2702*1b3f573fSAndroid Build Coastguard Worker        }
2703*1b3f573fSAndroid Build Coastguard Worker      }
2704*1b3f573fSAndroid Build Coastguard Worker    } else {  // Single field
2705*1b3f573fSAndroid Build Coastguard Worker      int32_t hasIndex = GPBFieldHasIndex(field);
2706*1b3f573fSAndroid Build Coastguard Worker      uint32_t fieldNum = GPBFieldNumber(field);
2707*1b3f573fSAndroid Build Coastguard Worker      BOOL selfHas = GPBGetHasIvar(self, hasIndex, fieldNum);
2708*1b3f573fSAndroid Build Coastguard Worker      BOOL otherHas = GPBGetHasIvar(other, hasIndex, fieldNum);
2709*1b3f573fSAndroid Build Coastguard Worker      if (selfHas != otherHas) {
2710*1b3f573fSAndroid Build Coastguard Worker        return NO;  // Differing has values, not equal.
2711*1b3f573fSAndroid Build Coastguard Worker      }
2712*1b3f573fSAndroid Build Coastguard Worker      if (!selfHas) {
2713*1b3f573fSAndroid Build Coastguard Worker        // Same has values, was no, nothing else to check for this field.
2714*1b3f573fSAndroid Build Coastguard Worker        continue;
2715*1b3f573fSAndroid Build Coastguard Worker      }
2716*1b3f573fSAndroid Build Coastguard Worker      // Now compare the values.
2717*1b3f573fSAndroid Build Coastguard Worker      GPBDataType fieldDataType = GPBGetFieldDataType(field);
2718*1b3f573fSAndroid Build Coastguard Worker      size_t fieldOffset = field->description_->offset;
2719*1b3f573fSAndroid Build Coastguard Worker      switch (fieldDataType) {
2720*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeBool: {
2721*1b3f573fSAndroid Build Coastguard Worker          // Bools are stored in has_bits to avoid needing explicit space in
2722*1b3f573fSAndroid Build Coastguard Worker          // the storage structure.
2723*1b3f573fSAndroid Build Coastguard Worker          // (the field number passed to the HasIvar helper doesn't really
2724*1b3f573fSAndroid Build Coastguard Worker          // matter since the offset is never negative)
2725*1b3f573fSAndroid Build Coastguard Worker          BOOL selfValue = GPBGetHasIvar(self, (int32_t)(fieldOffset), 0);
2726*1b3f573fSAndroid Build Coastguard Worker          BOOL otherValue = GPBGetHasIvar(other, (int32_t)(fieldOffset), 0);
2727*1b3f573fSAndroid Build Coastguard Worker          if (selfValue != otherValue) {
2728*1b3f573fSAndroid Build Coastguard Worker            return NO;
2729*1b3f573fSAndroid Build Coastguard Worker          }
2730*1b3f573fSAndroid Build Coastguard Worker          break;
2731*1b3f573fSAndroid Build Coastguard Worker        }
2732*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeSFixed32:
2733*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeInt32:
2734*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeSInt32:
2735*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeEnum:
2736*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeFixed32:
2737*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeUInt32:
2738*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeFloat: {
2739*1b3f573fSAndroid Build Coastguard Worker          GPBInternalCompileAssert(sizeof(float) == sizeof(uint32_t), float_not_32_bits);
2740*1b3f573fSAndroid Build Coastguard Worker          // These are all 32bit, signed/unsigned doesn't matter for equality.
2741*1b3f573fSAndroid Build Coastguard Worker          uint32_t *selfValPtr = (uint32_t *)&selfStorage[fieldOffset];
2742*1b3f573fSAndroid Build Coastguard Worker          uint32_t *otherValPtr = (uint32_t *)&otherStorage[fieldOffset];
2743*1b3f573fSAndroid Build Coastguard Worker          if (*selfValPtr != *otherValPtr) {
2744*1b3f573fSAndroid Build Coastguard Worker            return NO;
2745*1b3f573fSAndroid Build Coastguard Worker          }
2746*1b3f573fSAndroid Build Coastguard Worker          break;
2747*1b3f573fSAndroid Build Coastguard Worker        }
2748*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeSFixed64:
2749*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeInt64:
2750*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeSInt64:
2751*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeFixed64:
2752*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeUInt64:
2753*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeDouble: {
2754*1b3f573fSAndroid Build Coastguard Worker          GPBInternalCompileAssert(sizeof(double) == sizeof(uint64_t), double_not_64_bits);
2755*1b3f573fSAndroid Build Coastguard Worker          // These are all 64bit, signed/unsigned doesn't matter for equality.
2756*1b3f573fSAndroid Build Coastguard Worker          uint64_t *selfValPtr = (uint64_t *)&selfStorage[fieldOffset];
2757*1b3f573fSAndroid Build Coastguard Worker          uint64_t *otherValPtr = (uint64_t *)&otherStorage[fieldOffset];
2758*1b3f573fSAndroid Build Coastguard Worker          if (*selfValPtr != *otherValPtr) {
2759*1b3f573fSAndroid Build Coastguard Worker            return NO;
2760*1b3f573fSAndroid Build Coastguard Worker          }
2761*1b3f573fSAndroid Build Coastguard Worker          break;
2762*1b3f573fSAndroid Build Coastguard Worker        }
2763*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeBytes:
2764*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeString:
2765*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeMessage:
2766*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeGroup: {
2767*1b3f573fSAndroid Build Coastguard Worker          // Type doesn't matter here, they all implement -isEqual:.
2768*1b3f573fSAndroid Build Coastguard Worker          id *selfValPtr = (id *)&selfStorage[fieldOffset];
2769*1b3f573fSAndroid Build Coastguard Worker          id *otherValPtr = (id *)&otherStorage[fieldOffset];
2770*1b3f573fSAndroid Build Coastguard Worker          if (![*selfValPtr isEqual:*otherValPtr]) {
2771*1b3f573fSAndroid Build Coastguard Worker            return NO;
2772*1b3f573fSAndroid Build Coastguard Worker          }
2773*1b3f573fSAndroid Build Coastguard Worker          break;
2774*1b3f573fSAndroid Build Coastguard Worker        }
2775*1b3f573fSAndroid Build Coastguard Worker      } // switch()
2776*1b3f573fSAndroid Build Coastguard Worker    }   // if(mapOrArray)...else
2777*1b3f573fSAndroid Build Coastguard Worker  }  // for(fields)
2778*1b3f573fSAndroid Build Coastguard Worker
2779*1b3f573fSAndroid Build Coastguard Worker  // nil and empty are equal
2780*1b3f573fSAndroid Build Coastguard Worker  if (extensionMap_.count != 0 || otherMsg->extensionMap_.count != 0) {
2781*1b3f573fSAndroid Build Coastguard Worker    if (![extensionMap_ isEqual:otherMsg->extensionMap_]) {
2782*1b3f573fSAndroid Build Coastguard Worker      return NO;
2783*1b3f573fSAndroid Build Coastguard Worker    }
2784*1b3f573fSAndroid Build Coastguard Worker  }
2785*1b3f573fSAndroid Build Coastguard Worker
2786*1b3f573fSAndroid Build Coastguard Worker  // nil and empty are equal
2787*1b3f573fSAndroid Build Coastguard Worker  GPBUnknownFieldSet *otherUnknowns = otherMsg->unknownFields_;
2788*1b3f573fSAndroid Build Coastguard Worker  if ([unknownFields_ countOfFields] != 0 ||
2789*1b3f573fSAndroid Build Coastguard Worker      [otherUnknowns countOfFields] != 0) {
2790*1b3f573fSAndroid Build Coastguard Worker    if (![unknownFields_ isEqual:otherUnknowns]) {
2791*1b3f573fSAndroid Build Coastguard Worker      return NO;
2792*1b3f573fSAndroid Build Coastguard Worker    }
2793*1b3f573fSAndroid Build Coastguard Worker  }
2794*1b3f573fSAndroid Build Coastguard Worker
2795*1b3f573fSAndroid Build Coastguard Worker  return YES;
2796*1b3f573fSAndroid Build Coastguard Worker}
2797*1b3f573fSAndroid Build Coastguard Worker
2798*1b3f573fSAndroid Build Coastguard Worker// It is very difficult to implement a generic hash for ProtoBuf messages that
2799*1b3f573fSAndroid Build Coastguard Worker// will perform well. If you need hashing on your ProtoBufs (eg you are using
2800*1b3f573fSAndroid Build Coastguard Worker// them as dictionary keys) you will probably want to implement a ProtoBuf
2801*1b3f573fSAndroid Build Coastguard Worker// message specific hash as a category on your protobuf class. Do not make it a
2802*1b3f573fSAndroid Build Coastguard Worker// category on GPBMessage as you will conflict with this hash, and will possibly
2803*1b3f573fSAndroid Build Coastguard Worker// override hash for all generated protobufs. A good implementation of hash will
2804*1b3f573fSAndroid Build Coastguard Worker// be really fast, so we would recommend only hashing protobufs that have an
2805*1b3f573fSAndroid Build Coastguard Worker// identifier field of some kind that you can easily hash. If you implement
2806*1b3f573fSAndroid Build Coastguard Worker// hash, we would strongly recommend overriding isEqual: in your category as
2807*1b3f573fSAndroid Build Coastguard Worker// well, as the default implementation of isEqual: is extremely slow, and may
2808*1b3f573fSAndroid Build Coastguard Worker// drastically affect performance in large sets.
2809*1b3f573fSAndroid Build Coastguard Worker- (NSUInteger)hash {
2810*1b3f573fSAndroid Build Coastguard Worker  GPBDescriptor *descriptor = [[self class] descriptor];
2811*1b3f573fSAndroid Build Coastguard Worker  const NSUInteger prime = 19;
2812*1b3f573fSAndroid Build Coastguard Worker  uint8_t *storage = (uint8_t *)messageStorage_;
2813*1b3f573fSAndroid Build Coastguard Worker
2814*1b3f573fSAndroid Build Coastguard Worker  // Start with the descriptor and then mix it with some instance info.
2815*1b3f573fSAndroid Build Coastguard Worker  // Hopefully that will give a spread based on classes and what fields are set.
2816*1b3f573fSAndroid Build Coastguard Worker  NSUInteger result = (NSUInteger)descriptor;
2817*1b3f573fSAndroid Build Coastguard Worker
2818*1b3f573fSAndroid Build Coastguard Worker  for (GPBFieldDescriptor *field in descriptor->fields_) {
2819*1b3f573fSAndroid Build Coastguard Worker    if (GPBFieldIsMapOrArray(field)) {
2820*1b3f573fSAndroid Build Coastguard Worker      // Exact type doesn't matter, just check if there are any elements.
2821*1b3f573fSAndroid Build Coastguard Worker      NSArray *mapOrArray = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
2822*1b3f573fSAndroid Build Coastguard Worker      NSUInteger count = mapOrArray.count;
2823*1b3f573fSAndroid Build Coastguard Worker      if (count) {
2824*1b3f573fSAndroid Build Coastguard Worker        // NSArray/NSDictionary use count, use the field number and the count.
2825*1b3f573fSAndroid Build Coastguard Worker        result = prime * result + GPBFieldNumber(field);
2826*1b3f573fSAndroid Build Coastguard Worker        result = prime * result + count;
2827*1b3f573fSAndroid Build Coastguard Worker      }
2828*1b3f573fSAndroid Build Coastguard Worker    } else if (GPBGetHasIvarField(self, field)) {
2829*1b3f573fSAndroid Build Coastguard Worker      // Just using the field number seemed simple/fast, but then a small
2830*1b3f573fSAndroid Build Coastguard Worker      // message class where all the same fields are always set (to different
2831*1b3f573fSAndroid Build Coastguard Worker      // things would end up all with the same hash, so pull in some data).
2832*1b3f573fSAndroid Build Coastguard Worker      GPBDataType fieldDataType = GPBGetFieldDataType(field);
2833*1b3f573fSAndroid Build Coastguard Worker      size_t fieldOffset = field->description_->offset;
2834*1b3f573fSAndroid Build Coastguard Worker      switch (fieldDataType) {
2835*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeBool: {
2836*1b3f573fSAndroid Build Coastguard Worker          // Bools are stored in has_bits to avoid needing explicit space in
2837*1b3f573fSAndroid Build Coastguard Worker          // the storage structure.
2838*1b3f573fSAndroid Build Coastguard Worker          // (the field number passed to the HasIvar helper doesn't really
2839*1b3f573fSAndroid Build Coastguard Worker          // matter since the offset is never negative)
2840*1b3f573fSAndroid Build Coastguard Worker          BOOL value = GPBGetHasIvar(self, (int32_t)(fieldOffset), 0);
2841*1b3f573fSAndroid Build Coastguard Worker          result = prime * result + value;
2842*1b3f573fSAndroid Build Coastguard Worker          break;
2843*1b3f573fSAndroid Build Coastguard Worker        }
2844*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeSFixed32:
2845*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeInt32:
2846*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeSInt32:
2847*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeEnum:
2848*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeFixed32:
2849*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeUInt32:
2850*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeFloat: {
2851*1b3f573fSAndroid Build Coastguard Worker          GPBInternalCompileAssert(sizeof(float) == sizeof(uint32_t), float_not_32_bits);
2852*1b3f573fSAndroid Build Coastguard Worker          // These are all 32bit, just mix it in.
2853*1b3f573fSAndroid Build Coastguard Worker          uint32_t *valPtr = (uint32_t *)&storage[fieldOffset];
2854*1b3f573fSAndroid Build Coastguard Worker          result = prime * result + *valPtr;
2855*1b3f573fSAndroid Build Coastguard Worker          break;
2856*1b3f573fSAndroid Build Coastguard Worker        }
2857*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeSFixed64:
2858*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeInt64:
2859*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeSInt64:
2860*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeFixed64:
2861*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeUInt64:
2862*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeDouble: {
2863*1b3f573fSAndroid Build Coastguard Worker          GPBInternalCompileAssert(sizeof(double) == sizeof(uint64_t), double_not_64_bits);
2864*1b3f573fSAndroid Build Coastguard Worker          // These are all 64bit, just mix what fits into an NSUInteger in.
2865*1b3f573fSAndroid Build Coastguard Worker          uint64_t *valPtr = (uint64_t *)&storage[fieldOffset];
2866*1b3f573fSAndroid Build Coastguard Worker          result = prime * result + (NSUInteger)(*valPtr);
2867*1b3f573fSAndroid Build Coastguard Worker          break;
2868*1b3f573fSAndroid Build Coastguard Worker        }
2869*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeBytes:
2870*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeString: {
2871*1b3f573fSAndroid Build Coastguard Worker          // Type doesn't matter here, they both implement -hash:.
2872*1b3f573fSAndroid Build Coastguard Worker          id *valPtr = (id *)&storage[fieldOffset];
2873*1b3f573fSAndroid Build Coastguard Worker          result = prime * result + [*valPtr hash];
2874*1b3f573fSAndroid Build Coastguard Worker          break;
2875*1b3f573fSAndroid Build Coastguard Worker        }
2876*1b3f573fSAndroid Build Coastguard Worker
2877*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeMessage:
2878*1b3f573fSAndroid Build Coastguard Worker        case GPBDataTypeGroup: {
2879*1b3f573fSAndroid Build Coastguard Worker          GPBMessage **valPtr = (GPBMessage **)&storage[fieldOffset];
2880*1b3f573fSAndroid Build Coastguard Worker          // Could call -hash on the sub message, but that could recurse pretty
2881*1b3f573fSAndroid Build Coastguard Worker          // deep; follow the lead of NSArray/NSDictionary and don't really
2882*1b3f573fSAndroid Build Coastguard Worker          // recurse for hash, instead use the field number and the descriptor
2883*1b3f573fSAndroid Build Coastguard Worker          // of the sub message.  Yes, this could suck for a bunch of messages
2884*1b3f573fSAndroid Build Coastguard Worker          // where they all only differ in the sub messages, but if you are
2885*1b3f573fSAndroid Build Coastguard Worker          // using a message with sub messages for something that needs -hash,
2886*1b3f573fSAndroid Build Coastguard Worker          // odds are you are also copying them as keys, and that deep copy
2887*1b3f573fSAndroid Build Coastguard Worker          // will also suck.
2888*1b3f573fSAndroid Build Coastguard Worker          result = prime * result + GPBFieldNumber(field);
2889*1b3f573fSAndroid Build Coastguard Worker          result = prime * result + (NSUInteger)[[*valPtr class] descriptor];
2890*1b3f573fSAndroid Build Coastguard Worker          break;
2891*1b3f573fSAndroid Build Coastguard Worker        }
2892*1b3f573fSAndroid Build Coastguard Worker      } // switch()
2893*1b3f573fSAndroid Build Coastguard Worker    }
2894*1b3f573fSAndroid Build Coastguard Worker  }
2895*1b3f573fSAndroid Build Coastguard Worker
2896*1b3f573fSAndroid Build Coastguard Worker  // Unknowns and extensions are not included.
2897*1b3f573fSAndroid Build Coastguard Worker
2898*1b3f573fSAndroid Build Coastguard Worker  return result;
2899*1b3f573fSAndroid Build Coastguard Worker}
2900*1b3f573fSAndroid Build Coastguard Worker
2901*1b3f573fSAndroid Build Coastguard Worker#pragma mark - Description Support
2902*1b3f573fSAndroid Build Coastguard Worker
2903*1b3f573fSAndroid Build Coastguard Worker- (NSString *)description {
2904*1b3f573fSAndroid Build Coastguard Worker  NSString *textFormat = GPBTextFormatForMessage(self, @"    ");
2905*1b3f573fSAndroid Build Coastguard Worker  NSString *description = [NSString
2906*1b3f573fSAndroid Build Coastguard Worker      stringWithFormat:@"<%@ %p>: {\n%@}", [self class], self, textFormat];
2907*1b3f573fSAndroid Build Coastguard Worker  return description;
2908*1b3f573fSAndroid Build Coastguard Worker}
2909*1b3f573fSAndroid Build Coastguard Worker
2910*1b3f573fSAndroid Build Coastguard Worker#if defined(DEBUG) && DEBUG
2911*1b3f573fSAndroid Build Coastguard Worker
2912*1b3f573fSAndroid Build Coastguard Worker// Xcode 5.1 added support for custom quick look info.
2913*1b3f573fSAndroid Build Coastguard Worker// 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
2914*1b3f573fSAndroid Build Coastguard Worker- (id)debugQuickLookObject {
2915*1b3f573fSAndroid Build Coastguard Worker  return GPBTextFormatForMessage(self, nil);
2916*1b3f573fSAndroid Build Coastguard Worker}
2917*1b3f573fSAndroid Build Coastguard Worker
2918*1b3f573fSAndroid Build Coastguard Worker#endif  // DEBUG
2919*1b3f573fSAndroid Build Coastguard Worker
2920*1b3f573fSAndroid Build Coastguard Worker#pragma mark - SerializedSize
2921*1b3f573fSAndroid Build Coastguard Worker
2922*1b3f573fSAndroid Build Coastguard Worker- (size_t)serializedSize {
2923*1b3f573fSAndroid Build Coastguard Worker  GPBDescriptor *descriptor = [[self class] descriptor];
2924*1b3f573fSAndroid Build Coastguard Worker  size_t result = 0;
2925*1b3f573fSAndroid Build Coastguard Worker
2926*1b3f573fSAndroid Build Coastguard Worker  // Has check is done explicitly, so GPBGetObjectIvarWithFieldNoAutocreate()
2927*1b3f573fSAndroid Build Coastguard Worker  // avoids doing the has check again.
2928*1b3f573fSAndroid Build Coastguard Worker
2929*1b3f573fSAndroid Build Coastguard Worker  // Fields.
2930*1b3f573fSAndroid Build Coastguard Worker  for (GPBFieldDescriptor *fieldDescriptor in descriptor->fields_) {
2931*1b3f573fSAndroid Build Coastguard Worker    GPBFieldType fieldType = fieldDescriptor.fieldType;
2932*1b3f573fSAndroid Build Coastguard Worker    GPBDataType fieldDataType = GPBGetFieldDataType(fieldDescriptor);
2933*1b3f573fSAndroid Build Coastguard Worker
2934*1b3f573fSAndroid Build Coastguard Worker    // Single Fields
2935*1b3f573fSAndroid Build Coastguard Worker    if (fieldType == GPBFieldTypeSingle) {
2936*1b3f573fSAndroid Build Coastguard Worker      BOOL selfHas = GPBGetHasIvarField(self, fieldDescriptor);
2937*1b3f573fSAndroid Build Coastguard Worker      if (!selfHas) {
2938*1b3f573fSAndroid Build Coastguard Worker        continue;  // Nothing to do.
2939*1b3f573fSAndroid Build Coastguard Worker      }
2940*1b3f573fSAndroid Build Coastguard Worker
2941*1b3f573fSAndroid Build Coastguard Worker      uint32_t fieldNumber = GPBFieldNumber(fieldDescriptor);
2942*1b3f573fSAndroid Build Coastguard Worker
2943*1b3f573fSAndroid Build Coastguard Worker      switch (fieldDataType) {
2944*1b3f573fSAndroid Build Coastguard Worker#define CASE_SINGLE_POD(NAME, TYPE, FUNC_TYPE)                                \
2945*1b3f573fSAndroid Build Coastguard Worker        case GPBDataType##NAME: {                                             \
2946*1b3f573fSAndroid Build Coastguard Worker          TYPE fieldVal = GPBGetMessage##FUNC_TYPE##Field(self, fieldDescriptor); \
2947*1b3f573fSAndroid Build Coastguard Worker          result += GPBCompute##NAME##Size(fieldNumber, fieldVal);            \
2948*1b3f573fSAndroid Build Coastguard Worker          break;                                                              \
2949*1b3f573fSAndroid Build Coastguard Worker        }
2950*1b3f573fSAndroid Build Coastguard Worker#define CASE_SINGLE_OBJECT(NAME)                                              \
2951*1b3f573fSAndroid Build Coastguard Worker        case GPBDataType##NAME: {                                             \
2952*1b3f573fSAndroid Build Coastguard Worker          id fieldVal = GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor); \
2953*1b3f573fSAndroid Build Coastguard Worker          result += GPBCompute##NAME##Size(fieldNumber, fieldVal);            \
2954*1b3f573fSAndroid Build Coastguard Worker          break;                                                              \
2955*1b3f573fSAndroid Build Coastguard Worker        }
2956*1b3f573fSAndroid Build Coastguard Worker          CASE_SINGLE_POD(Bool, BOOL, Bool)
2957*1b3f573fSAndroid Build Coastguard Worker          CASE_SINGLE_POD(Fixed32, uint32_t, UInt32)
2958*1b3f573fSAndroid Build Coastguard Worker          CASE_SINGLE_POD(SFixed32, int32_t, Int32)
2959*1b3f573fSAndroid Build Coastguard Worker          CASE_SINGLE_POD(Float, float, Float)
2960*1b3f573fSAndroid Build Coastguard Worker          CASE_SINGLE_POD(Fixed64, uint64_t, UInt64)
2961*1b3f573fSAndroid Build Coastguard Worker          CASE_SINGLE_POD(SFixed64, int64_t, Int64)
2962*1b3f573fSAndroid Build Coastguard Worker          CASE_SINGLE_POD(Double, double, Double)
2963*1b3f573fSAndroid Build Coastguard Worker          CASE_SINGLE_POD(Int32, int32_t, Int32)
2964*1b3f573fSAndroid Build Coastguard Worker          CASE_SINGLE_POD(Int64, int64_t, Int64)
2965*1b3f573fSAndroid Build Coastguard Worker          CASE_SINGLE_POD(SInt32, int32_t, Int32)
2966*1b3f573fSAndroid Build Coastguard Worker          CASE_SINGLE_POD(SInt64, int64_t, Int64)
2967*1b3f573fSAndroid Build Coastguard Worker          CASE_SINGLE_POD(UInt32, uint32_t, UInt32)
2968*1b3f573fSAndroid Build Coastguard Worker          CASE_SINGLE_POD(UInt64, uint64_t, UInt64)
2969*1b3f573fSAndroid Build Coastguard Worker          CASE_SINGLE_OBJECT(Bytes)
2970*1b3f573fSAndroid Build Coastguard Worker          CASE_SINGLE_OBJECT(String)
2971*1b3f573fSAndroid Build Coastguard Worker          CASE_SINGLE_OBJECT(Message)
2972*1b3f573fSAndroid Build Coastguard Worker          CASE_SINGLE_OBJECT(Group)
2973*1b3f573fSAndroid Build Coastguard Worker          CASE_SINGLE_POD(Enum, int32_t, Int32)
2974*1b3f573fSAndroid Build Coastguard Worker#undef CASE_SINGLE_POD
2975*1b3f573fSAndroid Build Coastguard Worker#undef CASE_SINGLE_OBJECT
2976*1b3f573fSAndroid Build Coastguard Worker      }
2977*1b3f573fSAndroid Build Coastguard Worker
2978*1b3f573fSAndroid Build Coastguard Worker    // Repeated Fields
2979*1b3f573fSAndroid Build Coastguard Worker    } else if (fieldType == GPBFieldTypeRepeated) {
2980*1b3f573fSAndroid Build Coastguard Worker      id genericArray =
2981*1b3f573fSAndroid Build Coastguard Worker          GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor);
2982*1b3f573fSAndroid Build Coastguard Worker      NSUInteger count = [genericArray count];
2983*1b3f573fSAndroid Build Coastguard Worker      if (count == 0) {
2984*1b3f573fSAndroid Build Coastguard Worker        continue;  // Nothing to add.
2985*1b3f573fSAndroid Build Coastguard Worker      }
2986*1b3f573fSAndroid Build Coastguard Worker      __block size_t dataSize = 0;
2987*1b3f573fSAndroid Build Coastguard Worker
2988*1b3f573fSAndroid Build Coastguard Worker      switch (fieldDataType) {
2989*1b3f573fSAndroid Build Coastguard Worker#define CASE_REPEATED_POD(NAME, TYPE, ARRAY_TYPE)                             \
2990*1b3f573fSAndroid Build Coastguard Worker    CASE_REPEATED_POD_EXTRA(NAME, TYPE, ARRAY_TYPE, )
2991*1b3f573fSAndroid Build Coastguard Worker#define CASE_REPEATED_POD_EXTRA(NAME, TYPE, ARRAY_TYPE, ARRAY_ACCESSOR_NAME)  \
2992*1b3f573fSAndroid Build Coastguard Worker        case GPBDataType##NAME: {                                             \
2993*1b3f573fSAndroid Build Coastguard Worker          GPB##ARRAY_TYPE##Array *array = genericArray;                       \
2994*1b3f573fSAndroid Build Coastguard Worker          [array enumerate##ARRAY_ACCESSOR_NAME##ValuesWithBlock:^(TYPE value, NSUInteger idx, BOOL *stop) { \
2995*1b3f573fSAndroid Build Coastguard Worker            _Pragma("unused(idx, stop)");                                     \
2996*1b3f573fSAndroid Build Coastguard Worker            dataSize += GPBCompute##NAME##SizeNoTag(value);                   \
2997*1b3f573fSAndroid Build Coastguard Worker          }];                                                                 \
2998*1b3f573fSAndroid Build Coastguard Worker          break;                                                              \
2999*1b3f573fSAndroid Build Coastguard Worker        }
3000*1b3f573fSAndroid Build Coastguard Worker#define CASE_REPEATED_OBJECT(NAME)                                            \
3001*1b3f573fSAndroid Build Coastguard Worker        case GPBDataType##NAME: {                                             \
3002*1b3f573fSAndroid Build Coastguard Worker          for (id value in genericArray) {                                    \
3003*1b3f573fSAndroid Build Coastguard Worker            dataSize += GPBCompute##NAME##SizeNoTag(value);                   \
3004*1b3f573fSAndroid Build Coastguard Worker          }                                                                   \
3005*1b3f573fSAndroid Build Coastguard Worker          break;                                                              \
3006*1b3f573fSAndroid Build Coastguard Worker        }
3007*1b3f573fSAndroid Build Coastguard Worker          CASE_REPEATED_POD(Bool, BOOL, Bool)
3008*1b3f573fSAndroid Build Coastguard Worker          CASE_REPEATED_POD(Fixed32, uint32_t, UInt32)
3009*1b3f573fSAndroid Build Coastguard Worker          CASE_REPEATED_POD(SFixed32, int32_t, Int32)
3010*1b3f573fSAndroid Build Coastguard Worker          CASE_REPEATED_POD(Float, float, Float)
3011*1b3f573fSAndroid Build Coastguard Worker          CASE_REPEATED_POD(Fixed64, uint64_t, UInt64)
3012*1b3f573fSAndroid Build Coastguard Worker          CASE_REPEATED_POD(SFixed64, int64_t, Int64)
3013*1b3f573fSAndroid Build Coastguard Worker          CASE_REPEATED_POD(Double, double, Double)
3014*1b3f573fSAndroid Build Coastguard Worker          CASE_REPEATED_POD(Int32, int32_t, Int32)
3015*1b3f573fSAndroid Build Coastguard Worker          CASE_REPEATED_POD(Int64, int64_t, Int64)
3016*1b3f573fSAndroid Build Coastguard Worker          CASE_REPEATED_POD(SInt32, int32_t, Int32)
3017*1b3f573fSAndroid Build Coastguard Worker          CASE_REPEATED_POD(SInt64, int64_t, Int64)
3018*1b3f573fSAndroid Build Coastguard Worker          CASE_REPEATED_POD(UInt32, uint32_t, UInt32)
3019*1b3f573fSAndroid Build Coastguard Worker          CASE_REPEATED_POD(UInt64, uint64_t, UInt64)
3020*1b3f573fSAndroid Build Coastguard Worker          CASE_REPEATED_OBJECT(Bytes)
3021*1b3f573fSAndroid Build Coastguard Worker          CASE_REPEATED_OBJECT(String)
3022*1b3f573fSAndroid Build Coastguard Worker          CASE_REPEATED_OBJECT(Message)
3023*1b3f573fSAndroid Build Coastguard Worker          CASE_REPEATED_OBJECT(Group)
3024*1b3f573fSAndroid Build Coastguard Worker          CASE_REPEATED_POD_EXTRA(Enum, int32_t, Enum, Raw)
3025*1b3f573fSAndroid Build Coastguard Worker#undef CASE_REPEATED_POD
3026*1b3f573fSAndroid Build Coastguard Worker#undef CASE_REPEATED_POD_EXTRA
3027*1b3f573fSAndroid Build Coastguard Worker#undef CASE_REPEATED_OBJECT
3028*1b3f573fSAndroid Build Coastguard Worker      }  // switch
3029*1b3f573fSAndroid Build Coastguard Worker      result += dataSize;
3030*1b3f573fSAndroid Build Coastguard Worker      size_t tagSize = GPBComputeTagSize(GPBFieldNumber(fieldDescriptor));
3031*1b3f573fSAndroid Build Coastguard Worker      if (fieldDataType == GPBDataTypeGroup) {
3032*1b3f573fSAndroid Build Coastguard Worker        // Groups have both a start and an end tag.
3033*1b3f573fSAndroid Build Coastguard Worker        tagSize *= 2;
3034*1b3f573fSAndroid Build Coastguard Worker      }
3035*1b3f573fSAndroid Build Coastguard Worker      if (fieldDescriptor.isPackable) {
3036*1b3f573fSAndroid Build Coastguard Worker        result += tagSize;
3037*1b3f573fSAndroid Build Coastguard Worker        result += GPBComputeSizeTSizeAsInt32NoTag(dataSize);
3038*1b3f573fSAndroid Build Coastguard Worker      } else {
3039*1b3f573fSAndroid Build Coastguard Worker        result += count * tagSize;
3040*1b3f573fSAndroid Build Coastguard Worker      }
3041*1b3f573fSAndroid Build Coastguard Worker
3042*1b3f573fSAndroid Build Coastguard Worker    // Map<> Fields
3043*1b3f573fSAndroid Build Coastguard Worker    } else {  // fieldType == GPBFieldTypeMap
3044*1b3f573fSAndroid Build Coastguard Worker      if (GPBDataTypeIsObject(fieldDataType) &&
3045*1b3f573fSAndroid Build Coastguard Worker          (fieldDescriptor.mapKeyDataType == GPBDataTypeString)) {
3046*1b3f573fSAndroid Build Coastguard Worker        // If key type was string, then the map is an NSDictionary.
3047*1b3f573fSAndroid Build Coastguard Worker        NSDictionary *map =
3048*1b3f573fSAndroid Build Coastguard Worker            GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor);
3049*1b3f573fSAndroid Build Coastguard Worker        if (map) {
3050*1b3f573fSAndroid Build Coastguard Worker          result += GPBDictionaryComputeSizeInternalHelper(map, fieldDescriptor);
3051*1b3f573fSAndroid Build Coastguard Worker        }
3052*1b3f573fSAndroid Build Coastguard Worker      } else {
3053*1b3f573fSAndroid Build Coastguard Worker        // Type will be GPB*GroupDictionary, exact type doesn't matter.
3054*1b3f573fSAndroid Build Coastguard Worker        GPBInt32Int32Dictionary *map =
3055*1b3f573fSAndroid Build Coastguard Worker            GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor);
3056*1b3f573fSAndroid Build Coastguard Worker        result += [map computeSerializedSizeAsField:fieldDescriptor];
3057*1b3f573fSAndroid Build Coastguard Worker      }
3058*1b3f573fSAndroid Build Coastguard Worker    }
3059*1b3f573fSAndroid Build Coastguard Worker  }  // for(fields)
3060*1b3f573fSAndroid Build Coastguard Worker
3061*1b3f573fSAndroid Build Coastguard Worker  // Add any unknown fields.
3062*1b3f573fSAndroid Build Coastguard Worker  if (descriptor.wireFormat) {
3063*1b3f573fSAndroid Build Coastguard Worker    result += [unknownFields_ serializedSizeAsMessageSet];
3064*1b3f573fSAndroid Build Coastguard Worker  } else {
3065*1b3f573fSAndroid Build Coastguard Worker    result += [unknownFields_ serializedSize];
3066*1b3f573fSAndroid Build Coastguard Worker  }
3067*1b3f573fSAndroid Build Coastguard Worker
3068*1b3f573fSAndroid Build Coastguard Worker  // Add any extensions.
3069*1b3f573fSAndroid Build Coastguard Worker  for (GPBExtensionDescriptor *extension in extensionMap_) {
3070*1b3f573fSAndroid Build Coastguard Worker    id value = [extensionMap_ objectForKey:extension];
3071*1b3f573fSAndroid Build Coastguard Worker    result += GPBComputeExtensionSerializedSizeIncludingTag(extension, value);
3072*1b3f573fSAndroid Build Coastguard Worker  }
3073*1b3f573fSAndroid Build Coastguard Worker
3074*1b3f573fSAndroid Build Coastguard Worker  return result;
3075*1b3f573fSAndroid Build Coastguard Worker}
3076*1b3f573fSAndroid Build Coastguard Worker
3077*1b3f573fSAndroid Build Coastguard Worker#pragma mark - Resolve Methods Support
3078*1b3f573fSAndroid Build Coastguard Worker
3079*1b3f573fSAndroid Build Coastguard Workertypedef struct ResolveIvarAccessorMethodResult {
3080*1b3f573fSAndroid Build Coastguard Worker  IMP impToAdd;
3081*1b3f573fSAndroid Build Coastguard Worker  SEL encodingSelector;
3082*1b3f573fSAndroid Build Coastguard Worker} ResolveIvarAccessorMethodResult;
3083*1b3f573fSAndroid Build Coastguard Worker
3084*1b3f573fSAndroid Build Coastguard Worker// |field| can be __unsafe_unretained because they are created at startup
3085*1b3f573fSAndroid Build Coastguard Worker// and are essentially global. No need to pay for retain/release when
3086*1b3f573fSAndroid Build Coastguard Worker// they are captured in blocks.
3087*1b3f573fSAndroid Build Coastguard Workerstatic void ResolveIvarGet(__unsafe_unretained GPBFieldDescriptor *field,
3088*1b3f573fSAndroid Build Coastguard Worker                           ResolveIvarAccessorMethodResult *result) {
3089*1b3f573fSAndroid Build Coastguard Worker  GPBDataType fieldDataType = GPBGetFieldDataType(field);
3090*1b3f573fSAndroid Build Coastguard Worker  switch (fieldDataType) {
3091*1b3f573fSAndroid Build Coastguard Worker#define CASE_GET(NAME, TYPE, TRUE_NAME)                          \
3092*1b3f573fSAndroid Build Coastguard Worker    case GPBDataType##NAME: {                                    \
3093*1b3f573fSAndroid Build Coastguard Worker      result->impToAdd = imp_implementationWithBlock(^(id obj) { \
3094*1b3f573fSAndroid Build Coastguard Worker        return GPBGetMessage##TRUE_NAME##Field(obj, field);      \
3095*1b3f573fSAndroid Build Coastguard Worker       });                                                       \
3096*1b3f573fSAndroid Build Coastguard Worker      result->encodingSelector = @selector(get##NAME);           \
3097*1b3f573fSAndroid Build Coastguard Worker      break;                                                     \
3098*1b3f573fSAndroid Build Coastguard Worker    }
3099*1b3f573fSAndroid Build Coastguard Worker#define CASE_GET_OBJECT(NAME, TYPE, TRUE_NAME)                   \
3100*1b3f573fSAndroid Build Coastguard Worker    case GPBDataType##NAME: {                                    \
3101*1b3f573fSAndroid Build Coastguard Worker      result->impToAdd = imp_implementationWithBlock(^(id obj) { \
3102*1b3f573fSAndroid Build Coastguard Worker        return GPBGetObjectIvarWithField(obj, field);            \
3103*1b3f573fSAndroid Build Coastguard Worker       });                                                       \
3104*1b3f573fSAndroid Build Coastguard Worker      result->encodingSelector = @selector(get##NAME);           \
3105*1b3f573fSAndroid Build Coastguard Worker      break;                                                     \
3106*1b3f573fSAndroid Build Coastguard Worker    }
3107*1b3f573fSAndroid Build Coastguard Worker      CASE_GET(Bool, BOOL, Bool)
3108*1b3f573fSAndroid Build Coastguard Worker      CASE_GET(Fixed32, uint32_t, UInt32)
3109*1b3f573fSAndroid Build Coastguard Worker      CASE_GET(SFixed32, int32_t, Int32)
3110*1b3f573fSAndroid Build Coastguard Worker      CASE_GET(Float, float, Float)
3111*1b3f573fSAndroid Build Coastguard Worker      CASE_GET(Fixed64, uint64_t, UInt64)
3112*1b3f573fSAndroid Build Coastguard Worker      CASE_GET(SFixed64, int64_t, Int64)
3113*1b3f573fSAndroid Build Coastguard Worker      CASE_GET(Double, double, Double)
3114*1b3f573fSAndroid Build Coastguard Worker      CASE_GET(Int32, int32_t, Int32)
3115*1b3f573fSAndroid Build Coastguard Worker      CASE_GET(Int64, int64_t, Int64)
3116*1b3f573fSAndroid Build Coastguard Worker      CASE_GET(SInt32, int32_t, Int32)
3117*1b3f573fSAndroid Build Coastguard Worker      CASE_GET(SInt64, int64_t, Int64)
3118*1b3f573fSAndroid Build Coastguard Worker      CASE_GET(UInt32, uint32_t, UInt32)
3119*1b3f573fSAndroid Build Coastguard Worker      CASE_GET(UInt64, uint64_t, UInt64)
3120*1b3f573fSAndroid Build Coastguard Worker      CASE_GET_OBJECT(Bytes, id, Object)
3121*1b3f573fSAndroid Build Coastguard Worker      CASE_GET_OBJECT(String, id, Object)
3122*1b3f573fSAndroid Build Coastguard Worker      CASE_GET_OBJECT(Message, id, Object)
3123*1b3f573fSAndroid Build Coastguard Worker      CASE_GET_OBJECT(Group, id, Object)
3124*1b3f573fSAndroid Build Coastguard Worker      CASE_GET(Enum, int32_t, Enum)
3125*1b3f573fSAndroid Build Coastguard Worker#undef CASE_GET
3126*1b3f573fSAndroid Build Coastguard Worker  }
3127*1b3f573fSAndroid Build Coastguard Worker}
3128*1b3f573fSAndroid Build Coastguard Worker
3129*1b3f573fSAndroid Build Coastguard Worker// See comment about __unsafe_unretained on ResolveIvarGet.
3130*1b3f573fSAndroid Build Coastguard Workerstatic void ResolveIvarSet(__unsafe_unretained GPBFieldDescriptor *field,
3131*1b3f573fSAndroid Build Coastguard Worker                           ResolveIvarAccessorMethodResult *result) {
3132*1b3f573fSAndroid Build Coastguard Worker  GPBDataType fieldDataType = GPBGetFieldDataType(field);
3133*1b3f573fSAndroid Build Coastguard Worker  switch (fieldDataType) {
3134*1b3f573fSAndroid Build Coastguard Worker#define CASE_SET(NAME, TYPE, TRUE_NAME)                                       \
3135*1b3f573fSAndroid Build Coastguard Worker    case GPBDataType##NAME: {                                                 \
3136*1b3f573fSAndroid Build Coastguard Worker      result->impToAdd = imp_implementationWithBlock(^(id obj, TYPE value) {  \
3137*1b3f573fSAndroid Build Coastguard Worker        return GPBSet##TRUE_NAME##IvarWithFieldPrivate(obj, field, value);    \
3138*1b3f573fSAndroid Build Coastguard Worker      });                                                                     \
3139*1b3f573fSAndroid Build Coastguard Worker      result->encodingSelector = @selector(set##NAME:);                       \
3140*1b3f573fSAndroid Build Coastguard Worker      break;                                                                  \
3141*1b3f573fSAndroid Build Coastguard Worker    }
3142*1b3f573fSAndroid Build Coastguard Worker#define CASE_SET_COPY(NAME)                                                   \
3143*1b3f573fSAndroid Build Coastguard Worker    case GPBDataType##NAME: {                                                 \
3144*1b3f573fSAndroid Build Coastguard Worker      result->impToAdd = imp_implementationWithBlock(^(id obj, id value) {    \
3145*1b3f573fSAndroid Build Coastguard Worker        return GPBSetRetainedObjectIvarWithFieldPrivate(obj, field, [value copy]); \
3146*1b3f573fSAndroid Build Coastguard Worker      });                                                                     \
3147*1b3f573fSAndroid Build Coastguard Worker      result->encodingSelector = @selector(set##NAME:);                       \
3148*1b3f573fSAndroid Build Coastguard Worker      break;                                                                  \
3149*1b3f573fSAndroid Build Coastguard Worker    }
3150*1b3f573fSAndroid Build Coastguard Worker      CASE_SET(Bool, BOOL, Bool)
3151*1b3f573fSAndroid Build Coastguard Worker      CASE_SET(Fixed32, uint32_t, UInt32)
3152*1b3f573fSAndroid Build Coastguard Worker      CASE_SET(SFixed32, int32_t, Int32)
3153*1b3f573fSAndroid Build Coastguard Worker      CASE_SET(Float, float, Float)
3154*1b3f573fSAndroid Build Coastguard Worker      CASE_SET(Fixed64, uint64_t, UInt64)
3155*1b3f573fSAndroid Build Coastguard Worker      CASE_SET(SFixed64, int64_t, Int64)
3156*1b3f573fSAndroid Build Coastguard Worker      CASE_SET(Double, double, Double)
3157*1b3f573fSAndroid Build Coastguard Worker      CASE_SET(Int32, int32_t, Int32)
3158*1b3f573fSAndroid Build Coastguard Worker      CASE_SET(Int64, int64_t, Int64)
3159*1b3f573fSAndroid Build Coastguard Worker      CASE_SET(SInt32, int32_t, Int32)
3160*1b3f573fSAndroid Build Coastguard Worker      CASE_SET(SInt64, int64_t, Int64)
3161*1b3f573fSAndroid Build Coastguard Worker      CASE_SET(UInt32, uint32_t, UInt32)
3162*1b3f573fSAndroid Build Coastguard Worker      CASE_SET(UInt64, uint64_t, UInt64)
3163*1b3f573fSAndroid Build Coastguard Worker      CASE_SET_COPY(Bytes)
3164*1b3f573fSAndroid Build Coastguard Worker      CASE_SET_COPY(String)
3165*1b3f573fSAndroid Build Coastguard Worker      CASE_SET(Message, id, Object)
3166*1b3f573fSAndroid Build Coastguard Worker      CASE_SET(Group, id, Object)
3167*1b3f573fSAndroid Build Coastguard Worker      CASE_SET(Enum, int32_t, Enum)
3168*1b3f573fSAndroid Build Coastguard Worker#undef CASE_SET
3169*1b3f573fSAndroid Build Coastguard Worker  }
3170*1b3f573fSAndroid Build Coastguard Worker}
3171*1b3f573fSAndroid Build Coastguard Worker
3172*1b3f573fSAndroid Build Coastguard Worker+ (BOOL)resolveInstanceMethod:(SEL)sel {
3173*1b3f573fSAndroid Build Coastguard Worker  const GPBDescriptor *descriptor = [self descriptor];
3174*1b3f573fSAndroid Build Coastguard Worker  if (!descriptor) {
3175*1b3f573fSAndroid Build Coastguard Worker    return [super resolveInstanceMethod:sel];
3176*1b3f573fSAndroid Build Coastguard Worker  }
3177*1b3f573fSAndroid Build Coastguard Worker
3178*1b3f573fSAndroid Build Coastguard Worker  // NOTE: hasOrCountSel_/setHasSel_ will be NULL if the field for the given
3179*1b3f573fSAndroid Build Coastguard Worker  // message should not have has support (done in GPBDescriptor.m), so there is
3180*1b3f573fSAndroid Build Coastguard Worker  // no need for checks here to see if has*/setHas* are allowed.
3181*1b3f573fSAndroid Build Coastguard Worker  ResolveIvarAccessorMethodResult result = {NULL, NULL};
3182*1b3f573fSAndroid Build Coastguard Worker
3183*1b3f573fSAndroid Build Coastguard Worker  // See comment about __unsafe_unretained on ResolveIvarGet.
3184*1b3f573fSAndroid Build Coastguard Worker  for (__unsafe_unretained GPBFieldDescriptor *field in descriptor->fields_) {
3185*1b3f573fSAndroid Build Coastguard Worker    BOOL isMapOrArray = GPBFieldIsMapOrArray(field);
3186*1b3f573fSAndroid Build Coastguard Worker    if (!isMapOrArray) {
3187*1b3f573fSAndroid Build Coastguard Worker      // Single fields.
3188*1b3f573fSAndroid Build Coastguard Worker      if (sel == field->getSel_) {
3189*1b3f573fSAndroid Build Coastguard Worker        ResolveIvarGet(field, &result);
3190*1b3f573fSAndroid Build Coastguard Worker        break;
3191*1b3f573fSAndroid Build Coastguard Worker      } else if (sel == field->setSel_) {
3192*1b3f573fSAndroid Build Coastguard Worker        ResolveIvarSet(field, &result);
3193*1b3f573fSAndroid Build Coastguard Worker        break;
3194*1b3f573fSAndroid Build Coastguard Worker      } else if (sel == field->hasOrCountSel_) {
3195*1b3f573fSAndroid Build Coastguard Worker        int32_t index = GPBFieldHasIndex(field);
3196*1b3f573fSAndroid Build Coastguard Worker        uint32_t fieldNum = GPBFieldNumber(field);
3197*1b3f573fSAndroid Build Coastguard Worker        result.impToAdd = imp_implementationWithBlock(^(id obj) {
3198*1b3f573fSAndroid Build Coastguard Worker          return GPBGetHasIvar(obj, index, fieldNum);
3199*1b3f573fSAndroid Build Coastguard Worker        });
3200*1b3f573fSAndroid Build Coastguard Worker        result.encodingSelector = @selector(getBool);
3201*1b3f573fSAndroid Build Coastguard Worker        break;
3202*1b3f573fSAndroid Build Coastguard Worker      } else if (sel == field->setHasSel_) {
3203*1b3f573fSAndroid Build Coastguard Worker        result.impToAdd = imp_implementationWithBlock(^(id obj, BOOL value) {
3204*1b3f573fSAndroid Build Coastguard Worker          if (value) {
3205*1b3f573fSAndroid Build Coastguard Worker            [NSException raise:NSInvalidArgumentException
3206*1b3f573fSAndroid Build Coastguard Worker                        format:@"%@: %@ can only be set to NO (to clear field).",
3207*1b3f573fSAndroid Build Coastguard Worker                               [obj class],
3208*1b3f573fSAndroid Build Coastguard Worker                               NSStringFromSelector(field->setHasSel_)];
3209*1b3f573fSAndroid Build Coastguard Worker          }
3210*1b3f573fSAndroid Build Coastguard Worker          GPBClearMessageField(obj, field);
3211*1b3f573fSAndroid Build Coastguard Worker        });
3212*1b3f573fSAndroid Build Coastguard Worker        result.encodingSelector = @selector(setBool:);
3213*1b3f573fSAndroid Build Coastguard Worker        break;
3214*1b3f573fSAndroid Build Coastguard Worker      } else {
3215*1b3f573fSAndroid Build Coastguard Worker        GPBOneofDescriptor *oneof = field->containingOneof_;
3216*1b3f573fSAndroid Build Coastguard Worker        if (oneof && (sel == oneof->caseSel_)) {
3217*1b3f573fSAndroid Build Coastguard Worker          int32_t index = GPBFieldHasIndex(field);
3218*1b3f573fSAndroid Build Coastguard Worker          result.impToAdd = imp_implementationWithBlock(^(id obj) {
3219*1b3f573fSAndroid Build Coastguard Worker            return GPBGetHasOneof(obj, index);
3220*1b3f573fSAndroid Build Coastguard Worker          });
3221*1b3f573fSAndroid Build Coastguard Worker          result.encodingSelector = @selector(getEnum);
3222*1b3f573fSAndroid Build Coastguard Worker          break;
3223*1b3f573fSAndroid Build Coastguard Worker        }
3224*1b3f573fSAndroid Build Coastguard Worker      }
3225*1b3f573fSAndroid Build Coastguard Worker    } else {
3226*1b3f573fSAndroid Build Coastguard Worker      // map<>/repeated fields.
3227*1b3f573fSAndroid Build Coastguard Worker      if (sel == field->getSel_) {
3228*1b3f573fSAndroid Build Coastguard Worker        if (field.fieldType == GPBFieldTypeRepeated) {
3229*1b3f573fSAndroid Build Coastguard Worker          result.impToAdd = imp_implementationWithBlock(^(id obj) {
3230*1b3f573fSAndroid Build Coastguard Worker            return GetArrayIvarWithField(obj, field);
3231*1b3f573fSAndroid Build Coastguard Worker          });
3232*1b3f573fSAndroid Build Coastguard Worker        } else {
3233*1b3f573fSAndroid Build Coastguard Worker          result.impToAdd = imp_implementationWithBlock(^(id obj) {
3234*1b3f573fSAndroid Build Coastguard Worker            return GetMapIvarWithField(obj, field);
3235*1b3f573fSAndroid Build Coastguard Worker          });
3236*1b3f573fSAndroid Build Coastguard Worker        }
3237*1b3f573fSAndroid Build Coastguard Worker        result.encodingSelector = @selector(getArray);
3238*1b3f573fSAndroid Build Coastguard Worker        break;
3239*1b3f573fSAndroid Build Coastguard Worker      } else if (sel == field->setSel_) {
3240*1b3f573fSAndroid Build Coastguard Worker        // Local for syntax so the block can directly capture it and not the
3241*1b3f573fSAndroid Build Coastguard Worker        // full lookup.
3242*1b3f573fSAndroid Build Coastguard Worker        result.impToAdd = imp_implementationWithBlock(^(id obj, id value) {
3243*1b3f573fSAndroid Build Coastguard Worker          GPBSetObjectIvarWithFieldPrivate(obj, field, value);
3244*1b3f573fSAndroid Build Coastguard Worker        });
3245*1b3f573fSAndroid Build Coastguard Worker        result.encodingSelector = @selector(setArray:);
3246*1b3f573fSAndroid Build Coastguard Worker        break;
3247*1b3f573fSAndroid Build Coastguard Worker      } else if (sel == field->hasOrCountSel_) {
3248*1b3f573fSAndroid Build Coastguard Worker        result.impToAdd = imp_implementationWithBlock(^(id obj) {
3249*1b3f573fSAndroid Build Coastguard Worker          // Type doesn't matter, all *Array and *Dictionary types support
3250*1b3f573fSAndroid Build Coastguard Worker          // -count.
3251*1b3f573fSAndroid Build Coastguard Worker          NSArray *arrayOrMap =
3252*1b3f573fSAndroid Build Coastguard Worker              GPBGetObjectIvarWithFieldNoAutocreate(obj, field);
3253*1b3f573fSAndroid Build Coastguard Worker          return [arrayOrMap count];
3254*1b3f573fSAndroid Build Coastguard Worker        });
3255*1b3f573fSAndroid Build Coastguard Worker        result.encodingSelector = @selector(getArrayCount);
3256*1b3f573fSAndroid Build Coastguard Worker        break;
3257*1b3f573fSAndroid Build Coastguard Worker      }
3258*1b3f573fSAndroid Build Coastguard Worker    }
3259*1b3f573fSAndroid Build Coastguard Worker  }
3260*1b3f573fSAndroid Build Coastguard Worker  if (result.impToAdd) {
3261*1b3f573fSAndroid Build Coastguard Worker    const char *encoding =
3262*1b3f573fSAndroid Build Coastguard Worker        GPBMessageEncodingForSelector(result.encodingSelector, YES);
3263*1b3f573fSAndroid Build Coastguard Worker    Class msgClass = descriptor.messageClass;
3264*1b3f573fSAndroid Build Coastguard Worker    BOOL methodAdded = class_addMethod(msgClass, sel, result.impToAdd, encoding);
3265*1b3f573fSAndroid Build Coastguard Worker    // class_addMethod() is documented as also failing if the method was already
3266*1b3f573fSAndroid Build Coastguard Worker    // added; so we check if the method is already there and return success so
3267*1b3f573fSAndroid Build Coastguard Worker    // the method dispatch will still happen.  Why would it already be added?
3268*1b3f573fSAndroid Build Coastguard Worker    // Two threads could cause the same method to be bound at the same time,
3269*1b3f573fSAndroid Build Coastguard Worker    // but only one will actually bind it; the other still needs to return true
3270*1b3f573fSAndroid Build Coastguard Worker    // so things will dispatch.
3271*1b3f573fSAndroid Build Coastguard Worker    if (!methodAdded) {
3272*1b3f573fSAndroid Build Coastguard Worker      methodAdded = GPBClassHasSel(msgClass, sel);
3273*1b3f573fSAndroid Build Coastguard Worker    }
3274*1b3f573fSAndroid Build Coastguard Worker    return methodAdded;
3275*1b3f573fSAndroid Build Coastguard Worker  }
3276*1b3f573fSAndroid Build Coastguard Worker  return [super resolveInstanceMethod:sel];
3277*1b3f573fSAndroid Build Coastguard Worker}
3278*1b3f573fSAndroid Build Coastguard Worker
3279*1b3f573fSAndroid Build Coastguard Worker+ (BOOL)resolveClassMethod:(SEL)sel {
3280*1b3f573fSAndroid Build Coastguard Worker  // Extensions scoped to a Message and looked up via class methods.
3281*1b3f573fSAndroid Build Coastguard Worker  if (GPBResolveExtensionClassMethod(self, sel)) {
3282*1b3f573fSAndroid Build Coastguard Worker    return YES;
3283*1b3f573fSAndroid Build Coastguard Worker  }
3284*1b3f573fSAndroid Build Coastguard Worker  return [super resolveClassMethod:sel];
3285*1b3f573fSAndroid Build Coastguard Worker}
3286*1b3f573fSAndroid Build Coastguard Worker
3287*1b3f573fSAndroid Build Coastguard Worker#pragma mark - NSCoding Support
3288*1b3f573fSAndroid Build Coastguard Worker
3289*1b3f573fSAndroid Build Coastguard Worker+ (BOOL)supportsSecureCoding {
3290*1b3f573fSAndroid Build Coastguard Worker  return YES;
3291*1b3f573fSAndroid Build Coastguard Worker}
3292*1b3f573fSAndroid Build Coastguard Worker
3293*1b3f573fSAndroid Build Coastguard Worker- (instancetype)initWithCoder:(NSCoder *)aDecoder {
3294*1b3f573fSAndroid Build Coastguard Worker  self = [self init];
3295*1b3f573fSAndroid Build Coastguard Worker  if (self) {
3296*1b3f573fSAndroid Build Coastguard Worker    NSData *data =
3297*1b3f573fSAndroid Build Coastguard Worker        [aDecoder decodeObjectOfClass:[NSData class] forKey:kGPBDataCoderKey];
3298*1b3f573fSAndroid Build Coastguard Worker    if (data.length) {
3299*1b3f573fSAndroid Build Coastguard Worker      [self mergeFromData:data extensionRegistry:nil];
3300*1b3f573fSAndroid Build Coastguard Worker    }
3301*1b3f573fSAndroid Build Coastguard Worker  }
3302*1b3f573fSAndroid Build Coastguard Worker  return self;
3303*1b3f573fSAndroid Build Coastguard Worker}
3304*1b3f573fSAndroid Build Coastguard Worker
3305*1b3f573fSAndroid Build Coastguard Worker- (void)encodeWithCoder:(NSCoder *)aCoder {
3306*1b3f573fSAndroid Build Coastguard Worker#if defined(DEBUG) && DEBUG
3307*1b3f573fSAndroid Build Coastguard Worker  if (extensionMap_.count) {
3308*1b3f573fSAndroid Build Coastguard Worker    // Hint to go along with the docs on GPBMessage about this.
3309*1b3f573fSAndroid Build Coastguard Worker    //
3310*1b3f573fSAndroid Build Coastguard Worker    // Note: This is incomplete, in that it only checked the "root" message,
3311*1b3f573fSAndroid Build Coastguard Worker    // if a sub message in a field has extensions, the issue still exists. A
3312*1b3f573fSAndroid Build Coastguard Worker    // recursive check could be done here (like the work in
3313*1b3f573fSAndroid Build Coastguard Worker    // GPBMessageDropUnknownFieldsRecursively()), but that has the potential to
3314*1b3f573fSAndroid Build Coastguard Worker    // be expensive and could slow down serialization in DEBUG enough to cause
3315*1b3f573fSAndroid Build Coastguard Worker    // developers other problems.
3316*1b3f573fSAndroid Build Coastguard Worker    NSLog(@"Warning: writing out a GPBMessage (%@) via NSCoding and it"
3317*1b3f573fSAndroid Build Coastguard Worker          @" has %ld extensions; when read back in, those fields will be"
3318*1b3f573fSAndroid Build Coastguard Worker          @" in the unknownFields property instead.",
3319*1b3f573fSAndroid Build Coastguard Worker          [self class], (long)extensionMap_.count);
3320*1b3f573fSAndroid Build Coastguard Worker  }
3321*1b3f573fSAndroid Build Coastguard Worker#endif
3322*1b3f573fSAndroid Build Coastguard Worker  NSData *data = [self data];
3323*1b3f573fSAndroid Build Coastguard Worker  if (data.length) {
3324*1b3f573fSAndroid Build Coastguard Worker    [aCoder encodeObject:data forKey:kGPBDataCoderKey];
3325*1b3f573fSAndroid Build Coastguard Worker  }
3326*1b3f573fSAndroid Build Coastguard Worker}
3327*1b3f573fSAndroid Build Coastguard Worker
3328*1b3f573fSAndroid Build Coastguard Worker#pragma mark - KVC Support
3329*1b3f573fSAndroid Build Coastguard Worker
3330*1b3f573fSAndroid Build Coastguard Worker+ (BOOL)accessInstanceVariablesDirectly {
3331*1b3f573fSAndroid Build Coastguard Worker  // Make sure KVC doesn't use instance variables.
3332*1b3f573fSAndroid Build Coastguard Worker  return NO;
3333*1b3f573fSAndroid Build Coastguard Worker}
3334*1b3f573fSAndroid Build Coastguard Worker
3335*1b3f573fSAndroid Build Coastguard Worker@end
3336*1b3f573fSAndroid Build Coastguard Worker
3337*1b3f573fSAndroid Build Coastguard Worker#pragma mark - Messages from GPBUtilities.h but defined here for access to helpers.
3338*1b3f573fSAndroid Build Coastguard Worker
3339*1b3f573fSAndroid Build Coastguard Worker// Only exists for public api, no core code should use this.
3340*1b3f573fSAndroid Build Coastguard Workerid GPBGetMessageRepeatedField(GPBMessage *self, GPBFieldDescriptor *field) {
3341*1b3f573fSAndroid Build Coastguard Worker#if defined(DEBUG) && DEBUG
3342*1b3f573fSAndroid Build Coastguard Worker  if (field.fieldType != GPBFieldTypeRepeated) {
3343*1b3f573fSAndroid Build Coastguard Worker    [NSException raise:NSInvalidArgumentException
3344*1b3f573fSAndroid Build Coastguard Worker                format:@"%@.%@ is not a repeated field.",
3345*1b3f573fSAndroid Build Coastguard Worker     [self class], field.name];
3346*1b3f573fSAndroid Build Coastguard Worker  }
3347*1b3f573fSAndroid Build Coastguard Worker#endif
3348*1b3f573fSAndroid Build Coastguard Worker  return GetOrCreateArrayIvarWithField(self, field);
3349*1b3f573fSAndroid Build Coastguard Worker}
3350*1b3f573fSAndroid Build Coastguard Worker
3351*1b3f573fSAndroid Build Coastguard Worker// Only exists for public api, no core code should use this.
3352*1b3f573fSAndroid Build Coastguard Workerid GPBGetMessageMapField(GPBMessage *self, GPBFieldDescriptor *field) {
3353*1b3f573fSAndroid Build Coastguard Worker#if defined(DEBUG) && DEBUG
3354*1b3f573fSAndroid Build Coastguard Worker  if (field.fieldType != GPBFieldTypeMap) {
3355*1b3f573fSAndroid Build Coastguard Worker    [NSException raise:NSInvalidArgumentException
3356*1b3f573fSAndroid Build Coastguard Worker                format:@"%@.%@ is not a map<> field.",
3357*1b3f573fSAndroid Build Coastguard Worker     [self class], field.name];
3358*1b3f573fSAndroid Build Coastguard Worker  }
3359*1b3f573fSAndroid Build Coastguard Worker#endif
3360*1b3f573fSAndroid Build Coastguard Worker  return GetOrCreateMapIvarWithField(self, field);
3361*1b3f573fSAndroid Build Coastguard Worker}
3362*1b3f573fSAndroid Build Coastguard Worker
3363*1b3f573fSAndroid Build Coastguard Workerid GPBGetObjectIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) {
3364*1b3f573fSAndroid Build Coastguard Worker  NSCAssert(!GPBFieldIsMapOrArray(field), @"Shouldn't get here");
3365*1b3f573fSAndroid Build Coastguard Worker  if (!GPBFieldDataTypeIsMessage(field)) {
3366*1b3f573fSAndroid Build Coastguard Worker    if (GPBGetHasIvarField(self, field)) {
3367*1b3f573fSAndroid Build Coastguard Worker      uint8_t *storage = (uint8_t *)self->messageStorage_;
3368*1b3f573fSAndroid Build Coastguard Worker      id *typePtr = (id *)&storage[field->description_->offset];
3369*1b3f573fSAndroid Build Coastguard Worker      return *typePtr;
3370*1b3f573fSAndroid Build Coastguard Worker    }
3371*1b3f573fSAndroid Build Coastguard Worker    // Not set...non messages (string/data), get their default.
3372*1b3f573fSAndroid Build Coastguard Worker    return field.defaultValue.valueMessage;
3373*1b3f573fSAndroid Build Coastguard Worker  }
3374*1b3f573fSAndroid Build Coastguard Worker
3375*1b3f573fSAndroid Build Coastguard Worker  uint8_t *storage = (uint8_t *)self->messageStorage_;
3376*1b3f573fSAndroid Build Coastguard Worker  _Atomic(id) *typePtr = (_Atomic(id) *)&storage[field->description_->offset];
3377*1b3f573fSAndroid Build Coastguard Worker  id msg = atomic_load(typePtr);
3378*1b3f573fSAndroid Build Coastguard Worker  if (msg) {
3379*1b3f573fSAndroid Build Coastguard Worker    return msg;
3380*1b3f573fSAndroid Build Coastguard Worker  }
3381*1b3f573fSAndroid Build Coastguard Worker
3382*1b3f573fSAndroid Build Coastguard Worker  id expected = nil;
3383*1b3f573fSAndroid Build Coastguard Worker  id autocreated = GPBCreateMessageWithAutocreator(field.msgClass, self, field);
3384*1b3f573fSAndroid Build Coastguard Worker  if (atomic_compare_exchange_strong(typePtr, &expected, autocreated)) {
3385*1b3f573fSAndroid Build Coastguard Worker    // Value was set, return it.
3386*1b3f573fSAndroid Build Coastguard Worker    return autocreated;
3387*1b3f573fSAndroid Build Coastguard Worker  }
3388*1b3f573fSAndroid Build Coastguard Worker
3389*1b3f573fSAndroid Build Coastguard Worker  // Some other thread set it, release the one created and return what got set.
3390*1b3f573fSAndroid Build Coastguard Worker  GPBClearMessageAutocreator(autocreated);
3391*1b3f573fSAndroid Build Coastguard Worker  [autocreated release];
3392*1b3f573fSAndroid Build Coastguard Worker  return expected;
3393*1b3f573fSAndroid Build Coastguard Worker}
3394*1b3f573fSAndroid Build Coastguard Worker
3395*1b3f573fSAndroid Build Coastguard Worker#pragma clang diagnostic pop
3396