1#ifndef __GOOGLE_PROTOBUF_PHP_PROTOBUF_H__
2#define __GOOGLE_PROTOBUF_PHP_PROTOBUF_H__
3
4#include <php.h>
5
6#include "upb.h"
7
8#define PHP_PROTOBUF_EXTNAME "protobuf"
9#define PHP_PROTOBUF_VERSION "0.01"
10
11// Forward decls.
12struct DescriptorPool;
13struct Descriptor;
14struct FieldDescriptor;
15struct EnumDescriptor;
16struct MessageLayout;
17struct MessageField;
18struct MessageHeader;
19struct MessageBuilderContext;
20struct EnumBuilderContext;
21
22typedef struct DescriptorPool DescriptorPool;
23typedef struct Descriptor Descriptor;
24typedef struct FieldDescriptor FieldDescriptor;
25typedef struct OneofDescriptor OneofDescriptor;
26typedef struct EnumDescriptor EnumDescriptor;
27typedef struct MessageLayout MessageLayout;
28typedef struct MessageField MessageField;
29typedef struct MessageHeader MessageHeader;
30typedef struct MessageBuilderContext MessageBuilderContext;
31typedef struct OneofBuilderContext OneofBuilderContext;
32typedef struct EnumBuilderContext EnumBuilderContext;
33
34extern zend_class_entry* builder_type;
35extern zend_class_entry* descriptor_type;
36extern zend_class_entry* message_builder_context_type;
37
38extern DescriptorPool* generated_pool;  // The actual generated pool
39
40ZEND_BEGIN_MODULE_GLOBALS(protobuf)
41  zval* generated_pool;
42  zend_object_handlers* message_handlers;
43  HashTable upb_def_to_php_obj_map;
44ZEND_END_MODULE_GLOBALS(protobuf)
45
46ZEND_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
53
54// -----------------------------------------------------------------------------
55// PHP functions and global variables.
56// -----------------------------------------------------------------------------
57
58PHP_MINIT_FUNCTION(protobuf);
59
60// -----------------------------------------------------------------------------
61// PHP class structure.
62// -----------------------------------------------------------------------------
63
64struct DescriptorPool {
65  zend_object std;
66  upb_symtab* symtab;
67  HashTable* pending_list;
68};
69
70struct Descriptor {
71  zend_object std;
72  const upb_msgdef* msgdef;
73  MessageLayout* layout;
74  // zval* klass;  // begins as NULL
75  // const upb_handlers* fill_handlers;
76  // const upb_pbdecodermethod* fill_method;
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;
83};
84
85struct FieldDescriptor {
86  zend_object std;
87  const upb_fielddef* fielddef;
88};
89
90struct OneofDescriptor {
91  zend_object std;
92  const upb_oneofdef* oneofdef;
93};
94
95struct EnumDescriptor {
96  zend_object std;
97  const upb_enumdef* enumdef;
98  // zval* module;  // begins as NULL
99};
100
101// -----------------------------------------------------------------------------
102// Native slot storage abstraction.
103// -----------------------------------------------------------------------------
104
105#define NATIVE_SLOT_MAX_SIZE sizeof(uint64_t)
106
107size_t native_slot_size(upb_fieldtype_t type);
108
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).
119bool is_map_field(const upb_fielddef* field);
120const upb_fielddef* map_field_key(const upb_fielddef* field);
121const upb_fielddef* map_field_value(const upb_fielddef* field);
122
123// These operate on a map-entry msgdef.
124const upb_fielddef* map_entry_key(const upb_msgdef* msgdef);
125const upb_fielddef* map_entry_value(const upb_msgdef* msgdef);
126
127// -----------------------------------------------------------------------------
128// Message layout / storage.
129// -----------------------------------------------------------------------------
130
131#define MESSAGE_FIELD_NO_CASE ((size_t)-1)
132
133struct MessageField {
134  size_t offset;
135  size_t case_offset;  // for oneofs, a uint32. Else, MESSAGE_FIELD_NO_CASE.
136};
137
138struct MessageLayout {
139  const upb_msgdef* msgdef;
140  MessageField* fields;
141  size_t size;
142};
143
144void layout_init(MessageLayout* layout, void* storage);
145zval* layout_get(MessageLayout* layout, const void* storage,
146                 const upb_fielddef* field TSRMLS_DC);
147MessageLayout* create_layout(const upb_msgdef* msgdef);
148void free_layout(MessageLayout* layout);
149zval* native_slot_get(upb_fieldtype_t type, /*VALUE type_class,*/
150                      const void* memory TSRMLS_DC);
151
152// -----------------------------------------------------------------------------
153// Message class creation.
154// -----------------------------------------------------------------------------
155
156struct MessageHeader {
157  zend_object std;
158  Descriptor* descriptor;  // kept alive by self.class.descriptor reference.
159                           // Data comes after this.
160};
161
162struct MessageBuilderContext {
163  zend_object std;
164  zval* descriptor;
165  zval* pool;
166};
167
168struct OneofBuilderContext {
169  zend_object std;
170  // VALUE descriptor;
171  // VALUE builder;
172};
173
174struct EnumBuilderContext {
175  zend_object std;
176  // VALUE enumdesc;
177};
178
179// Forward-declare all of the PHP method implementations.
180
181DescriptorPool* php_to_descriptor_pool(zval* value TSRMLS_DC);
182zend_object_value descriptor_pool_create(zend_class_entry *ce TSRMLS_DC);
183void descriptor_pool_free_c(DescriptorPool* object TSRMLS_DC);
184void descriptor_pool_free(void* object TSRMLS_DC);
185void descriptor_pool_init_c_instance(DescriptorPool* pool TSRMLS_DC);
186PHP_METHOD(DescriptorPool, addMessage);
187PHP_METHOD(DescriptorPool, finalize);
188
189Descriptor* php_to_descriptor(zval* value TSRMLS_DC);
190zend_object_value descriptor_create(zend_class_entry *ce TSRMLS_DC);
191void descriptor_init_c_instance(Descriptor* intern TSRMLS_DC);
192void descriptor_free_c(Descriptor* object TSRMLS_DC);
193void descriptor_free(void* object TSRMLS_DC);
194void descriptor_name_set(Descriptor *desc, const char *name);
195
196MessageBuilderContext* php_to_message_builder_context(zval* value TSRMLS_DC);
197zend_object_value message_builder_context_create(
198    zend_class_entry* ce TSRMLS_DC);
199void message_builder_context_init_c_instance(
200    MessageBuilderContext* intern TSRMLS_DC);
201void message_builder_context_free_c(MessageBuilderContext* object TSRMLS_DC);
202void message_builder_context_free(void* object TSRMLS_DC);
203PHP_METHOD(MessageBuilderContext, optional);
204PHP_METHOD(MessageBuilderContext, finalizeToPool);
205
206PHP_METHOD(Message, encode);
207const zend_class_entry* build_class_from_descriptor(
208    zval* php_descriptor TSRMLS_DC);
209
210PHP_FUNCTION(get_generated_pool);
211
212// -----------------------------------------------------------------------------
213// Global map from upb {msg,enum}defs to wrapper Descriptor/EnumDescriptor
214// instances.
215// ----------------------------------------------------------------------------
216
217void add_def_obj(const void* def, zval* value);
218zval* get_def_obj(const void* def);
219
220// -----------------------------------------------------------------------------
221// Utilities.
222// -----------------------------------------------------------------------------
223
224// PHP Array utils.
225#define Z_ARRVAL_SIZE_P(zval_p) zend_hash_num_elements(Z_ARRVAL_P(zval_p))
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
228
229#define DEFINE_PHP_OBJECT(class_name, class_name_lower, name) \
230  do {                                                        \
231    zval* name;                                               \
232    MAKE_STD_ZVAL(name);                                      \
233    object_init_ex(name, class_name_lower##_type);            \
234  } while (0)
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
260void 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
269// Memory management
270
271#define ALLOC(class_name) (class_name*) emalloc(sizeof(class_name))
272#define ALLOC_N(class_name, n) (class_name*) emalloc(sizeof(class_name) * n)
273#define FREE(object) efree(object)
274
275// Type Checking
276#define CHECK_TYPE(field, type)             \
277  if (Z_TYPE_P(field) != type) {            \
278    zend_error(E_ERROR, "Unexpected type"); \
279  }
280
281#endif  // __GOOGLE_PROTOBUF_PHP_PROTOBUF_H__
282