-
Notifications
You must be signed in to change notification settings - Fork 15.5k
/
GPBDescriptor_PackagePrivate.h
338 lines (289 loc) · 13.1 KB
/
GPBDescriptor_PackagePrivate.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
// This header is private to the ProtobolBuffers library and must NOT be
// included by any sources outside this library. The contents of this file are
// subject to change at any time without notice.
#import "GPBDescriptor.h"
#import "GPBWireFormat.h"
// Describes attributes of the field.
typedef NS_OPTIONS(uint16_t, GPBFieldFlags) {
GPBFieldNone = 0,
// These map to standard protobuf concepts.
GPBFieldRequired = 1 << 0,
GPBFieldRepeated = 1 << 1,
GPBFieldPacked = 1 << 2,
GPBFieldOptional = 1 << 3,
GPBFieldHasDefaultValue = 1 << 4,
// Indicate that the field should "clear" when set to zero value. This is the
// proto3 non optional behavior for singular data (ints, data, string, enum)
// fields.
GPBFieldClearHasIvarOnZero = 1 << 5,
// Indicates the field needs custom handling for the TextFormat name, if not
// set, the name can be derived from the ObjC name.
GPBFieldTextFormatNameCustom = 1 << 6,
// This flag has never had any meaning, it was set on all enum fields.
GPBFieldHasEnumDescriptor = 1 << 7,
// These are not standard protobuf concepts, they are specific to the
// Objective C runtime.
// These bits are used to mark the field as a map and what the key
// type is.
GPBFieldMapKeyMask = 0xF << 8,
GPBFieldMapKeyInt32 = 1 << 8,
GPBFieldMapKeyInt64 = 2 << 8,
GPBFieldMapKeyUInt32 = 3 << 8,
GPBFieldMapKeyUInt64 = 4 << 8,
GPBFieldMapKeySInt32 = 5 << 8,
GPBFieldMapKeySInt64 = 6 << 8,
GPBFieldMapKeyFixed32 = 7 << 8,
GPBFieldMapKeyFixed64 = 8 << 8,
GPBFieldMapKeySFixed32 = 9 << 8,
GPBFieldMapKeySFixed64 = 10 << 8,
GPBFieldMapKeyBool = 11 << 8,
GPBFieldMapKeyString = 12 << 8,
// If the enum for this field is "closed", meaning that it:
// - Has a fixed set of named values.
// - Encountering values not in this set causes them to be treated as unknown
// fields.
// - The first value (i.e., the default) may be nonzero.
// NOTE: This could be tracked just on the GPBEnumDescriptor, but to support
// previously generated code, there would be not data to get the behavior
// correct, so instead it is tracked on the field. If old source compatibility
// is removed, this could be removed and the GPBEnumDescription fetched from
// the GPBFieldDescriptor instead.
GPBFieldClosedEnum = 1 << 12,
};
// NOTE: The structures defined here have their members ordered to minimize
// their size. This directly impacts the size of apps since these exist per
// field/extension.
typedef struct GPBFileDescription {
// The proto package for the file.
const char *package;
// The objc_class_prefix option if present.
const char *prefix;
// The file's proto syntax.
GPBFileSyntax syntax;
} GPBFileDescription;
// Describes a single field in a protobuf as it is represented as an ivar.
typedef struct GPBMessageFieldDescription {
// Name of ivar.
// Note that we looked into using a SEL here instead (which really is just a C string)
// but there is not a way to initialize an SEL with a constant (@selector is not constant) so the
// additional code generated to initialize the value is actually bigger in size than just using a
// C identifier for large apps.
const char *name;
union {
// className is deprecated and will be removed in favor of clazz.
// kept around right now for backwards compatibility.
// clazz is used iff GPBDescriptorInitializationFlag_UsesClassRefs is set.
char *className; // Name of the class of the message.
Class clazz; // Class of the message.
// For enums only.
GPBEnumDescriptorFunc enumDescFunc;
} dataTypeSpecific;
// The field number for the ivar.
uint32_t number;
// The index (in bits) into _has_storage_.
// >= 0: the bit to use for a value being set.
// = GPBNoHasBit(INT32_MAX): no storage used.
// < 0: in a oneOf, use a full int32 to record the field active.
int32_t hasIndex;
// Offset of the variable into it's structure struct.
uint32_t offset;
// Field flags. Use accessor functions below.
GPBFieldFlags flags;
// Data type of the ivar.
GPBDataType dataType;
} GPBMessageFieldDescription;
// If a message uses fields where they provide default values that are non zero, then this
// struct is used to provide the values along with the field info.
typedef struct GPBMessageFieldDescriptionWithDefault {
// Default value for the ivar.
GPBGenericValue defaultValue;
GPBMessageFieldDescription core;
} GPBMessageFieldDescriptionWithDefault;
// Describes attributes of the extension.
typedef NS_OPTIONS(uint8_t, GPBExtensionOptions) {
GPBExtensionNone = 0,
// These map to standard protobuf concepts.
GPBExtensionRepeated = 1 << 0,
GPBExtensionPacked = 1 << 1,
GPBExtensionSetWireFormat = 1 << 2,
};
// An extension
typedef struct GPBExtensionDescription {
GPBGenericValue defaultValue;
const char *singletonName;
// Before 3.12, `extendedClass` was just a `const char *`. Thanks to nested
// initialization
// (https://en.cppreference.com/w/c/language/struct_initialization#Nested_initialization) old
// generated code with `.extendedClass = GPBStringifySymbol(Something)` still works; and the
// current generator can use `extendedClass.clazz`, to pass a Class reference.
union {
const char *name;
Class clazz;
} extendedClass;
// Before 3.12, this was `const char *messageOrGroupClassName`. In the
// initial 3.12 release, we moved the `union messageOrGroupClass`, and failed
// to realize that would break existing source code for extensions. So to
// keep existing source code working, we added an unnamed union (C11) to
// provide both the old field name and the new union. This keeps both older
// and newer code working.
// Background: https://github.com/protocolbuffers/protobuf/issues/7555
union {
const char *messageOrGroupClassName;
union {
const char *name;
Class clazz;
} messageOrGroupClass;
};
GPBEnumDescriptorFunc enumDescriptorFunc;
int32_t fieldNumber;
GPBDataType dataType;
GPBExtensionOptions options;
} GPBExtensionDescription;
typedef NS_OPTIONS(uint32_t, GPBDescriptorInitializationFlags) {
GPBDescriptorInitializationFlag_None = 0,
GPBDescriptorInitializationFlag_FieldsWithDefault = 1 << 0,
GPBDescriptorInitializationFlag_WireFormat = 1 << 1,
// This is used as a stopgap as we move from using class names to class
// references. The runtime needs to support both until we allow a
// breaking change in the runtime.
GPBDescriptorInitializationFlag_UsesClassRefs = 1 << 2,
// This flag is used to indicate that the generated sources already contain
// the `GPBFieldClearHasIvarOnZero` flag and it doesn't have to be computed
// at startup. This allows older generated code to still work with the
// current runtime library.
GPBDescriptorInitializationFlag_Proto3OptionalKnown = 1 << 3,
// This flag is used to indicate that the generated sources already contain
// the `GPBFieldCloseEnum` flag and it doesn't have to be computed at startup.
// This allows the older generated code to still work with the current runtime
// library.
GPBDescriptorInitializationFlag_ClosedEnumSupportKnown = 1 << 4,
};
@interface GPBDescriptor () {
@package
NSArray *fields_;
NSArray *oneofs_;
uint32_t storageSize_;
}
// fieldDescriptions and fileDescription have to be long lived, they are held as raw pointers.
+ (instancetype)allocDescriptorForClass:(Class)messageClass
messageName:(NSString *)messageName
fileDescription:(GPBFileDescription *)fileDescription
fields:(void *)fieldDescriptions
fieldCount:(uint32_t)fieldCount
storageSize:(uint32_t)storageSize
flags:(GPBDescriptorInitializationFlags)flags;
// Called right after init to provide extra information to avoid init having
// an explosion of args. These pointers are recorded, so they are expected
// to live for the lifetime of the app.
- (void)setupOneofs:(const char **)oneofNames
count:(uint32_t)count
firstHasIndex:(int32_t)firstHasIndex;
- (void)setupExtraTextInfo:(const char *)extraTextFormatInfo;
- (void)setupExtensionRanges:(const GPBExtensionRange *)ranges count:(int32_t)count;
- (void)setupContainingMessageClass:(Class)msgClass;
@end
@interface GPBOneofDescriptor () {
@package
const char *name_;
NSArray *fields_;
}
// name must be long lived.
- (instancetype)initWithName:(const char *)name fields:(NSArray *)fields;
@end
@interface GPBFieldDescriptor () {
@package
GPBMessageFieldDescription *description_;
GPB_UNSAFE_UNRETAINED GPBOneofDescriptor *containingOneof_;
}
@end
typedef NS_OPTIONS(uint32_t, GPBEnumDescriptorInitializationFlags) {
GPBEnumDescriptorInitializationFlag_None = 0,
// Available: 1 << 0
// Marks this enum as a closed enum.
GPBEnumDescriptorInitializationFlag_IsClosed = 1 << 1,
};
@interface GPBEnumDescriptor ()
// valueNames, values and extraTextFormatInfo have to be long lived, they are
// held as raw pointers.
+ (instancetype)allocDescriptorForName:(NSString *)name
valueNames:(const char *)valueNames
values:(const int32_t *)values
count:(uint32_t)valueCount
enumVerifier:(GPBEnumValidationFunc)enumVerifier
flags:(GPBEnumDescriptorInitializationFlags)flags;
+ (instancetype)allocDescriptorForName:(NSString *)name
valueNames:(const char *)valueNames
values:(const int32_t *)values
count:(uint32_t)valueCount
enumVerifier:(GPBEnumValidationFunc)enumVerifier
flags:(GPBEnumDescriptorInitializationFlags)flags
extraTextFormatInfo:(const char *)extraTextFormatInfo;
@end
@interface GPBExtensionDescriptor () {
@package
GPBExtensionDescription *description_;
}
@property(nonatomic, readonly) GPBWireFormat wireType;
// For repeated extensions, alternateWireType is the wireType with the opposite
// value for the packable property. i.e. - if the extension was marked packed
// it would be the wire type for unpacked; if the extension was marked unpacked,
// it would be the wire type for packed.
@property(nonatomic, readonly) GPBWireFormat alternateWireType;
// description has to be long lived, it is held as a raw pointer.
- (instancetype)initWithExtensionDescription:(GPBExtensionDescription *)desc
usesClassRefs:(BOOL)usesClassRefs;
- (NSComparisonResult)compareByFieldNumber:(GPBExtensionDescriptor *)other;
@end
CF_EXTERN_C_BEGIN
// Direct access is use for speed, to avoid even internally declaring things
// read/write, etc. The warning is enabled in the project to ensure code calling
// protos can turn on -Wdirect-ivar-access without issues.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdirect-ivar-access"
GPB_INLINE BOOL GPBFieldIsMapOrArray(GPBFieldDescriptor *field) {
return (field->description_->flags & (GPBFieldRepeated | GPBFieldMapKeyMask)) != 0;
}
GPB_INLINE GPBDataType GPBGetFieldDataType(GPBFieldDescriptor *field) {
return field->description_->dataType;
}
GPB_INLINE int32_t GPBFieldHasIndex(GPBFieldDescriptor *field) {
return field->description_->hasIndex;
}
GPB_INLINE uint32_t GPBFieldNumber(GPBFieldDescriptor *field) {
return field->description_->number;
}
GPB_INLINE BOOL GPBFieldIsClosedEnum(GPBFieldDescriptor *field) {
return (field->description_->flags & GPBFieldClosedEnum) != 0;
}
#pragma clang diagnostic pop
uint32_t GPBFieldTag(GPBFieldDescriptor *self);
// For repeated fields, alternateWireType is the wireType with the opposite
// value for the packable property. i.e. - if the field was marked packed it
// would be the wire type for unpacked; if the field was marked unpacked, it
// would be the wire type for packed.
uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self);
GPB_INLINE BOOL GPBExtensionIsRepeated(GPBExtensionDescription *description) {
return (description->options & GPBExtensionRepeated) != 0;
}
GPB_INLINE BOOL GPBExtensionIsPacked(GPBExtensionDescription *description) {
return (description->options & GPBExtensionPacked) != 0;
}
GPB_INLINE BOOL GPBExtensionIsWireFormat(GPBExtensionDescription *description) {
return (description->options & GPBExtensionSetWireFormat) != 0;
}
// Helper for compile time assets.
#ifndef GPBInternalCompileAssert
#define GPBInternalCompileAssert(test, msg) _Static_assert((test), #msg)
#endif // GPBInternalCompileAssert
// Sanity check that there isn't padding between the field description
// structures with and without a default.
GPBInternalCompileAssert(sizeof(GPBMessageFieldDescriptionWithDefault) ==
(sizeof(GPBGenericValue) + sizeof(GPBMessageFieldDescription)),
DescriptionsWithDefault_different_size_than_expected);
CF_EXTERN_C_END