|
@@ -57,6 +57,31 @@ size_t native_slot_size(upb_fieldtype_t type) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static bool native_slot_is_default(upb_fieldtype_t type, void* memory) {
|
|
|
+ switch (type) {
|
|
|
+#define CASE_TYPE(upb_type, c_type) \
|
|
|
+ case UPB_TYPE_##upb_type: { \
|
|
|
+ return DEREF(memory, c_type) == 0; \
|
|
|
+ }
|
|
|
+ CASE_TYPE(INT32, int32_t )
|
|
|
+ CASE_TYPE(UINT32, uint32_t)
|
|
|
+ CASE_TYPE(ENUM, int32_t )
|
|
|
+ CASE_TYPE(INT64, int64_t )
|
|
|
+ CASE_TYPE(UINT64, uint64_t)
|
|
|
+ CASE_TYPE(FLOAT, float )
|
|
|
+ CASE_TYPE(DOUBLE, double )
|
|
|
+ CASE_TYPE(BOOL, int8_t )
|
|
|
+
|
|
|
+#undef CASE_TYPE
|
|
|
+ case UPB_TYPE_STRING:
|
|
|
+ case UPB_TYPE_BYTES:
|
|
|
+ return Z_STRLEN_PP(DEREF(memory, zval**)) == 0;
|
|
|
+ case UPB_TYPE_MESSAGE:
|
|
|
+ return Z_TYPE_PP(DEREF(memory, zval**)) == IS_NULL;
|
|
|
+ default: return false;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
bool native_slot_set(upb_fieldtype_t type, const zend_class_entry* klass,
|
|
|
void* memory, zval* value TSRMLS_DC) {
|
|
|
switch (type) {
|
|
@@ -499,7 +524,6 @@ void layout_init(MessageLayout* layout, void* storage,
|
|
|
repeated_field_create_with_type(repeated_field_type, field,
|
|
|
property_ptr TSRMLS_CC);
|
|
|
DEREF(memory, zval**) = property_ptr;
|
|
|
- property_ptr = NULL;
|
|
|
} else {
|
|
|
native_slot_init(upb_fielddef_type(field), memory, property_ptr);
|
|
|
}
|
|
@@ -601,6 +625,196 @@ void layout_set(MessageLayout* layout, MessageHeader* header,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+void layout_merge(MessageLayout* layout, MessageHeader* from,
|
|
|
+ MessageHeader* to TSRMLS_DC) {
|
|
|
+ int i, j;
|
|
|
+ upb_msg_field_iter it;
|
|
|
+
|
|
|
+ for (upb_msg_field_begin(&it, layout->msgdef), i = 0; !upb_msg_field_done(&it);
|
|
|
+ upb_msg_field_next(&it), i++) {
|
|
|
+ const upb_fielddef* field = upb_msg_iter_field(&it);
|
|
|
+
|
|
|
+ void* to_memory = slot_memory(layout, message_data(to), field);
|
|
|
+ void* from_memory = slot_memory(layout, message_data(from), field);
|
|
|
+
|
|
|
+ if (upb_fielddef_containingoneof(field)) {
|
|
|
+ uint32_t oneof_case_offset =
|
|
|
+ layout->fields[upb_fielddef_index(field)].case_offset +
|
|
|
+ sizeof(MessageHeader);
|
|
|
+ // For a oneof, check that this field is actually present -- skip all the
|
|
|
+ // below if not.
|
|
|
+ if (DEREF(((uint8_t*)from + oneof_case_offset), uint32_t) !=
|
|
|
+ upb_fielddef_number(field)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ uint32_t* from_oneof_case = slot_oneof_case(layout, message_data(from), field);
|
|
|
+ uint32_t* to_oneof_case = slot_oneof_case(layout, message_data(to), field);
|
|
|
+
|
|
|
+ // For non-singular fields, the related memory needs to point to the
|
|
|
+ // actual zval in properties table first.
|
|
|
+ switch (upb_fielddef_type(field)) {
|
|
|
+ case UPB_TYPE_MESSAGE:
|
|
|
+ case UPB_TYPE_STRING:
|
|
|
+ case UPB_TYPE_BYTES: {
|
|
|
+ int property_cache_index =
|
|
|
+ layout->fields[upb_fielddef_index(field)].cache_index;
|
|
|
+ DEREF(to_memory, zval**) =
|
|
|
+ &(to->std.properties_table)[property_cache_index];
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ *to_oneof_case = *from_oneof_case;
|
|
|
+
|
|
|
+ // Otherwise, fall through to the appropriate singular-field handler
|
|
|
+ // below.
|
|
|
+ }
|
|
|
+
|
|
|
+ if (is_map_field(field)) {
|
|
|
+ int size, key_length, value_length;
|
|
|
+ MapIter map_it;
|
|
|
+
|
|
|
+ zval* to_map_php = *DEREF(to_memory, zval**);
|
|
|
+ zval* from_map_php = *DEREF(from_memory, zval**);
|
|
|
+ Map* to_map = zend_object_store_get_object(to_map_php TSRMLS_CC);
|
|
|
+ Map* from_map = zend_object_store_get_object(from_map_php TSRMLS_CC);
|
|
|
+
|
|
|
+ size = upb_strtable_count(&from_map->table);
|
|
|
+ if (size == 0) continue;
|
|
|
+
|
|
|
+ for (map_begin(from_map_php, &map_it TSRMLS_CC); !map_done(&map_it);
|
|
|
+ map_next(&map_it)) {
|
|
|
+ const char* key = map_iter_key(&map_it, &key_length);
|
|
|
+ upb_value value = map_iter_value(&map_it, &value_length);
|
|
|
+ void* mem = upb_value_memory(&value);
|
|
|
+ switch (to_map->value_type) {
|
|
|
+ case UPB_TYPE_MESSAGE: {
|
|
|
+ zval* new_message;
|
|
|
+ message_create_with_type(to_map->msg_ce, &new_message TSRMLS_CC);
|
|
|
+ Z_ADDREF_P(new_message);
|
|
|
+
|
|
|
+ zval* subdesc_php = get_ce_obj(to_map->msg_ce);
|
|
|
+ Descriptor* subdesc =
|
|
|
+ zend_object_store_get_object(subdesc_php TSRMLS_CC);
|
|
|
+ MessageHeader* sub_from =
|
|
|
+ (MessageHeader*)zend_object_store_get_object(DEREF(mem, zval*)
|
|
|
+ TSRMLS_CC);
|
|
|
+ MessageHeader* sub_to =
|
|
|
+ (MessageHeader*)zend_object_store_get_object(
|
|
|
+ new_message TSRMLS_CC);
|
|
|
+ layout_merge(subdesc->layout, sub_from, sub_to TSRMLS_CC);
|
|
|
+ DEREF(mem, zval*) = new_message;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case UPB_TYPE_BYTES:
|
|
|
+ case UPB_TYPE_STRING:
|
|
|
+ Z_ADDREF_PP((zval**)mem);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ map_index_set(to_map, key, key_length, value);
|
|
|
+ }
|
|
|
+
|
|
|
+ } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
|
|
|
+ zval* to_array_php = *DEREF(to_memory, zval**);
|
|
|
+ zval* from_array_php = *DEREF(from_memory, zval**);
|
|
|
+ RepeatedField* to_array =
|
|
|
+ zend_object_store_get_object(to_array_php TSRMLS_CC);
|
|
|
+ RepeatedField* from_array =
|
|
|
+ zend_object_store_get_object(from_array_php TSRMLS_CC);
|
|
|
+
|
|
|
+ int size = zend_hash_num_elements(HASH_OF(from_array->array));
|
|
|
+ if (size > 0) {
|
|
|
+ for (j = 0; j < size; j++) {
|
|
|
+ void* memory = NULL;
|
|
|
+ zend_hash_index_find(HASH_OF(from_array->array), j, (void**)&memory);
|
|
|
+ switch (to_array->type) {
|
|
|
+ case UPB_TYPE_STRING:
|
|
|
+ case UPB_TYPE_BYTES: {
|
|
|
+ zval* str;
|
|
|
+ MAKE_STD_ZVAL(str);
|
|
|
+ ZVAL_STRINGL(str, Z_STRVAL_PP((zval**)memory),
|
|
|
+ Z_STRLEN_PP((zval**)memory), 1);
|
|
|
+ memory = &str;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case UPB_TYPE_MESSAGE: {
|
|
|
+ zval* new_message;
|
|
|
+ message_create_with_type(from_array->msg_ce, &new_message TSRMLS_CC);
|
|
|
+ Z_ADDREF_P(new_message);
|
|
|
+
|
|
|
+ zval* subdesc_php = get_ce_obj(from_array->msg_ce);
|
|
|
+ Descriptor* subdesc =
|
|
|
+ zend_object_store_get_object(subdesc_php TSRMLS_CC);
|
|
|
+ MessageHeader* sub_from =
|
|
|
+ (MessageHeader*)zend_object_store_get_object(
|
|
|
+ DEREF(memory, zval*) TSRMLS_CC);
|
|
|
+ MessageHeader* sub_to =
|
|
|
+ (MessageHeader*)zend_object_store_get_object(
|
|
|
+ new_message TSRMLS_CC);
|
|
|
+ layout_merge(subdesc->layout, sub_from, sub_to TSRMLS_CC);
|
|
|
+
|
|
|
+ memory = &new_message;
|
|
|
+ }
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ repeated_field_push_native(to_array, memory TSRMLS_CC);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ upb_fieldtype_t type = upb_fielddef_type(field);
|
|
|
+ zend_class_entry *ce = NULL;
|
|
|
+ if (!native_slot_is_default(type, from_memory)) {
|
|
|
+ switch (type) {
|
|
|
+#define CASE_TYPE(upb_type, c_type) \
|
|
|
+ case UPB_TYPE_##upb_type: { \
|
|
|
+ DEREF(to_memory, c_type) = DEREF(from_memory, c_type); \
|
|
|
+ break; \
|
|
|
+ }
|
|
|
+ CASE_TYPE(INT32, int32_t)
|
|
|
+ CASE_TYPE(UINT32, uint32_t)
|
|
|
+ CASE_TYPE(ENUM, int32_t)
|
|
|
+ CASE_TYPE(INT64, int64_t)
|
|
|
+ CASE_TYPE(UINT64, uint64_t)
|
|
|
+ CASE_TYPE(FLOAT, float)
|
|
|
+ CASE_TYPE(DOUBLE, double)
|
|
|
+ CASE_TYPE(BOOL, int8_t)
|
|
|
+
|
|
|
+#undef CASE_TYPE
|
|
|
+ case UPB_TYPE_STRING:
|
|
|
+ case UPB_TYPE_BYTES:
|
|
|
+ native_slot_set(type, NULL, value_memory(field, to_memory),
|
|
|
+ *DEREF(from_memory, zval**) TSRMLS_CC);
|
|
|
+ break;
|
|
|
+ case UPB_TYPE_MESSAGE: {
|
|
|
+ const upb_msgdef* msg = upb_fielddef_msgsubdef(field);
|
|
|
+ zval* desc_php = get_def_obj(msg);
|
|
|
+ Descriptor* desc = zend_object_store_get_object(desc_php TSRMLS_CC);
|
|
|
+ ce = desc->klass;
|
|
|
+ if (native_slot_is_default(type, to_memory)) {
|
|
|
+ zval* new_message = NULL;
|
|
|
+ message_create_with_type(ce, &new_message TSRMLS_CC);
|
|
|
+ native_slot_set(type, ce, value_memory(field, to_memory),
|
|
|
+ new_message TSRMLS_CC);
|
|
|
+ }
|
|
|
+ MessageHeader* sub_from =
|
|
|
+ (MessageHeader*)zend_object_store_get_object(
|
|
|
+ *DEREF(from_memory, zval**) TSRMLS_CC);
|
|
|
+ MessageHeader* sub_to =
|
|
|
+ (MessageHeader*)zend_object_store_get_object(
|
|
|
+ *DEREF(to_memory, zval**) TSRMLS_CC);
|
|
|
+ layout_merge(desc->layout, sub_from, sub_to TSRMLS_CC);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
const char* layout_get_oneof_case(MessageLayout* layout, const void* storage,
|
|
|
const upb_oneofdef* oneof TSRMLS_DC) {
|
|
|
upb_oneof_iter i;
|