blob: 9eb4081bac18baa2bd5c9fec97daf4f8bcf102f7 [file] [log] [blame]
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc. All rights reserved.
Thomas Van Lenten30650d82015-05-01 08:57:16 -04003//
Joshua Haberman44bd65b2023-09-08 17:43:14 -07004// Use of this source code is governed by a BSD-style
5// license that can be found in the LICENSE file or at
6// https://developers.google.com/open-source/licenses/bsd
Thomas Van Lenten30650d82015-05-01 08:57:16 -04007
8#import "GPBDescriptor_PackagePrivate.h"
9
10#import <objc/runtime.h>
11
Thomas Van Lenten189f6322022-09-19 17:21:13 -040012#import "GPBMessage_PackagePrivate.h"
Thomas Van Lenten30650d82015-05-01 08:57:16 -040013#import "GPBUtilities_PackagePrivate.h"
14#import "GPBWireFormat.h"
Thomas Van Lenten30650d82015-05-01 08:57:16 -040015
Protobuf Team Bot3a742662022-11-15 08:56:51 -080016@interface GPBDescriptor ()
17- (instancetype)initWithClass:(Class)messageClass
Protobuf Team Botf4c79722023-02-08 06:29:16 -080018 messageName:(NSString *)messageName
19 fileDescription:(GPBFileDescription *)fileDescription
Protobuf Team Bot3a742662022-11-15 08:56:51 -080020 fields:(NSArray *)fields
21 storageSize:(uint32_t)storage
22 wireFormat:(BOOL)wireFormat;
23@end
24
25@interface GPBFieldDescriptor ()
26// Single initializer
27// description has to be long lived, it is held as a raw pointer.
28- (instancetype)initWithFieldDescription:(void *)description
Protobuf Team Botecde3712023-02-08 09:11:39 -080029 descriptorFlags:(GPBDescriptorInitializationFlags)descriptorFlags;
Protobuf Team Bot3a742662022-11-15 08:56:51 -080030
31@end
32
33@interface GPBEnumDescriptor ()
34- (instancetype)initWithName:(NSString *)name
35 valueNames:(const char *)valueNames
36 values:(const int32_t *)values
37 count:(uint32_t)valueCount
Protobuf Team Bot7bb699b2022-11-15 08:59:25 -080038 enumVerifier:(GPBEnumValidationFunc)enumVerifier
39 flags:(GPBEnumDescriptorInitializationFlags)flags;
Protobuf Team Bot3a742662022-11-15 08:56:51 -080040@end
41
Thomas Van Lentenc8a440d2016-05-25 13:46:00 -040042// Direct access is use for speed, to avoid even internally declaring things
43// read/write, etc. The warning is enabled in the project to ensure code calling
44// protos can turn on -Wdirect-ivar-access without issues.
45#pragma clang diagnostic push
46#pragma clang diagnostic ignored "-Wdirect-ivar-access"
47
Thomas Van Lenten337ec302016-08-16 11:26:49 -040048// The addresses of these variables are used as keys for objc_getAssociatedObject.
Thomas Van Lenten30650d82015-05-01 08:57:16 -040049static const char kTextFormatExtraValueKey = 0;
Dave MacLachlan74956e12019-12-17 17:32:09 -080050static const char kParentClassValueKey = 0;
Thomas Van Lenten337ec302016-08-16 11:26:49 -040051static const char kClassNameSuffixKey = 0;
Protobuf Team Botf4c79722023-02-08 06:29:16 -080052static const char kFileDescriptorCacheKey = 0;
Thomas Van Lenten30650d82015-05-01 08:57:16 -040053
54// Utility function to generate selectors on the fly.
Thomas Van Lenten189f6322022-09-19 17:21:13 -040055static SEL SelFromStrings(const char *prefix, const char *middle, const char *suffix,
56 BOOL takesArg) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -040057 if (prefix == NULL && suffix == NULL && !takesArg) {
58 return sel_getUid(middle);
59 }
60 const size_t prefixLen = prefix != NULL ? strlen(prefix) : 0;
61 const size_t middleLen = strlen(middle);
62 const size_t suffixLen = suffix != NULL ? strlen(suffix) : 0;
Thomas Van Lenten189f6322022-09-19 17:21:13 -040063 size_t totalLen = prefixLen + middleLen + suffixLen + 1; // include space for null on end.
Thomas Van Lenten30650d82015-05-01 08:57:16 -040064 if (takesArg) {
65 totalLen += 1;
66 }
67 char buffer[totalLen];
68 if (prefix != NULL) {
69 memcpy(buffer, prefix, prefixLen);
70 memcpy(buffer + prefixLen, middle, middleLen);
71 buffer[prefixLen] = (char)toupper(buffer[prefixLen]);
72 } else {
73 memcpy(buffer, middle, middleLen);
74 }
75 if (suffix != NULL) {
76 memcpy(buffer + prefixLen + middleLen, suffix, suffixLen);
77 }
78 if (takesArg) {
79 buffer[totalLen - 2] = ':';
80 }
81 // Always null terminate it.
82 buffer[totalLen - 1] = 0;
83
84 SEL result = sel_getUid(buffer);
85 return result;
86}
87
Thomas Van Lenten189f6322022-09-19 17:21:13 -040088static NSArray *NewFieldsArrayForHasIndex(int hasIndex, NSArray *allMessageFields)
Thomas Van Lenten30650d82015-05-01 08:57:16 -040089 __attribute__((ns_returns_retained));
90
Thomas Van Lenten189f6322022-09-19 17:21:13 -040091static NSArray *NewFieldsArrayForHasIndex(int hasIndex, NSArray *allMessageFields) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -040092 NSMutableArray *result = [[NSMutableArray alloc] init];
93 for (GPBFieldDescriptor *fieldDesc in allMessageFields) {
94 if (fieldDesc->description_->hasIndex == hasIndex) {
95 [result addObject:fieldDesc];
96 }
97 }
98 return result;
99}
100
101@implementation GPBDescriptor {
102 Class messageClass_;
Protobuf Team Botf4c79722023-02-08 06:29:16 -0800103 NSString *messageName_;
104 const GPBFileDescription *fileDescription_;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400105 BOOL wireFormat_;
106}
107
108@synthesize messageClass = messageClass_;
109@synthesize fields = fields_;
110@synthesize oneofs = oneofs_;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400111@synthesize extensionRanges = extensionRanges_;
112@synthesize extensionRangesCount = extensionRangesCount_;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400113@synthesize wireFormat = wireFormat_;
114
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400115+ (instancetype)allocDescriptorForClass:(Class)messageClass
Protobuf Team Botf4c79722023-02-08 06:29:16 -0800116 messageName:(NSString *)messageName
117 fileDescription:(GPBFileDescription *)fileDescription
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400118 fields:(void *)fieldDescriptions
119 fieldCount:(uint32_t)fieldCount
120 storageSize:(uint32_t)storageSize
121 flags:(GPBDescriptorInitializationFlags)flags {
Protobuf Team Bot6e5a01b2023-01-31 13:11:17 -0800122 // Compute the unknown flags by this version of the runtime and then check the passed in flags
123 // (from the generated code) to detect when sources from a newer version are being used with an
124 // older runtime.
125 GPBDescriptorInitializationFlags unknownFlags =
126 ~(GPBDescriptorInitializationFlag_FieldsWithDefault |
127 GPBDescriptorInitializationFlag_WireFormat | GPBDescriptorInitializationFlag_UsesClassRefs |
128 GPBDescriptorInitializationFlag_Proto3OptionalKnown |
129 GPBDescriptorInitializationFlag_ClosedEnumSupportKnown);
130 if ((flags & unknownFlags) != 0) {
131 GPBRuntimeMatchFailure();
132 }
Protobuf Team Bot5e6fbbb2023-02-08 07:30:33 -0800133
134#if defined(DEBUG) && DEBUG
135 NSAssert((flags & GPBDescriptorInitializationFlag_UsesClassRefs) != 0,
136 @"Internal error: all fields should have class refs");
Protobuf Team Bot699561f2023-02-08 08:15:28 -0800137 NSAssert((flags & GPBDescriptorInitializationFlag_Proto3OptionalKnown) != 0,
138 @"Internal error: proto3 optional should be known");
Protobuf Team Bot9d0ce3e2023-02-08 08:42:56 -0800139 NSAssert((flags & GPBDescriptorInitializationFlag_ClosedEnumSupportKnown) != 0,
140 @"Internal error: close enum should be known");
Protobuf Team Botecde3712023-02-08 09:11:39 -0800141
142 // `messageName` and `fileDescription` should both be set or both be unset depending on if this is
143 // being called from current code generation or legacy code generation.
144 NSAssert((messageName == nil) == (fileDescription == NULL),
145 @"name and fileDescription should always be provided together");
Protobuf Team Bot5e6fbbb2023-02-08 07:30:33 -0800146#endif
147
Protobuf Team Bot3a742662022-11-15 08:56:51 -0800148 NSMutableArray *fields =
149 (fieldCount ? [[NSMutableArray alloc] initWithCapacity:fieldCount] : nil);
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400150 BOOL fieldsIncludeDefault = (flags & GPBDescriptorInitializationFlag_FieldsWithDefault) != 0;
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400151
152 void *desc;
Protobuf Team Bot6e5a01b2023-01-31 13:11:17 -0800153 GPBFieldFlags mergedFieldFlags = GPBFieldNone;
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400154 for (uint32_t i = 0; i < fieldCount; ++i) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400155 // Need correctly typed pointer for array indexing below to work.
156 if (fieldsIncludeDefault) {
Protobuf Team Bot3a742662022-11-15 08:56:51 -0800157 desc = &(((GPBMessageFieldDescriptionWithDefault *)fieldDescriptions)[i]);
Protobuf Team Bot6e5a01b2023-01-31 13:11:17 -0800158 mergedFieldFlags |=
159 (((GPBMessageFieldDescriptionWithDefault *)fieldDescriptions)[i]).core.flags;
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400160 } else {
Protobuf Team Bot3a742662022-11-15 08:56:51 -0800161 desc = &(((GPBMessageFieldDescription *)fieldDescriptions)[i]);
Protobuf Team Bot6e5a01b2023-01-31 13:11:17 -0800162 mergedFieldFlags |= (((GPBMessageFieldDescription *)fieldDescriptions)[i]).flags;
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400163 }
164 GPBFieldDescriptor *fieldDescriptor =
Protobuf Team Botecde3712023-02-08 09:11:39 -0800165 [[GPBFieldDescriptor alloc] initWithFieldDescription:desc descriptorFlags:flags];
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400166 [fields addObject:fieldDescriptor];
167 [fieldDescriptor release];
168 }
Protobuf Team Bot6e5a01b2023-01-31 13:11:17 -0800169 // No real value in checking all the fields individually, just check the combined flags at the
170 // end.
171 GPBFieldFlags unknownFieldFlags =
172 ~(GPBFieldRequired | GPBFieldRepeated | GPBFieldPacked | GPBFieldOptional |
173 GPBFieldHasDefaultValue | GPBFieldClearHasIvarOnZero | GPBFieldTextFormatNameCustom |
174 GPBFieldHasEnumDescriptor | GPBFieldMapKeyMask | GPBFieldClosedEnum);
175 if ((mergedFieldFlags & unknownFieldFlags) != 0) {
176 GPBRuntimeMatchFailure();
177 }
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400178
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400179 BOOL wireFormat = (flags & GPBDescriptorInitializationFlag_WireFormat) != 0;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400180 GPBDescriptor *descriptor = [[self alloc] initWithClass:messageClass
Protobuf Team Botf4c79722023-02-08 06:29:16 -0800181 messageName:messageName
182 fileDescription:fileDescription
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400183 fields:fields
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400184 storageSize:storageSize
185 wireFormat:wireFormat];
186 [fields release];
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400187 return descriptor;
188}
189
Protobuf Team Bot48ff4f62023-01-26 11:37:19 -0800190+ (instancetype)allocDescriptorForClass:(Class)messageClass
Protobuf Team Botf4c79722023-02-08 06:29:16 -0800191 file:(GPBFileDescriptor *)file
192 fields:(void *)fieldDescriptions
193 fieldCount:(uint32_t)fieldCount
194 storageSize:(uint32_t)storageSize
195 flags:(GPBDescriptorInitializationFlags)flags {
196 GPBInternalCompileAssert(GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION <= 30006,
197 time_to_remove_this_old_version_shim);
198
Protobuf Team Bot5e6fbbb2023-02-08 07:30:33 -0800199 BOOL fixClassRefs = (flags & GPBDescriptorInitializationFlag_UsesClassRefs) == 0;
200 GPBInternalCompileAssert(GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION <= 30003,
201 time_to_remove_non_class_ref_support);
202
Protobuf Team Bot699561f2023-02-08 08:15:28 -0800203 BOOL fixProto3Optional = (flags & GPBDescriptorInitializationFlag_Proto3OptionalKnown) == 0;
204 GPBInternalCompileAssert(GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION <= 30004,
205 time_to_remove_proto3_optional_fallback);
206
Protobuf Team Bot9d0ce3e2023-02-08 08:42:56 -0800207 BOOL fixClosedEnums = (flags & GPBDescriptorInitializationFlag_ClosedEnumSupportKnown) == 0;
208 GPBInternalCompileAssert(GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION <= 30005,
209 time_to_remove_closed_enum_fallback);
210
211 if (fixClassRefs || fixProto3Optional || fixClosedEnums) {
Protobuf Team Bot5e6fbbb2023-02-08 07:30:33 -0800212 BOOL fieldsIncludeDefault = (flags & GPBDescriptorInitializationFlag_FieldsWithDefault) != 0;
Protobuf Team Bot699561f2023-02-08 08:15:28 -0800213#pragma clang diagnostic push
214#pragma clang diagnostic ignored "-Wdeprecated-declarations"
215 GPBFileSyntax fileSyntax = file.syntax;
216#pragma clang diagnostic pop
Protobuf Team Bot5e6fbbb2023-02-08 07:30:33 -0800217
218 for (uint32_t i = 0; i < fieldCount; ++i) {
219 GPBMessageFieldDescription *coreDesc;
220 if (fieldsIncludeDefault) {
221 coreDesc = &((((GPBMessageFieldDescriptionWithDefault *)fieldDescriptions)[i]).core);
222 } else {
223 coreDesc = &(((GPBMessageFieldDescription *)fieldDescriptions)[i]);
224 }
225
Protobuf Team Bot699561f2023-02-08 08:15:28 -0800226 if (fixClassRefs && GPBDataTypeIsMessage(coreDesc->dataType)) {
Protobuf Team Bot5e6fbbb2023-02-08 07:30:33 -0800227 const char *className = coreDesc->dataTypeSpecific.className;
228 Class msgClass = objc_getClass(className);
229 NSAssert(msgClass, @"Class %s not defined", className);
230 coreDesc->dataTypeSpecific.clazz = msgClass;
231 }
Protobuf Team Bot699561f2023-02-08 08:15:28 -0800232
233 if (fixProto3Optional) {
234 // If it was...
235 // - proto3 syntax
236 // - not repeated/map
237 // - not in a oneof (negative has index)
238 // - not a message (the flag doesn't make sense for messages)
239 BOOL clearOnZero = ((fileSyntax == GPBFileSyntaxProto3) &&
240 ((coreDesc->flags & (GPBFieldRepeated | GPBFieldMapKeyMask)) == 0) &&
241 (coreDesc->hasIndex >= 0) && !GPBDataTypeIsMessage(coreDesc->dataType));
242 if (clearOnZero) {
243 coreDesc->flags |= GPBFieldClearHasIvarOnZero;
244 }
245 }
Protobuf Team Bot9d0ce3e2023-02-08 08:42:56 -0800246
247 if (fixClosedEnums) {
248 // NOTE: This isn't correct, it is using the syntax of the file that
249 // declared the field, not the syntax of the file that declared the
250 // enum; but for older generated code, that's all we have and that happens
251 // to be what the runtime was doing (even though it was wrong). This is
252 // only wrong in the rare cases an enum is declared in a proto3 syntax
253 // file but used for a field in the proto2 syntax file.
254 BOOL isClosedEnum =
Thomas Van Lentenff259f72023-08-11 08:59:53 -0700255 (coreDesc->dataType == GPBDataTypeEnum && fileSyntax == GPBFileSyntaxProto2);
Protobuf Team Bot9d0ce3e2023-02-08 08:42:56 -0800256 if (isClosedEnum) {
257 coreDesc->flags |= GPBFieldClosedEnum;
258 }
259 }
Protobuf Team Bot5e6fbbb2023-02-08 07:30:33 -0800260 }
Protobuf Team Bot699561f2023-02-08 08:15:28 -0800261 flags |= (GPBDescriptorInitializationFlag_UsesClassRefs |
Protobuf Team Bot9d0ce3e2023-02-08 08:42:56 -0800262 GPBDescriptorInitializationFlag_Proto3OptionalKnown |
263 GPBDescriptorInitializationFlag_ClosedEnumSupportKnown);
Protobuf Team Bot5e6fbbb2023-02-08 07:30:33 -0800264 }
265
Protobuf Team Botf4c79722023-02-08 06:29:16 -0800266 GPBDescriptor *result = [self allocDescriptorForClass:messageClass
267 messageName:nil
Protobuf Team Botecde3712023-02-08 09:11:39 -0800268 fileDescription:NULL
Protobuf Team Botf4c79722023-02-08 06:29:16 -0800269 fields:fieldDescriptions
270 fieldCount:fieldCount
271 storageSize:storageSize
272 flags:flags];
Protobuf Team Botf4c79722023-02-08 06:29:16 -0800273 objc_setAssociatedObject(result, &kFileDescriptorCacheKey, file,
274 OBJC_ASSOCIATION_RETAIN_NONATOMIC);
275 return result;
276}
277
278+ (instancetype)allocDescriptorForClass:(Class)messageClass
Protobuf Team Bot48ff4f62023-01-26 11:37:19 -0800279 rootClass:(__unused Class)rootClass
280 file:(GPBFileDescriptor *)file
281 fields:(void *)fieldDescriptions
282 fieldCount:(uint32_t)fieldCount
283 storageSize:(uint32_t)storageSize
284 flags:(GPBDescriptorInitializationFlags)flags {
Protobuf Team Bot663fca12023-01-31 09:07:43 -0800285 GPBInternalCompileAssert(GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION <= 30006,
286 time_to_remove_this_old_version_shim);
Protobuf Team Bot48ff4f62023-01-26 11:37:19 -0800287 // The rootClass is no longer used, but it is passed as [ROOT class] to
288 // ensure it was started up during initialization also when the message
289 // scopes extensions.
290 return [self allocDescriptorForClass:messageClass
291 file:file
292 fields:fieldDescriptions
293 fieldCount:fieldCount
294 storageSize:storageSize
295 flags:flags];
296}
297
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400298- (instancetype)initWithClass:(Class)messageClass
Protobuf Team Botf4c79722023-02-08 06:29:16 -0800299 messageName:(NSString *)messageName
300 fileDescription:(GPBFileDescription *)fileDescription
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400301 fields:(NSArray *)fields
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400302 storageSize:(uint32_t)storageSize
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400303 wireFormat:(BOOL)wireFormat {
304 if ((self = [super init])) {
305 messageClass_ = messageClass;
Protobuf Team Botf4c79722023-02-08 06:29:16 -0800306 messageName_ = [messageName copy];
307 fileDescription_ = fileDescription;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400308 fields_ = [fields retain];
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400309 storageSize_ = storageSize;
310 wireFormat_ = wireFormat;
311 }
312 return self;
313}
314
315- (void)dealloc {
Protobuf Team Botf4c79722023-02-08 06:29:16 -0800316 [messageName_ release];
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400317 [fields_ release];
318 [oneofs_ release];
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400319 [super dealloc];
320}
321
Protobuf Team Bot8f799092023-01-31 07:43:13 -0800322// No need to provide -hash/-isEqual: as the instances are singletons and the
323// default from NSObject is fine.
324- (instancetype)copyWithZone:(__unused NSZone *)zone {
325 // Immutable.
326 return [self retain];
327}
328
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400329- (void)setupOneofs:(const char **)oneofNames
330 count:(uint32_t)count
331 firstHasIndex:(int32_t)firstHasIndex {
332 NSCAssert(firstHasIndex < 0, @"Should always be <0");
333 NSMutableArray *oneofs = [[NSMutableArray alloc] initWithCapacity:count];
334 for (uint32_t i = 0, hasIndex = firstHasIndex; i < count; ++i, --hasIndex) {
335 const char *name = oneofNames[i];
336 NSArray *fieldsForOneof = NewFieldsArrayForHasIndex(hasIndex, fields_);
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400337 NSCAssert(fieldsForOneof.count > 0, @"No fields for this oneof? (%s:%d)", name, hasIndex);
338 GPBOneofDescriptor *oneofDescriptor = [[GPBOneofDescriptor alloc] initWithName:name
339 fields:fieldsForOneof];
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400340 [oneofs addObject:oneofDescriptor];
341 [oneofDescriptor release];
342 [fieldsForOneof release];
343 }
344 oneofs_ = oneofs;
345}
346
347- (void)setupExtraTextInfo:(const char *)extraTextFormatInfo {
348 // Extra info is a compile time option, so skip the work if not needed.
349 if (extraTextFormatInfo) {
350 NSValue *extraInfoValue = [NSValue valueWithPointer:extraTextFormatInfo];
351 for (GPBFieldDescriptor *fieldDescriptor in fields_) {
352 if (fieldDescriptor->description_->flags & GPBFieldTextFormatNameCustom) {
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400353 objc_setAssociatedObject(fieldDescriptor, &kTextFormatExtraValueKey, extraInfoValue,
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400354 OBJC_ASSOCIATION_RETAIN_NONATOMIC);
355 }
356 }
357 }
358}
359
360- (void)setupExtensionRanges:(const GPBExtensionRange *)ranges count:(int32_t)count {
361 extensionRanges_ = ranges;
362 extensionRangesCount_ = count;
363}
364
Dave MacLachlan74956e12019-12-17 17:32:09 -0800365- (void)setupContainingMessageClass:(Class)messageClass {
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400366 objc_setAssociatedObject(self, &kParentClassValueKey, messageClass, OBJC_ASSOCIATION_ASSIGN);
Dave MacLachlan74956e12019-12-17 17:32:09 -0800367}
368
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400369- (void)setupContainingMessageClassName:(const char *)msgClassName {
Protobuf Team Bot663fca12023-01-31 09:07:43 -0800370 GPBInternalCompileAssert(GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION <= 30003,
371 time_to_remove_this_old_version_shim);
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400372 // Note: Only fetch the class here, can't send messages to it because
373 // that could cause cycles back to this class within +initialize if
374 // two messages have each other in fields (i.e. - they build a graph).
Dave MacLachlan74956e12019-12-17 17:32:09 -0800375 Class clazz = objc_getClass(msgClassName);
376 NSAssert(clazz, @"Class %s not defined", msgClassName);
377 [self setupContainingMessageClass:clazz];
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400378}
379
380- (void)setupMessageClassNameSuffix:(NSString *)suffix {
Protobuf Team Botf4c79722023-02-08 06:29:16 -0800381 GPBInternalCompileAssert(GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION <= 30007,
382 time_to_remove_this_old_version_shim);
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400383 if (suffix.length) {
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400384 objc_setAssociatedObject(self, &kClassNameSuffixKey, suffix, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400385 }
386}
387
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400388- (NSString *)name {
389 return NSStringFromClass(messageClass_);
390}
391
Protobuf Team Botf4c79722023-02-08 06:29:16 -0800392- (GPBFileDescriptor *)file {
393 @synchronized(self) {
394 GPBFileDescriptor *result = objc_getAssociatedObject(self, &kFileDescriptorCacheKey);
395 if (!result) {
396#if defined(DEBUG) && DEBUG
397 NSAssert(fileDescription_ != NULL, @"Internal error in generation/startup");
398#endif
399 // `package` and `prefix` can both be NULL if there wasn't one for the file.
400 NSString *package = fileDescription_->package ? @(fileDescription_->package) : @"";
401 if (fileDescription_->prefix) {
402 result = [[GPBFileDescriptor alloc] initWithPackage:package
403 objcPrefix:@(fileDescription_->prefix)
404 syntax:fileDescription_->syntax];
405
406 } else {
407 result = [[GPBFileDescriptor alloc] initWithPackage:package
408 syntax:fileDescription_->syntax];
409 }
410 objc_setAssociatedObject(result, &kFileDescriptorCacheKey, result,
411 OBJC_ASSOCIATION_RETAIN_NONATOMIC);
412 }
413 return result;
414 }
415}
416
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400417- (GPBDescriptor *)containingType {
Dave MacLachlan74956e12019-12-17 17:32:09 -0800418 Class parentClass = objc_getAssociatedObject(self, &kParentClassValueKey);
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400419 return [parentClass descriptor];
420}
421
422- (NSString *)fullName {
Protobuf Team Botf4c79722023-02-08 06:29:16 -0800423 GPBDescriptor *parent = self.containingType;
424 if (messageName_) {
425 if (parent) {
426 return [NSString stringWithFormat:@"%@.%@", parent.fullName, messageName_];
427 }
428 if (fileDescription_->package) {
429 return [NSString stringWithFormat:@"%s.%@", fileDescription_->package, messageName_];
430 }
431 return messageName_;
432 }
433
434 GPBInternalCompileAssert(GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION <= 30007,
435 time_to_remove_this_old_approach);
436 // NOTE: When this code path is removed, this also means this api can't return nil any more but
437 // that would be a breaking code change (not longer a Swift optional), so changing that will be
438 // harder.
439
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400440 NSString *className = NSStringFromClass(self.messageClass);
441 GPBFileDescriptor *file = self.file;
442 NSString *objcPrefix = file.objcPrefix;
443 if (objcPrefix && ![className hasPrefix:objcPrefix]) {
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400444 NSAssert(0, @"Class didn't have correct prefix? (%@ - %@)", className, objcPrefix);
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400445 return nil;
446 }
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400447
448 NSString *name = nil;
449 if (parent) {
450 NSString *parentClassName = NSStringFromClass(parent.messageClass);
451 // The generator will add _Class to avoid reserved words, drop it.
452 NSString *suffix = objc_getAssociatedObject(parent, &kClassNameSuffixKey);
453 if (suffix) {
454 if (![parentClassName hasSuffix:suffix]) {
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400455 NSAssert(0, @"ParentMessage class didn't have correct suffix? (%@ - %@)", className,
456 suffix);
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400457 return nil;
458 }
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400459 parentClassName = [parentClassName substringToIndex:(parentClassName.length - suffix.length)];
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400460 }
461 NSString *parentPrefix = [parentClassName stringByAppendingString:@"_"];
462 if (![className hasPrefix:parentPrefix]) {
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400463 NSAssert(0, @"Class didn't have the correct parent name prefix? (%@ - %@)", parentPrefix,
464 className);
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400465 return nil;
466 }
467 name = [className substringFromIndex:parentPrefix.length];
468 } else {
469 name = [className substringFromIndex:objcPrefix.length];
470 }
471
472 // The generator will add _Class to avoid reserved words, drop it.
473 NSString *suffix = objc_getAssociatedObject(self, &kClassNameSuffixKey);
474 if (suffix) {
475 if (![name hasSuffix:suffix]) {
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400476 NSAssert(0, @"Message class didn't have correct suffix? (%@ - %@)", name, suffix);
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400477 return nil;
478 }
479 name = [name substringToIndex:(name.length - suffix.length)];
480 }
481
482 NSString *prefix = (parent != nil ? parent.fullName : file.package);
483 NSString *result;
484 if (prefix.length > 0) {
485 result = [NSString stringWithFormat:@"%@.%@", prefix, name];
486 } else {
487 result = name;
488 }
489 return result;
490}
491
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400492- (GPBFieldDescriptor *)fieldWithNumber:(uint32_t)fieldNumber {
493 for (GPBFieldDescriptor *descriptor in fields_) {
494 if (GPBFieldNumber(descriptor) == fieldNumber) {
495 return descriptor;
496 }
497 }
498 return nil;
499}
500
501- (GPBFieldDescriptor *)fieldWithName:(NSString *)name {
502 for (GPBFieldDescriptor *descriptor in fields_) {
503 if ([descriptor.name isEqual:name]) {
504 return descriptor;
505 }
506 }
507 return nil;
508}
509
510- (GPBOneofDescriptor *)oneofWithName:(NSString *)name {
511 for (GPBOneofDescriptor *descriptor in oneofs_) {
512 if ([descriptor.name isEqual:name]) {
513 return descriptor;
514 }
515 }
516 return nil;
517}
518
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400519@end
520
521@implementation GPBFileDescriptor {
522 NSString *package_;
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400523 NSString *objcPrefix_;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400524 GPBFileSyntax syntax_;
525}
526
527@synthesize package = package_;
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400528@synthesize objcPrefix = objcPrefix_;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400529@synthesize syntax = syntax_;
530
531- (instancetype)initWithPackage:(NSString *)package
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400532 objcPrefix:(NSString *)objcPrefix
533 syntax:(GPBFileSyntax)syntax {
534 self = [super init];
535 if (self) {
536 package_ = [package copy];
537 objcPrefix_ = [objcPrefix copy];
538 syntax_ = syntax;
539 }
540 return self;
541}
542
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400543- (instancetype)initWithPackage:(NSString *)package syntax:(GPBFileSyntax)syntax {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400544 self = [super init];
545 if (self) {
546 package_ = [package copy];
547 syntax_ = syntax;
548 }
549 return self;
550}
551
Sergio Campamá71f4a9c2016-06-14 06:28:22 -0700552- (void)dealloc {
553 [package_ release];
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400554 [objcPrefix_ release];
Sergio Campamá71f4a9c2016-06-14 06:28:22 -0700555 [super dealloc];
556}
557
Protobuf Team Botf17a6292023-01-27 11:27:21 -0800558- (BOOL)isEqual:(id)other {
559 if (other == self) {
560 return YES;
561 }
562 if (![other isKindOfClass:[GPBFileDescriptor class]]) {
563 return NO;
564 }
565 GPBFileDescriptor *otherFile = other;
566 // objcPrefix can be nil, otherwise, straight up compare.
567 return (syntax_ == otherFile->syntax_ && [package_ isEqual:otherFile->package_] &&
568 (objcPrefix_ == otherFile->objcPrefix_ ||
569 (otherFile->objcPrefix_ && [objcPrefix_ isEqual:otherFile->objcPrefix_])));
570}
571
572- (NSUInteger)hash {
573 // The prefix is recommended to be the same for a given package, so just hash
574 // the package.
575 return [package_ hash];
576}
577
Protobuf Team Bot8f799092023-01-31 07:43:13 -0800578- (instancetype)copyWithZone:(__unused NSZone *)zone {
579 // Immutable.
580 return [self retain];
581}
582
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400583@end
584
585@implementation GPBOneofDescriptor
586
587@synthesize fields = fields_;
588
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400589- (instancetype)initWithName:(const char *)name fields:(NSArray *)fields {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400590 self = [super init];
591 if (self) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400592 name_ = name;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400593 fields_ = [fields retain];
594 for (GPBFieldDescriptor *fieldDesc in fields) {
595 fieldDesc->containingOneof_ = self;
596 }
597
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400598 caseSel_ = SelFromStrings(NULL, name, "OneOfCase", NO);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400599 }
600 return self;
601}
602
603- (void)dealloc {
604 [fields_ release];
605 [super dealloc];
606}
607
Protobuf Team Bot8f799092023-01-31 07:43:13 -0800608// No need to provide -hash/-isEqual: as the instances are singletons and the
609// default from NSObject is fine.
610- (instancetype)copyWithZone:(__unused NSZone *)zone {
611 // Immutable.
612 return [self retain];
613}
614
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400615- (NSString *)name {
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400616 return (NSString *_Nonnull)@(name_);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400617}
618
619- (GPBFieldDescriptor *)fieldWithNumber:(uint32_t)fieldNumber {
620 for (GPBFieldDescriptor *descriptor in fields_) {
621 if (GPBFieldNumber(descriptor) == fieldNumber) {
622 return descriptor;
623 }
624 }
625 return nil;
626}
627
628- (GPBFieldDescriptor *)fieldWithName:(NSString *)name {
629 for (GPBFieldDescriptor *descriptor in fields_) {
630 if ([descriptor.name isEqual:name]) {
631 return descriptor;
632 }
633 }
634 return nil;
635}
636
637@end
638
639uint32_t GPBFieldTag(GPBFieldDescriptor *self) {
640 GPBMessageFieldDescription *description = self->description_;
641 GPBWireFormat format;
642 if ((description->flags & GPBFieldMapKeyMask) != 0) {
643 // Maps are repeated messages on the wire.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400644 format = GPBWireFormatForType(GPBDataTypeMessage, NO);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400645 } else {
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400646 format =
647 GPBWireFormatForType(description->dataType, ((description->flags & GPBFieldPacked) != 0));
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400648 }
649 return GPBWireFormatMakeTag(description->number, format);
650}
651
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400652uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) {
653 GPBMessageFieldDescription *description = self->description_;
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400654 NSCAssert((description->flags & GPBFieldRepeated) != 0, @"Only valid on repeated fields");
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400655 GPBWireFormat format =
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400656 GPBWireFormatForType(description->dataType, ((description->flags & GPBFieldPacked) == 0));
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400657 return GPBWireFormatMakeTag(description->number, format);
658}
659
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400660@implementation GPBFieldDescriptor {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400661 GPBGenericValue defaultValue_;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400662
663 // Message ivars
664 Class msgClass_;
665
666 // Enum ivars.
Protobuf Team Bot7140f6f2022-11-14 09:04:23 -0800667 GPBEnumDescriptor *enumDescriptor_;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400668}
669
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400670@synthesize msgClass = msgClass_;
671@synthesize containingOneof = containingOneof_;
672
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400673- (instancetype)initWithFieldDescription:(void *)description
Protobuf Team Botecde3712023-02-08 09:11:39 -0800674 descriptorFlags:(GPBDescriptorInitializationFlags)descriptorFlags {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400675 if ((self = [super init])) {
Protobuf Team Bot83677a92022-11-23 10:52:09 -0800676 BOOL includesDefault =
Protobuf Team Bot48ff4f62023-01-26 11:37:19 -0800677 (descriptorFlags & GPBDescriptorInitializationFlag_FieldsWithDefault) != 0;
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400678 GPBMessageFieldDescription *coreDesc;
679 if (includesDefault) {
680 coreDesc = &(((GPBMessageFieldDescriptionWithDefault *)description)->core);
681 } else {
682 coreDesc = description;
683 }
684 description_ = coreDesc;
685 getSel_ = sel_getUid(coreDesc->name);
686 setSel_ = SelFromStrings("set", coreDesc->name, NULL, YES);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400687
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400688 GPBDataType dataType = coreDesc->dataType;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400689 BOOL isMessage = GPBDataTypeIsMessage(dataType);
690 BOOL isMapOrArray = GPBFieldIsMapOrArray(self);
691
692 if (isMapOrArray) {
693 // map<>/repeated fields get a *Count property (inplace of a has*) to
694 // support checking if there are any entries without triggering
695 // autocreation.
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400696 hasOrCountSel_ = SelFromStrings(NULL, coreDesc->name, "_Count", NO);
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400697 } else {
Thomas Van Lentendddeed22020-04-24 13:40:59 -0400698 // It is a single field; it gets has/setHas selectors if...
Thomas Van Lenten8d224b42020-04-08 11:34:37 -0400699 // - not in a oneof (negative has index)
700 // - not clearing on zero
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400701 if ((coreDesc->hasIndex >= 0) && ((coreDesc->flags & GPBFieldClearHasIvarOnZero) == 0)) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400702 hasOrCountSel_ = SelFromStrings("has", coreDesc->name, NULL, NO);
703 setHasSel_ = SelFromStrings("setHas", coreDesc->name, NULL, YES);
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400704 }
705 }
706
707 // Extra type specific data.
708 if (isMessage) {
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400709 // Note: Only fetch the class here, can't send messages to it because
710 // that could cause cycles back to this class within +initialize if
711 // two messages have each other in fields (i.e. - they build a graph).
Protobuf Team Bot5e6fbbb2023-02-08 07:30:33 -0800712 msgClass_ = coreDesc->dataTypeSpecific.clazz;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400713 } else if (dataType == GPBDataTypeEnum) {
Protobuf Team Bot7bb699b2022-11-15 08:59:25 -0800714 enumDescriptor_ = coreDesc->dataTypeSpecific.enumDescFunc();
715#if defined(DEBUG) && DEBUG
Protobuf Team Bot7140f6f2022-11-14 09:04:23 -0800716 NSAssert((coreDesc->flags & GPBFieldHasEnumDescriptor) != 0,
717 @"Field must have GPBFieldHasEnumDescriptor set");
Protobuf Team Bot7bb699b2022-11-15 08:59:25 -0800718#endif // DEBUG
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400719 }
720
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400721 // Non map<>/repeated fields can have defaults in proto2 syntax.
722 if (!isMapOrArray && includesDefault) {
723 defaultValue_ = ((GPBMessageFieldDescriptionWithDefault *)description)->defaultValue;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400724 if (dataType == GPBDataTypeBytes) {
725 // Data stored as a length prefixed (network byte order) c-string in
726 // descriptor structure.
727 const uint8_t *bytes = (const uint8_t *)defaultValue_.valueData;
728 if (bytes) {
Thomas Van Lentend570d482018-01-31 15:25:13 -0500729 uint32_t length;
730 memcpy(&length, bytes, sizeof(length));
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400731 length = ntohl(length);
732 bytes += sizeof(length);
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400733 defaultValue_.valueData = [[NSData alloc] initWithBytes:bytes length:length];
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400734 }
735 }
736 }
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400737 }
738 return self;
739}
740
741- (void)dealloc {
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400742 if (description_->dataType == GPBDataTypeBytes && !(description_->flags & GPBFieldRepeated)) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400743 [defaultValue_.valueData release];
744 }
745 [super dealloc];
746}
747
Protobuf Team Bot8f799092023-01-31 07:43:13 -0800748// No need to provide -hash/-isEqual: as the instances are singletons and the
749// default from NSObject is fine.
750- (instancetype)copyWithZone:(__unused NSZone *)zone {
751 // Immutable.
752 return [self retain];
753}
754
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400755- (GPBDataType)dataType {
756 return description_->dataType;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400757}
758
759- (BOOL)hasDefaultValue {
760 return (description_->flags & GPBFieldHasDefaultValue) != 0;
761}
762
763- (uint32_t)number {
764 return description_->number;
765}
766
767- (NSString *)name {
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400768 return (NSString *_Nonnull)@(description_->name);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400769}
770
771- (BOOL)isRequired {
772 return (description_->flags & GPBFieldRequired) != 0;
773}
774
775- (BOOL)isOptional {
776 return (description_->flags & GPBFieldOptional) != 0;
777}
778
779- (GPBFieldType)fieldType {
780 GPBFieldFlags flags = description_->flags;
781 if ((flags & GPBFieldRepeated) != 0) {
782 return GPBFieldTypeRepeated;
783 } else if ((flags & GPBFieldMapKeyMask) != 0) {
784 return GPBFieldTypeMap;
785 } else {
786 return GPBFieldTypeSingle;
787 }
788}
789
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400790- (GPBDataType)mapKeyDataType {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400791 switch (description_->flags & GPBFieldMapKeyMask) {
792 case GPBFieldMapKeyInt32:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400793 return GPBDataTypeInt32;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400794 case GPBFieldMapKeyInt64:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400795 return GPBDataTypeInt64;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400796 case GPBFieldMapKeyUInt32:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400797 return GPBDataTypeUInt32;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400798 case GPBFieldMapKeyUInt64:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400799 return GPBDataTypeUInt64;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400800 case GPBFieldMapKeySInt32:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400801 return GPBDataTypeSInt32;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400802 case GPBFieldMapKeySInt64:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400803 return GPBDataTypeSInt64;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400804 case GPBFieldMapKeyFixed32:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400805 return GPBDataTypeFixed32;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400806 case GPBFieldMapKeyFixed64:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400807 return GPBDataTypeFixed64;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400808 case GPBFieldMapKeySFixed32:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400809 return GPBDataTypeSFixed32;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400810 case GPBFieldMapKeySFixed64:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400811 return GPBDataTypeSFixed64;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400812 case GPBFieldMapKeyBool:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400813 return GPBDataTypeBool;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400814 case GPBFieldMapKeyString:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400815 return GPBDataTypeString;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400816
817 default:
818 NSAssert(0, @"Not a map type");
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400819 return GPBDataTypeInt32; // For lack of anything better.
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400820 }
821}
822
823- (BOOL)isPackable {
824 return (description_->flags & GPBFieldPacked) != 0;
825}
826
827- (BOOL)isValidEnumValue:(int32_t)value {
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400828 NSAssert(description_->dataType == GPBDataTypeEnum, @"Field Must be of type GPBDataTypeEnum");
Protobuf Team Bot7140f6f2022-11-14 09:04:23 -0800829 return enumDescriptor_.enumVerifier(value);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400830}
831
Protobuf Team Bot47862bb2022-11-14 12:19:34 -0800832- (GPBEnumDescriptor *)enumDescriptor {
833 return enumDescriptor_;
834}
835
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400836- (GPBGenericValue)defaultValue {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400837 // Depends on the fact that defaultValue_ is initialized either to "0/nil" or
838 // to an actual defaultValue in our initializer.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400839 GPBGenericValue value = defaultValue_;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400840
841 if (!(description_->flags & GPBFieldRepeated)) {
842 // We special handle data and strings. If they are nil, we replace them
843 // with empty string/empty data.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400844 GPBDataType type = description_->dataType;
845 if (type == GPBDataTypeBytes && value.valueData == nil) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400846 value.valueData = GPBEmptyNSData();
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400847 } else if (type == GPBDataTypeString && value.valueString == nil) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400848 value.valueString = @"";
849 }
850 }
851 return value;
852}
853
854- (NSString *)textFormatName {
855 if ((description_->flags & GPBFieldTextFormatNameCustom) != 0) {
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400856 NSValue *extraInfoValue = objc_getAssociatedObject(self, &kTextFormatExtraValueKey);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400857 // Support can be left out at generation time.
858 if (!extraInfoValue) {
859 return nil;
860 }
861 const uint8_t *extraTextFormatInfo = [extraInfoValue pointerValue];
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400862 return GPBDecodeTextFormatName(extraTextFormatInfo, GPBFieldNumber(self), self.name);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400863 }
864
865 // The logic here has to match SetCommonFieldVariables() from
Thomas Van Lenten53d8b032022-10-04 10:59:48 -0400866 // objectivec/field.cc in the proto compiler.
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400867 NSString *name = self.name;
868 NSUInteger len = [name length];
869
870 // Remove the "_p" added to reserved names.
871 if ([name hasSuffix:@"_p"]) {
872 name = [name substringToIndex:(len - 2)];
873 len = [name length];
874 }
875
876 // Remove "Array" from the end for repeated fields.
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400877 if (((description_->flags & GPBFieldRepeated) != 0) && [name hasSuffix:@"Array"]) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400878 name = [name substringToIndex:(len - 5)];
879 len = [name length];
880 }
881
882 // Groups vs. other fields.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400883 if (description_->dataType == GPBDataTypeGroup) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400884 // Just capitalize the first letter.
885 unichar firstChar = [name characterAtIndex:0];
886 if (firstChar >= 'a' && firstChar <= 'z') {
887 NSString *firstCharString =
888 [NSString stringWithFormat:@"%C", (unichar)(firstChar - 'a' + 'A')];
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400889 NSString *result = [name stringByReplacingCharactersInRange:NSMakeRange(0, 1)
890 withString:firstCharString];
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400891 return result;
892 }
893 return name;
894
895 } else {
896 // Undo the CamelCase.
897 NSMutableString *result = [NSMutableString stringWithCapacity:len];
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400898 for (uint32_t i = 0; i < len; i++) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400899 unichar c = [name characterAtIndex:i];
900 if (c >= 'A' && c <= 'Z') {
901 if (i > 0) {
902 [result appendFormat:@"_%C", (unichar)(c - 'A' + 'a')];
903 } else {
904 [result appendFormat:@"%C", c];
905 }
906 } else {
907 [result appendFormat:@"%C", c];
908 }
909 }
910 return result;
911 }
912}
913
914@end
915
916@implementation GPBEnumDescriptor {
917 NSString *name_;
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400918 // valueNames_ is a single c string with all of the value names appended
919 // together, each null terminated. -calcValueNameOffsets fills in
920 // nameOffsets_ with the offsets to allow quicker access to the individual
921 // names.
922 const char *valueNames_;
923 const int32_t *values_;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400924 GPBEnumValidationFunc enumVerifier_;
925 const uint8_t *extraTextFormatInfo_;
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400926 uint32_t *nameOffsets_;
927 uint32_t valueCount_;
Protobuf Team Bot7bb699b2022-11-15 08:59:25 -0800928 uint32_t flags_;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400929}
930
931@synthesize name = name_;
932@synthesize enumVerifier = enumVerifier_;
933
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400934+ (instancetype)allocDescriptorForName:(NSString *)name
935 valueNames:(const char *)valueNames
936 values:(const int32_t *)values
937 count:(uint32_t)valueCount
Protobuf Team Bot7bb699b2022-11-15 08:59:25 -0800938 enumVerifier:(GPBEnumValidationFunc)enumVerifier
939 flags:(GPBEnumDescriptorInitializationFlags)flags {
Protobuf Team Bot6e5a01b2023-01-31 13:11:17 -0800940 // Compute the unknown flags by this version of the runtime and then check the passed in flags
941 // (from the generated code) to detect when sources from a newer version are being used with an
942 // older runtime.
943 GPBEnumDescriptorInitializationFlags unknownFlags =
944 ~(GPBEnumDescriptorInitializationFlag_IsClosed);
945 if ((flags & unknownFlags) != 0) {
946 GPBRuntimeMatchFailure();
947 }
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400948 GPBEnumDescriptor *descriptor = [[self alloc] initWithName:name
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400949 valueNames:valueNames
950 values:values
951 count:valueCount
Protobuf Team Bot7bb699b2022-11-15 08:59:25 -0800952 enumVerifier:enumVerifier
953 flags:flags];
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400954 return descriptor;
955}
956
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400957+ (instancetype)allocDescriptorForName:(NSString *)name
958 valueNames:(const char *)valueNames
959 values:(const int32_t *)values
960 count:(uint32_t)valueCount
961 enumVerifier:(GPBEnumValidationFunc)enumVerifier
Protobuf Team Bot7bb699b2022-11-15 08:59:25 -0800962 flags:(GPBEnumDescriptorInitializationFlags)flags
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400963 extraTextFormatInfo:(const char *)extraTextFormatInfo {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400964 // Call the common case.
965 GPBEnumDescriptor *descriptor = [self allocDescriptorForName:name
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400966 valueNames:valueNames
967 values:values
968 count:valueCount
Protobuf Team Bot7bb699b2022-11-15 08:59:25 -0800969 enumVerifier:enumVerifier
970 flags:flags];
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400971 // Set the extra info.
972 descriptor->extraTextFormatInfo_ = (const uint8_t *)extraTextFormatInfo;
973 return descriptor;
974}
975
Protobuf Team Bot7bb699b2022-11-15 08:59:25 -0800976+ (instancetype)allocDescriptorForName:(NSString *)name
977 valueNames:(const char *)valueNames
978 values:(const int32_t *)values
979 count:(uint32_t)valueCount
980 enumVerifier:(GPBEnumValidationFunc)enumVerifier {
Protobuf Team Bot663fca12023-01-31 09:07:43 -0800981 GPBInternalCompileAssert(GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION <= 30005,
982 time_to_remove_this_old_version_shim);
Protobuf Team Bot7bb699b2022-11-15 08:59:25 -0800983 return [self allocDescriptorForName:name
984 valueNames:valueNames
985 values:values
986 count:valueCount
987 enumVerifier:enumVerifier
988 flags:GPBEnumDescriptorInitializationFlag_None];
989}
990
991+ (instancetype)allocDescriptorForName:(NSString *)name
992 valueNames:(const char *)valueNames
993 values:(const int32_t *)values
994 count:(uint32_t)valueCount
995 enumVerifier:(GPBEnumValidationFunc)enumVerifier
996 extraTextFormatInfo:(const char *)extraTextFormatInfo {
Protobuf Team Bot663fca12023-01-31 09:07:43 -0800997 GPBInternalCompileAssert(GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION <= 30005,
998 time_to_remove_this_old_version_shim);
Protobuf Team Bot7bb699b2022-11-15 08:59:25 -0800999 return [self allocDescriptorForName:name
1000 valueNames:valueNames
1001 values:values
1002 count:valueCount
1003 enumVerifier:enumVerifier
1004 flags:GPBEnumDescriptorInitializationFlag_None
1005 extraTextFormatInfo:extraTextFormatInfo];
1006}
1007
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001008- (instancetype)initWithName:(NSString *)name
Thomas Van Lenten79a23c42016-03-17 10:04:21 -04001009 valueNames:(const char *)valueNames
1010 values:(const int32_t *)values
1011 count:(uint32_t)valueCount
Protobuf Team Bot7bb699b2022-11-15 08:59:25 -08001012 enumVerifier:(GPBEnumValidationFunc)enumVerifier
1013 flags:(GPBEnumDescriptorInitializationFlags)flags {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001014 if ((self = [super init])) {
1015 name_ = [name copy];
Thomas Van Lenten79a23c42016-03-17 10:04:21 -04001016 valueNames_ = valueNames;
1017 values_ = values;
1018 valueCount_ = valueCount;
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001019 enumVerifier_ = enumVerifier;
Protobuf Team Bot7bb699b2022-11-15 08:59:25 -08001020 flags_ = flags;
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001021 }
1022 return self;
1023}
1024
Thomas Van Lenten79a23c42016-03-17 10:04:21 -04001025- (void)dealloc {
1026 [name_ release];
1027 if (nameOffsets_) free(nameOffsets_);
1028 [super dealloc];
1029}
1030
Protobuf Team Bot8f799092023-01-31 07:43:13 -08001031// No need to provide -hash/-isEqual: as the instances are singletons and the
1032// default from NSObject is fine.
1033- (instancetype)copyWithZone:(__unused NSZone *)zone {
1034 // Immutable.
1035 return [self retain];
1036}
1037
Protobuf Team Bot7bb699b2022-11-15 08:59:25 -08001038- (BOOL)isClosed {
1039 return (flags_ & GPBEnumDescriptorInitializationFlag_IsClosed) != 0;
1040}
1041
Thomas Van Lenten79a23c42016-03-17 10:04:21 -04001042- (void)calcValueNameOffsets {
1043 @synchronized(self) {
1044 if (nameOffsets_ != NULL) {
1045 return;
1046 }
1047 uint32_t *offsets = malloc(valueCount_ * sizeof(uint32_t));
Parveen Bhatia29f27bf2018-10-19 15:37:00 -04001048 if (!offsets) return;
Thomas Van Lenten79a23c42016-03-17 10:04:21 -04001049 const char *scan = valueNames_;
1050 for (uint32_t i = 0; i < valueCount_; ++i) {
1051 offsets[i] = (uint32_t)(scan - valueNames_);
1052 while (*scan != '\0') ++scan;
1053 ++scan; // Step over the null.
1054 }
1055 nameOffsets_ = offsets;
1056 }
1057}
1058
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001059- (NSString *)enumNameForValue:(int32_t)number {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -04001060 for (uint32_t i = 0; i < valueCount_; ++i) {
1061 if (values_[i] == number) {
leovitch28049022018-05-29 21:08:00 +09001062 return [self getEnumNameForIndex:i];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001063 }
1064 }
1065 return nil;
1066}
1067
1068- (BOOL)getValue:(int32_t *)outValue forEnumName:(NSString *)name {
1069 // Must have the prefix.
1070 NSUInteger prefixLen = name_.length + 1;
1071 if ((name.length <= prefixLen) || ![name hasPrefix:name_] ||
1072 ([name characterAtIndex:prefixLen - 1] != '_')) {
1073 return NO;
1074 }
1075
1076 // Skip over the prefix.
1077 const char *nameAsCStr = [name UTF8String];
1078 nameAsCStr += prefixLen;
1079
Protobuf Team Bot8be2ce32022-12-19 11:47:50 -08001080 [self calcValueNameOffsets];
Parveen Bhatia29f27bf2018-10-19 15:37:00 -04001081 if (nameOffsets_ == NULL) return NO;
Thomas Van Lenten79a23c42016-03-17 10:04:21 -04001082
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001083 // Find it.
Thomas Van Lenten79a23c42016-03-17 10:04:21 -04001084 for (uint32_t i = 0; i < valueCount_; ++i) {
1085 const char *valueName = valueNames_ + nameOffsets_[i];
1086 if (strcmp(nameAsCStr, valueName) == 0) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001087 if (outValue) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -04001088 *outValue = values_[i];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001089 }
1090 return YES;
1091 }
1092 }
1093 return NO;
1094}
1095
Thomas Van Lentenbe0d7f62016-06-27 14:24:59 -04001096- (BOOL)getValue:(int32_t *)outValue forEnumTextFormatName:(NSString *)textFormatName {
Protobuf Team Bot8be2ce32022-12-19 11:47:50 -08001097 [self calcValueNameOffsets];
Thomas Van Lenten189f6322022-09-19 17:21:13 -04001098 if (nameOffsets_ == NULL) return NO;
Dimitris Koutsogiorgas37ca94f2016-06-24 17:40:29 -07001099
Thomas Van Lenten189f6322022-09-19 17:21:13 -04001100 for (uint32_t i = 0; i < valueCount_; ++i) {
1101 NSString *valueTextFormatName = [self getEnumTextFormatNameForIndex:i];
1102 if ([valueTextFormatName isEqual:textFormatName]) {
1103 if (outValue) {
1104 *outValue = values_[i];
1105 }
1106 return YES;
Dimitris Koutsogiorgas37ca94f2016-06-24 17:40:29 -07001107 }
Thomas Van Lenten189f6322022-09-19 17:21:13 -04001108 }
1109 return NO;
Dimitris Koutsogiorgas37ca94f2016-06-24 17:40:29 -07001110}
1111
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001112- (NSString *)textFormatNameForValue:(int32_t)number {
1113 // Find the EnumValue descriptor and its index.
Thomas Van Lenten79a23c42016-03-17 10:04:21 -04001114 BOOL foundIt = NO;
1115 uint32_t valueDescriptorIndex;
Thomas Van Lenten189f6322022-09-19 17:21:13 -04001116 for (valueDescriptorIndex = 0; valueDescriptorIndex < valueCount_; ++valueDescriptorIndex) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -04001117 if (values_[valueDescriptorIndex] == number) {
1118 foundIt = YES;
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001119 break;
1120 }
1121 }
1122
Thomas Van Lenten79a23c42016-03-17 10:04:21 -04001123 if (!foundIt) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001124 return nil;
1125 }
leovitch28049022018-05-29 21:08:00 +09001126 return [self getEnumTextFormatNameForIndex:valueDescriptorIndex];
1127}
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001128
leovitch28049022018-05-29 21:08:00 +09001129- (uint32_t)enumNameCount {
1130 return valueCount_;
1131}
1132
1133- (NSString *)getEnumNameForIndex:(uint32_t)index {
Protobuf Team Bot8be2ce32022-12-19 11:47:50 -08001134 [self calcValueNameOffsets];
Parveen Bhatia29f27bf2018-10-19 15:37:00 -04001135 if (nameOffsets_ == NULL) return nil;
leovitch28049022018-05-29 21:08:00 +09001136
1137 if (index >= valueCount_) {
1138 return nil;
1139 }
1140 const char *valueName = valueNames_ + nameOffsets_[index];
1141 NSString *fullName = [NSString stringWithFormat:@"%@_%s", name_, valueName];
1142 return fullName;
1143}
1144
1145- (NSString *)getEnumTextFormatNameForIndex:(uint32_t)index {
Protobuf Team Bot8be2ce32022-12-19 11:47:50 -08001146 [self calcValueNameOffsets];
Parveen Bhatia29f27bf2018-10-19 15:37:00 -04001147 if (nameOffsets_ == NULL) return nil;
leovitch28049022018-05-29 21:08:00 +09001148
1149 if (index >= valueCount_) {
1150 return nil;
1151 }
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001152 NSString *result = nil;
1153 // Naming adds an underscore between enum name and value name, skip that also.
leovitch28049022018-05-29 21:08:00 +09001154 const char *valueName = valueNames_ + nameOffsets_[index];
Thomas Van Lenten79a23c42016-03-17 10:04:21 -04001155 NSString *shortName = @(valueName);
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001156
1157 // See if it is in the map of special format handling.
1158 if (extraTextFormatInfo_) {
Thomas Van Lenten189f6322022-09-19 17:21:13 -04001159 result = GPBDecodeTextFormatName(extraTextFormatInfo_, (int32_t)index, shortName);
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001160 }
Thomas Van Lenten53d8b032022-10-04 10:59:48 -04001161 // Logic here needs to match what objectivec/enum.cc does in the proto
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001162 // compiler.
1163 if (result == nil) {
1164 NSUInteger len = [shortName length];
1165 NSMutableString *worker = [NSMutableString stringWithCapacity:len];
1166 for (NSUInteger i = 0; i < len; i++) {
1167 unichar c = [shortName characterAtIndex:i];
1168 if (i > 0 && c >= 'A' && c <= 'Z') {
1169 [worker appendString:@"_"];
1170 }
1171 [worker appendFormat:@"%c", toupper((char)c)];
1172 }
1173 result = worker;
1174 }
1175 return result;
1176}
1177
1178@end
1179
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001180@implementation GPBExtensionDescriptor {
1181 GPBGenericValue defaultValue_;
1182}
1183
Dave MacLachlan74956e12019-12-17 17:32:09 -08001184- (instancetype)initWithExtensionDescription:(GPBExtensionDescription *)desc
1185 usesClassRefs:(BOOL)usesClassRefs {
Protobuf Team Bot6e5a01b2023-01-31 13:11:17 -08001186 // Compute the unknown options by this version of the runtime and then check the passed in
1187 // descriptor's options (from the generated code) to detect when sources from a newer version are
1188 // being used with an older runtime.
1189 GPBExtensionOptions unknownOptions =
1190 ~(GPBExtensionRepeated | GPBExtensionPacked | GPBExtensionSetWireFormat);
1191 if ((desc->options & unknownOptions) != 0) {
1192 GPBRuntimeMatchFailure();
1193 }
1194
Protobuf Team Bot5e6fbbb2023-02-08 07:30:33 -08001195#if defined(DEBUG) && DEBUG
1196 NSAssert(usesClassRefs, @"Internal error: all extensions should have class refs");
1197#endif
1198
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001199 if ((self = [super init])) {
Dave MacLachlan74956e12019-12-17 17:32:09 -08001200 description_ = desc;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001201
1202 GPBDataType type = description_->dataType;
1203 if (type == GPBDataTypeBytes) {
1204 // Data stored as a length prefixed c-string in descriptor records.
Thomas Van Lenten189f6322022-09-19 17:21:13 -04001205 const uint8_t *bytes = (const uint8_t *)description_->defaultValue.valueData;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001206 if (bytes) {
Thomas Van Lentend570d482018-01-31 15:25:13 -05001207 uint32_t length;
1208 memcpy(&length, bytes, sizeof(length));
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001209 // The length is stored in network byte order.
1210 length = ntohl(length);
1211 bytes += sizeof(length);
Thomas Van Lenten189f6322022-09-19 17:21:13 -04001212 defaultValue_.valueData = [[NSData alloc] initWithBytes:bytes length:length];
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001213 }
1214 } else if (type == GPBDataTypeMessage || type == GPBDataTypeGroup) {
1215 // The default is looked up in -defaultValue instead since extensions
Protobuf Team Bot5e6fbbb2023-02-08 07:30:33 -08001216 // aren't common, we avoid the hit startup hit and it avoids initialization
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001217 // order issues.
1218 } else {
Dave MacLachlan74956e12019-12-17 17:32:09 -08001219 defaultValue_ = description_->defaultValue;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001220 }
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001221 }
1222 return self;
1223}
1224
Dave MacLachlan74956e12019-12-17 17:32:09 -08001225- (instancetype)initWithExtensionDescription:(GPBExtensionDescription *)desc {
Protobuf Team Bot663fca12023-01-31 09:07:43 -08001226 GPBInternalCompileAssert(GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION <= 30003,
1227 time_to_remove_this_old_version_shim);
Protobuf Team Bot5e6fbbb2023-02-08 07:30:33 -08001228
1229 const char *className = desc->messageOrGroupClass.name;
1230 if (className) {
1231 Class clazz = objc_lookUpClass(className);
1232 NSAssert(clazz != Nil, @"Class %s not defined", className);
1233 desc->messageOrGroupClass.clazz = clazz;
1234 }
1235
1236 const char *extendedClassName = desc->extendedClass.name;
1237 if (extendedClassName) {
1238 Class clazz = objc_lookUpClass(extendedClassName);
1239 NSAssert(clazz, @"Class %s not defined", extendedClassName);
1240 desc->extendedClass.clazz = clazz;
1241 }
1242
1243 return [self initWithExtensionDescription:desc usesClassRefs:YES];
Dave MacLachlan74956e12019-12-17 17:32:09 -08001244}
1245
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001246- (void)dealloc {
Thomas Van Lenten189f6322022-09-19 17:21:13 -04001247 if ((description_->dataType == GPBDataTypeBytes) && !GPBExtensionIsRepeated(description_)) {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001248 [defaultValue_.valueData release];
1249 }
1250 [super dealloc];
1251}
1252
Protobuf Team Bot8f799092023-01-31 07:43:13 -08001253// No need to provide -hash/-isEqual: as the instances are singletons and the
1254// default from NSObject is fine.
Thomas Van Lenten2fb33b82022-09-20 09:14:32 -04001255- (instancetype)copyWithZone:(__unused NSZone *)zone {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001256 // Immutable.
1257 return [self retain];
1258}
1259
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001260- (NSString *)singletonName {
Thomas Van Lenten189f6322022-09-19 17:21:13 -04001261 return (NSString *_Nonnull)@(description_->singletonName);
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001262}
1263
1264- (const char *)singletonNameC {
1265 return description_->singletonName;
1266}
1267
1268- (uint32_t)fieldNumber {
1269 return description_->fieldNumber;
1270}
1271
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001272- (GPBDataType)dataType {
1273 return description_->dataType;
1274}
1275
1276- (GPBWireFormat)wireType {
Thomas Van Lenten189f6322022-09-19 17:21:13 -04001277 return GPBWireFormatForType(description_->dataType, GPBExtensionIsPacked(description_));
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001278}
1279
1280- (GPBWireFormat)alternateWireType {
Thomas Van Lenten189f6322022-09-19 17:21:13 -04001281 NSAssert(GPBExtensionIsRepeated(description_), @"Only valid on repeated extensions");
1282 return GPBWireFormatForType(description_->dataType, !GPBExtensionIsPacked(description_));
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001283}
1284
1285- (BOOL)isRepeated {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001286 return GPBExtensionIsRepeated(description_);
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001287}
1288
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001289- (BOOL)isPackable {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001290 return GPBExtensionIsPacked(description_);
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001291}
1292
1293- (Class)msgClass {
Dave MacLachlan74956e12019-12-17 17:32:09 -08001294 return description_->messageOrGroupClass.clazz;
1295}
1296
1297- (Class)containingMessageClass {
1298 return description_->extendedClass.clazz;
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001299}
1300
1301- (GPBEnumDescriptor *)enumDescriptor {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001302 if (description_->dataType == GPBDataTypeEnum) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001303 GPBEnumDescriptor *enumDescriptor = description_->enumDescriptorFunc();
1304 return enumDescriptor;
1305 }
1306 return nil;
1307}
1308
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001309- (id)defaultValue {
1310 if (GPBExtensionIsRepeated(description_)) {
1311 return nil;
1312 }
1313
1314 switch (description_->dataType) {
1315 case GPBDataTypeBool:
1316 return @(defaultValue_.valueBool);
1317 case GPBDataTypeFloat:
1318 return @(defaultValue_.valueFloat);
1319 case GPBDataTypeDouble:
1320 return @(defaultValue_.valueDouble);
1321 case GPBDataTypeInt32:
1322 case GPBDataTypeSInt32:
1323 case GPBDataTypeEnum:
1324 case GPBDataTypeSFixed32:
1325 return @(defaultValue_.valueInt32);
1326 case GPBDataTypeInt64:
1327 case GPBDataTypeSInt64:
1328 case GPBDataTypeSFixed64:
1329 return @(defaultValue_.valueInt64);
1330 case GPBDataTypeUInt32:
1331 case GPBDataTypeFixed32:
1332 return @(defaultValue_.valueUInt32);
1333 case GPBDataTypeUInt64:
1334 case GPBDataTypeFixed64:
1335 return @(defaultValue_.valueUInt64);
1336 case GPBDataTypeBytes:
1337 // Like message fields, the default is zero length data.
Thomas Van Lenten189f6322022-09-19 17:21:13 -04001338 return (defaultValue_.valueData ? defaultValue_.valueData : GPBEmptyNSData());
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001339 case GPBDataTypeString:
1340 // Like message fields, the default is zero length string.
1341 return (defaultValue_.valueString ? defaultValue_.valueString : @"");
1342 case GPBDataTypeGroup:
1343 case GPBDataTypeMessage:
1344 return nil;
1345 }
1346}
1347
1348- (NSComparisonResult)compareByFieldNumber:(GPBExtensionDescriptor *)other {
1349 int32_t selfNumber = description_->fieldNumber;
1350 int32_t otherNumber = other->description_->fieldNumber;
1351 if (selfNumber < otherNumber) {
1352 return NSOrderedAscending;
1353 } else if (selfNumber == otherNumber) {
1354 return NSOrderedSame;
1355 } else {
1356 return NSOrderedDescending;
1357 }
1358}
1359
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001360@end
Thomas Van Lentenc8a440d2016-05-25 13:46:00 -04001361
1362#pragma clang diagnostic pop