OLD | NEW |
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 #ifndef __GOOGLE_PROTOBUF_PHP_PROTOBUF_H__ | 1 #ifndef __GOOGLE_PROTOBUF_PHP_PROTOBUF_H__ |
32 #define __GOOGLE_PROTOBUF_PHP_PROTOBUF_H__ | 2 #define __GOOGLE_PROTOBUF_PHP_PROTOBUF_H__ |
33 | 3 |
34 #include <php.h> | 4 #include <php.h> |
35 | 5 |
36 // ubp.h has to be placed after php.h. Othwise, php.h will introduce NDEBUG. | |
37 #include "upb.h" | 6 #include "upb.h" |
38 | 7 |
39 #define PHP_PROTOBUF_EXTNAME "protobuf" | 8 #define PHP_PROTOBUF_EXTNAME "protobuf" |
40 #define PHP_PROTOBUF_VERSION "3.1.0a1" | 9 #define PHP_PROTOBUF_VERSION "0.01" |
41 | 10 |
42 #define MAX_LENGTH_OF_INT64 20 | 11 // Forward decls. |
43 #define SIZEOF_INT64 8 | |
44 | |
45 // ----------------------------------------------------------------------------- | |
46 // Forward Declaration | |
47 // ---------------------------------------------------------------------------- | |
48 | |
49 struct DescriptorPool; | 12 struct DescriptorPool; |
50 struct Descriptor; | 13 struct Descriptor; |
| 14 struct FieldDescriptor; |
51 struct EnumDescriptor; | 15 struct EnumDescriptor; |
52 struct FieldDescriptor; | 16 struct MessageLayout; |
53 struct MessageField; | 17 struct MessageField; |
54 struct MessageHeader; | 18 struct MessageHeader; |
55 struct MessageLayout; | 19 struct MessageBuilderContext; |
56 struct RepeatedField; | 20 struct EnumBuilderContext; |
57 struct RepeatedFieldIter; | |
58 struct MapField; | |
59 | 21 |
60 typedef struct DescriptorPool DescriptorPool; | 22 typedef struct DescriptorPool DescriptorPool; |
61 typedef struct Descriptor Descriptor; | 23 typedef struct Descriptor Descriptor; |
| 24 typedef struct FieldDescriptor FieldDescriptor; |
| 25 typedef struct OneofDescriptor OneofDescriptor; |
62 typedef struct EnumDescriptor EnumDescriptor; | 26 typedef struct EnumDescriptor EnumDescriptor; |
63 typedef struct FieldDescriptor FieldDescriptor; | 27 typedef struct MessageLayout MessageLayout; |
64 typedef struct MessageField MessageField; | 28 typedef struct MessageField MessageField; |
65 typedef struct MessageHeader MessageHeader; | 29 typedef struct MessageHeader MessageHeader; |
66 typedef struct MessageLayout MessageLayout; | 30 typedef struct MessageBuilderContext MessageBuilderContext; |
67 typedef struct RepeatedField RepeatedField; | 31 typedef struct OneofBuilderContext OneofBuilderContext; |
68 typedef struct RepeatedFieldIter RepeatedFieldIter; | 32 typedef struct EnumBuilderContext EnumBuilderContext; |
69 typedef struct MapField MapField; | 33 |
| 34 extern zend_class_entry* builder_type; |
| 35 extern zend_class_entry* descriptor_type; |
| 36 extern zend_class_entry* message_builder_context_type; |
| 37 |
| 38 extern DescriptorPool* generated_pool; // The actual generated pool |
| 39 |
| 40 ZEND_BEGIN_MODULE_GLOBALS(protobuf) |
| 41 zval* generated_pool; |
| 42 zend_object_handlers* message_handlers; |
| 43 HashTable upb_def_to_php_obj_map; |
| 44 ZEND_END_MODULE_GLOBALS(protobuf) |
| 45 |
| 46 ZEND_DECLARE_MODULE_GLOBALS(protobuf) |
| 47 |
| 48 #ifdef ZTS |
| 49 #define PROTOBUF_G(v) TSRMG(protobuf_globals_id, zend_protobuf_globals*, v) |
| 50 #else |
| 51 #define PROTOBUF_G(v) (protobuf_globals.v) |
| 52 #endif |
70 | 53 |
71 // ----------------------------------------------------------------------------- | 54 // ----------------------------------------------------------------------------- |
72 // Globals. | 55 // PHP functions and global variables. |
73 // ----------------------------------------------------------------------------- | 56 // ----------------------------------------------------------------------------- |
74 | 57 |
75 ZEND_BEGIN_MODULE_GLOBALS(protobuf) | 58 PHP_MINIT_FUNCTION(protobuf); |
76 ZEND_END_MODULE_GLOBALS(protobuf) | |
77 | |
78 // Init module and PHP classes. | |
79 void descriptor_init(TSRMLS_D); | |
80 void enum_descriptor_init(TSRMLS_D); | |
81 void descriptor_pool_init(TSRMLS_D); | |
82 void gpb_type_init(TSRMLS_D); | |
83 void map_field_init(TSRMLS_D); | |
84 void repeated_field_init(TSRMLS_D); | |
85 void repeated_field_iter_init(TSRMLS_D); | |
86 void util_init(TSRMLS_D); | |
87 void message_init(TSRMLS_D); | |
88 | |
89 // Global map from upb {msg,enum}defs to wrapper Descriptor/EnumDescriptor | |
90 // instances. | |
91 void add_def_obj(const void* def, zval* value); | |
92 zval* get_def_obj(const void* def); | |
93 | |
94 // Global map from PHP class entries to wrapper Descriptor/EnumDescriptor | |
95 // instances. | |
96 void add_ce_obj(const void* ce, zval* value); | |
97 zval* get_ce_obj(const void* ce); | |
98 | |
99 extern zend_class_entry* map_field_type; | |
100 extern zend_class_entry* repeated_field_type; | |
101 | 59 |
102 // ----------------------------------------------------------------------------- | 60 // ----------------------------------------------------------------------------- |
103 // Descriptor. | 61 // PHP class structure. |
104 // ----------------------------------------------------------------------------- | 62 // ----------------------------------------------------------------------------- |
105 | 63 |
106 struct DescriptorPool { | 64 struct DescriptorPool { |
107 zend_object std; | 65 zend_object std; |
108 upb_symtab* symtab; | 66 upb_symtab* symtab; |
109 HashTable* pending_list; | 67 HashTable* pending_list; |
110 }; | 68 }; |
111 | 69 |
112 PHP_METHOD(DescriptorPool, getGeneratedPool); | |
113 PHP_METHOD(DescriptorPool, internalAddGeneratedFile); | |
114 | |
115 extern zval* generated_pool_php; // wrapper of generated pool | |
116 extern DescriptorPool* generated_pool; // The actual generated pool | |
117 | |
118 struct Descriptor { | 70 struct Descriptor { |
119 zend_object std; | 71 zend_object std; |
120 const upb_msgdef* msgdef; | 72 const upb_msgdef* msgdef; |
121 MessageLayout* layout; | 73 MessageLayout* layout; |
122 zend_class_entry* klass; // begins as NULL | 74 // zval* klass; // begins as NULL |
123 const upb_handlers* fill_handlers; | 75 // const upb_handlers* fill_handlers; |
124 const upb_pbdecodermethod* fill_method; | 76 // const upb_pbdecodermethod* fill_method; |
125 const upb_handlers* pb_serialize_handlers; | 77 const upb_handlers* pb_serialize_handlers; |
| 78 // const upb_handlers* json_serialize_handlers; |
| 79 // Handlers hold type class references for sub-message fields directly in some |
| 80 // cases. We need to keep these rooted because they might otherwise be |
| 81 // collected. |
| 82 // zval_array typeclass_references; |
126 }; | 83 }; |
127 | 84 |
128 extern zend_class_entry* descriptor_type; | |
129 | |
130 void descriptor_name_set(Descriptor *desc, const char *name); | |
131 | |
132 struct FieldDescriptor { | 85 struct FieldDescriptor { |
133 zend_object std; | 86 zend_object std; |
134 const upb_fielddef* fielddef; | 87 const upb_fielddef* fielddef; |
135 }; | 88 }; |
136 | 89 |
| 90 struct OneofDescriptor { |
| 91 zend_object std; |
| 92 const upb_oneofdef* oneofdef; |
| 93 }; |
| 94 |
137 struct EnumDescriptor { | 95 struct EnumDescriptor { |
138 zend_object std; | 96 zend_object std; |
139 const upb_enumdef* enumdef; | 97 const upb_enumdef* enumdef; |
140 zend_class_entry* klass; // begins as NULL | 98 // zval* module; // begins as NULL |
141 // VALUE module; // begins as nil | |
142 }; | 99 }; |
143 | 100 |
144 extern zend_class_entry* enum_descriptor_type; | |
145 | |
146 // ----------------------------------------------------------------------------- | 101 // ----------------------------------------------------------------------------- |
147 // Message class creation. | 102 // Native slot storage abstraction. |
148 // ----------------------------------------------------------------------------- | 103 // ----------------------------------------------------------------------------- |
149 | 104 |
150 void* message_data(void* msg); | 105 #define NATIVE_SLOT_MAX_SIZE sizeof(uint64_t) |
151 | 106 |
152 // Build PHP class for given descriptor. Instead of building from scratch, this | 107 size_t native_slot_size(upb_fieldtype_t type); |
153 // function modifies existing class which has been partially defined in PHP | |
154 // code. | |
155 void build_class_from_descriptor(zval* php_descriptor TSRMLS_DC); | |
156 | 108 |
157 extern zend_object_handlers* message_handlers; | 109 #define MAP_KEY_FIELD 1 |
| 110 #define MAP_VALUE_FIELD 2 |
| 111 |
| 112 // Oneof case slot value to indicate that no oneof case is set. The value `0` is |
| 113 // safe because field numbers are used as case identifiers, and no field can |
| 114 // have a number of 0. |
| 115 #define ONEOF_CASE_NONE 0 |
| 116 |
| 117 // These operate on a map field (i.e., a repeated field of submessages whose |
| 118 // submessage type is a map-entry msgdef). |
| 119 bool is_map_field(const upb_fielddef* field); |
| 120 const upb_fielddef* map_field_key(const upb_fielddef* field); |
| 121 const upb_fielddef* map_field_value(const upb_fielddef* field); |
| 122 |
| 123 // These operate on a map-entry msgdef. |
| 124 const upb_fielddef* map_entry_key(const upb_msgdef* msgdef); |
| 125 const upb_fielddef* map_entry_value(const upb_msgdef* msgdef); |
158 | 126 |
159 // ----------------------------------------------------------------------------- | 127 // ----------------------------------------------------------------------------- |
160 // Message layout / storage. | 128 // Message layout / storage. |
161 // ----------------------------------------------------------------------------- | 129 // ----------------------------------------------------------------------------- |
162 | 130 |
163 /* | |
164 * In c extension, each protobuf message is a zval instance. The zval instance | |
165 * is like union, which can be used to store int, string, zend_object_value and | |
166 * etc. For protobuf message, the zval instance is used to store the | |
167 * zend_object_value. | |
168 * | |
169 * The zend_object_value is composed of handlers and a handle to look up the | |
170 * actual stored data. The handlers are pointers to functions, e.g., read, | |
171 * write, and etc, to access properties. | |
172 * | |
173 * The actual data of protobuf messages is stored as MessageHeader in zend | |
174 * engine's central repository. Each MessageHeader instance is composed of a | |
175 * zend_object, a Descriptor instance and the real message data. | |
176 * | |
177 * For the reason that PHP's native types may not be large enough to store | |
178 * protobuf message's field (e.g., int64), all message's data is stored in | |
179 * custom memory layout and is indexed by the Descriptor instance. | |
180 * | |
181 * The zend_object contains the zend class entry and the properties table. The | |
182 * zend class entry contains all information about protobuf message's | |
183 * corresponding PHP class. The most useful information is the offset table of | |
184 * properties. Because read access to properties requires returning zval | |
185 * instance, we need to convert data from the custom layout to zval instance. | |
186 * Instead of creating zval instance for every read access, we use the zval | |
187 * instances in the properties table in the zend_object as cache. When | |
188 * accessing properties, the offset is needed to find the zval property in | |
189 * zend_object's properties table. These properties will be updated using the | |
190 * data from custom memory layout only when reading these properties. | |
191 * | |
192 * zval | |
193 * |-zend_object_value obj | |
194 * |-zend_object_handlers* handlers -> |-read_property_handler | |
195 * | |-write_property_handler | |
196 * | ++++++++++++++++++++++ | |
197 * |-zend_object_handle handle -> + central repository + | |
198 * ++++++++++++++++++++++ | |
199 * MessageHeader <-----------------| | |
200 * |-zend_object std | |
201 * | |-class_entry* ce -> class_entry | |
202 * | | |-HashTable properties_table (name->offset) | |
203 * | |-zval** properties_table <------------------------------| | |
204 * | |------> zval* property(cache) | |
205 * |-Descriptor* desc (name->offset) | |
206 * |-void** data <-----------| | |
207 * |-----------------------> void* property(data) | |
208 * | |
209 */ | |
210 | |
211 #define MESSAGE_FIELD_NO_CASE ((size_t)-1) | 131 #define MESSAGE_FIELD_NO_CASE ((size_t)-1) |
212 | 132 |
213 struct MessageField { | 133 struct MessageField { |
214 size_t offset; | 134 size_t offset; |
215 int cache_index; // Each field except oneof field has a zval cache to avoid | 135 size_t case_offset; // for oneofs, a uint32. Else, MESSAGE_FIELD_NO_CASE. |
216 // multiple creation when being accessed. | |
217 size_t case_offset; // for oneofs, a uint32. Else, MESSAGE_FIELD_NO_CASE. | |
218 }; | 136 }; |
219 | 137 |
220 struct MessageLayout { | 138 struct MessageLayout { |
221 const upb_msgdef* msgdef; | 139 const upb_msgdef* msgdef; |
222 MessageField* fields; | 140 MessageField* fields; |
223 size_t size; | 141 size_t size; |
224 }; | 142 }; |
225 | 143 |
| 144 void layout_init(MessageLayout* layout, void* storage); |
| 145 zval* layout_get(MessageLayout* layout, const void* storage, |
| 146 const upb_fielddef* field TSRMLS_DC); |
| 147 MessageLayout* create_layout(const upb_msgdef* msgdef); |
| 148 void free_layout(MessageLayout* layout); |
| 149 zval* native_slot_get(upb_fieldtype_t type, /*VALUE type_class,*/ |
| 150 const void* memory TSRMLS_DC); |
| 151 |
| 152 // ----------------------------------------------------------------------------- |
| 153 // Message class creation. |
| 154 // ----------------------------------------------------------------------------- |
| 155 |
226 struct MessageHeader { | 156 struct MessageHeader { |
227 zend_object std; // Stores properties table and class info of PHP instance. | 157 zend_object std; |
228 // This is needed for MessageHeader to be accessed via PHP. | 158 Descriptor* descriptor; // kept alive by self.class.descriptor reference. |
229 Descriptor* descriptor; // Kept alive by self.class.descriptor reference. | 159 // Data comes after this. |
230 // The real message data is appended after MessageHeader. | |
231 }; | 160 }; |
232 | 161 |
233 MessageLayout* create_layout(const upb_msgdef* msgdef); | 162 struct MessageBuilderContext { |
234 void layout_init(MessageLayout* layout, void* storage, | 163 zend_object std; |
235 zval** properties_table TSRMLS_DC); | 164 zval* descriptor; |
236 zval* layout_get(MessageLayout* layout, const void* storage, | 165 zval* pool; |
237 const upb_fielddef* field, zval** cache TSRMLS_DC); | 166 }; |
238 void layout_set(MessageLayout* layout, MessageHeader* header, | |
239 const upb_fielddef* field, zval* val TSRMLS_DC); | |
240 void free_layout(MessageLayout* layout); | |
241 | 167 |
242 PHP_METHOD(Message, readOneof); | 168 struct OneofBuilderContext { |
243 PHP_METHOD(Message, writeOneof); | 169 zend_object std; |
244 PHP_METHOD(Message, __construct); | 170 // VALUE descriptor; |
| 171 // VALUE builder; |
| 172 }; |
| 173 |
| 174 struct EnumBuilderContext { |
| 175 zend_object std; |
| 176 // VALUE enumdesc; |
| 177 }; |
| 178 |
| 179 // Forward-declare all of the PHP method implementations. |
| 180 |
| 181 DescriptorPool* php_to_descriptor_pool(zval* value TSRMLS_DC); |
| 182 zend_object_value descriptor_pool_create(zend_class_entry *ce TSRMLS_DC); |
| 183 void descriptor_pool_free_c(DescriptorPool* object TSRMLS_DC); |
| 184 void descriptor_pool_free(void* object TSRMLS_DC); |
| 185 void descriptor_pool_init_c_instance(DescriptorPool* pool TSRMLS_DC); |
| 186 PHP_METHOD(DescriptorPool, addMessage); |
| 187 PHP_METHOD(DescriptorPool, finalize); |
| 188 |
| 189 Descriptor* php_to_descriptor(zval* value TSRMLS_DC); |
| 190 zend_object_value descriptor_create(zend_class_entry *ce TSRMLS_DC); |
| 191 void descriptor_init_c_instance(Descriptor* intern TSRMLS_DC); |
| 192 void descriptor_free_c(Descriptor* object TSRMLS_DC); |
| 193 void descriptor_free(void* object TSRMLS_DC); |
| 194 void descriptor_name_set(Descriptor *desc, const char *name); |
| 195 |
| 196 MessageBuilderContext* php_to_message_builder_context(zval* value TSRMLS_DC); |
| 197 zend_object_value message_builder_context_create( |
| 198 zend_class_entry* ce TSRMLS_DC); |
| 199 void message_builder_context_init_c_instance( |
| 200 MessageBuilderContext* intern TSRMLS_DC); |
| 201 void message_builder_context_free_c(MessageBuilderContext* object TSRMLS_DC); |
| 202 void message_builder_context_free(void* object TSRMLS_DC); |
| 203 PHP_METHOD(MessageBuilderContext, optional); |
| 204 PHP_METHOD(MessageBuilderContext, finalizeToPool); |
| 205 |
| 206 PHP_METHOD(Message, encode); |
| 207 const zend_class_entry* build_class_from_descriptor( |
| 208 zval* php_descriptor TSRMLS_DC); |
| 209 |
| 210 PHP_FUNCTION(get_generated_pool); |
245 | 211 |
246 // ----------------------------------------------------------------------------- | 212 // ----------------------------------------------------------------------------- |
247 // Encode / Decode. | 213 // Global map from upb {msg,enum}defs to wrapper Descriptor/EnumDescriptor |
248 // ----------------------------------------------------------------------------- | 214 // instances. |
| 215 // ---------------------------------------------------------------------------- |
249 | 216 |
250 // Maximum depth allowed during encoding, to avoid stack overflows due to | 217 void add_def_obj(const void* def, zval* value); |
251 // cycles. | 218 zval* get_def_obj(const void* def); |
252 #define ENCODE_MAX_NESTING 63 | |
253 | |
254 // Constructs the upb decoder method for parsing messages of this type. | |
255 // This is called from the message class creation code. | |
256 const upb_pbdecodermethod *new_fillmsg_decodermethod(Descriptor *desc, | |
257 const void *owner); | |
258 | |
259 PHP_METHOD(Message, encode); | |
260 PHP_METHOD(Message, decode); | |
261 | |
262 // ----------------------------------------------------------------------------- | |
263 // Type check / conversion. | |
264 // ----------------------------------------------------------------------------- | |
265 | |
266 bool protobuf_convert_to_int32(zval* from, int32_t* to); | |
267 bool protobuf_convert_to_uint32(zval* from, uint32_t* to); | |
268 bool protobuf_convert_to_int64(zval* from, int64_t* to); | |
269 bool protobuf_convert_to_uint64(zval* from, uint64_t* to); | |
270 bool protobuf_convert_to_float(zval* from, float* to); | |
271 bool protobuf_convert_to_double(zval* from, double* to); | |
272 bool protobuf_convert_to_bool(zval* from, int8_t* to); | |
273 bool protobuf_convert_to_string(zval* from); | |
274 | |
275 PHP_METHOD(Util, checkInt32); | |
276 PHP_METHOD(Util, checkUint32); | |
277 PHP_METHOD(Util, checkInt64); | |
278 PHP_METHOD(Util, checkUint64); | |
279 PHP_METHOD(Util, checkEnum); | |
280 PHP_METHOD(Util, checkFloat); | |
281 PHP_METHOD(Util, checkDouble); | |
282 PHP_METHOD(Util, checkBool); | |
283 PHP_METHOD(Util, checkString); | |
284 PHP_METHOD(Util, checkBytes); | |
285 PHP_METHOD(Util, checkMessage); | |
286 PHP_METHOD(Util, checkRepeatedField); | |
287 | |
288 // ----------------------------------------------------------------------------- | |
289 // Native slot storage abstraction. | |
290 // ----------------------------------------------------------------------------- | |
291 | |
292 #define NATIVE_SLOT_MAX_SIZE sizeof(uint64_t) | |
293 | |
294 size_t native_slot_size(upb_fieldtype_t type); | |
295 bool native_slot_set(upb_fieldtype_t type, const zend_class_entry* klass, | |
296 void* memory, zval* value TSRMLS_DC); | |
297 void native_slot_init(upb_fieldtype_t type, void* memory, zval** cache); | |
298 // For each property, in order to avoid conversion between the zval object and | |
299 // the actual data type during parsing/serialization, the containing message | |
300 // object use the custom memory layout to store the actual data type for each | |
301 // property inside of it. To access a property from php code, the property | |
302 // needs to be converted to a zval object. The message object is not responsible | |
303 // for providing such a zval object. Instead the caller needs to provide one | |
304 // (cache) and update it with the actual data (memory). | |
305 void native_slot_get(upb_fieldtype_t type, const void* memory, | |
306 zval** cache TSRMLS_DC); | |
307 void native_slot_get_default(upb_fieldtype_t type, zval** cache TSRMLS_DC); | |
308 | |
309 // ----------------------------------------------------------------------------- | |
310 // Map Field. | |
311 // ----------------------------------------------------------------------------- | |
312 | |
313 extern zend_object_handlers* map_field_handlers; | |
314 | |
315 typedef struct { | |
316 zend_object std; | |
317 upb_fieldtype_t key_type; | |
318 upb_fieldtype_t value_type; | |
319 const zend_class_entry* msg_ce; // class entry for value message | |
320 upb_strtable table; | |
321 } Map; | |
322 | |
323 typedef struct { | |
324 Map* self; | |
325 upb_strtable_iter it; | |
326 } MapIter; | |
327 | |
328 void map_begin(zval* self, MapIter* iter TSRMLS_DC); | |
329 void map_next(MapIter* iter); | |
330 bool map_done(MapIter* iter); | |
331 const char* map_iter_key(MapIter* iter, int* len); | |
332 upb_value map_iter_value(MapIter* iter, int* len); | |
333 | |
334 // These operate on a map-entry msgdef. | |
335 const upb_fielddef* map_entry_key(const upb_msgdef* msgdef); | |
336 const upb_fielddef* map_entry_value(const upb_msgdef* msgdef); | |
337 | |
338 zend_object_value map_field_create(zend_class_entry *ce TSRMLS_DC); | |
339 void map_field_create_with_type(zend_class_entry *ce, const upb_fielddef *field, | |
340 zval **map_field TSRMLS_DC); | |
341 void map_field_free(void* object TSRMLS_DC); | |
342 void* upb_value_memory(upb_value* v); | |
343 | |
344 #define MAP_KEY_FIELD 1 | |
345 #define MAP_VALUE_FIELD 2 | |
346 | |
347 // These operate on a map field (i.e., a repeated field of submessages whose | |
348 // submessage type is a map-entry msgdef). | |
349 bool is_map_field(const upb_fielddef* field); | |
350 const upb_fielddef* map_field_key(const upb_fielddef* field); | |
351 const upb_fielddef* map_field_value(const upb_fielddef* field); | |
352 | |
353 bool map_index_set(Map *intern, const char* keyval, int length, upb_value v); | |
354 | |
355 PHP_METHOD(MapField, __construct); | |
356 PHP_METHOD(MapField, offsetExists); | |
357 PHP_METHOD(MapField, offsetGet); | |
358 PHP_METHOD(MapField, offsetSet); | |
359 PHP_METHOD(MapField, offsetUnset); | |
360 PHP_METHOD(MapField, count); | |
361 | |
362 // ----------------------------------------------------------------------------- | |
363 // Repeated Field. | |
364 // ----------------------------------------------------------------------------- | |
365 | |
366 extern zend_object_handlers* repeated_field_handlers; | |
367 | |
368 struct RepeatedField { | |
369 zend_object std; | |
370 zval* array; | |
371 upb_fieldtype_t type; | |
372 const zend_class_entry* msg_ce; // class entry for containing message | |
373 // (for message field only). | |
374 }; | |
375 | |
376 struct RepeatedFieldIter { | |
377 zend_object std; | |
378 RepeatedField* repeated_field; | |
379 long position; | |
380 }; | |
381 | |
382 void repeated_field_create_with_type(zend_class_entry* ce, | |
383 const upb_fielddef* field, | |
384 zval** repeated_field TSRMLS_DC); | |
385 // Return the element at the index position from the repeated field. There is | |
386 // not restriction on the type of stored elements. | |
387 void *repeated_field_index_native(RepeatedField *intern, int index TSRMLS_DC); | |
388 // Add the element to the end of the repeated field. There is not restriction on | |
389 // the type of stored elements. | |
390 void repeated_field_push_native(RepeatedField *intern, void *value TSRMLS_DC); | |
391 | |
392 PHP_METHOD(RepeatedField, __construct); | |
393 PHP_METHOD(RepeatedField, append); | |
394 PHP_METHOD(RepeatedField, offsetExists); | |
395 PHP_METHOD(RepeatedField, offsetGet); | |
396 PHP_METHOD(RepeatedField, offsetSet); | |
397 PHP_METHOD(RepeatedField, offsetUnset); | |
398 PHP_METHOD(RepeatedField, count); | |
399 PHP_METHOD(RepeatedField, getIterator); | |
400 | |
401 PHP_METHOD(RepeatedFieldIter, rewind); | |
402 PHP_METHOD(RepeatedFieldIter, current); | |
403 PHP_METHOD(RepeatedFieldIter, key); | |
404 PHP_METHOD(RepeatedFieldIter, next); | |
405 PHP_METHOD(RepeatedFieldIter, valid); | |
406 | |
407 // ----------------------------------------------------------------------------- | |
408 // Oneof Field. | |
409 // ----------------------------------------------------------------------------- | |
410 | |
411 typedef struct { | |
412 zend_object std; | |
413 upb_oneofdef* oneofdef; | |
414 int index; // Index of field in oneof. -1 if not set. | |
415 char value[NATIVE_SLOT_MAX_SIZE]; | |
416 } Oneof; | |
417 | |
418 // Oneof case slot value to indicate that no oneof case is set. The value `0` is | |
419 // safe because field numbers are used as case identifiers, and no field can | |
420 // have a number of 0. | |
421 #define ONEOF_CASE_NONE 0 | |
422 | |
423 // ----------------------------------------------------------------------------- | |
424 // Upb. | |
425 // ----------------------------------------------------------------------------- | |
426 | |
427 upb_fieldtype_t to_fieldtype(upb_descriptortype_t type); | |
428 const zend_class_entry *field_type_class(const upb_fielddef *field TSRMLS_DC); | |
429 | 219 |
430 // ----------------------------------------------------------------------------- | 220 // ----------------------------------------------------------------------------- |
431 // Utilities. | 221 // Utilities. |
432 // ----------------------------------------------------------------------------- | 222 // ----------------------------------------------------------------------------- |
433 | 223 |
434 // PHP <-> C conversion. | 224 // PHP Array utils. |
435 #define UNBOX(class_name, val) \ | 225 #define Z_ARRVAL_SIZE_P(zval_p) zend_hash_num_elements(Z_ARRVAL_P(zval_p)) |
436 (class_name*)zend_object_store_get_object(val TSRMLS_CC); | 226 #define Z_ARRVAL_BEGIN_P(zval_p) Z_ARRVAL_P(zval_p)->pListHead |
| 227 #define Z_BUCKET_NEXT_PP(bucket_pp) *bucket_pp = (*bucket_pp)->pListNext |
437 | 228 |
438 #define BOX(class_name, wrapper, intern, free_func) \ | 229 #define DEFINE_PHP_OBJECT(class_name, class_name_lower, name) \ |
439 MAKE_STD_ZVAL(wrapper); \ | 230 do { \ |
440 Z_TYPE_P(wrapper) = IS_OBJECT; \ | 231 zval* name; \ |
441 Z_OBJVAL_P(wrapper) \ | 232 MAKE_STD_ZVAL(name); \ |
442 .handle = \ | 233 object_init_ex(name, class_name_lower##_type); \ |
443 zend_objects_store_put(intern, NULL, free_func, NULL TSRMLS_CC); \ | 234 } while (0) |
444 Z_OBJVAL_P(wrapper).handlers = zend_get_std_object_handlers(); | 235 |
| 236 #define DEFINE_PHP_WRAPPER(class_name, class_name_lower, name, intern) \ |
| 237 zval* name; \ |
| 238 MAKE_STD_ZVAL(name); \ |
| 239 object_init_ex(name, class_name_lower##_type); \ |
| 240 Z_OBJVAL_P(name) \ |
| 241 .handle = zend_objects_store_put( \ |
| 242 intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, \ |
| 243 class_name_lower##_free, NULL TSRMLS_CC); |
| 244 |
| 245 #define DEFINE_PHP_ZVAL(name) \ |
| 246 do { \ |
| 247 zval* name; \ |
| 248 MAKE_STD_ZVAL(name); \ |
| 249 } while (0) |
| 250 |
| 251 #define DEFINE_PHP_STRING(name, value) \ |
| 252 do { \ |
| 253 zval* name; \ |
| 254 MAKE_STD_ZVAL(name); \ |
| 255 ZVAL_STRING(name, value, 1); \ |
| 256 } while (0) |
| 257 |
| 258 // Upb Utilities |
| 259 |
| 260 void check_upb_status(const upb_status* status, const char* msg); |
| 261 |
| 262 #define CHECK_UPB(code, msg) \ |
| 263 do { \ |
| 264 upb_status status = UPB_STATUS_INIT; \ |
| 265 code; \ |
| 266 check_upb_status(&status, msg); \ |
| 267 } while (0) |
445 | 268 |
446 // Memory management | 269 // Memory management |
| 270 |
447 #define ALLOC(class_name) (class_name*) emalloc(sizeof(class_name)) | 271 #define ALLOC(class_name) (class_name*) emalloc(sizeof(class_name)) |
448 #define PEMALLOC(class_name) (class_name*) pemalloc(sizeof(class_name), 1) | |
449 #define ALLOC_N(class_name, n) (class_name*) emalloc(sizeof(class_name) * n) | 272 #define ALLOC_N(class_name, n) (class_name*) emalloc(sizeof(class_name) * n) |
450 #define FREE(object) efree(object) | 273 #define FREE(object) efree(object) |
451 #define PEFREE(object) pefree(object, 1) | |
452 | 274 |
453 // Create PHP internal instance. | 275 // Type Checking |
454 #define CREATE(class_name, intern, init_func) \ | 276 #define CHECK_TYPE(field, type) \ |
455 intern = ALLOC(class_name); \ | 277 if (Z_TYPE_P(field) != type) { \ |
456 memset(intern, 0, sizeof(class_name)); \ | 278 zend_error(E_ERROR, "Unexpected type"); \ |
457 init_func(intern TSRMLS_CC); | 279 } |
458 | |
459 // String argument. | |
460 #define STR(str) (str), strlen(str) | |
461 | |
462 // Zend Value | |
463 #define Z_OBJ_P(zval_p) \ | |
464 ((zend_object*)(EG(objects_store) \ | |
465 .object_buckets[Z_OBJ_HANDLE_P(zval_p)] \ | |
466 .bucket.obj.object)) | |
467 | 280 |
468 #endif // __GOOGLE_PROTOBUF_PHP_PROTOBUF_H__ | 281 #endif // __GOOGLE_PROTOBUF_PHP_PROTOBUF_H__ |
OLD | NEW |