blob: 3d3d7349ec786d8a9e62d45b49036bc496f286c5 [file] [log] [blame]
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc. All rights reserved.
3// https://developers.google.com/protocol-buffers/
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
8//
9// * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11// * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15// * Neither the name of Google Inc. nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31#import <Foundation/Foundation.h>
32
33#import "GPBUtilities.h"
34
35#import "GPBDescriptor_PackagePrivate.h"
36
37// Macros for stringifying library symbols. These are used in the generated
Dave MacLachlanaa1d7e72020-01-19 17:46:35 -080038// GPB descriptor classes wherever a library symbol name is represented as a
39// string.
Thomas Van Lenten30650d82015-05-01 08:57:16 -040040#define GPBStringify(S) #S
41#define GPBStringifySymbol(S) GPBStringify(S)
42
43#define GPBNSStringify(S) @#S
44#define GPBNSStringifySymbol(S) GPBNSStringify(S)
45
Dave MacLachlanaa1d7e72020-01-19 17:46:35 -080046// Macros for generating a Class from a class name. These are used in
47// the generated GPB descriptor classes wherever an Objective C class
48// reference is needed for a generated class.
49#define GPBObjCClassSymbol(name) OBJC_CLASS_$_##name
50#define GPBObjCClass(name) \
51 ((__bridge Class)&(GPBObjCClassSymbol(name)))
52#define GPBObjCClassDeclaration(name) \
53 extern const GPBObjcClass_t GPBObjCClassSymbol(name)
54
Thomas Van Lenten30650d82015-05-01 08:57:16 -040055// Constant to internally mark when there is no has bit.
56#define GPBNoHasBit INT32_MAX
57
58CF_EXTERN_C_BEGIN
59
Thomas Van Lentend846b0b2015-06-08 16:24:57 -040060// These two are used to inject a runtime check for version mismatch into the
61// generated sources to make sure they are linked with a supporting runtime.
Thomas Van Lenten1aa65002016-09-15 13:27:17 -040062void GPBCheckRuntimeVersionSupport(int32_t objcRuntimeVersion);
63GPB_INLINE void GPB_DEBUG_CHECK_RUNTIME_VERSIONS() {
64 // NOTE: By being inline here, this captures the value from the library's
65 // headers at the time the generated code was compiled.
66#if defined(DEBUG) && DEBUG
67 GPBCheckRuntimeVersionSupport(GOOGLE_PROTOBUF_OBJC_VERSION);
68#endif
69}
70
71// Legacy version of the checks, remove when GOOGLE_PROTOBUF_OBJC_GEN_VERSION
72// goes away (see more info in GPBBootstrap.h).
Thomas Van Lentend846b0b2015-06-08 16:24:57 -040073void GPBCheckRuntimeVersionInternal(int32_t version);
74GPB_INLINE void GPBDebugCheckRuntimeVersion() {
Thomas Van Lentenc8a440d2016-05-25 13:46:00 -040075#if defined(DEBUG) && DEBUG
Thomas Van Lentend846b0b2015-06-08 16:24:57 -040076 GPBCheckRuntimeVersionInternal(GOOGLE_PROTOBUF_OBJC_GEN_VERSION);
77#endif
78}
79
Thomas Van Lenten30650d82015-05-01 08:57:16 -040080// Conversion functions for de/serializing floating point types.
81
82GPB_INLINE int64_t GPBConvertDoubleToInt64(double v) {
Thomas Van Lenten58464392019-09-20 10:52:34 -040083 GPBInternalCompileAssert(sizeof(double) == sizeof(int64_t), double_not_64_bits);
84 int64_t result;
85 memcpy(&result, &v, sizeof(result));
86 return result;
Thomas Van Lenten30650d82015-05-01 08:57:16 -040087}
88
89GPB_INLINE int32_t GPBConvertFloatToInt32(float v) {
Thomas Van Lenten58464392019-09-20 10:52:34 -040090 GPBInternalCompileAssert(sizeof(float) == sizeof(int32_t), float_not_32_bits);
91 int32_t result;
92 memcpy(&result, &v, sizeof(result));
93 return result;
Thomas Van Lenten30650d82015-05-01 08:57:16 -040094}
95
96GPB_INLINE double GPBConvertInt64ToDouble(int64_t v) {
Thomas Van Lenten58464392019-09-20 10:52:34 -040097 GPBInternalCompileAssert(sizeof(double) == sizeof(int64_t), double_not_64_bits);
98 double result;
99 memcpy(&result, &v, sizeof(result));
100 return result;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400101}
102
103GPB_INLINE float GPBConvertInt32ToFloat(int32_t v) {
Thomas Van Lenten58464392019-09-20 10:52:34 -0400104 GPBInternalCompileAssert(sizeof(float) == sizeof(int32_t), float_not_32_bits);
105 float result;
106 memcpy(&result, &v, sizeof(result));
107 return result;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400108}
109
110GPB_INLINE int32_t GPBLogicalRightShift32(int32_t value, int32_t spaces) {
111 return (int32_t)((uint32_t)(value) >> spaces);
112}
113
114GPB_INLINE int64_t GPBLogicalRightShift64(int64_t value, int32_t spaces) {
115 return (int64_t)((uint64_t)(value) >> spaces);
116}
117
118// Decode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers
119// into values that can be efficiently encoded with varint. (Otherwise,
120// negative values must be sign-extended to 64 bits to be varint encoded,
121// thus always taking 10 bytes on the wire.)
122GPB_INLINE int32_t GPBDecodeZigZag32(uint32_t n) {
Sergio Campamae5050982016-08-16 08:56:50 -0700123 return (int32_t)(GPBLogicalRightShift32((int32_t)n, 1) ^ -((int32_t)(n) & 1));
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400124}
125
126// Decode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers
127// into values that can be efficiently encoded with varint. (Otherwise,
128// negative values must be sign-extended to 64 bits to be varint encoded,
129// thus always taking 10 bytes on the wire.)
130GPB_INLINE int64_t GPBDecodeZigZag64(uint64_t n) {
Sergio Campamae5050982016-08-16 08:56:50 -0700131 return (int64_t)(GPBLogicalRightShift64((int64_t)n, 1) ^ -((int64_t)(n) & 1));
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400132}
133
134// Encode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers
135// into values that can be efficiently encoded with varint. (Otherwise,
136// negative values must be sign-extended to 64 bits to be varint encoded,
137// thus always taking 10 bytes on the wire.)
138GPB_INLINE uint32_t GPBEncodeZigZag32(int32_t n) {
139 // Note: the right-shift must be arithmetic
Thomas Van Lenten953adb12018-01-31 11:59:57 -0500140 return ((uint32_t)n << 1) ^ (uint32_t)(n >> 31);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400141}
142
143// Encode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers
144// into values that can be efficiently encoded with varint. (Otherwise,
145// negative values must be sign-extended to 64 bits to be varint encoded,
146// thus always taking 10 bytes on the wire.)
147GPB_INLINE uint64_t GPBEncodeZigZag64(int64_t n) {
148 // Note: the right-shift must be arithmetic
Thomas Van Lenten953adb12018-01-31 11:59:57 -0500149 return ((uint64_t)n << 1) ^ (uint64_t)(n >> 63);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400150}
151
Thomas Van Lentenc8a440d2016-05-25 13:46:00 -0400152#pragma clang diagnostic push
153#pragma clang diagnostic ignored "-Wswitch-enum"
154#pragma clang diagnostic ignored "-Wdirect-ivar-access"
155
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400156GPB_INLINE BOOL GPBDataTypeIsObject(GPBDataType type) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400157 switch (type) {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400158 case GPBDataTypeBytes:
159 case GPBDataTypeString:
160 case GPBDataTypeMessage:
161 case GPBDataTypeGroup:
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400162 return YES;
163 default:
164 return NO;
165 }
166}
167
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400168GPB_INLINE BOOL GPBDataTypeIsMessage(GPBDataType type) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400169 switch (type) {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400170 case GPBDataTypeMessage:
171 case GPBDataTypeGroup:
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400172 return YES;
173 default:
174 return NO;
175 }
176}
177
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400178GPB_INLINE BOOL GPBFieldDataTypeIsMessage(GPBFieldDescriptor *field) {
179 return GPBDataTypeIsMessage(field->description_->dataType);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400180}
181
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400182GPB_INLINE BOOL GPBFieldDataTypeIsObject(GPBFieldDescriptor *field) {
183 return GPBDataTypeIsObject(field->description_->dataType);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400184}
185
186GPB_INLINE BOOL GPBExtensionIsMessage(GPBExtensionDescriptor *ext) {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400187 return GPBDataTypeIsMessage(ext->description_->dataType);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400188}
189
190// The field is an array/map or it has an object value.
191GPB_INLINE BOOL GPBFieldStoresObject(GPBFieldDescriptor *field) {
192 GPBMessageFieldDescription *desc = field->description_;
193 if ((desc->flags & (GPBFieldRepeated | GPBFieldMapKeyMask)) != 0) {
194 return YES;
195 }
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400196 return GPBDataTypeIsObject(desc->dataType);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400197}
198
199BOOL GPBGetHasIvar(GPBMessage *self, int32_t index, uint32_t fieldNumber);
200void GPBSetHasIvar(GPBMessage *self, int32_t idx, uint32_t fieldNumber,
201 BOOL value);
202uint32_t GPBGetHasOneof(GPBMessage *self, int32_t index);
203
204GPB_INLINE BOOL
205GPBGetHasIvarField(GPBMessage *self, GPBFieldDescriptor *field) {
206 GPBMessageFieldDescription *fieldDesc = field->description_;
207 return GPBGetHasIvar(self, fieldDesc->hasIndex, fieldDesc->number);
208}
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400209
Thomas Van Lentenc8a440d2016-05-25 13:46:00 -0400210#pragma clang diagnostic pop
211
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400212//%PDDM-DEFINE GPB_IVAR_SET_DECL(NAME, TYPE)
Thomas Van Lentene1e5b8a2020-04-10 15:55:32 -0400213//%void GPBSet##NAME##IvarWithFieldPrivate(GPBMessage *self,
214//% NAME$S GPBFieldDescriptor *field,
215//% NAME$S TYPE value);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400216//%PDDM-EXPAND GPB_IVAR_SET_DECL(Bool, BOOL)
217// This block of code is generated, do not edit it directly.
Dave MacLachlanab48ecf2020-01-20 13:47:20 -0800218// clang-format off
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400219
Thomas Van Lentene1e5b8a2020-04-10 15:55:32 -0400220void GPBSetBoolIvarWithFieldPrivate(GPBMessage *self,
221 GPBFieldDescriptor *field,
222 BOOL value);
Dave MacLachlanab48ecf2020-01-20 13:47:20 -0800223// clang-format on
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400224//%PDDM-EXPAND GPB_IVAR_SET_DECL(Int32, int32_t)
225// This block of code is generated, do not edit it directly.
Dave MacLachlanab48ecf2020-01-20 13:47:20 -0800226// clang-format off
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400227
Thomas Van Lentene1e5b8a2020-04-10 15:55:32 -0400228void GPBSetInt32IvarWithFieldPrivate(GPBMessage *self,
229 GPBFieldDescriptor *field,
230 int32_t value);
Dave MacLachlanab48ecf2020-01-20 13:47:20 -0800231// clang-format on
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400232//%PDDM-EXPAND GPB_IVAR_SET_DECL(UInt32, uint32_t)
233// This block of code is generated, do not edit it directly.
Dave MacLachlanab48ecf2020-01-20 13:47:20 -0800234// clang-format off
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400235
Thomas Van Lentene1e5b8a2020-04-10 15:55:32 -0400236void GPBSetUInt32IvarWithFieldPrivate(GPBMessage *self,
237 GPBFieldDescriptor *field,
238 uint32_t value);
Dave MacLachlanab48ecf2020-01-20 13:47:20 -0800239// clang-format on
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400240//%PDDM-EXPAND GPB_IVAR_SET_DECL(Int64, int64_t)
241// This block of code is generated, do not edit it directly.
Dave MacLachlanab48ecf2020-01-20 13:47:20 -0800242// clang-format off
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400243
Thomas Van Lentene1e5b8a2020-04-10 15:55:32 -0400244void GPBSetInt64IvarWithFieldPrivate(GPBMessage *self,
245 GPBFieldDescriptor *field,
246 int64_t value);
Dave MacLachlanab48ecf2020-01-20 13:47:20 -0800247// clang-format on
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400248//%PDDM-EXPAND GPB_IVAR_SET_DECL(UInt64, uint64_t)
249// This block of code is generated, do not edit it directly.
Dave MacLachlanab48ecf2020-01-20 13:47:20 -0800250// clang-format off
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400251
Thomas Van Lentene1e5b8a2020-04-10 15:55:32 -0400252void GPBSetUInt64IvarWithFieldPrivate(GPBMessage *self,
253 GPBFieldDescriptor *field,
254 uint64_t value);
Dave MacLachlanab48ecf2020-01-20 13:47:20 -0800255// clang-format on
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400256//%PDDM-EXPAND GPB_IVAR_SET_DECL(Float, float)
257// This block of code is generated, do not edit it directly.
Dave MacLachlanab48ecf2020-01-20 13:47:20 -0800258// clang-format off
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400259
Thomas Van Lentene1e5b8a2020-04-10 15:55:32 -0400260void GPBSetFloatIvarWithFieldPrivate(GPBMessage *self,
261 GPBFieldDescriptor *field,
262 float value);
Dave MacLachlanab48ecf2020-01-20 13:47:20 -0800263// clang-format on
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400264//%PDDM-EXPAND GPB_IVAR_SET_DECL(Double, double)
265// This block of code is generated, do not edit it directly.
Dave MacLachlanab48ecf2020-01-20 13:47:20 -0800266// clang-format off
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400267
Thomas Van Lentene1e5b8a2020-04-10 15:55:32 -0400268void GPBSetDoubleIvarWithFieldPrivate(GPBMessage *self,
269 GPBFieldDescriptor *field,
270 double value);
Dave MacLachlanab48ecf2020-01-20 13:47:20 -0800271// clang-format on
Thomas Van Lentene1e5b8a2020-04-10 15:55:32 -0400272//%PDDM-EXPAND-END (7 expansions)
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400273
Thomas Van Lentene1e5b8a2020-04-10 15:55:32 -0400274void GPBSetEnumIvarWithFieldPrivate(GPBMessage *self,
275 GPBFieldDescriptor *field,
276 int32_t value);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400277
278id GPBGetObjectIvarWithField(GPBMessage *self, GPBFieldDescriptor *field);
279
Thomas Van Lentene1e5b8a2020-04-10 15:55:32 -0400280void GPBSetObjectIvarWithFieldPrivate(GPBMessage *self,
281 GPBFieldDescriptor *field, id value);
282void GPBSetRetainedObjectIvarWithFieldPrivate(GPBMessage *self,
283 GPBFieldDescriptor *field,
284 id __attribute__((ns_consumed))
285 value);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400286
287// GPBGetObjectIvarWithField will automatically create the field (message) if
288// it doesn't exist. GPBGetObjectIvarWithFieldNoAutocreate will return nil.
289id GPBGetObjectIvarWithFieldNoAutocreate(GPBMessage *self,
290 GPBFieldDescriptor *field);
291
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400292// Clears and releases the autocreated message ivar, if it's autocreated. If
293// it's not set as autocreated, this method does nothing.
294void GPBClearAutocreatedMessageIvarWithField(GPBMessage *self,
295 GPBFieldDescriptor *field);
296
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400297// Returns an Objective C encoding for |selector|. |instanceSel| should be
298// YES if it's an instance selector (as opposed to a class selector).
299// |selector| must be a selector from MessageSignatureProtocol.
300const char *GPBMessageEncodingForSelector(SEL selector, BOOL instanceSel);
301
302// Helper for text format name encoding.
Peter Newmane2cc2de2020-08-10 19:08:25 +0100303// decodeData is the data describing the special decodes.
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400304// key and inputString are the input that needs decoding.
305NSString *GPBDecodeTextFormatName(const uint8_t *decodeData, int32_t key,
306 NSString *inputString);
307
Thomas Van Lentene1e5b8a2020-04-10 15:55:32 -0400308
Thomas Van Lenten3c8e9592020-04-13 10:49:16 -0400309// Shims from the older generated code into the runtime.
Thomas Van Lentene1e5b8a2020-04-10 15:55:32 -0400310void GPBSetInt32IvarWithFieldInternal(GPBMessage *self,
311 GPBFieldDescriptor *field,
312 int32_t value,
313 GPBFileSyntax syntax);
Thomas Van Lenten3c8e9592020-04-13 10:49:16 -0400314void GPBMaybeClearOneof(GPBMessage *self, GPBOneofDescriptor *oneof,
315 int32_t oneofHasIndex, uint32_t fieldNumberNotToClear);
Thomas Van Lentene1e5b8a2020-04-10 15:55:32 -0400316
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400317// A series of selectors that are used solely to get @encoding values
318// for them by the dynamic protobuf runtime code. See
Dave MacLachlan37a66722017-11-14 15:16:04 -0800319// GPBMessageEncodingForSelector for details. GPBRootObject conforms to
320// the protocol so that it is encoded in the Objective C runtime.
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400321@protocol GPBMessageSignatureProtocol
322@optional
323
324#define GPB_MESSAGE_SIGNATURE_ENTRY(TYPE, NAME) \
325 -(TYPE)get##NAME; \
326 -(void)set##NAME : (TYPE)value; \
327 -(TYPE)get##NAME##AtIndex : (NSUInteger)index;
328
329GPB_MESSAGE_SIGNATURE_ENTRY(BOOL, Bool)
330GPB_MESSAGE_SIGNATURE_ENTRY(uint32_t, Fixed32)
331GPB_MESSAGE_SIGNATURE_ENTRY(int32_t, SFixed32)
332GPB_MESSAGE_SIGNATURE_ENTRY(float, Float)
333GPB_MESSAGE_SIGNATURE_ENTRY(uint64_t, Fixed64)
334GPB_MESSAGE_SIGNATURE_ENTRY(int64_t, SFixed64)
335GPB_MESSAGE_SIGNATURE_ENTRY(double, Double)
336GPB_MESSAGE_SIGNATURE_ENTRY(int32_t, Int32)
337GPB_MESSAGE_SIGNATURE_ENTRY(int64_t, Int64)
338GPB_MESSAGE_SIGNATURE_ENTRY(int32_t, SInt32)
339GPB_MESSAGE_SIGNATURE_ENTRY(int64_t, SInt64)
340GPB_MESSAGE_SIGNATURE_ENTRY(uint32_t, UInt32)
341GPB_MESSAGE_SIGNATURE_ENTRY(uint64_t, UInt64)
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400342GPB_MESSAGE_SIGNATURE_ENTRY(NSData *, Bytes)
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400343GPB_MESSAGE_SIGNATURE_ENTRY(NSString *, String)
344GPB_MESSAGE_SIGNATURE_ENTRY(GPBMessage *, Message)
345GPB_MESSAGE_SIGNATURE_ENTRY(GPBMessage *, Group)
346GPB_MESSAGE_SIGNATURE_ENTRY(int32_t, Enum)
347
348#undef GPB_MESSAGE_SIGNATURE_ENTRY
349
350- (id)getArray;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400351- (NSUInteger)getArrayCount;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400352- (void)setArray:(NSArray *)array;
353+ (id)getClassValue;
354@end
355
Thomas Van Lenten2d1c5e22017-03-02 14:50:10 -0500356BOOL GPBClassHasSel(Class aClass, SEL sel);
357
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400358CF_EXTERN_C_END