diff options
Diffstat (limited to 'ruby/ext/google/protobuf_c/encode_decode.c')
-rw-r--r-- | ruby/ext/google/protobuf_c/encode_decode.c | 88 |
1 files changed, 36 insertions, 52 deletions
diff --git a/ruby/ext/google/protobuf_c/encode_decode.c b/ruby/ext/google/protobuf_c/encode_decode.c index 08c72bcc..edbbe6a5 100644 --- a/ruby/ext/google/protobuf_c/encode_decode.c +++ b/ruby/ext/google/protobuf_c/encode_decode.c @@ -280,11 +280,6 @@ rb_data_type_t MapParseFrame_type = { { MapParseFrame_mark, MapParseFrame_free, NULL }, }; -// Array of Ruby objects wrapping map_parse_frame_t. -// We don't allow multiple concurrent decodes, so we assume that this global -// variable is specific to the "current" decode. -VALUE map_parse_frames; - static map_parse_frame_t* map_push_frame(VALUE map, const map_handlerdata_t* handlerdata) { map_parse_frame_t* frame = ALLOC(map_parse_frame_t); @@ -293,16 +288,12 @@ static map_parse_frame_t* map_push_frame(VALUE map, native_slot_init(handlerdata->key_field_type, &frame->key_storage); native_slot_init(handlerdata->value_field_type, &frame->value_storage); - rb_ary_push(map_parse_frames, + Map_set_frame(map, TypedData_Wrap_Struct(rb_cObject, &MapParseFrame_type, frame)); return frame; } -static void map_pop_frame() { - rb_ary_pop(map_parse_frames); -} - // Handler to begin a map entry: allocates a temporary frame. This is the // 'startsubmsg' handler on the msgdef that contains the map field. static void *startmapentry_handler(void *closure, const void *hd) { @@ -336,7 +327,7 @@ static bool endmap_handler(void *closure, const void *hd, upb_status* s) { &frame->value_storage); Map_index_set(frame->map, key, value); - map_pop_frame(); + Map_set_frame(frame->map, Qnil); return true; } @@ -514,7 +505,7 @@ static void add_handlers_for_singular_field(upb_handlers *h, case UPB_TYPE_INT64: case UPB_TYPE_UINT64: case UPB_TYPE_DOUBLE: - upb_shim_set(h, f, offset, -1); + upb_msg_setscalarhandler(h, f, offset, -1); break; case UPB_TYPE_STRING: case UPB_TYPE_BYTES: { @@ -775,10 +766,6 @@ VALUE Message_decode(VALUE klass, VALUE data) { msg_rb = rb_class_new_instance(0, NULL, msgklass); TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg); - // We generally expect this to be clear already, but clear it in case parsing - // previously got interrupted somehow. - rb_ary_clear(map_parse_frames); - { const upb_pbdecodermethod* method = msgdef_decodermethod(desc); const upb_handlers* h = upb_pbdecodermethod_desthandlers(method); @@ -823,10 +810,6 @@ VALUE Message_decode_json(VALUE klass, VALUE data) { msg_rb = rb_class_new_instance(0, NULL, msgklass); TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg); - // We generally expect this to be clear already, but clear it in case parsing - // previously got interrupted somehow. - rb_ary_clear(map_parse_frames); - { const upb_json_parsermethod* method = msgdef_jsonparsermethod(desc); stackenv se; @@ -914,18 +897,14 @@ void stringsink_uninit(stringsink *sink) { // semantics, which means that we have true field presence, we will want to // modify msgvisitor so that it emits all present fields rather than all // non-default-value fields. -// -// Likewise, when implementing JSON serialization, we may need to have a -// 'verbose' mode that outputs all fields and a 'concise' mode that outputs only -// those with non-default values. static void putmsg(VALUE msg, const Descriptor* desc, - upb_sink *sink, int depth); + upb_sink *sink, int depth, bool emit_defaults); static upb_selector_t getsel(const upb_fielddef *f, upb_handlertype_t type) { upb_selector_t ret; bool ok = upb_handlers_getselector(f, type, &ret); - UPB_ASSERT_VAR(ok, ok); + UPB_ASSERT(ok); return ret; } @@ -939,9 +918,9 @@ static void putstr(VALUE str, const upb_fielddef *f, upb_sink *sink) { // We should be guaranteed that the string has the correct encoding because // we ensured this at assignment time and then froze the string. if (upb_fielddef_type(f) == UPB_TYPE_STRING) { - assert(rb_enc_from_index(ENCODING_GET(value)) == kRubyStringUtf8Encoding); + assert(rb_enc_from_index(ENCODING_GET(str)) == kRubyStringUtf8Encoding); } else { - assert(rb_enc_from_index(ENCODING_GET(value)) == kRubyString8bitEncoding); + assert(rb_enc_from_index(ENCODING_GET(str)) == kRubyString8bitEncoding); } upb_sink_startstr(sink, getsel(f, UPB_HANDLER_STARTSTR), RSTRING_LEN(str), @@ -952,7 +931,7 @@ static void putstr(VALUE str, const upb_fielddef *f, upb_sink *sink) { } static void putsubmsg(VALUE submsg, const upb_fielddef *f, upb_sink *sink, - int depth) { + int depth, bool emit_defaults) { upb_sink subsink; VALUE descriptor; Descriptor* subdesc; @@ -963,12 +942,12 @@ static void putsubmsg(VALUE submsg, const upb_fielddef *f, upb_sink *sink, subdesc = ruby_to_Descriptor(descriptor); upb_sink_startsubmsg(sink, getsel(f, UPB_HANDLER_STARTSUBMSG), &subsink); - putmsg(submsg, subdesc, &subsink, depth + 1); + putmsg(submsg, subdesc, &subsink, depth + 1, emit_defaults); upb_sink_endsubmsg(sink, getsel(f, UPB_HANDLER_ENDSUBMSG)); } static void putary(VALUE ary, const upb_fielddef *f, upb_sink *sink, - int depth) { + int depth, bool emit_defaults) { upb_sink subsink; upb_fieldtype_t type = upb_fielddef_type(f); upb_selector_t sel = 0; @@ -1005,7 +984,7 @@ static void putary(VALUE ary, const upb_fielddef *f, upb_sink *sink, putstr(*((VALUE *)memory), f, &subsink); break; case UPB_TYPE_MESSAGE: - putsubmsg(*((VALUE *)memory), f, &subsink, depth); + putsubmsg(*((VALUE *)memory), f, &subsink, depth, emit_defaults); break; #undef T @@ -1019,7 +998,8 @@ static void put_ruby_value(VALUE value, const upb_fielddef *f, VALUE type_class, int depth, - upb_sink *sink) { + upb_sink *sink, + bool emit_defaults) { upb_selector_t sel = 0; if (upb_fielddef_isprimitive(f)) { sel = getsel(f, upb_handlers_getprimitivehandlertype(f)); @@ -1059,12 +1039,12 @@ static void put_ruby_value(VALUE value, putstr(value, f, sink); break; case UPB_TYPE_MESSAGE: - putsubmsg(value, f, sink, depth); + putsubmsg(value, f, sink, depth, emit_defaults); } } static void putmap(VALUE map, const upb_fielddef *f, upb_sink *sink, - int depth) { + int depth, bool emit_defaults) { Map* self; upb_sink subsink; const upb_fielddef* key_field; @@ -1090,9 +1070,9 @@ static void putmap(VALUE map, const upb_fielddef *f, upb_sink *sink, &entry_sink); upb_sink_startmsg(&entry_sink); - put_ruby_value(key, key_field, Qnil, depth + 1, &entry_sink); + put_ruby_value(key, key_field, Qnil, depth + 1, &entry_sink, emit_defaults); put_ruby_value(value, value_field, self->value_type_class, depth + 1, - &entry_sink); + &entry_sink, emit_defaults); upb_sink_endmsg(&entry_sink, &status); upb_sink_endsubmsg(&subsink, getsel(f, UPB_HANDLER_ENDSUBMSG)); @@ -1102,7 +1082,7 @@ static void putmap(VALUE map, const upb_fielddef *f, upb_sink *sink, } static void putmsg(VALUE msg_rb, const Descriptor* desc, - upb_sink *sink, int depth) { + upb_sink *sink, int depth, bool emit_defaults) { MessageHeader* msg; upb_msg_field_iter i; upb_status status; @@ -1144,31 +1124,31 @@ static void putmsg(VALUE msg_rb, const Descriptor* desc, if (is_map_field(f)) { VALUE map = DEREF(msg, offset, VALUE); - if (map != Qnil) { - putmap(map, f, sink, depth); + if (map != Qnil || emit_defaults) { + putmap(map, f, sink, depth, emit_defaults); } } else if (upb_fielddef_isseq(f)) { VALUE ary = DEREF(msg, offset, VALUE); if (ary != Qnil) { - putary(ary, f, sink, depth); + putary(ary, f, sink, depth, emit_defaults); } } else if (upb_fielddef_isstring(f)) { VALUE str = DEREF(msg, offset, VALUE); - if (is_matching_oneof || RSTRING_LEN(str) > 0) { + if (is_matching_oneof || emit_defaults || RSTRING_LEN(str) > 0) { putstr(str, f, sink); } } else if (upb_fielddef_issubmsg(f)) { - putsubmsg(DEREF(msg, offset, VALUE), f, sink, depth); + putsubmsg(DEREF(msg, offset, VALUE), f, sink, depth, emit_defaults); } else { upb_selector_t sel = getsel(f, upb_handlers_getprimitivehandlertype(f)); -#define T(upbtypeconst, upbtype, ctype, default_value) \ - case upbtypeconst: { \ - ctype value = DEREF(msg, offset, ctype); \ - if (is_matching_oneof || value != default_value) { \ - upb_sink_put##upbtype(sink, sel, value); \ - } \ - } \ +#define T(upbtypeconst, upbtype, ctype, default_value) \ + case upbtypeconst: { \ + ctype value = DEREF(msg, offset, ctype); \ + if (is_matching_oneof || emit_defaults || value != default_value) { \ + upb_sink_put##upbtype(sink, sel, value); \ + } \ + } \ break; switch (upb_fielddef_type(f)) { @@ -1246,7 +1226,7 @@ VALUE Message_encode(VALUE klass, VALUE msg_rb) { stackenv_init(&se, "Error occurred during encoding: %s"); encoder = upb_pb_encoder_create(&se.env, serialize_handlers, &sink.sink); - putmsg(msg_rb, desc, upb_pb_encoder_input(encoder), 0); + putmsg(msg_rb, desc, upb_pb_encoder_input(encoder), 0, false); ret = rb_str_new(sink.ptr, sink.len); @@ -1268,6 +1248,7 @@ VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) { Descriptor* desc = ruby_to_Descriptor(descriptor); VALUE msg_rb; VALUE preserve_proto_fieldnames = Qfalse; + VALUE emit_defaults = Qfalse; stringsink sink; if (argc < 1 || argc > 2) { @@ -1283,6 +1264,9 @@ VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) { } preserve_proto_fieldnames = rb_hash_lookup2( hash_args, ID2SYM(rb_intern("preserve_proto_fieldnames")), Qfalse); + + emit_defaults = rb_hash_lookup2( + hash_args, ID2SYM(rb_intern("emit_defaults")), Qfalse); } stringsink_init(&sink); @@ -1297,7 +1281,7 @@ VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) { stackenv_init(&se, "Error occurred during encoding: %s"); printer = upb_json_printer_create(&se.env, serialize_handlers, &sink.sink); - putmsg(msg_rb, desc, upb_json_printer_input(printer), 0); + putmsg(msg_rb, desc, upb_json_printer_input(printer), 0, RTEST(emit_defaults)); ret = rb_enc_str_new(sink.ptr, sink.len, rb_utf8_encoding()); |