1// 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// This header is private to the ProtobolBuffers library and must NOT be
32// included by any sources outside this library. The contents of this file are
33// subject to change at any time without notice.
34
35#import "GPBDescriptor.h"
36#import "GPBWireFormat.h"
37
38// Describes attributes of the field.
39typedef NS_OPTIONS(uint16_t, GPBFieldFlags) {
40  // These map to standard protobuf concepts.
41  GPBFieldRequired        = 1 << 0,
42  GPBFieldRepeated        = 1 << 1,
43  GPBFieldPacked          = 1 << 2,
44  GPBFieldOptional        = 1 << 3,
45  GPBFieldHasDefaultValue = 1 << 4,
46
47  // Indicates the field needs custom handling for the TextFormat name, if not
48  // set, the name can be derived from the ObjC name.
49  GPBFieldTextFormatNameCustom = 1 << 6,
50  // Indicates the field has an enum descriptor.
51  GPBFieldHasEnumDescriptor = 1 << 7,
52
53  // These are not standard protobuf concepts, they are specific to the
54  // Objective C runtime.
55
56  // These bits are used to mark the field as a map and what the key
57  // type is.
58  GPBFieldMapKeyMask     = 0xF << 8,
59  GPBFieldMapKeyInt32    =  1 << 8,
60  GPBFieldMapKeyInt64    =  2 << 8,
61  GPBFieldMapKeyUInt32   =  3 << 8,
62  GPBFieldMapKeyUInt64   =  4 << 8,
63  GPBFieldMapKeySInt32   =  5 << 8,
64  GPBFieldMapKeySInt64   =  6 << 8,
65  GPBFieldMapKeyFixed32  =  7 << 8,
66  GPBFieldMapKeyFixed64  =  8 << 8,
67  GPBFieldMapKeySFixed32 =  9 << 8,
68  GPBFieldMapKeySFixed64 = 10 << 8,
69  GPBFieldMapKeyBool     = 11 << 8,
70  GPBFieldMapKeyString   = 12 << 8,
71};
72
73// NOTE: The structures defined here have their members ordered to minimize
74// their size. This directly impacts the size of apps since these exist per
75// field/extension.
76
77// Describes a single field in a protobuf as it is represented as an ivar.
78typedef struct GPBMessageFieldDescription {
79  // Name of ivar.
80  const char *name;
81  union {
82    const char *className;  // Name for message class.
83    // For enums only: If EnumDescriptors are compiled in, it will be that,
84    // otherwise it will be the verifier.
85    GPBEnumDescriptorFunc enumDescFunc;
86    GPBEnumValidationFunc enumVerifier;
87  } dataTypeSpecific;
88  // The field number for the ivar.
89  uint32_t number;
90  // The index (in bits) into _has_storage_.
91  //   >= 0: the bit to use for a value being set.
92  //   = GPBNoHasBit(INT32_MAX): no storage used.
93  //   < 0: in a oneOf, use a full int32 to record the field active.
94  int32_t hasIndex;
95  // Offset of the variable into it's structure struct.
96  uint32_t offset;
97  // Field flags. Use accessor functions below.
98  GPBFieldFlags flags;
99  // Data type of the ivar.
100  GPBDataType dataType;
101} GPBMessageFieldDescription;
102
103// Fields in messages defined in a 'proto2' syntax file can provide a default
104// value. This struct provides the default along with the field info.
105typedef struct GPBMessageFieldDescriptionWithDefault {
106  // Default value for the ivar.
107  GPBGenericValue defaultValue;
108
109  GPBMessageFieldDescription core;
110} GPBMessageFieldDescriptionWithDefault;
111
112// Describes attributes of the extension.
113typedef NS_OPTIONS(uint8_t, GPBExtensionOptions) {
114  // These map to standard protobuf concepts.
115  GPBExtensionRepeated      = 1 << 0,
116  GPBExtensionPacked        = 1 << 1,
117  GPBExtensionSetWireFormat = 1 << 2,
118};
119
120// An extension
121typedef struct GPBExtensionDescription {
122  GPBGenericValue defaultValue;
123  const char *singletonName;
124  const char *extendedClass;
125  const char *messageOrGroupClassName;
126  GPBEnumDescriptorFunc enumDescriptorFunc;
127  int32_t fieldNumber;
128  GPBDataType dataType;
129  GPBExtensionOptions options;
130} GPBExtensionDescription;
131
132typedef NS_OPTIONS(uint32_t, GPBDescriptorInitializationFlags) {
133  GPBDescriptorInitializationFlag_FieldsWithDefault = 1 << 0,
134  GPBDescriptorInitializationFlag_WireFormat        = 1 << 1,
135};
136
137@interface GPBDescriptor () {
138 @package
139  NSArray *fields_;
140  NSArray *oneofs_;
141  uint32_t storageSize_;
142}
143
144// fieldDescriptions have to be long lived, they are held as raw pointers.
145+ (instancetype)
146    allocDescriptorForClass:(Class)messageClass
147                  rootClass:(Class)rootClass
148                       file:(GPBFileDescriptor *)file
149                     fields:(void *)fieldDescriptions
150                 fieldCount:(uint32_t)fieldCount
151                storageSize:(uint32_t)storageSize
152                      flags:(GPBDescriptorInitializationFlags)flags;
153
154- (instancetype)initWithClass:(Class)messageClass
155                         file:(GPBFileDescriptor *)file
156                       fields:(NSArray *)fields
157                  storageSize:(uint32_t)storage
158                   wireFormat:(BOOL)wireFormat;
159
160// Called right after init to provide extra information to avoid init having
161// an explosion of args. These pointers are recorded, so they are expected
162// to live for the lifetime of the app.
163- (void)setupOneofs:(const char **)oneofNames
164              count:(uint32_t)count
165      firstHasIndex:(int32_t)firstHasIndex;
166- (void)setupExtraTextInfo:(const char *)extraTextFormatInfo;
167- (void)setupExtensionRanges:(const GPBExtensionRange *)ranges count:(int32_t)count;
168
169@end
170
171@interface GPBFileDescriptor ()
172- (instancetype)initWithPackage:(NSString *)package
173                         syntax:(GPBFileSyntax)syntax;
174@end
175
176@interface GPBOneofDescriptor () {
177 @package
178  const char *name_;
179  NSArray *fields_;
180  SEL caseSel_;
181}
182// name must be long lived.
183- (instancetype)initWithName:(const char *)name fields:(NSArray *)fields;
184@end
185
186@interface GPBFieldDescriptor () {
187 @package
188  GPBMessageFieldDescription *description_;
189  GPB_UNSAFE_UNRETAINED GPBOneofDescriptor *containingOneof_;
190
191  SEL getSel_;
192  SEL setSel_;
193  SEL hasOrCountSel_;  // *Count for map<>/repeated fields, has* otherwise.
194  SEL setHasSel_;
195}
196
197// Single initializer
198// description has to be long lived, it is held as a raw pointer.
199- (instancetype)initWithFieldDescription:(void *)description
200                         includesDefault:(BOOL)includesDefault
201                                  syntax:(GPBFileSyntax)syntax;
202@end
203
204@interface GPBEnumDescriptor ()
205// valueNames, values and extraTextFormatInfo have to be long lived, they are
206// held as raw pointers.
207+ (instancetype)
208    allocDescriptorForName:(NSString *)name
209                valueNames:(const char *)valueNames
210                    values:(const int32_t *)values
211                     count:(uint32_t)valueCount
212              enumVerifier:(GPBEnumValidationFunc)enumVerifier;
213+ (instancetype)
214    allocDescriptorForName:(NSString *)name
215                valueNames:(const char *)valueNames
216                    values:(const int32_t *)values
217                     count:(uint32_t)valueCount
218              enumVerifier:(GPBEnumValidationFunc)enumVerifier
219       extraTextFormatInfo:(const char *)extraTextFormatInfo;
220
221- (instancetype)initWithName:(NSString *)name
222                  valueNames:(const char *)valueNames
223                      values:(const int32_t *)values
224                       count:(uint32_t)valueCount
225                enumVerifier:(GPBEnumValidationFunc)enumVerifier;
226@end
227
228@interface GPBExtensionDescriptor () {
229 @package
230  GPBExtensionDescription *description_;
231}
232@property(nonatomic, readonly) GPBWireFormat wireType;
233
234// For repeated extensions, alternateWireType is the wireType with the opposite
235// value for the packable property.  i.e. - if the extension was marked packed
236// it would be the wire type for unpacked; if the extension was marked unpacked,
237// it would be the wire type for packed.
238@property(nonatomic, readonly) GPBWireFormat alternateWireType;
239
240// description has to be long lived, it is held as a raw pointer.
241- (instancetype)initWithExtensionDescription:
242    (GPBExtensionDescription *)description;
243- (NSComparisonResult)compareByFieldNumber:(GPBExtensionDescriptor *)other;
244@end
245
246CF_EXTERN_C_BEGIN
247
248GPB_INLINE BOOL GPBFieldIsMapOrArray(GPBFieldDescriptor *field) {
249  return (field->description_->flags &
250          (GPBFieldRepeated | GPBFieldMapKeyMask)) != 0;
251}
252
253GPB_INLINE GPBDataType GPBGetFieldDataType(GPBFieldDescriptor *field) {
254  return field->description_->dataType;
255}
256
257GPB_INLINE int32_t GPBFieldHasIndex(GPBFieldDescriptor *field) {
258  return field->description_->hasIndex;
259}
260
261GPB_INLINE uint32_t GPBFieldNumber(GPBFieldDescriptor *field) {
262  return field->description_->number;
263}
264
265uint32_t GPBFieldTag(GPBFieldDescriptor *self);
266
267// For repeated fields, alternateWireType is the wireType with the opposite
268// value for the packable property.  i.e. - if the field was marked packed it
269// would be the wire type for unpacked; if the field was marked unpacked, it
270// would be the wire type for packed.
271uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self);
272
273GPB_INLINE BOOL GPBPreserveUnknownFields(GPBFileSyntax syntax) {
274  return syntax != GPBFileSyntaxProto3;
275}
276
277GPB_INLINE BOOL GPBHasPreservingUnknownEnumSemantics(GPBFileSyntax syntax) {
278  return syntax == GPBFileSyntaxProto3;
279}
280
281GPB_INLINE BOOL GPBExtensionIsRepeated(GPBExtensionDescription *description) {
282  return (description->options & GPBExtensionRepeated) != 0;
283}
284
285GPB_INLINE BOOL GPBExtensionIsPacked(GPBExtensionDescription *description) {
286  return (description->options & GPBExtensionPacked) != 0;
287}
288
289GPB_INLINE BOOL GPBExtensionIsWireFormat(GPBExtensionDescription *description) {
290  return (description->options & GPBExtensionSetWireFormat) != 0;
291}
292
293// Helper for compile time assets.
294#ifndef _GPBCompileAssert
295  #if __has_feature(c_static_assert) || __has_extension(c_static_assert)
296    #define _GPBCompileAssert(test, msg) _Static_assert((test), #msg)
297  #else
298    // Pre-Xcode 7 support.
299    #define _GPBCompileAssertSymbolInner(line, msg) _GPBCompileAssert ## line ## __ ## msg
300    #define _GPBCompileAssertSymbol(line, msg) _GPBCompileAssertSymbolInner(line, msg)
301    #define _GPBCompileAssert(test, msg) \
302        typedef char _GPBCompileAssertSymbol(__LINE__, msg) [ ((test) ? 1 : -1) ]
303  #endif  // __has_feature(c_static_assert) || __has_extension(c_static_assert)
304#endif // _GPBCompileAssert
305
306// Sanity check that there isn't padding between the field description
307// structures with and without a default.
308_GPBCompileAssert(sizeof(GPBMessageFieldDescriptionWithDefault) ==
309                  (sizeof(GPBGenericValue) +
310                   sizeof(GPBMessageFieldDescription)),
311                  DescriptionsWithDefault_different_size_than_expected);
312
313CF_EXTERN_C_END
314