From a2bea0a0012b4adbc50c47246d968a85cb88cec2 Mon Sep 17 00:00:00 2001 From: Chris Fallin Date: Thu, 12 Feb 2015 16:08:01 -0800 Subject: Properly support maps in Ruby protoc and another bugfix. Previously, we supported map fields in the Ruby DSL. However, we never connected the final link in the chain and generated `map` DSL commands for map fields in `.proto` files. My apologies -- I had been testing with the DSL directly so I missed this. Also fixed a handlerdata-setup-infinite-loop when a map value field's type is its containing message. --- ruby/ext/google/protobuf_c/encode_decode.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) (limited to 'ruby/ext') diff --git a/ruby/ext/google/protobuf_c/encode_decode.c b/ruby/ext/google/protobuf_c/encode_decode.c index 0630f567..256fc829 100644 --- a/ruby/ext/google/protobuf_c/encode_decode.c +++ b/ruby/ext/google/protobuf_c/encode_decode.c @@ -208,7 +208,7 @@ typedef struct { size_t ofs; upb_fieldtype_t key_field_type; upb_fieldtype_t value_field_type; - VALUE value_field_typeclass; + const upb_def* value_field_subdef; } map_handlerdata_t; // Temporary frame for map parsing: at the beginning of a map entry message, a @@ -248,8 +248,15 @@ static bool endmap_handler(void *closure, const void *hd, upb_status* s) { VALUE key = native_slot_get( mapdata->key_field_type, Qnil, &frame->key_storage); + + VALUE value_field_typeclass = Qnil; + if (mapdata->value_field_type == UPB_TYPE_MESSAGE || + mapdata->value_field_type == UPB_TYPE_ENUM) { + value_field_typeclass = get_def_obj(mapdata->value_field_subdef); + } + VALUE value = native_slot_get( - mapdata->value_field_type, mapdata->value_field_typeclass, + mapdata->value_field_type, value_field_typeclass, &frame->value_storage); Map_index_set(frame->map, key, value); @@ -280,17 +287,7 @@ static map_handlerdata_t* new_map_handlerdata( MAP_VALUE_FIELD); assert(value_field != NULL); hd->value_field_type = upb_fielddef_type(value_field); - hd->value_field_typeclass = field_type_class(value_field); - - // Ensure that value_field_typeclass is properly GC-rooted. We must do this - // because we hold a reference to the Ruby class in the handlerdata, which is - // owned by the handlers. The handlers are owned by *this* message's Ruby - // object, but each Ruby object is rooted independently at the def -> Ruby - // object map. So we have to ensure that the Ruby objects we depend on will - // stick around as long as we're around. - if (hd->value_field_typeclass != Qnil) { - rb_ary_push(desc->typeclass_references, hd->value_field_typeclass); - } + hd->value_field_subdef = upb_fielddef_subdef(value_field); return hd; } -- cgit v1.2.3 From 315b93fdccd329a8492e6df8e06c7c305a678a5e Mon Sep 17 00:00:00 2001 From: Chris Fallin Date: Fri, 13 Feb 2015 14:32:09 -0800 Subject: Addressed code-review comment. --- ruby/ext/google/protobuf_c/encode_decode.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'ruby/ext') diff --git a/ruby/ext/google/protobuf_c/encode_decode.c b/ruby/ext/google/protobuf_c/encode_decode.c index 256fc829..5730504d 100644 --- a/ruby/ext/google/protobuf_c/encode_decode.c +++ b/ruby/ext/google/protobuf_c/encode_decode.c @@ -208,6 +208,10 @@ typedef struct { size_t ofs; upb_fieldtype_t key_field_type; upb_fieldtype_t value_field_type; + + // We know that we can hold this reference because the handlerdata has the + // same lifetime as the upb_handlers struct, and the upb_handlers struct holds + // a reference to the upb_msgdef, which in turn has references to its subdefs. const upb_def* value_field_subdef; } map_handlerdata_t; -- cgit v1.2.3