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 |
1 #ifndef __GOOGLE_PROTOBUF_PHP_PROTOBUF_H__ | 31 #ifndef __GOOGLE_PROTOBUF_PHP_PROTOBUF_H__ |
2 #define __GOOGLE_PROTOBUF_PHP_PROTOBUF_H__ | 32 #define __GOOGLE_PROTOBUF_PHP_PROTOBUF_H__ |
3 | 33 |
4 #include <php.h> | 34 #include <php.h> |
5 | 35 |
| 36 // ubp.h has to be placed after php.h. Othwise, php.h will introduce NDEBUG. |
6 #include "upb.h" | 37 #include "upb.h" |
7 | 38 |
8 #define PHP_PROTOBUF_EXTNAME "protobuf" | 39 #define PHP_PROTOBUF_EXTNAME "protobuf" |
9 #define PHP_PROTOBUF_VERSION "0.01" | 40 #define PHP_PROTOBUF_VERSION "3.1.0a1" |
10 | 41 |
11 // Forward decls. | 42 #define MAX_LENGTH_OF_INT64 20 |
| 43 #define SIZEOF_INT64 8 |
| 44 |
| 45 // ----------------------------------------------------------------------------- |
| 46 // Forward Declaration |
| 47 // ---------------------------------------------------------------------------- |
| 48 |
12 struct DescriptorPool; | 49 struct DescriptorPool; |
13 struct Descriptor; | 50 struct Descriptor; |
| 51 struct EnumDescriptor; |
14 struct FieldDescriptor; | 52 struct FieldDescriptor; |
15 struct EnumDescriptor; | |
16 struct MessageLayout; | |
17 struct MessageField; | 53 struct MessageField; |
18 struct MessageHeader; | 54 struct MessageHeader; |
19 struct MessageBuilderContext; | 55 struct MessageLayout; |
20 struct EnumBuilderContext; | 56 struct RepeatedField; |
| 57 struct RepeatedFieldIter; |
| 58 struct MapField; |
21 | 59 |
22 typedef struct DescriptorPool DescriptorPool; | 60 typedef struct DescriptorPool DescriptorPool; |
23 typedef struct Descriptor Descriptor; | 61 typedef struct Descriptor Descriptor; |
| 62 typedef struct EnumDescriptor EnumDescriptor; |
24 typedef struct FieldDescriptor FieldDescriptor; | 63 typedef struct FieldDescriptor FieldDescriptor; |
25 typedef struct OneofDescriptor OneofDescriptor; | |
26 typedef struct EnumDescriptor EnumDescriptor; | |
27 typedef struct MessageLayout MessageLayout; | |
28 typedef struct MessageField MessageField; | 64 typedef struct MessageField MessageField; |
29 typedef struct MessageHeader MessageHeader; | 65 typedef struct MessageHeader MessageHeader; |
30 typedef struct MessageBuilderContext MessageBuilderContext; | 66 typedef struct MessageLayout MessageLayout; |
31 typedef struct OneofBuilderContext OneofBuilderContext; | 67 typedef struct RepeatedField RepeatedField; |
32 typedef struct EnumBuilderContext EnumBuilderContext; | 68 typedef struct RepeatedFieldIter RepeatedFieldIter; |
| 69 typedef struct MapField MapField; |
33 | 70 |
34 extern zend_class_entry* builder_type; | 71 // ----------------------------------------------------------------------------- |
35 extern zend_class_entry* descriptor_type; | 72 // Globals. |
36 extern zend_class_entry* message_builder_context_type; | 73 // ----------------------------------------------------------------------------- |
37 | |
38 extern DescriptorPool* generated_pool; // The actual generated pool | |
39 | 74 |
40 ZEND_BEGIN_MODULE_GLOBALS(protobuf) | 75 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) | 76 ZEND_END_MODULE_GLOBALS(protobuf) |
45 | 77 |
46 ZEND_DECLARE_MODULE_GLOBALS(protobuf) | 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); |
47 | 88 |
48 #ifdef ZTS | 89 // Global map from upb {msg,enum}defs to wrapper Descriptor/EnumDescriptor |
49 #define PROTOBUF_G(v) TSRMG(protobuf_globals_id, zend_protobuf_globals*, v) | 90 // instances. |
50 #else | 91 void add_def_obj(const void* def, zval* value); |
51 #define PROTOBUF_G(v) (protobuf_globals.v) | 92 zval* get_def_obj(const void* def); |
52 #endif | 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; |
53 | 101 |
54 // ----------------------------------------------------------------------------- | 102 // ----------------------------------------------------------------------------- |
55 // PHP functions and global variables. | 103 // Descriptor. |
56 // ----------------------------------------------------------------------------- | |
57 | |
58 PHP_MINIT_FUNCTION(protobuf); | |
59 | |
60 // ----------------------------------------------------------------------------- | |
61 // PHP class structure. | |
62 // ----------------------------------------------------------------------------- | 104 // ----------------------------------------------------------------------------- |
63 | 105 |
64 struct DescriptorPool { | 106 struct DescriptorPool { |
65 zend_object std; | 107 zend_object std; |
66 upb_symtab* symtab; | 108 upb_symtab* symtab; |
67 HashTable* pending_list; | 109 HashTable* pending_list; |
68 }; | 110 }; |
69 | 111 |
| 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 |
70 struct Descriptor { | 118 struct Descriptor { |
71 zend_object std; | 119 zend_object std; |
72 const upb_msgdef* msgdef; | 120 const upb_msgdef* msgdef; |
73 MessageLayout* layout; | 121 MessageLayout* layout; |
74 // zval* klass; // begins as NULL | 122 zend_class_entry* klass; // begins as NULL |
75 // const upb_handlers* fill_handlers; | 123 const upb_handlers* fill_handlers; |
76 // const upb_pbdecodermethod* fill_method; | 124 const upb_pbdecodermethod* fill_method; |
77 const upb_handlers* pb_serialize_handlers; | 125 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; | |
83 }; | 126 }; |
84 | 127 |
| 128 extern zend_class_entry* descriptor_type; |
| 129 |
| 130 void descriptor_name_set(Descriptor *desc, const char *name); |
| 131 |
85 struct FieldDescriptor { | 132 struct FieldDescriptor { |
86 zend_object std; | 133 zend_object std; |
87 const upb_fielddef* fielddef; | 134 const upb_fielddef* fielddef; |
88 }; | 135 }; |
89 | 136 |
90 struct OneofDescriptor { | |
91 zend_object std; | |
92 const upb_oneofdef* oneofdef; | |
93 }; | |
94 | |
95 struct EnumDescriptor { | 137 struct EnumDescriptor { |
96 zend_object std; | 138 zend_object std; |
97 const upb_enumdef* enumdef; | 139 const upb_enumdef* enumdef; |
98 // zval* module; // begins as NULL | 140 zend_class_entry* klass; // begins as NULL |
| 141 // VALUE module; // begins as nil |
99 }; | 142 }; |
100 | 143 |
| 144 extern zend_class_entry* enum_descriptor_type; |
| 145 |
101 // ----------------------------------------------------------------------------- | 146 // ----------------------------------------------------------------------------- |
102 // Native slot storage abstraction. | 147 // Message class creation. |
103 // ----------------------------------------------------------------------------- | 148 // ----------------------------------------------------------------------------- |
104 | 149 |
105 #define NATIVE_SLOT_MAX_SIZE sizeof(uint64_t) | 150 void* message_data(void* msg); |
106 | 151 |
107 size_t native_slot_size(upb_fieldtype_t type); | 152 // Build PHP class for given descriptor. Instead of building from scratch, this |
| 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); |
108 | 156 |
109 #define MAP_KEY_FIELD 1 | 157 extern zend_object_handlers* message_handlers; |
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); | |
126 | 158 |
127 // ----------------------------------------------------------------------------- | 159 // ----------------------------------------------------------------------------- |
128 // Message layout / storage. | 160 // Message layout / storage. |
129 // ----------------------------------------------------------------------------- | 161 // ----------------------------------------------------------------------------- |
130 | 162 |
| 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 |
131 #define MESSAGE_FIELD_NO_CASE ((size_t)-1) | 211 #define MESSAGE_FIELD_NO_CASE ((size_t)-1) |
132 | 212 |
133 struct MessageField { | 213 struct MessageField { |
134 size_t offset; | 214 size_t offset; |
135 size_t case_offset; // for oneofs, a uint32. Else, MESSAGE_FIELD_NO_CASE. | 215 int cache_index; // Each field except oneof field has a zval cache to avoid |
| 216 // multiple creation when being accessed. |
| 217 size_t case_offset; // for oneofs, a uint32. Else, MESSAGE_FIELD_NO_CASE. |
136 }; | 218 }; |
137 | 219 |
138 struct MessageLayout { | 220 struct MessageLayout { |
139 const upb_msgdef* msgdef; | 221 const upb_msgdef* msgdef; |
140 MessageField* fields; | 222 MessageField* fields; |
141 size_t size; | 223 size_t size; |
142 }; | 224 }; |
143 | 225 |
144 void layout_init(MessageLayout* layout, void* storage); | 226 struct MessageHeader { |
| 227 zend_object std; // Stores properties table and class info of PHP instance. |
| 228 // This is needed for MessageHeader to be accessed via PHP. |
| 229 Descriptor* descriptor; // Kept alive by self.class.descriptor reference. |
| 230 // The real message data is appended after MessageHeader. |
| 231 }; |
| 232 |
| 233 MessageLayout* create_layout(const upb_msgdef* msgdef); |
| 234 void layout_init(MessageLayout* layout, void* storage, |
| 235 zval** properties_table TSRMLS_DC); |
145 zval* layout_get(MessageLayout* layout, const void* storage, | 236 zval* layout_get(MessageLayout* layout, const void* storage, |
146 const upb_fielddef* field TSRMLS_DC); | 237 const upb_fielddef* field, zval** cache TSRMLS_DC); |
147 MessageLayout* create_layout(const upb_msgdef* msgdef); | 238 void layout_set(MessageLayout* layout, MessageHeader* header, |
| 239 const upb_fielddef* field, zval* val TSRMLS_DC); |
148 void free_layout(MessageLayout* layout); | 240 void free_layout(MessageLayout* layout); |
149 zval* native_slot_get(upb_fieldtype_t type, /*VALUE type_class,*/ | 241 |
150 const void* memory TSRMLS_DC); | 242 PHP_METHOD(Message, readOneof); |
151 | 243 PHP_METHOD(Message, writeOneof); |
152 // ----------------------------------------------------------------------------- | 244 PHP_METHOD(Message, __construct); |
153 // Message class creation. | 245 |
154 // ----------------------------------------------------------------------------- | 246 // ----------------------------------------------------------------------------- |
155 | 247 // Encode / Decode. |
156 struct MessageHeader { | 248 // ----------------------------------------------------------------------------- |
157 zend_object std; | 249 |
158 Descriptor* descriptor; // kept alive by self.class.descriptor reference. | 250 // Maximum depth allowed during encoding, to avoid stack overflows due to |
159 // Data comes after this. | 251 // cycles. |
160 }; | 252 #define ENCODE_MAX_NESTING 63 |
161 | 253 |
162 struct MessageBuilderContext { | 254 // Constructs the upb decoder method for parsing messages of this type. |
163 zend_object std; | 255 // This is called from the message class creation code. |
164 zval* descriptor; | 256 const upb_pbdecodermethod *new_fillmsg_decodermethod(Descriptor *desc, |
165 zval* pool; | 257 const void *owner); |
166 }; | |
167 | |
168 struct OneofBuilderContext { | |
169 zend_object std; | |
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 | 258 |
206 PHP_METHOD(Message, encode); | 259 PHP_METHOD(Message, encode); |
207 const zend_class_entry* build_class_from_descriptor( | 260 PHP_METHOD(Message, decode); |
208 zval* php_descriptor TSRMLS_DC); | 261 |
209 | 262 // ----------------------------------------------------------------------------- |
210 PHP_FUNCTION(get_generated_pool); | 263 // Type check / conversion. |
211 | 264 // ----------------------------------------------------------------------------- |
212 // ----------------------------------------------------------------------------- | 265 |
213 // Global map from upb {msg,enum}defs to wrapper Descriptor/EnumDescriptor | 266 bool protobuf_convert_to_int32(zval* from, int32_t* to); |
214 // instances. | 267 bool protobuf_convert_to_uint32(zval* from, uint32_t* to); |
215 // ---------------------------------------------------------------------------- | 268 bool protobuf_convert_to_int64(zval* from, int64_t* to); |
216 | 269 bool protobuf_convert_to_uint64(zval* from, uint64_t* to); |
217 void add_def_obj(const void* def, zval* value); | 270 bool protobuf_convert_to_float(zval* from, float* to); |
218 zval* get_def_obj(const void* def); | 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); |
219 | 429 |
220 // ----------------------------------------------------------------------------- | 430 // ----------------------------------------------------------------------------- |
221 // Utilities. | 431 // Utilities. |
222 // ----------------------------------------------------------------------------- | 432 // ----------------------------------------------------------------------------- |
223 | 433 |
224 // PHP Array utils. | 434 // PHP <-> C conversion. |
225 #define Z_ARRVAL_SIZE_P(zval_p) zend_hash_num_elements(Z_ARRVAL_P(zval_p)) | 435 #define UNBOX(class_name, val) \ |
226 #define Z_ARRVAL_BEGIN_P(zval_p) Z_ARRVAL_P(zval_p)->pListHead | 436 (class_name*)zend_object_store_get_object(val TSRMLS_CC); |
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) | |
268 | 445 |
269 // Memory management | 446 // Memory management |
270 | |
271 #define ALLOC(class_name) (class_name*) emalloc(sizeof(class_name)) | 447 #define ALLOC(class_name) (class_name*) emalloc(sizeof(class_name)) |
| 448 #define PEMALLOC(class_name) (class_name*) pemalloc(sizeof(class_name), 1) |
272 #define ALLOC_N(class_name, n) (class_name*) emalloc(sizeof(class_name) * n) | 449 #define ALLOC_N(class_name, n) (class_name*) emalloc(sizeof(class_name) * n) |
273 #define FREE(object) efree(object) | 450 #define FREE(object) efree(object) |
274 | 451 #define PEFREE(object) pefree(object, 1) |
275 // Type Checking | 452 |
276 #define CHECK_TYPE(field, type) \ | 453 // Create PHP internal instance. |
277 if (Z_TYPE_P(field) != type) { \ | 454 #define CREATE(class_name, intern, init_func) \ |
278 zend_error(E_ERROR, "Unexpected type"); \ | 455 intern = ALLOC(class_name); \ |
279 } | 456 memset(intern, 0, sizeof(class_name)); \ |
| 457 init_func(intern TSRMLS_CC); |
| 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)) |
280 | 467 |
281 #endif // __GOOGLE_PROTOBUF_PHP_PROTOBUF_H__ | 468 #endif // __GOOGLE_PROTOBUF_PHP_PROTOBUF_H__ |
OLD | NEW |