Home | History | Annotate | Download | only in protobuf
      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.
     12 struct DescriptorPool;
     13 struct Descriptor;
     14 struct FieldDescriptor;
     15 struct EnumDescriptor;
     16 struct MessageLayout;
     17 struct MessageField;
     18 struct MessageHeader;
     19 struct MessageBuilderContext;
     20 struct EnumBuilderContext;
     21 
     22 typedef struct DescriptorPool DescriptorPool;
     23 typedef struct Descriptor Descriptor;
     24 typedef struct FieldDescriptor FieldDescriptor;
     25 typedef struct OneofDescriptor OneofDescriptor;
     26 typedef struct EnumDescriptor EnumDescriptor;
     27 typedef struct MessageLayout MessageLayout;
     28 typedef struct MessageField MessageField;
     29 typedef struct MessageHeader MessageHeader;
     30 typedef struct MessageBuilderContext MessageBuilderContext;
     31 typedef struct OneofBuilderContext OneofBuilderContext;
     32 typedef struct EnumBuilderContext EnumBuilderContext;
     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
     53 
     54 // -----------------------------------------------------------------------------
     55 // PHP functions and global variables.
     56 // -----------------------------------------------------------------------------
     57 
     58 PHP_MINIT_FUNCTION(protobuf);
     59 
     60 // -----------------------------------------------------------------------------
     61 // PHP class structure.
     62 // -----------------------------------------------------------------------------
     63 
     64 struct DescriptorPool {
     65   zend_object std;
     66   upb_symtab* symtab;
     67   HashTable* pending_list;
     68 };
     69 
     70 struct 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 
     85 struct FieldDescriptor {
     86   zend_object std;
     87   const upb_fielddef* fielddef;
     88 };
     89 
     90 struct OneofDescriptor {
     91   zend_object std;
     92   const upb_oneofdef* oneofdef;
     93 };
     94 
     95 struct 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 
    107 size_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).
    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 
    127 // -----------------------------------------------------------------------------
    128 // Message layout / storage.
    129 // -----------------------------------------------------------------------------
    130 
    131 #define MESSAGE_FIELD_NO_CASE ((size_t)-1)
    132 
    133 struct MessageField {
    134   size_t offset;
    135   size_t case_offset;  // for oneofs, a uint32. Else, MESSAGE_FIELD_NO_CASE.
    136 };
    137 
    138 struct MessageLayout {
    139   const upb_msgdef* msgdef;
    140   MessageField* fields;
    141   size_t size;
    142 };
    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 
    156 struct MessageHeader {
    157   zend_object std;
    158   Descriptor* descriptor;  // kept alive by self.class.descriptor reference.
    159                            // Data comes after this.
    160 };
    161 
    162 struct MessageBuilderContext {
    163   zend_object std;
    164   zval* descriptor;
    165   zval* pool;
    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 
    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);
    211 
    212 // -----------------------------------------------------------------------------
    213 // Global map from upb {msg,enum}defs to wrapper Descriptor/EnumDescriptor
    214 // instances.
    215 // ----------------------------------------------------------------------------
    216 
    217 void add_def_obj(const void* def, zval* value);
    218 zval* 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 
    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 
    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