From a323f1e65da2c512f971a2edf1918a0cca340015 Mon Sep 17 00:00:00 2001 From: Paul Yang Date: Fri, 27 Jan 2017 13:17:54 -0800 Subject: Oneof accessor should return the field name that is actually set. (#2631) --- php/ext/google/protobuf/message.c | 20 ++++++++++++++++++++ php/ext/google/protobuf/protobuf.h | 3 +++ php/ext/google/protobuf/storage.c | 21 ++++++++++++++++++++- 3 files changed, 43 insertions(+), 1 deletion(-) (limited to 'php/ext') diff --git a/php/ext/google/protobuf/message.c b/php/ext/google/protobuf/message.c index 16e397f5..f5a9499d 100644 --- a/php/ext/google/protobuf/message.c +++ b/php/ext/google/protobuf/message.c @@ -41,6 +41,7 @@ static zend_function_entry message_methods[] = { PHP_ME(Message, decode, NULL, ZEND_ACC_PUBLIC) PHP_ME(Message, readOneof, NULL, ZEND_ACC_PROTECTED) PHP_ME(Message, writeOneof, NULL, ZEND_ACC_PROTECTED) + PHP_ME(Message, whichOneof, NULL, ZEND_ACC_PROTECTED) PHP_ME(Message, __construct, NULL, ZEND_ACC_PROTECTED) {NULL, NULL, NULL} }; @@ -258,3 +259,22 @@ PHP_METHOD(Message, writeOneof) { layout_set(msg->descriptor->layout, msg, field, value TSRMLS_CC); } + +PHP_METHOD(Message, whichOneof) { + char* oneof_name; + int length; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &oneof_name, + &length) == FAILURE) { + return; + } + + MessageHeader* msg = + (MessageHeader*)zend_object_store_get_object(getThis() TSRMLS_CC); + + const upb_oneofdef* oneof = + upb_msgdef_ntoo(msg->descriptor->msgdef, oneof_name, length); + const char* oneof_case_name = layout_get_oneof_case( + msg->descriptor->layout, message_data(msg), oneof TSRMLS_CC); + RETURN_STRING(oneof_case_name, 1); +} diff --git a/php/ext/google/protobuf/protobuf.h b/php/ext/google/protobuf/protobuf.h index 8022a9aa..bd01005b 100644 --- a/php/ext/google/protobuf/protobuf.h +++ b/php/ext/google/protobuf/protobuf.h @@ -237,10 +237,13 @@ zval* layout_get(MessageLayout* layout, const void* storage, const upb_fielddef* field, zval** cache TSRMLS_DC); void layout_set(MessageLayout* layout, MessageHeader* header, const upb_fielddef* field, zval* val TSRMLS_DC); +const char* layout_get_oneof_case(MessageLayout* layout, const void* storage, + const upb_oneofdef* oneof TSRMLS_DC); void free_layout(MessageLayout* layout); PHP_METHOD(Message, readOneof); PHP_METHOD(Message, writeOneof); +PHP_METHOD(Message, whichOneof); PHP_METHOD(Message, __construct); // ----------------------------------------------------------------------------- diff --git a/php/ext/google/protobuf/storage.c b/php/ext/google/protobuf/storage.c index 8a2b3a22..42bcce59 100644 --- a/php/ext/google/protobuf/storage.c +++ b/php/ext/google/protobuf/storage.c @@ -527,7 +527,7 @@ zval* layout_get(MessageLayout* layout, const void* storage, } void layout_set(MessageLayout* layout, MessageHeader* header, - const upb_fielddef* field, zval* val TSRMLS_DC) { + const upb_fielddef* field, zval* val TSRMLS_DC) { void* storage = message_data(header); void* memory = slot_memory(layout, storage, field); uint32_t* oneof_case = slot_oneof_case(layout, storage, field); @@ -582,3 +582,22 @@ void layout_set(MessageLayout* layout, MessageHeader* header, native_slot_set(type, ce, value_memory(field, memory), val TSRMLS_CC); } } + +const char* layout_get_oneof_case(MessageLayout* layout, const void* storage, + const upb_oneofdef* oneof TSRMLS_DC) { + upb_oneof_iter i; + const upb_fielddef* first_field; + + // Oneof is guaranteed to have at least one field. Get the first field. + for(upb_oneof_begin(&i, oneof); !upb_oneof_done(&i); upb_oneof_next(&i)) { + first_field = upb_oneof_iter_field(&i); + break; + } + + uint32_t* oneof_case = slot_oneof_case(layout, storage, first_field); + if (*oneof_case == 0) { + return ""; + } + const upb_fielddef* field = upb_oneofdef_itof(oneof, *oneof_case); + return upb_fielddef_name(field); +} -- cgit v1.2.3