From 23adfeb00327fbdccacc99806acb1a9a073bd8e0 Mon Sep 17 00:00:00 2001 From: Paul Yang Date: Thu, 26 Oct 2017 14:41:43 -0700 Subject: Reserve unknown in Ruby (#3763) * Reserve unknown in ruby * Revert ruby tests. Wait for cpp impl for conformance test * Add conformance test for preserving unknown * Add unknown field conformance test to csharp failure list. * Fix comments * Fix comment * Fix comments * Fix typo * Use stringsink_string directly * Mark hd unused * Remove unused encodeunknown_handlerfunc --- ruby/ext/google/protobuf_c/encode_decode.c | 131 ++++++++++++++++------------- 1 file changed, 72 insertions(+), 59 deletions(-) (limited to 'ruby/ext/google/protobuf_c/encode_decode.c') diff --git a/ruby/ext/google/protobuf_c/encode_decode.c b/ruby/ext/google/protobuf_c/encode_decode.c index edbbe6a5..d1b6e89e 100644 --- a/ruby/ext/google/protobuf_c/encode_decode.c +++ b/ruby/ext/google/protobuf_c/encode_decode.c @@ -44,6 +44,56 @@ VALUE noleak_rb_str_cat(VALUE rb_str, const char *str, long len) { return rb_str; } +// The code below also comes from upb's prototype Ruby binding, developed by +// haberman@. + +/* stringsink *****************************************************************/ + +static void *stringsink_start(void *_sink, const void *hd, size_t size_hint) { + stringsink *sink = _sink; + sink->len = 0; + return sink; +} + +static size_t stringsink_string(void *_sink, const void *hd, const char *ptr, + size_t len, const upb_bufhandle *handle) { + stringsink *sink = _sink; + size_t new_size = sink->size; + + UPB_UNUSED(hd); + UPB_UNUSED(handle); + + while (sink->len + len > new_size) { + new_size *= 2; + } + + if (new_size != sink->size) { + sink->ptr = realloc(sink->ptr, new_size); + sink->size = new_size; + } + + memcpy(sink->ptr + sink->len, ptr, len); + sink->len += len; + + return len; +} + +void stringsink_init(stringsink *sink) { + upb_byteshandler_init(&sink->handler); + upb_byteshandler_setstartstr(&sink->handler, stringsink_start, NULL); + upb_byteshandler_setstring(&sink->handler, stringsink_string, NULL); + + upb_bytessink_reset(&sink->sink, &sink->handler, sink); + + sink->size = 32; + sink->ptr = malloc(sink->size); + sink->len = 0; +} + +void stringsink_uninit(stringsink *sink) { + free(sink->ptr); +} + // ----------------------------------------------------------------------------- // Parsing. // ----------------------------------------------------------------------------- @@ -613,6 +663,20 @@ static void add_handlers_for_oneof_field(upb_handlers *h, upb_handlerattr_uninit(&attr); } +static bool unknown_field_handler(void* closure, const void* hd, + const char* buf, size_t size) { + UPB_UNUSED(hd); + + MessageHeader* msg = (MessageHeader*)closure; + if (msg->unknown_fields == NULL) { + msg->unknown_fields = malloc(sizeof(stringsink)); + stringsink_init(msg->unknown_fields); + } + + stringsink_string(msg->unknown_fields, NULL, buf, size, NULL); + + return true; +} static void add_handlers_for_message(const void *closure, upb_handlers *h) { const upb_msgdef* msgdef = upb_handlers_msgdef(h); @@ -634,6 +698,9 @@ static void add_handlers_for_message(const void *closure, upb_handlers *h) { desc->layout = create_layout(desc->msgdef); } + upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER; + upb_handlers_setunknown(h, unknown_field_handler, &attr); + for (upb_msg_field_begin(&i, desc->msgdef); !upb_msg_field_done(&i); upb_msg_field_next(&i)) { @@ -831,65 +898,6 @@ VALUE Message_decode_json(VALUE klass, VALUE data) { // ----------------------------------------------------------------------------- // Serializing. // ----------------------------------------------------------------------------- -// -// The code below also comes from upb's prototype Ruby binding, developed by -// haberman@. - -/* stringsink *****************************************************************/ - -// This should probably be factored into a common upb component. - -typedef struct { - upb_byteshandler handler; - upb_bytessink sink; - char *ptr; - size_t len, size; -} stringsink; - -static void *stringsink_start(void *_sink, const void *hd, size_t size_hint) { - stringsink *sink = _sink; - sink->len = 0; - return sink; -} - -static size_t stringsink_string(void *_sink, const void *hd, const char *ptr, - size_t len, const upb_bufhandle *handle) { - stringsink *sink = _sink; - size_t new_size = sink->size; - - UPB_UNUSED(hd); - UPB_UNUSED(handle); - - while (sink->len + len > new_size) { - new_size *= 2; - } - - if (new_size != sink->size) { - sink->ptr = realloc(sink->ptr, new_size); - sink->size = new_size; - } - - memcpy(sink->ptr + sink->len, ptr, len); - sink->len += len; - - return len; -} - -void stringsink_init(stringsink *sink) { - upb_byteshandler_init(&sink->handler); - upb_byteshandler_setstartstr(&sink->handler, stringsink_start, NULL); - upb_byteshandler_setstring(&sink->handler, stringsink_string, NULL); - - upb_bytessink_reset(&sink->sink, &sink->handler, sink); - - sink->size = 32; - sink->ptr = malloc(sink->size); - sink->len = 0; -} - -void stringsink_uninit(stringsink *sink) { - free(sink->ptr); -} /* msgvisitor *****************************************************************/ @@ -1171,6 +1179,11 @@ static void putmsg(VALUE msg_rb, const Descriptor* desc, } } + stringsink* unknown = msg->unknown_fields; + if (unknown != NULL) { + upb_sink_putunknown(sink, unknown->ptr, unknown->len); + } + upb_sink_endmsg(sink, &status); } -- cgit v1.2.3